Skip to content

Commit 6003510

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/master' into implement-1787
2 parents ea8f0c6 + 4da56fd commit 6003510

207 files changed

Lines changed: 13458 additions & 1974 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: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace StyleCop.Analyzers.DocumentationRules
55
{
66
using System;
7+
using System.Collections.Generic;
78
using System.Collections.Immutable;
89
using System.Composition;
910
using System.Text;
@@ -18,6 +19,7 @@ namespace StyleCop.Analyzers.DocumentationRules
1819
using Microsoft.CodeAnalysis.Formatting;
1920
using StyleCop.Analyzers.Helpers;
2021
using StyleCop.Analyzers.Settings.ObjectModel;
22+
using Path = System.IO.Path;
2123

2224
/// <summary>
2325
/// Implements a code fix for file header diagnostics.
@@ -136,8 +138,9 @@ private static SyntaxNode ReplaceWellFormedMultiLineCommentHeader(Document docum
136138
// Pad line that used to be next to a /*
137139
triviaStringParts[0] = commentIndentation + interlinePadding + " " + triviaStringParts[0];
138140
StringBuilder sb = StringBuilderPool.Allocate();
141+
string fileName = Path.GetFileName(document.FilePath);
139142
var copyrightText = commentIndentation + interlinePadding + " " +
140-
GetCopyrightText(commentIndentation + interlinePadding, settings.DocumentationRules.CopyrightText, newLineText);
143+
GetCopyrightText(commentIndentation + interlinePadding, settings.DocumentationRules.GetCopyrightText(fileName), newLineText);
141144
var newHeader = WrapInXmlComment(commentIndentation + interlinePadding, copyrightText, document.Name, settings, newLineText);
142145

143146
sb.Append(commentIndentation);
@@ -212,6 +215,9 @@ private static SyntaxNode ReplaceHeader(Document document, SyntaxNode root, Styl
212215
var leadingSpaces = string.Empty;
213216
string possibleLeadingSpaces = string.Empty;
214217

218+
// remove header decoration lines, they will be re-generated
219+
trivia = RemoveHeaderDecorationLines(trivia, settings);
220+
215221
// Need to do this with index so we get the line endings correct.
216222
for (int i = 0; i < trivia.Count; i++)
217223
{
@@ -350,31 +356,71 @@ private static SyntaxNode AddHeader(Document document, SyntaxNode root, string n
350356
return root.WithLeadingTrivia(newTrivia);
351357
}
352358

353-
private static SyntaxTriviaList CreateNewHeader(string prefixWithLeadingSpaces, string filename, StyleCopSettings settings, string newLineText)
359+
private static SyntaxTriviaList CreateNewHeader(string prefixWithLeadingSpaces, string fileName, StyleCopSettings settings, string newLineText)
354360
{
355-
var copyrightText = prefixWithLeadingSpaces + " " + GetCopyrightText(prefixWithLeadingSpaces, settings.DocumentationRules.CopyrightText, newLineText);
361+
var copyrightText = prefixWithLeadingSpaces + " " + GetCopyrightText(prefixWithLeadingSpaces, settings.DocumentationRules.GetCopyrightText(fileName), newLineText);
356362
var newHeader = settings.DocumentationRules.XmlHeader
357-
? WrapInXmlComment(prefixWithLeadingSpaces, copyrightText, filename, settings, newLineText)
363+
? WrapInXmlComment(prefixWithLeadingSpaces, copyrightText, fileName, settings, newLineText)
358364
: copyrightText;
359365
return SyntaxFactory.ParseLeadingTrivia(newHeader);
360366
}
361367

362-
private static string WrapInXmlComment(string prefixWithLeadingSpaces, string copyrightText, string filename, StyleCopSettings settings, string newLineText)
368+
private static string WrapInXmlComment(string prefixWithLeadingSpaces, string copyrightText, string fileName, StyleCopSettings settings, string newLineText)
363369
{
364-
string encodedFilename = new XAttribute("t", filename).ToString().Substring(2).Trim('"');
370+
string encodedFilename = new XAttribute("t", fileName).ToString().Substring(2).Trim('"');
365371
string encodedCompanyName = new XAttribute("t", settings.DocumentationRules.CompanyName).ToString().Substring(2).Trim('"');
366372
string encodedCopyrightText = new XText(copyrightText).ToString();
367373

368-
return
374+
string copyrightString =
369375
$"{prefixWithLeadingSpaces} <copyright file=\"{encodedFilename}\" company=\"{encodedCompanyName}\">" + newLineText
370376
+ encodedCopyrightText + newLineText
371377
+ prefixWithLeadingSpaces + " </copyright>";
378+
379+
if (!string.IsNullOrEmpty(settings.DocumentationRules.HeaderDecoration))
380+
{
381+
return
382+
$"{prefixWithLeadingSpaces} {settings.DocumentationRules.HeaderDecoration}" + newLineText
383+
+ copyrightString + newLineText
384+
+ $"{prefixWithLeadingSpaces} {settings.DocumentationRules.HeaderDecoration}";
385+
}
386+
387+
return copyrightString;
372388
}
373389

374390
private static string GetCopyrightText(string prefixWithLeadingSpaces, string copyrightText, string newLineText)
375391
{
376392
copyrightText = copyrightText.Replace("\r\n", "\n");
377393
return string.Join(newLineText + prefixWithLeadingSpaces + " ", copyrightText.Split('\n')).Replace(prefixWithLeadingSpaces + " " + newLineText, prefixWithLeadingSpaces + newLineText);
378394
}
395+
396+
private static SyntaxTriviaList RemoveHeaderDecorationLines(SyntaxTriviaList trivia, StyleCopSettings settings)
397+
{
398+
if (!string.IsNullOrEmpty(settings.DocumentationRules.HeaderDecoration))
399+
{
400+
var decorationRemovalList = new List<int>();
401+
for (int i = 0; i < trivia.Count; i++)
402+
{
403+
var triviaLine = trivia[i];
404+
if (triviaLine.Kind() == SyntaxKind.SingleLineCommentTrivia && triviaLine.ToFullString().Contains(settings.DocumentationRules.HeaderDecoration))
405+
{
406+
decorationRemovalList.Add(i);
407+
408+
// also remove the line break
409+
if (i + 1 < trivia.Count && trivia[i + 1].Kind() == SyntaxKind.EndOfLineTrivia)
410+
{
411+
decorationRemovalList.Add(i + 1);
412+
}
413+
}
414+
}
415+
416+
// Remove decoration lines in reverse order.
417+
for (int i = decorationRemovalList.Count - 1; i >= 0; i--)
418+
{
419+
trivia = trivia.RemoveAt(decorationRemovalList[i]);
420+
}
421+
}
422+
423+
return trivia;
424+
}
379425
}
380426
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1609SA1610CodeFixProvider.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
4444
{
4545
foreach (var diagnostic in context.Diagnostics)
4646
{
47-
context.RegisterCodeFix(
48-
CodeAction.Create(
49-
DocumentationResources.SA1609SA1610CodeFix,
50-
cancellationToken => this.GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
51-
nameof(SA1609SA1610CodeFixProvider)),
52-
diagnostic);
47+
if (!diagnostic.Properties.ContainsKey(PropertyDocumentationBase.NoCodeFixKey))
48+
{
49+
context.RegisterCodeFix(
50+
CodeAction.Create(
51+
DocumentationResources.SA1609SA1610CodeFix,
52+
cancellationToken => this.GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
53+
nameof(SA1609SA1610CodeFixProvider)),
54+
diagnostic);
55+
}
5356
}
5457

5558
return SpecializedTasks.CompletedTask;

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1615SA1616CodeFixProvider.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
7575
DocumentationCommentTriviaSyntax documentationComment =
7676
methodDeclarationSyntax?.GetDocumentationCommentTriviaSyntax()
7777
?? delegateDeclarationSyntax?.GetDocumentationCommentTriviaSyntax();
78-
if (documentationComment == null)
78+
bool canIgnoreDocumentation =
79+
documentationComment == null
80+
|| documentationComment.Content
81+
.Where(x => x is XmlElementSyntax || x is XmlEmptyElementSyntax)
82+
.All(x => string.Equals(x.GetName()?.ToString(), XmlCommentHelper.IncludeXmlTag));
83+
84+
if (canIgnoreDocumentation)
7985
{
8086
return document;
8187
}

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1617CodeFixProvider.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,15 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
3939
{
4040
foreach (Diagnostic diagnostic in context.Diagnostics)
4141
{
42-
context.RegisterCodeFix(
43-
CodeAction.Create(
44-
DocumentationResources.SA1617CodeFix,
45-
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
46-
nameof(SA1617CodeFixProvider)),
47-
diagnostic);
42+
if (!diagnostic.Properties.ContainsKey(SA1617VoidReturnValueMustNotBeDocumented.NoCodeFixKey))
43+
{
44+
context.RegisterCodeFix(
45+
CodeAction.Create(
46+
DocumentationResources.SA1617CodeFix,
47+
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
48+
nameof(SA1617CodeFixProvider)),
49+
diagnostic);
50+
}
4851
}
4952

5053
return SpecializedTasks.CompletedTask;

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1642SA1643CodeFixProvider.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ namespace StyleCop.Analyzers.DocumentationRules
66
using System;
77
using System.Collections.Immutable;
88
using System.Composition;
9+
using System.Globalization;
910
using System.Linq;
1011
using System.Text.RegularExpressions;
12+
using System.Threading;
1113
using System.Threading.Tasks;
1214
using Helpers;
1315
using Microsoft.CodeAnalysis;
@@ -48,16 +50,20 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
4850

4951
foreach (var diagnostic in context.Diagnostics)
5052
{
51-
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
53+
if (diagnostic.Properties.ContainsKey(StandardTextDiagnosticBase.NoCodeFixKey))
54+
{
55+
continue;
56+
}
5257

58+
var node = root.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
5359
var xmlElementSyntax = node as XmlElementSyntax;
5460

5561
if (xmlElementSyntax != null)
5662
{
5763
context.RegisterCodeFix(
5864
CodeAction.Create(
5965
DocumentationResources.SA1642SA1643CodeFix,
60-
cancellationToken => GetTransformedDocumentAsync(context.Document, root, xmlElementSyntax),
66+
cancellationToken => GetTransformedDocumentAsync(context.Document, root, xmlElementSyntax, cancellationToken),
6167
nameof(SA1642SA1643CodeFixProvider)),
6268
diagnostic);
6369
}
@@ -74,11 +80,14 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
7480
}
7581
}
7682

77-
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node)
83+
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node, CancellationToken cancellationToken)
7884
{
7985
var typeDeclaration = node.FirstAncestorOrSelf<BaseTypeDeclarationSyntax>();
8086
var declarationSyntax = node.FirstAncestorOrSelf<BaseMethodDeclarationSyntax>();
8187
bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration);
88+
var settings = document.Project.AnalyzerOptions.GetStyleCopSettings(cancellationToken);
89+
var culture = new CultureInfo(settings.DocumentationRules.DocumentationCulture);
90+
var resourceManager = DocumentationResources.ResourceManager;
8291

8392
TypeParameterListSyntax typeParameterList;
8493
ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax;
@@ -94,35 +103,29 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
94103
ImmutableArray<string> standardText;
95104
if (declarationSyntax is ConstructorDeclarationSyntax)
96105
{
106+
var typeKindText = resourceManager.GetString(isStruct ? nameof(DocumentationResources.TypeTextStruct) : nameof(DocumentationResources.TypeTextClass), culture);
97107
if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword))
98108
{
99-
if (isStruct)
100-
{
101-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " struct.");
102-
}
103-
else
104-
{
105-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " class.");
106-
}
109+
standardText = ImmutableArray.Create(
110+
string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextFirstPart), culture), typeKindText),
111+
string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextSecondPart), culture), typeKindText));
107112
}
108113
else
109114
{
110115
// Prefer to insert the "non-private" wording for all constructors, even though both are considered
111116
// acceptable for private constructors by the diagnostic.
112117
// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/413
113-
if (isStruct)
114-
{
115-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " struct.");
116-
}
117-
else
118-
{
119-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " class.");
120-
}
118+
standardText = ImmutableArray.Create(
119+
string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextFirstPart), culture), typeKindText),
120+
string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextSecondPart), culture), typeKindText));
121121
}
122122
}
123123
else if (declarationSyntax is DestructorDeclarationSyntax)
124124
{
125-
standardText = SA1643DestructorSummaryDocumentationMustBeginWithStandardText.DestructorStandardText;
125+
standardText =
126+
ImmutableArray.Create(
127+
resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextFirstPart), culture),
128+
resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextSecondPart), culture));
126129
}
127130
else
128131
{

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1651CodeFixProvider.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
4444
{
4545
foreach (var diagnostic in context.Diagnostics)
4646
{
47+
if (diagnostic.Properties.ContainsKey(SA1651DoNotUsePlaceholderElements.NoCodeFixKey))
48+
{
49+
// skip diagnostics that should not offer a code fix.
50+
continue;
51+
}
52+
4753
var documentRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
4854
SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan, findInsideTrivia: true, getInnermostNodeForTie: true);
4955
if (syntax == null)

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/RenameHelper.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ public static async Task<bool> IsValidNewMemberNameAsync(SemanticModel semanticM
5252

5353
var containingSymbol = symbol.ContainingSymbol;
5454

55+
if (symbol.Kind == SymbolKind.TypeParameter)
56+
{
57+
// If the symbol is a type parameter, the name can't be the same as any type parameters of the containing type.
58+
var parentSymbol = containingSymbol?.ContainingSymbol as INamedTypeSymbol;
59+
if (parentSymbol != null
60+
&& parentSymbol.TypeParameters.Any(t => t.Name == name))
61+
{
62+
return false;
63+
}
64+
65+
// Move up one level for the next validation step.
66+
containingSymbol = containingSymbol?.ContainingSymbol;
67+
}
68+
5569
var containingNamespaceOrTypeSymbol = containingSymbol as INamespaceOrTypeSymbol;
5670
if (containingNamespaceOrTypeSymbol != null)
5771
{

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/MaintainabilityRules/SA1119CodeFixProvider.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,18 @@ private static SyntaxNode GetReplacement(ParenthesizedExpressionSyntax oldNode)
6767
var leadingTrivia = SyntaxFactory.TriviaList(oldNode.OpenParenToken.GetAllTrivia().Concat(oldNode.Expression.GetLeadingTrivia()));
6868
var trailingTrivia = oldNode.Expression.GetTrailingTrivia().AddRange(oldNode.CloseParenToken.GetAllTrivia());
6969

70+
// Workaround for Roslyn not handling elastic markers for directive trivia correctly.
71+
if (!leadingTrivia.Any())
72+
{
73+
var previousToken = oldNode.OpenParenToken.GetPreviousToken();
74+
if (TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia) == -1)
75+
{
76+
leadingTrivia = SyntaxFactory.TriviaList(SyntaxFactory.Space);
77+
}
78+
}
79+
7080
return oldNode.Expression
71-
.WithLeadingTrivia(leadingTrivia.Any() ? leadingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker))
81+
.WithLeadingTrivia(leadingTrivia)
7282
.WithTrailingTrivia(trailingTrivia.Any() ? trailingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));
7383
}
7484

0 commit comments

Comments
 (0)