Skip to content

Commit fc44eb9

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/stabilization'
2 parents 836d74a + c97b2b7 commit fc44eb9

8 files changed

Lines changed: 349 additions & 78 deletions

File tree

StyleCop.Analyzers/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
<ItemGroup>
4545
<PackageReference Include="AsyncUsageAnalyzers" Version="1.0.0-alpha003" PrivateAssets="all" />
4646
<PackageReference Include="DotNetAnalyzers.DocumentationAnalyzers" Version="1.0.0-beta.46" PrivateAssets="all" />
47-
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-rc.94" PrivateAssets="all" />
47+
<PackageReference Include="StyleCop.Analyzers" Version="1.1.1-rc.101" PrivateAssets="all" />
4848
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeStyle" Version="2.11.0-beta2-63603-03" PrivateAssets="all" />
4949
</ItemGroup>
5050

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1135CodeFixProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
6565
private static SyntaxNode GetReplacementNode(SemanticModel semanticModel, UsingDirectiveSyntax node, CancellationToken cancellationToken)
6666
{
6767
SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(node.Name, cancellationToken);
68-
var symbolNameSyntax = SyntaxFactory.ParseName(symbolInfo.Symbol.ToQualifiedString());
68+
var symbolNameSyntax = SyntaxFactory.ParseName(symbolInfo.Symbol.ToQualifiedString(node.Name));
6969

7070
var newName = GetReplacementName(symbolNameSyntax, node.Name);
7171
return node.WithName((NameSyntax)newName);

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/ReadabilityRules/SA1135CSharp7UnitTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,41 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp7.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.ReadabilityRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.ReadabilityRules.SA1135UsingDirectivesMustBeQualified,
13+
StyleCop.Analyzers.ReadabilityRules.SA1135CodeFixProvider>;
714

815
public class SA1135CSharp7UnitTests : SA1135UnitTests
916
{
17+
[Fact]
18+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
19+
public async Task TestTupleTypeInUsingAliasAsync()
20+
{
21+
var testCode = @"
22+
namespace TestNamespace
23+
{
24+
using Example = System.Collections.Generic.List<(int, int)>;
25+
}
26+
";
27+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
28+
}
29+
30+
[Fact]
31+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
32+
public async Task TestTupleTypeWithNamedElementsInUsingAliasAsync()
33+
{
34+
var testCode = @"
35+
namespace TestNamespace
36+
{
37+
using Example = System.Collections.Generic.List<(int x, int y)>;
38+
}
39+
";
40+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
41+
}
1042
}
1143
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1135UnitTests.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Test.ReadabilityRules
55
{
66
using System.Threading;
77
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis;
89
using Microsoft.CodeAnalysis.Testing;
910
using StyleCop.Analyzers.ReadabilityRules;
1011
using Xunit;
@@ -319,5 +320,100 @@ namespace MyNamespace {
319320

320321
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
321322
}
323+
324+
[Fact]
325+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
326+
public async Task TestOmittedTypeInGenericAsync()
327+
{
328+
var testCode = @"
329+
namespace TestNamespace
330+
{
331+
using Example = System.Collections.Generic.List<>;
332+
}
333+
";
334+
335+
var expected = new DiagnosticResult("CS7003", DiagnosticSeverity.Error).WithLocation(4, 48).WithMessage("Unexpected use of an unbound generic name");
336+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
337+
}
338+
339+
[Fact]
340+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
341+
public async Task TestNullableTypeInGenericAsync()
342+
{
343+
var testCode = @"
344+
namespace TestNamespace
345+
{
346+
using Example = System.Collections.Generic.List<int?>;
347+
}
348+
";
349+
350+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
351+
}
352+
353+
[Fact]
354+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
355+
public async Task TestGlobalQualifiedTypeInGenericAsync()
356+
{
357+
var testCode = @"
358+
namespace TestNamespace
359+
{
360+
using Example = System.Collections.Generic.List<global::System.Int32>;
361+
}
362+
";
363+
364+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
365+
}
366+
367+
[Fact]
368+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
369+
public async Task TestTypeInGlobalNamespaceAsync()
370+
{
371+
var testCode = @"
372+
namespace TestNamespace
373+
{
374+
using Example = MyClass;
375+
}
376+
377+
class MyClass
378+
{
379+
}
380+
";
381+
382+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
383+
}
384+
385+
[Fact]
386+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
387+
public async Task TestAliasTypeNestedInGenericAsync()
388+
{
389+
var testCode = @"
390+
namespace TestNamespace
391+
{
392+
using Example = System.Collections.Immutable.ImmutableDictionary<int, int>.Builder;
393+
}
394+
";
395+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
396+
}
397+
398+
[Fact]
399+
[WorkItem(2879, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2879")]
400+
public async Task TestValueTupleInUsingAliasAsync()
401+
{
402+
var testCode = @"
403+
namespace System
404+
{
405+
using Example = System.Collections.Generic.List<ValueTuple<int, int>>;
406+
}
407+
";
408+
var fixedCode = @"
409+
namespace System
410+
{
411+
using Example = System.Collections.Generic.List<System.ValueTuple<int, int>>;
412+
}
413+
";
414+
415+
var expected = Diagnostic(SA1135UsingDirectivesMustBeQualified.DescriptorType).WithLocation(4, 5).WithArguments("System.Collections.Generic.List<System.ValueTuple<int, int>>");
416+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
417+
}
322418
}
323419
}

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/SymbolNameHelpers.cs

Lines changed: 103 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace StyleCop.Analyzers.Helpers
55
{
66
using System.Text;
77
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp;
89
using Microsoft.CodeAnalysis.CSharp.Syntax;
910
using StyleCop.Analyzers.Lightup;
1011

@@ -17,83 +18,138 @@ internal static class SymbolNameHelpers
1718
private const string GenericTypeParametersClose = ">";
1819
private const string GenericSeparator = ", ";
1920

21+
private const string TupleTypeOpen = "(";
22+
private const string TupleTypeClose = ")";
23+
private const string TupleElementSeparator = ", ";
24+
2025
/// <summary>
2126
/// Generates the qualified name for the given symbol.
2227
/// </summary>
2328
/// <param name="symbol">The symbol to use.</param>
29+
/// <param name="name">The syntax node which resolves to the symbol.</param>
2430
/// <returns>The generated qualified name.</returns>
25-
public static string ToQualifiedString(this ISymbol symbol)
31+
public static string ToQualifiedString(this ISymbol symbol, NameSyntax name)
2632
{
2733
var builder = ObjectPools.StringBuilderPool.Allocate();
34+
AppendQualifiedSymbolName(builder, symbol, name);
35+
return ObjectPools.StringBuilderPool.ReturnAndFree(builder);
36+
}
2837

29-
if (symbol is INamedTypeSymbol namedTypeSymbol)
38+
private static bool AppendQualifiedSymbolName(StringBuilder builder, ISymbol symbol, TypeSyntax type)
39+
{
40+
switch (symbol.Kind)
3041
{
31-
if (SpecialTypeHelper.TryGetPredefinedType(namedTypeSymbol.SpecialType, out PredefinedTypeSyntax specialTypeSyntax))
42+
case SymbolKind.ArrayType:
43+
var arraySymbol = (IArrayTypeSymbol)symbol;
44+
AppendQualifiedSymbolName(builder, arraySymbol.ElementType, (type as ArrayTypeSyntax)?.ElementType);
45+
builder
46+
.Append("[")
47+
.Append(',', arraySymbol.Rank - 1)
48+
.Append("]");
49+
return true;
50+
51+
case SymbolKind.Namespace:
52+
var namespaceSymbol = (INamespaceSymbol)symbol;
53+
if (namespaceSymbol.IsGlobalNamespace)
3254
{
33-
return specialTypeSyntax.ToFullString();
55+
return false;
3456
}
3557

36-
if (namedTypeSymbol.IsTupleType())
58+
builder.Append(namespaceSymbol.ToDisplayString());
59+
return true;
60+
61+
case SymbolKind.NamedType:
62+
var namedTypeSymbol = (INamedTypeSymbol)symbol;
63+
if (SpecialTypeHelper.TryGetPredefinedType(namedTypeSymbol.SpecialType, out var specialTypeSyntax))
3764
{
38-
namedTypeSymbol = namedTypeSymbol.TupleUnderlyingType();
65+
builder.Append(specialTypeSyntax.ToFullString());
66+
return true;
3967
}
68+
else if (namedTypeSymbol.IsTupleType())
69+
{
70+
if (TupleTypeSyntaxWrapper.IsInstance(type))
71+
{
72+
var tupleType = (TupleTypeSyntaxWrapper)type;
73+
74+
builder.Append(TupleTypeOpen);
75+
var elements = namedTypeSymbol.TupleElements();
76+
for (int i = 0; i < elements.Length; i++)
77+
{
78+
var field = elements[i];
79+
var fieldType = tupleType.Elements.Count > i ? tupleType.Elements[i] : default;
4080

41-
AppendQualifiedSymbolName(builder, namedTypeSymbol);
81+
if (i > 0)
82+
{
83+
builder.Append(TupleElementSeparator);
84+
}
85+
86+
AppendQualifiedSymbolName(builder, field.Type, fieldType.Type);
87+
if (field != field.CorrespondingTupleField())
88+
{
89+
builder.Append(" ").Append(field.Name);
90+
}
91+
}
4292

43-
if (namedTypeSymbol.IsGenericType)
93+
builder.Append(TupleTypeClose);
94+
return true;
95+
}
96+
else
97+
{
98+
return AppendQualifiedSymbolName(builder, namedTypeSymbol.TupleUnderlyingType(), type);
99+
}
100+
}
101+
else if (namedTypeSymbol.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
102+
{
103+
AppendQualifiedSymbolName(builder, namedTypeSymbol.TypeArguments[0], (type as NullableTypeSyntax)?.ElementType);
104+
builder.Append("?");
105+
return true;
106+
}
107+
else
44108
{
45-
builder.Append(GenericTypeParametersOpen);
109+
if (AppendQualifiedSymbolName(builder, symbol.ContainingSymbol, (type as QualifiedNameSyntax)?.Left))
110+
{
111+
builder.Append(".");
112+
}
46113

47-
foreach (var typeArgument in namedTypeSymbol.TypeArguments)
114+
builder.Append(symbol.Name);
115+
if (namedTypeSymbol.IsGenericType && !namedTypeSymbol.TypeArguments.IsEmpty)
48116
{
49-
if (typeArgument is INamedTypeSymbol namedTypeArgument && typeArgument.IsTupleType())
50-
{
51-
builder.Append(namedTypeArgument.TupleUnderlyingType().ToQualifiedString());
52-
}
53-
else
117+
builder.Append(GenericTypeParametersOpen);
118+
var arguments = namedTypeSymbol.TypeArguments;
119+
var argumentTypes = type is QualifiedNameSyntax qualifiedName
120+
? (qualifiedName.Right as GenericNameSyntax)?.TypeArgumentList
121+
: (type as GenericNameSyntax)?.TypeArgumentList;
122+
123+
for (int i = 0; i < arguments.Length; i++)
54124
{
55-
builder.Append(typeArgument.ToQualifiedString());
125+
var argument = arguments[i];
126+
var argumentType = argumentTypes != null && argumentTypes.Arguments.Count > i ? argumentTypes.Arguments[i] : null;
127+
128+
if (i > 0)
129+
{
130+
builder.Append(GenericSeparator);
131+
}
132+
133+
if (!argumentType.IsKind(SyntaxKind.OmittedTypeArgument))
134+
{
135+
AppendQualifiedSymbolName(builder, argument, argumentType);
136+
}
56137
}
57138

58-
builder.Append(GenericSeparator);
139+
builder.Append(GenericTypeParametersClose);
59140
}
60141

61-
builder.Remove(builder.Length - GenericSeparator.Length, GenericSeparator.Length);
62-
builder.Append(GenericTypeParametersClose);
142+
return true;
63143
}
64-
}
65-
else
66-
{
67-
AppendQualifiedSymbolName(builder, symbol);
68-
}
69-
70-
return ObjectPools.StringBuilderPool.ReturnAndFree(builder);
71-
}
72-
73-
private static void AppendQualifiedSymbolName(StringBuilder builder, ISymbol symbol)
74-
{
75-
switch (symbol)
76-
{
77-
case IArrayTypeSymbol arraySymbol:
78-
builder
79-
.Append(arraySymbol.ElementType.ContainingNamespace.ToDisplayString())
80-
.Append(".")
81-
.Append(arraySymbol.ElementType.Name)
82-
.Append("[")
83-
.Append(',', arraySymbol.Rank - 1)
84-
.Append("]");
85-
break;
86144

87145
default:
88-
if (!symbol.ContainingNamespace.IsGlobalNamespace)
146+
if (symbol != null)
89147
{
90-
builder
91-
.Append(symbol.ContainingNamespace.ToDisplayString())
92-
.Append(".");
148+
builder.Append(symbol.Name);
149+
return true;
93150
}
94151

95-
builder.Append(symbol.Name);
96-
break;
152+
return false;
97153
}
98154
}
99155
}

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/CSharp7.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ See [dotnet/roslyn@c2af711](https://github.com/dotnet/roslyn/commit/c2af71127234
6161
* [ ] `Microsoft.CodeAnalysis.IArrayTypeSymbol.Sizes.get -> System.Collections.Immutable.ImmutableArray<int>`
6262
* [ ] `Microsoft.CodeAnalysis.IDiscardSymbol`
6363
* [ ] `Microsoft.CodeAnalysis.IDiscardSymbol.Type.get -> Microsoft.CodeAnalysis.ITypeSymbol`
64-
* [ ] `Microsoft.CodeAnalysis.IFieldSymbol.CorrespondingTupleField.get -> Microsoft.CodeAnalysis.IFieldSymbol`
64+
* [x] `Microsoft.CodeAnalysis.IFieldSymbol.CorrespondingTupleField.get -> Microsoft.CodeAnalysis.IFieldSymbol`
6565
* [ ] `Microsoft.CodeAnalysis.ILocalSymbol.IsRef.get -> bool`
6666
* [ ] `Microsoft.CodeAnalysis.IMethodSymbol.RefCustomModifiers.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.CustomModifier>`
6767
* [ ] `Microsoft.CodeAnalysis.IMethodSymbol.ReturnsByRef.get -> bool`
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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.Lightup
5+
{
6+
using System;
7+
using Microsoft.CodeAnalysis;
8+
9+
internal static class IFieldSymbolExtensions
10+
{
11+
private static readonly Func<IFieldSymbol, IFieldSymbol> CorrespondingTupleFieldAccessor;
12+
13+
static IFieldSymbolExtensions()
14+
{
15+
CorrespondingTupleFieldAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<IFieldSymbol, IFieldSymbol>(typeof(IFieldSymbol), nameof(CorrespondingTupleField));
16+
}
17+
18+
public static IFieldSymbol CorrespondingTupleField(this IFieldSymbol symbol)
19+
{
20+
return CorrespondingTupleFieldAccessor(symbol);
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)