Skip to content

Commit 0973688

Browse files
committed
Merge branch 'master'
2 parents bfc3e48 + 7d97301 commit 0973688

54 files changed

Lines changed: 1933 additions & 187 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/FileHeaderCodeFixProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
6666
private static async Task<Document> GetTransformedDocumentAsync(Document document, CancellationToken cancellationToken)
6767
{
6868
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
69-
var settings = document.Project.AnalyzerOptions.GetStyleCopSettings();
69+
var settings = document.Project.AnalyzerOptions.GetStyleCopSettings(cancellationToken);
7070

7171
var fileHeader = FileHeaderHelpers.ParseFileHeader(root);
7272
SyntaxNode newSyntaxRoot;

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/IndentationHelper.cs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Helpers
55
{
66
using Microsoft.CodeAnalysis;
77
using Microsoft.CodeAnalysis.CSharp;
8+
using StyleCop.Analyzers.Helpers.ObjectPools;
89

910
/// <summary>
1011
/// Provides helper methods to work with indentation.
@@ -43,7 +44,7 @@ public static SyntaxToken GetFirstTokenOnTextLine(SyntaxToken token)
4344
/// <returns>The number of steps that the node is indented.</returns>
4445
public static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxNode node)
4546
{
46-
return GetIndentationSteps(indentationOptions, node.GetLeadingTrivia());
47+
return GetIndentationSteps(indentationOptions, node.SyntaxTree, node.GetLeadingTrivia());
4748
}
4849

4950
/// <summary>
@@ -54,7 +55,7 @@ public static int GetIndentationSteps(IndentationOptions indentationOptions, Syn
5455
/// <returns>The number of steps that the token is indented.</returns>
5556
public static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxToken token)
5657
{
57-
return GetIndentationSteps(indentationOptions, token.LeadingTrivia);
58+
return GetIndentationSteps(indentationOptions, token.SyntaxTree, token.LeadingTrivia);
5859
}
5960

6061
/// <summary>
@@ -92,25 +93,38 @@ public static SyntaxTrivia GenerateWhitespaceTrivia(IndentationOptions indentati
9293
return SyntaxFactory.Whitespace(GenerateIndentationString(indentationOptions, indentationSteps));
9394
}
9495

95-
private static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxTriviaList leadingTrivia)
96+
private static int GetIndentationSteps(IndentationOptions indentationOptions, SyntaxTree syntaxTree, SyntaxTriviaList leadingTrivia)
9697
{
97-
SyntaxTriviaList.Reversed reversed = leadingTrivia.Reverse();
98-
int indentationCount = 0;
98+
var triviaSpan = syntaxTree.GetLineSpan(leadingTrivia.FullSpan);
9999

100-
foreach (SyntaxTrivia trivia in reversed)
100+
// There is no indentation when the leading trivia doesn't begin at the start of the line.
101+
if ((triviaSpan.StartLinePosition == triviaSpan.EndLinePosition) && (triviaSpan.StartLinePosition.Character > 0))
102+
{
103+
return 0;
104+
}
105+
106+
var builder = StringBuilderPool.Allocate();
107+
108+
foreach (SyntaxTrivia trivia in leadingTrivia.Reverse())
101109
{
102110
if (!trivia.IsKind(SyntaxKind.WhitespaceTrivia))
103111
{
104112
break;
105113
}
106114

107-
foreach (char c in trivia.ToFullString())
108-
{
109-
indentationCount += c == '\t' ? indentationOptions.TabSize : 1;
110-
}
115+
builder.Insert(0, trivia.ToFullString());
111116
}
112117

113-
return indentationCount / indentationOptions.IndentationSize;
118+
var tabSize = indentationOptions.TabSize;
119+
var indentationCount = 0;
120+
for (var i = 0; i < builder.Length; i++)
121+
{
122+
indentationCount += builder[i] == '\t' ? tabSize - (indentationCount % tabSize) : 1;
123+
}
124+
125+
StringBuilderPool.ReturnAndFree(builder);
126+
127+
return (indentationCount + (indentationOptions.IndentationSize / 2)) / indentationOptions.IndentationSize;
114128
}
115129
}
116130
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ private static SyntaxNode ReAddFileHeader(SyntaxNode syntaxRoot, SyntaxNode newS
154154
}
155155

156156
var newFirstToken = newSyntaxRoot.GetFirstToken();
157-
return newSyntaxRoot.ReplaceToken(newFirstToken, newFirstToken.WithLeadingTrivia(fileHeader));
157+
var newLeadingTrivia = newFirstToken.LeadingTrivia.InsertRange(0, fileHeader);
158+
return newSyntaxRoot.ReplaceToken(newFirstToken, newFirstToken.WithLeadingTrivia(newLeadingTrivia));
158159
}
159160

160161
private static int CountNamespaces(SyntaxList<MemberDeclarationSyntax> members)

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1120CodeFixProvider.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
8888

8989
private static bool TriviaHasLeadingContentOnLine(SyntaxNode root, SyntaxTrivia commentTrivia)
9090
{
91+
if (commentTrivia.SpanStart == 0)
92+
{
93+
// It is impossible to have leading content at the start of the file.
94+
return false;
95+
}
96+
9197
var nodeBeforeStart = commentTrivia.SpanStart - 1;
9298
var nodeBefore = root.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(nodeBeforeStart, 1));
9399

