Skip to content

Commit 97f435b

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/master' into fix-included-documentation
2 parents 72111ab + 1f6c929 commit 97f435b

63 files changed

Lines changed: 3521 additions & 429 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/SA1642SA1643CodeFixProvider.cs

Lines changed: 18 additions & 19 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;
@@ -61,7 +63,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
6163
context.RegisterCodeFix(
6264
CodeAction.Create(
6365
DocumentationResources.SA1642SA1643CodeFix,
64-
cancellationToken => GetTransformedDocumentAsync(context.Document, root, xmlElementSyntax),
66+
cancellationToken => GetTransformedDocumentAsync(context.Document, root, xmlElementSyntax, cancellationToken),
6567
nameof(SA1642SA1643CodeFixProvider)),
6668
diagnostic);
6769
}
@@ -78,11 +80,14 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
7880
}
7981
}
8082

81-
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)
8284
{
8385
var typeDeclaration = node.FirstAncestorOrSelf<BaseTypeDeclarationSyntax>();
8486
var declarationSyntax = node.FirstAncestorOrSelf<BaseMethodDeclarationSyntax>();
8587
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;
8691

8792
TypeParameterListSyntax typeParameterList;
8893
ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax;
@@ -98,35 +103,29 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
98103
ImmutableArray<string> standardText;
99104
if (declarationSyntax is ConstructorDeclarationSyntax)
100105
{
106+
var typeKindText = resourceManager.GetString(isStruct ? nameof(DocumentationResources.TypeTextStruct) : nameof(DocumentationResources.TypeTextClass), culture);
101107
if (declarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword))
102108
{
103-
if (isStruct)
104-
{
105-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " struct.");
106-
}
107-
else
108-
{
109-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.StaticConstructorStandardText, " class.");
110-
}
109+
standardText = ImmutableArray.Create(
110+
string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextFirstPart), culture), typeKindText),
111+
string.Format(resourceManager.GetString(nameof(DocumentationResources.StaticConstructorStandardTextSecondPart), culture), typeKindText));
111112
}
112113
else
113114
{
114115
// Prefer to insert the "non-private" wording for all constructors, even though both are considered
115116
// acceptable for private constructors by the diagnostic.
116117
// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/413
117-
if (isStruct)
118-
{
119-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " struct.");
120-
}
121-
else
122-
{
123-
standardText = ImmutableArray.Create(SA1642ConstructorSummaryDocumentationMustBeginWithStandardText.NonPrivateConstructorStandardText, " class.");
124-
}
118+
standardText = ImmutableArray.Create(
119+
string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextFirstPart), culture), typeKindText),
120+
string.Format(resourceManager.GetString(nameof(DocumentationResources.NonPrivateConstructorStandardTextSecondPart), culture), typeKindText));
125121
}
126122
}
127123
else if (declarationSyntax is DestructorDeclarationSyntax)
128124
{
129-
standardText = SA1643DestructorSummaryDocumentationMustBeginWithStandardText.DestructorStandardText;
125+
standardText =
126+
ImmutableArray.Create(
127+
resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextFirstPart), culture),
128+
resourceManager.GetString(nameof(DocumentationResources.DestructorStandardTextSecondPart), culture));
130129
}
131130
else
132131
{

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/MaintainabilityRules/SA1402CodeFixProvider.cs

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ namespace StyleCop.Analyzers.MaintainabilityRules
1616
using StyleCop.Analyzers.Helpers;
1717

1818
/// <summary>
19-
/// Implements a code fix for <see cref="SA1402FileMayOnlyContainASingleClass"/>.
19+
/// Implements a code fix for <see cref="SA1402FileMayOnlyContainASingleType"/>.
2020
/// </summary>
2121
/// <remarks>
22-
/// <para>To fix a violation of this rule, move each class into its own file.</para>
22+
/// <para>To fix a violation of this rule, move each type into its own file.</para>
2323
/// </remarks>
2424
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SA1402CodeFixProvider))]
2525
[Shared]
2626
internal class SA1402CodeFixProvider : CodeFixProvider
2727
{
2828
/// <inheritdoc/>
2929
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
30-
ImmutableArray.Create(SA1402FileMayOnlyContainASingleClass.DiagnosticId);
30+
ImmutableArray.Create(SA1402FileMayOnlyContainASingleType.DiagnosticId);
3131

3232
/// <inheritdoc/>
3333
public override FixAllProvider GetFixAllProvider()
@@ -56,32 +56,17 @@ private static async Task<Solution> GetTransformedSolutionAsync(Document documen
5656
{
5757
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
5858
SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
59-
BaseTypeDeclarationSyntax baseTypeDeclarationSyntax = node as BaseTypeDeclarationSyntax;
60-
DelegateDeclarationSyntax delegateDeclarationSyntax = node as DelegateDeclarationSyntax;
61-
if (baseTypeDeclarationSyntax == null && delegateDeclarationSyntax == null)
59+
var memberDeclarationSyntax = node as MemberDeclarationSyntax;
60+
if (memberDeclarationSyntax == null)
6261
{
6362
return document.Project.Solution;
6463
}
6564

6665
DocumentId extractedDocumentId = DocumentId.CreateNewId(document.Project.Id);
67-
string extractedDocumentName = baseTypeDeclarationSyntax.Identifier.ValueText;
68-
if (baseTypeDeclarationSyntax != null)
69-
{
70-
TypeDeclarationSyntax typeDeclarationSyntax = baseTypeDeclarationSyntax as TypeDeclarationSyntax;
71-
if (typeDeclarationSyntax?.TypeParameterList?.Parameters.Count > 0)
72-
{
73-
extractedDocumentName += "`" + typeDeclarationSyntax.TypeParameterList.Parameters.Count;
74-
}
75-
}
76-
else
77-
{
78-
if (delegateDeclarationSyntax.TypeParameterList?.Parameters.Count > 0)
79-
{
80-
extractedDocumentName += "`" + delegateDeclarationSyntax.TypeParameterList.Parameters.Count;
81-
}
82-
}
83-
84-
extractedDocumentName += ".cs";
66+
string suffix;
67+
FileNameHelpers.GetFileNameAndSuffix(document.Name, out suffix);
68+
var settings = document.Project.AnalyzerOptions.GetStyleCopSettings(cancellationToken);
69+
string extractedDocumentName = FileNameHelpers.GetConventionalFileName(memberDeclarationSyntax, settings.DocumentationRules.FileNamingConvention) + suffix;
8570

8671
List<SyntaxNode> nodesToRemoveFromExtracted = new List<SyntaxNode>();
8772
SyntaxNode previous = node;
@@ -111,8 +96,8 @@ private static async Task<Solution> GetTransformedSolutionAsync(Document documen
11196
}
11297
}
11398

99+
// Add the new file
114100
SyntaxNode extractedDocumentNode = root.RemoveNodes(nodesToRemoveFromExtracted, SyntaxRemoveOptions.KeepUnbalancedDirectives);
115-
116101
Solution updatedSolution = document.Project.Solution.AddDocument(extractedDocumentId, extractedDocumentName, extractedDocumentNode, document.Folders);
117102

118103
// Make sure to also add the file to linked projects
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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.Linq;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Helpers;
13+
using Microsoft.CodeAnalysis;
14+
using Microsoft.CodeAnalysis.CodeActions;
15+
using Microsoft.CodeAnalysis.CodeFixes;
16+
using Microsoft.CodeAnalysis.CSharp;
17+
using Microsoft.CodeAnalysis.CSharp.Syntax;
18+
using Microsoft.CodeAnalysis.Text;
19+
20+
/// <summary>
21+
/// Implements a code fix for <see cref="SA1139UseLiteralSuffixNotationInsteadOfCasting"/>.
22+
/// </summary>
23+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(SA1139CodeFixProvider))]
24+
[Shared]
25+
internal class SA1139CodeFixProvider : CodeFixProvider
26+
{
27+
private static readonly Dictionary<SyntaxKind, string> LiteralSyntaxKindToSuffix = new Dictionary<SyntaxKind, string>()
28+
{
29+
{ SyntaxKind.IntKeyword, string.Empty },
30+
{ SyntaxKind.LongKeyword, "L" },
31+
{ SyntaxKind.ULongKeyword, "UL" },
32+
{ SyntaxKind.UIntKeyword, "U" },
33+
{ SyntaxKind.FloatKeyword, "F" },
34+
{ SyntaxKind.DoubleKeyword, "D" },
35+
{ SyntaxKind.DecimalKeyword, "M" }
36+
};
37+
38+
private static readonly char[] LettersAllowedInLiteralSuffix = LiteralSyntaxKindToSuffix.Values
39+
.SelectMany(s => s.ToCharArray()).Distinct()
40+
.SelectMany(c => new[] { char.ToLowerInvariant(c), c })
41+
.ToArray();
42+
43+
/// <inheritdoc/>
44+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
45+
ImmutableArray.Create(SA1139UseLiteralSuffixNotationInsteadOfCasting.DiagnosticId);
46+
47+
/// <inheritdoc/>
48+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
49+
{
50+
foreach (var diagnostic in context.Diagnostics)
51+
{
52+
context.RegisterCodeFix(
53+
CodeAction.Create(
54+
ReadabilityResources.SA1139CodeFix,
55+
cancellationToken => GetTransformedDocumentAsync(context.Document, diagnostic, cancellationToken),
56+
nameof(SA1139CodeFixProvider)),
57+
diagnostic);
58+
}
59+
60+
return SpecializedTasks.CompletedTask;
61+
}
62+
63+
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
64+
{
65+
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
66+
var oldSemanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
67+
68+
var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) as CastExpressionSyntax;
69+
if (node == null)
70+
{
71+
return document;
72+
}
73+
74+
var replacementNode = GenerateReplacementNode(node);
75+
var newSyntaxRoot = syntaxRoot.ReplaceNode(node, replacementNode);
76+
var newDocument = document.WithSyntaxRoot(newSyntaxRoot);
77+
var newSemanticModel = await newDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
78+
var newNode = newSemanticModel.SyntaxTree.GetRoot().FindNode(
79+
span: new TextSpan(start: node.FullSpan.Start, length: replacementNode.FullSpan.Length),
80+
getInnermostNodeForTie: true);
81+
82+
var oldConstantValue = oldSemanticModel.GetConstantValue(node).Value;
83+
var newConstantValueOption = newSemanticModel.GetConstantValue(newNode, cancellationToken);
84+
if (newConstantValueOption.HasValue && oldConstantValue.Equals(newConstantValueOption.Value))
85+
{
86+
return newDocument;
87+
}
88+
else
89+
{
90+
var newNodeBasedOnValue = GenerateReplacementNodeBasedOnValue(node, oldConstantValue);
91+
newSyntaxRoot = syntaxRoot.ReplaceNode(node, newNodeBasedOnValue);
92+
return document.WithSyntaxRoot(newSyntaxRoot);
93+
}
94+
}
95+
96+
private static SyntaxNode GenerateReplacementNode(CastExpressionSyntax node)
97+
{
98+
var plusMinusSyntax = node.Expression as PrefixUnaryExpressionSyntax;
99+
var literalExpressionSyntax =
100+
plusMinusSyntax == null ?
101+
(LiteralExpressionSyntax)node.Expression :
102+
(LiteralExpressionSyntax)plusMinusSyntax.Operand;
103+
var typeToken = node.Type.GetFirstToken();
104+
var prefix = plusMinusSyntax == null
105+
? string.Empty
106+
: plusMinusSyntax.OperatorToken.Text;
107+
var literalWithoutSuffix = literalExpressionSyntax.StripLiteralSuffix();
108+
var correspondingSuffix = LiteralSyntaxKindToSuffix[typeToken.Kind()];
109+
var fixedCodePreservingText = SyntaxFactory.ParseExpression(prefix + literalWithoutSuffix + correspondingSuffix);
110+
111+
return fixedCodePreservingText.WithTriviaFrom(node);
112+
}
113+
114+
private static SyntaxNode GenerateReplacementNodeBasedOnValue(CastExpressionSyntax node, object desiredValue)
115+
{
116+
var typeToken = node.Type.GetFirstToken();
117+
var correspondingSuffix = LiteralSyntaxKindToSuffix[typeToken.Kind()];
118+
var fixedCodePreservingText = SyntaxFactory.ParseExpression(desiredValue + correspondingSuffix);
119+
120+
return fixedCodePreservingText.WithTriviaFrom(node);
121+
}
122+
}
123+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
<Compile Include="ReadabilityRules\SA1133CodeFixProvider.cs" />
134134
<Compile Include="ReadabilityRules\SA1134CodeFixProvider.cs" />
135135
<Compile Include="ReadabilityRules\SA1136CodeFixProvider.cs" />
136+
<Compile Include="ReadabilityRules\SA1139CodeFixProvider.cs" />
136137
<Compile Include="ReadabilityRules\SX1101CodeFixProvider.cs" />
137138
<Compile Include="Settings\SettingsFileCodeFixProvider.cs" />
138139
<Compile Include="SpacingRules\SA1003CodeFixProvider.cs" />

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/StyleCop.Analyzers.nuspec

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
<!-- Binaries and symbols -->
2121
<file src="bin\$Configuration$\StyleCop.Analyzers.dll" target="analyzers\dotnet\cs" />
22+
<file src="bin\$Configuration$\**\StyleCop.Analyzers.resources.dll" target="analyzers\dotnet\cs" />
2223
<file src="bin\$Configuration$\StyleCop.Analyzers.pdb" target="analyzers\dotnet\cs" />
2324
<file src="bin\$Configuration$\StyleCop.Analyzers.CodeFixes.dll" target="analyzers\dotnet\cs" />
25+
<file src="bin\$Configuration$\**\StyleCop.Analyzers.CodeFixes.resources.dll" target="analyzers\dotnet\cs" />
2426
<file src="bin\$Configuration$\StyleCop.Analyzers.CodeFixes.pdb" target="analyzers\dotnet\cs" />
2527
<file src="..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll" target="analyzers\dotnet\cs" />
2628

0 commit comments

Comments
 (0)