Skip to content

Commit 9f0707c

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/master' into fix-1745
2 parents 399028f + 95acc4e commit 9f0707c

32 files changed

Lines changed: 1094 additions & 190 deletions

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1518CodeFixProvider.cs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ namespace StyleCop.Analyzers.LayoutRules
55
{
66
using System.Collections.Immutable;
77
using System.Composition;
8-
using System.Linq;
98
using System.Threading;
109
using System.Threading.Tasks;
1110
using Helpers;
1211
using Microsoft.CodeAnalysis;
1312
using Microsoft.CodeAnalysis.CodeActions;
1413
using Microsoft.CodeAnalysis.CodeFixes;
15-
using Microsoft.CodeAnalysis.CSharp;
14+
using Microsoft.CodeAnalysis.Text;
15+
using Settings.ObjectModel;
1616

1717
/// <summary>
1818
/// Implements a code fix for <see cref="SA1518CodeMustNotContainBlankLinesAtEndOfFile"/>.
@@ -28,50 +28,61 @@ internal class SA1518CodeFixProvider : CodeFixProvider
2828
/// <inheritdoc/>
2929
public override FixAllProvider GetFixAllProvider()
3030
{
31-
return CustomFixAllProviders.BatchFixer;
31+
return FixAll.Instance;
3232
}
3333

3434
/// <inheritdoc/>
3535
public override Task RegisterCodeFixesAsync(CodeFixContext context)
3636
{
37-
foreach (Diagnostic diagnostic in context.Diagnostics)
37+
var settings = SettingsHelper.GetStyleCopSettings(context.Document.Project.AnalyzerOptions, context.CancellationToken);
38+
foreach (var diagnostic in context.Diagnostics)
3839
{
3940
context.RegisterCodeFix(
4041
CodeAction.Create(
4142
LayoutResources.SA1518CodeFix,
42-
cancellationToken => GetTransformedDocumentAsync(context.Document, cancellationToken),
43+
cancellationToken => FixEndOfFileAsync(context.Document, diagnostic, settings.LayoutRules.NewlineAtEndOfFile, cancellationToken),
4344
nameof(SA1518CodeFixProvider)),
4445
diagnostic);
4546
}
4647

4748
return SpecializedTasks.CompletedTask;
4849
}
4950

50-
private static async Task<Document> GetTransformedDocumentAsync(Document document, CancellationToken token)
51+
/// <summary>
52+
/// Fixes the whitespace at the end of a document.
53+
/// </summary>
54+
/// <param name="document">The document to be changed.</param>
55+
/// <param name="diagnostic">The diagnostic to fix.</param>
56+
/// <param name="newlineAtEndOfFile">A <see cref="EndOfFileHandling"/> value indicating the desired behavior.</param>
57+
/// <param name="cancellationToken">The cancellation token associated with the fix action.</param>
58+
/// <returns>The transformed document.</returns>
59+
private static async Task<Document> FixEndOfFileAsync(Document document, Diagnostic diagnostic, EndOfFileHandling newlineAtEndOfFile, CancellationToken cancellationToken)
5160
{
52-
var syntaxRoot = await document.GetSyntaxRootAsync(token).ConfigureAwait(false);
53-
54-
var lastToken = syntaxRoot.GetLastToken(includeZeroWidth: true);
55-
56-
var newLastToken = StripViolatingWhitespace(lastToken);
57-
var newSyntaxRoot = syntaxRoot.ReplaceToken(lastToken, newLastToken);
58-
var newDocument = document.WithSyntaxRoot(newSyntaxRoot);
59-
60-
return newDocument;
61+
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
62+
string replacement = newlineAtEndOfFile == EndOfFileHandling.Omit ? string.Empty : "\r\n";
63+
return document.WithText(text.WithChanges(new TextChange(diagnostic.Location.SourceSpan, replacement)));
6164
}
6265

63-
private static SyntaxToken StripViolatingWhitespace(SyntaxToken token)
66+
private class FixAll : DocumentBasedFixAllProvider
6467
{
65-
SyntaxToken result = token;
68+
public static FixAllProvider Instance { get; } =
69+
new FixAll();
6670

67-
var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(token.LeadingTrivia);
68-
if (trailingWhitespaceIndex != -1)
71+
protected override string CodeActionTitle =>
72+
LayoutResources.SA1518CodeFix;
73+
74+
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document)
6975
{
70-
var newTriviaList = SyntaxFactory.TriviaList(token.LeadingTrivia.Take(trailingWhitespaceIndex));
71-
result = token.WithLeadingTrivia(newTriviaList);
72-
}
76+
var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false);
77+
if (diagnostics.IsEmpty)
78+
{
79+
return null;
80+
}
7381

74-
return result;
82+
var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, fixAllContext.CancellationToken);
83+
Document updatedDocument = await FixEndOfFileAsync(document, diagnostics[0], settings.LayoutRules.NewlineAtEndOfFile, fixAllContext.CancellationToken).ConfigureAwait(false);
84+
return await updatedDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
85+
}
7586
}
7687
}
7788
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/UsingCodeFixProvider.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
7474
{
7575
var compilationUnit = (CompilationUnitSyntax)syntaxRoot;
7676

77+
var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken);
7778
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
7879
var indentationOptions = IndentationOptions.FromDocument(document);
7980