@@ -96,6 +102,12 @@ private static bool TriviaHasLeadingContentOnLine(SyntaxNode root, SyntaxTrivia
96102

97103
private static bool TriviaHasTrailingContentOnLine(SyntaxNode root, SyntaxTrivia commentTrivia)
98104
{
105+
if (commentTrivia.Span.End == root.Span.End)
106+
{
107+
// It is impossible to have trailing content at the end of the file.
108+
return false;
109+
}
110+
99111
var nodeAfterTriviaStart = commentTrivia.Span.End + 1;
100112
var nodeAfterTrivia = root.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(nodeAfterTriviaStart, 1));
101113

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1600UnitTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ public async Task TestRegressionMethodGlobalNamespaceAsync(string code, int colu
3333

3434
var expected = new[]
3535
{
36-
this.CSharpDiagnostic().WithLocation(4, column),
3736
new DiagnosticResult
3837
{
3938
Id = "CS0116",
4039
Severity = DiagnosticSeverity.Error,
4140
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 4, column) },
4241
Message = "A namespace cannot directly contain members such as fields or methods"
43-
}
42+
},
43+
this.CSharpDiagnostic().WithLocation(4, column)
4444
};
4545

4646
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public class ClassName
142142
/// </summary>
143143
public ##
144144
}";
145-
var expected = new[]
145+
DiagnosticResult[] expected =
146146
{
147147
this.CSharpDiagnostic().WithLocation(10, 38).WithArguments("param1"),
148148
this.CSharpDiagnostic().WithLocation(10, 53).WithArguments("param2"),
@@ -152,6 +152,83 @@ public class ClassName
152152
await this.VerifyCSharpDiagnosticAsync(testCode.Replace("##", p), expected, CancellationToken.None).ConfigureAwait(false);
153153
}
154154

155+
/// <summary>
156+
/// Verifies that valid operator declarations will not produce diagnostics.
157+
/// </summary>
158+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
159+
[Fact]
160+
public async Task VerifyValidOperatorDeclarationsAsync()
161+
{
162+
var testCode = @"
163+
/// <summary>
164+
/// Test class
165+
/// </summary>
166+
public class TestClass
167+
{
168+
/// <summary>
169+
/// Foo
170+
/// </summary>
171+
/// <param name=""value"">The value to use.</param>
172+
public static TestClass operator +(TestClass value)
173+
{
174+
return value;
175+
}
176+
177+
/// <summary>
178+
/// Foo
179+
/// </summary>
180+
/// <param name=""value"">The value to use.</param>
181+
public static explicit operator TestClass(int value)
182+
{
183+
return new TestClass();
184+
}
185+
}
186+
";
187+
188+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
189+
}
190+
191+
/// <summary>
192+
/// Verifies that invalid operator declarations will produce the expected diagnostics.
193+
/// </summary>
194+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
195+
[Fact]
196+
public async Task VerifyInvalidOperatorDeclarationsAsync()
197+
{
198+
var testCode = @"
199+
/// <summary>
200+
/// Test class
201+
/// </summary>
202+
public class TestClass
203+
{
204+
/// <summary>
205+
/// Foo
206+
/// </summary>
207+
public static TestClass operator +(TestClass value)
208+
{
209+
return value;
210+
}
211+
212+
/// <summary>
213+
/// Foo
214+
/// </summary>
215+
public static explicit operator TestClass(int value)
216+
{
217+
return new TestClass();
218+
}
219+
}
220+
";
221+
222+
DiagnosticResult[] expected =
223+
{
224+
this.CSharpDiagnostic().WithLocation(10, 50).WithArguments("value"),
225+
this.CSharpDiagnostic().WithLocation(18, 51).WithArguments("value")
226+
};
227+
228+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
229+
}
230+
231+
/// <inheritdoc/>
155232
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
156233
{
157234
yield return new SA1611ElementParametersMustBeDocumented();

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1648UnitTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ public async Task TestTypeWithEmptyBaseListAsync(string declaration)
8181
[InlineData("string this [string f] { get { return f; } }")]
8282
[InlineData("event System.Action foo;")]
8383
[InlineData("event System.Action Foo { add { } remove { } }")]
84+
[InlineData("~Test() { }")]
85+
[InlineData("public static Test operator +(Test value) { return value; }")]
86+
[InlineData("public static explicit operator Test(int value) { return new Test(); }")]
8487
public async Task TestMemberThatShouldNotHaveInheritDocAsync(string declaration)
8588
{
8689
var testCode = @"class Test

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1649UnitTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ public async Task VerifyStyleCopNamingConventionForGenericTypeAsync(string typeK
169169

170170
var expectedDiagnostic = this.CSharpDiagnostic().WithLocation("TestType`3.cs", 3, 13 + typeKeyword.Length);
171171
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostic, CancellationToken.None, "TestType`3.cs").ConfigureAwait(false);
172+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, "TestType.cs").ConfigureAwait(false);
172173
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, "TestType{T1,T2,T3}.cs").ConfigureAwait(false);
173174
await this.VerifyRenameAsync(testCode, "TestType{T1,T2,T3}.cs", CancellationToken.None).ConfigureAwait(false);
174175
}
@@ -194,6 +195,9 @@ public async Task VerifyMetadataNamingConventionForGenericTypeAsync(string typeK
194195

195196
var expectedDiagnostic = this.CSharpDiagnostic().WithLocation("TestType{T1,T2,T3}.cs", 3, 13 + typeKeyword.Length);
196197
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostic, CancellationToken.None, "TestType{T1,T2,T3}.cs").ConfigureAwait(false);
198+
199+
expectedDiagnostic = this.CSharpDiagnostic().WithLocation("TestType.cs", 3, 13 + typeKeyword.Length);
200+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostic, CancellationToken.None, "TestType.cs").ConfigureAwait(false);
197201
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None, "TestType`3.cs").ConfigureAwait(false);
198202
await this.VerifyRenameAsync(testCode, "TestType`3.cs", CancellationToken.None).ConfigureAwait(false);
199203
}

0 commit comments

Comments
 (0)