Skip to content

Commit e8d9684

Browse files
committed
merge with master
2 parents 4434257 + 40fcf00 commit e8d9684

85 files changed

Lines changed: 5367 additions & 756 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/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/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

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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.MaintainabilityRules
5+
{
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Collections.Immutable;
9+
using System.Composition;
10+
using System.Linq;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
using Helpers;
14+
using Microsoft.CodeAnalysis;
15+
using Microsoft.CodeAnalysis.CodeActions;
16+
using Microsoft.CodeAnalysis.CodeFixes;
17+
using Microsoft.CodeAnalysis.CSharp;
18+
using Microsoft.CodeAnalysis.CSharp.Syntax;
19+
20+
/// <summary>
21+
/// Implements a code fix for <see cref="SA1413UseTrailingCommasInMultiLineInitializers"/>.
22+
/// </summary>
23+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SA1413CodeFixProvider))]
24+
[Shared]
25+
internal class SA1413CodeFixProvider : CodeFixProvider
26+
{
27+
/// <inheritdoc/>
28+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
29+
ImmutableArray.Create(SA1413UseTrailingCommasInMultiLineInitializers.DiagnosticId);
30+
31+
/// <inheritdoc/>
32+
public override FixAllProvider GetFixAllProvider()
33+
{
34+
return CustomFixAllProviders.BatchFixer;
35+
}
36+
37+
/// <inheritdoc/>
38+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
39+
{
40+
foreach (var diagnostic in context.Diagnostics)
41+
{
42+
context.RegisterCodeFix(
43+
CodeAction.Create(
44+
MaintainabilityResources.SA1413CodeFix,
45+
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
46+
nameof(SA1413CodeFixProvider)),
47+
diagnostic);
48+
}
49+
50+
return SpecializedTasks.CompletedTask;
51+
}
52+
53+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
54+
{
55+
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
56+
var parent = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).Parent;
57+
58+
SyntaxNode newParent = null;
59+
switch (parent.Kind())
60+
{
61+
case SyntaxKind.ObjectInitializerExpression:
62+
case SyntaxKind.ArrayInitializerExpression:
63+
case SyntaxKind.CollectionInitializerExpression:
64+
newParent = RewriteInitializer((InitializerExpressionSyntax)parent);
65+
break;
66+
67+
case SyntaxKind.AnonymousObjectCreationExpression:
68+
newParent = RewriteAnonymousObjectInitializer((AnonymousObjectCreationExpressionSyntax)parent);
69+
break;
70+
71+
default:
72+
throw new InvalidOperationException("Unknown initializer type: " + parent.Kind());
73+
}
74+
75+
var newSyntaxRoot = syntaxRoot.ReplaceNode(parent, newParent);
76+
77+
var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting());
78+
return newDocument;
79+
}
80+
81+
private static SyntaxNode RewriteInitializer(InitializerExpressionSyntax initializer)
82+
{
83+
var existingItems = new List<ExpressionSyntax>(initializer.Expressions);
84+
var last = existingItems.Last();
85+
existingItems.Remove(last);
86+
existingItems.Add(last.WithoutTrailingTrivia());
87+
88+
var existingSeparators = initializer.Expressions.GetSeparators();
89+
var newSeparators = new List<SyntaxToken>(existingSeparators);
90+
newSeparators.Add(SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(last.GetTrailingTrivia()));
91+
92+
var newInitializerExpressions = SyntaxFactory.SeparatedList(
93+
existingItems,
94+
newSeparators);
95+
96+
var fixedInitializer = initializer.WithExpressions(newInitializerExpressions);
97+
return fixedInitializer;
98+
}
99+
100+
private static SyntaxNode RewriteAnonymousObjectInitializer(AnonymousObjectCreationExpressionSyntax initializer)
101+
{
102+
var existingItems = new List<AnonymousObjectMemberDeclaratorSyntax>(initializer.Initializers);
103+
var last = existingItems.Last();
104+
existingItems.Remove(last);
105+
existingItems.Add(last.WithoutTrailingTrivia());
106+
107+
var existingSeparators = initializer.Initializers.GetSeparators();
108+
var newSeparators = new List<SyntaxToken>(existingSeparators);
109+
newSeparators.Add(SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(last.GetTrailingTrivia()));
110+
111+
var newInitializerExpressions = SyntaxFactory.SeparatedList(
112+
existingItems,
113+
newSeparators);
114+
115+
var fixedInitializer = initializer.WithInitializers(newInitializerExpressions);
116+
return fixedInitializer;
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)