80-
var usingsHelper = new UsingsHelper(semanticModel, document, compilationUnit);
81+
var usingsHelper = new UsingsHelper(settings, semanticModel, document, compilationUnit);
8182
var namespaceCount = CountNamespaces(compilationUnit.Members);
8283

8384
// Only move using declarations inside the namespace when
@@ -436,15 +437,17 @@ public DirectiveSpan FindContainingSpan(SyntaxNode node)
436437

437438
private class UsingsHelper
438439
{
440+
private readonly StyleCopSettings settings;
439441
private readonly SemanticModel semanticModel;
440442
private readonly DirectiveSpan conditionalDirectiveTree;
441443
private readonly bool separateSystemDirectives;
442444

443-
public UsingsHelper(SemanticModel semanticModel, Document document, CompilationUnitSyntax compilationUnit)
445+
public UsingsHelper(StyleCopSettings settings, SemanticModel semanticModel, Document document, CompilationUnitSyntax compilationUnit)
444446
{
447+
this.settings = settings;
445448
this.semanticModel = semanticModel;
446449
this.conditionalDirectiveTree = DirectiveSpan.BuildConditionalDirectiveTree(compilationUnit);
447-
this.separateSystemDirectives = !document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1208SystemUsingDirectivesMustBePlacedBeforeOtherUsingDirectives.DiagnosticId);
450+
this.separateSystemDirectives = settings.OrderingRules.SystemUsingDirectivesFirst;
448451

449452
this.ProcessUsingDirectives(compilationUnit.Usings);
450453
this.ProcessMembers(compilationUnit.Members);
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.ReadabilityRules
5+
{
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Composition;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Helpers;
12+
using Microsoft.CodeAnalysis;
13+
using Microsoft.CodeAnalysis.CodeActions;
14+
using Microsoft.CodeAnalysis.CodeFixes;
15+
using Microsoft.CodeAnalysis.CSharp;
16+
using Microsoft.CodeAnalysis.CSharp.Syntax;
17+
18+
/// <summary>
19+
/// Implements a code fix for <see cref="SA1133DoNotCombineAttributes"/>.
20+
/// </summary>
21+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SA1133CodeFixProvider))]
22+
[Shared]
23+
internal class SA1133CodeFixProvider : CodeFixProvider
24+
{
25+
/// <inheritdoc/>
26+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
27+
ImmutableArray.Create(SA1133DoNotCombineAttributes.DiagnosticId);
28+
29+
/// <inheritdoc/>
30+
public override FixAllProvider GetFixAllProvider()
31+
{
32+
return CustomFixAllProviders.BatchFixer;
33+
}
34+
35+
/// <inheritdoc/>
36+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
37+
{
38+
foreach (var diagnostic in context.Diagnostics)
39+
{
40+
context.RegisterCodeFix(
41+
CodeAction.Create(
42+
ReadabilityResources.SA1133CodeFix,
43+
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
44+
nameof(SA1133CodeFixProvider)),
45+
diagnostic);
46+
}
47+
48+
return SpecializedTasks.CompletedTask;
49+
}
50+
51+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
52+
{
53+
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
54+
var violatingAttribute = (AttributeSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan).Parent;
55+
var attributeList = (AttributeListSyntax)violatingAttribute.Parent;
56+
var newAttributeLists = new List<AttributeListSyntax>();
57+
58+
var indentationOptions = IndentationOptions.FromDocument(document);
59+
var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, attributeList);
60+
var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps);
61+
62+
for (var i = 0; i < attributeList.Attributes.Count; i++)
63+
{
64+
var newAttributes = SyntaxFactory.SingletonSeparatedList(attributeList.Attributes[i]);
65+
var newAttributeList = SyntaxFactory.AttributeList(attributeList.Target, newAttributes);
66+
67+
newAttributeList = (i == 0)
68+
? newAttributeList.WithLeadingTrivia(attributeList.GetLeadingTrivia())
69+
: newAttributeList.WithLeadingTrivia(indentationTrivia);
70+
71+
newAttributeList = (i == (attributeList.Attributes.Count - 1))
72+
? newAttributeList.WithTrailingTrivia(attributeList.GetTrailingTrivia())
73+
: newAttributeList.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);
74+
75+
newAttributeLists.Add(newAttributeList);
76+
}
77+
78+
var newSyntaxRoot = syntaxRoot.ReplaceNode(attributeList, newAttributeLists);
79+
var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting());
80+
81+
return newDocument;
82+
}
83+
}
84+
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.CodeFixes.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
<Compile Include="ReadabilityRules\SA1129CodeFixProvider.cs" />
128128
<Compile Include="ReadabilityRules\SA1131CodeFixProvider.cs" />
129129
<Compile Include="ReadabilityRules\SA1132CodeFixProvider.cs" />
130+
<Compile Include="ReadabilityRules\SA1133CodeFixProvider.cs" />
130131
<Compile Include="ReadabilityRules\SX1101CodeFixProvider.cs" />
131132
<Compile Include="Settings\SettingsFileCodeFixProvider.cs" />
132133
<Compile Include="SpacingRules\SA1003CodeFixProvider.cs" />

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1623UnitTests.cs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,43 @@ public class SA1623UnitTests : CodeFixVerifier
2020
/// <summary>
2121
/// Verifies that property documentation that does not start with the appropriate text will result in a diagnostic.
2222
/// </summary>
23+
/// <param name="accessibility">The accessibility of the property.</param>
2324
/// <param name="type">The type to use for the property.</param>
2425
/// <param name="accessors">The accessors for the property.</param>
2526
/// <param name="expectedArgument">The expected argument for the diagnostic message.</param>
2627
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
2728
[Theory]
28-
[InlineData("int", "{ get; set; }", "Gets or sets")]
29-
[InlineData("int", "{ get; }", "Gets")]
30-
[InlineData("int", "{ get; private set; }", "Gets")]
31-
[InlineData("int", "{ set { } }", "Sets")]
32-
[InlineData("int", "{ private get { return 0; } set { } }", "Sets")]
33-
[InlineData("bool", "{ get; set; }", "Gets or sets a value indicating whether")]
34-
[InlineData("bool", "{ get; }", "Gets a value indicating whether")]
35-
[InlineData("bool", "{ get; private set; }", "Gets a value indicating whether")]
36-
[InlineData("bool", "{ set { } }", "Sets a value indicating whether")]
37-
[InlineData("bool", "{ private get { return false; } set { } }", "Sets a value indicating whether")]
38-
public async Task VerifyDocumentationWithWrongStartingTextWillProduceDiagnosticAsync(string type, string accessors, string expectedArgument)
29+
[InlineData("public", "int", "{ get; set; }", "Gets or sets")]
30+
[InlineData("public", "int", "{ get; protected set; }", "Gets or sets")]
31+
[InlineData("public", "int", "{ get; protected internal set; }", "Gets or sets")]
32+
[InlineData("public", "int", "{ get; internal set; }", "Gets")]
33+
[InlineData("public", "int", "{ get; private set; }", "Gets")]
34+
[InlineData("public", "int", "{ get; }", "Gets")]
35+
[InlineData("public", "int", "{ set { } }", "Sets")]
36+
[InlineData("public", "int", "{ internal get { return 0; } set { } }", "Sets")]
37+
[InlineData("public", "int", "{ private get { return 0; } set { } }", "Sets")]
38+
[InlineData("public", "bool", "{ get; set; }", "Gets or sets a value indicating whether")]
39+
[InlineData("public", "bool", "{ get; }", "Gets a value indicating whether")]
40+
[InlineData("public", "bool", "{ get; private set; }", "Gets a value indicating whether")]
41+
[InlineData("public", "bool", "{ set { } }", "Sets a value indicating whether")]
42+
[InlineData("public", "bool", "{ private get { return false; } set { } }", "Sets a value indicating whether")]
43+
[InlineData("protected", "int", "{ get; private set; }", "Gets")]
44+
[InlineData("protected", "int", "{ private get { return 0; } set { } }", "Sets")]
45+
[InlineData("protected internal", "int", "{ get; internal set; }", "Gets")]
46+
[InlineData("protected internal", "int", "{ get; private set; }", "Gets")]
47+
[InlineData("protected internal", "int", "{ internal get { return 0; } set { } }", "Sets")]
48+
[InlineData("protected internal", "int", "{ private get { return 0; } set { } }", "Sets")]
49+
[InlineData("internal", "int", "{ get; private set; }", "Gets")]
50+
[InlineData("internal", "int", "{ private get { return 0; } set { } }", "Sets")]
51+
public async Task VerifyDocumentationWithWrongStartingTextWillProduceDiagnosticAsync(string accessibility, string type, string accessors, string expectedArgument)
3952
{
4053
var testCode = $@"
4154
public class TestClass
4255
{{
4356
/// <summary>
4457
/// The first test value.
4558
/// </summary>
46-
public {type} TestProperty {accessors}
59+
{accessibility} {type} TestProperty {accessors}
4760
}}
4861
";
4962

@@ -53,11 +66,11 @@ public class TestClass
5366
/// <summary>
5467
/// {expectedArgument} the first test value.
5568
/// </summary>
56-
public {type} TestProperty {accessors}
69+
{accessibility} {type} TestProperty {accessors}
5770
}}
5871
";
5972

60-
var expected = this.CSharpDiagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor).WithLocation(7, 13 + type.Length).WithArguments(expectedArgument);
73+
var expected = this.CSharpDiagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor).WithLocation(7, 7 + accessibility.Length + type.Length).WithArguments(expectedArgument);
6174

6275
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
6376
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);

0 commit comments

Comments
 (0)