Skip to content

Commit 33a2929

Browse files
authored
Merge pull request #3678 from bjornhellander/feature/global-using-alias-3
Update SA1121 and SA1404 to detect global using aliases, using GetImportScopes and compiling expression trees
2 parents 7cc41e2 + 6fd4e67 commit 33a2929

File tree

21 files changed

+857
-41
lines changed

21 files changed

+857
-41
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp10.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.CSharp9.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp10UnitTests : IImportScopeWrapperCSharp9UnitTests
9+
{
10+
}
11+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp11.Lightup
5+
{
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Microsoft.CodeAnalysis;
12+
using Microsoft.CodeAnalysis.CSharp;
13+
using Microsoft.CodeAnalysis.Text;
14+
using StyleCop.Analyzers.Lightup;
15+
using StyleCop.Analyzers.Test.CSharp10.Lightup;
16+
using StyleCop.Analyzers.Test.Verifiers;
17+
using Xunit;
18+
19+
public partial class IImportScopeWrapperCSharp11UnitTests : IImportScopeWrapperCSharp10UnitTests
20+
{
21+
[Theory]
22+
[InlineData(1)]
23+
[InlineData(2)]
24+
public async Task TestCompatibleInstanceAsync(int numberOfAliasSymbols)
25+
{
26+
var obj = await CreateImportScopeAsync(numberOfAliasSymbols, CancellationToken.None).ConfigureAwait(false);
27+
Assert.True(IImportScopeWrapper.IsInstance(obj));
28+
var wrapper = IImportScopeWrapper.FromObject(obj);
29+
Assert.Equal(obj.Aliases, wrapper.Aliases);
30+
}
31+
32+
private static async Task<IImportScope> CreateImportScopeAsync(int numberOfAliasSymbols, CancellationToken cancellationToken)
33+
{
34+
var aliasDirectives = new List<string>(numberOfAliasSymbols);
35+
for (var i = 0; i < numberOfAliasSymbols; i++)
36+
{
37+
aliasDirectives.Add($"global using Alias{i} = System.String;");
38+
}
39+
40+
var source = string.Join(Environment.NewLine, aliasDirectives);
41+
if (source.Length > 0)
42+
{
43+
source += Environment.NewLine;
44+
}
45+
46+
source += @"
47+
namespace TestNamespace
48+
{
49+
public class TestClass
50+
{
51+
}
52+
}
53+
";
54+
55+
var workspace = GenericAnalyzerTest.CreateWorkspace();
56+
var projectId = ProjectId.CreateNewId();
57+
58+
var references = await GenericAnalyzerTest.ReferenceAssemblies
59+
.ResolveAsync(LanguageNames.CSharp, cancellationToken).ConfigureAwait(false);
60+
61+
var solution = workspace.CurrentSolution
62+
.AddProject(projectId, "TestProject", "TestProject", LanguageNames.CSharp)
63+
.WithProjectCompilationOptions(projectId, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
64+
.WithProjectParseOptions(projectId, new CSharpParseOptions(LanguageVersionEx.CSharp11))
65+
.AddMetadataReferences(projectId, references);
66+
67+
var documentId = DocumentId.CreateNewId(projectId);
68+
solution = solution.AddDocument(documentId, "Test.cs", SourceText.From(source));
69+
70+
var project = solution.GetProject(projectId)!;
71+
var compilation = (await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!;
72+
var syntaxTree = compilation.SyntaxTrees.Single();
73+
var semanticModel = compilation.GetSemanticModel(syntaxTree);
74+
var importScopes = semanticModel.GetImportScopes(syntaxTree.Length, cancellationToken);
75+
76+
var result = importScopes.FirstOrDefault(scope => scope.Aliases.Length == numberOfAliasSymbols);
77+
if (result == null)
78+
{
79+
throw new InvalidOperationException("Could not create an import scope with the expected number of alias symbols.");
80+
}
81+
82+
return result;
83+
}
84+
}
85+
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1404CSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.MaintainabilityRules;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
11+
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.MaintainabilityRules.SA1404CodeAnalysisSuppressionMustHaveJustification,
14+
StyleCop.Analyzers.MaintainabilityRules.SA1404CodeFixProvider>;
715

816
public partial class SA1404CSharp11UnitTests : SA1404CSharp10UnitTests
917
{
18+
// NOTE: This tests a fix for a c# 10 feature, but the Roslyn API used to solve it wasn't available in the version
19+
// we use in the c# 10 test project, so the test was added here instead.
20+
[Fact]
21+
[WorkItem(3594, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3594")]
22+
public async Task TestUsingNameChangeInGlobalUsingInAnotherFileAsync()
23+
{
24+
var testCode1 = @"
25+
global using MySuppressionAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;";
26+
27+
var testCode2 = @"
28+
public class Foo
29+
{
30+
[[|MySuppression(null, null)|]]
31+
public void Bar()
32+
{
33+
34+
}
35+
}";
36+
37+
var fixedCode2 = @"
38+
public class Foo
39+
{
40+
[MySuppression(null, null, Justification = """ + SA1404CodeAnalysisSuppressionMustHaveJustification.JustificationPlaceholder + @""")]
41+
public void Bar()
42+
{
43+
44+
}
45+
}";
46+
47+
await new CSharpTest()
48+
{
49+
TestSources = { testCode1, testCode2 },
50+
FixedSources = { testCode1, fixedCode2 },
51+
RemainingDiagnostics =
52+
{
53+
Diagnostic().WithLocation("/0/Test1.cs", 4, 32),
54+
},
55+
NumberOfIncrementalIterations = 2,
56+
NumberOfFixAllIterations = 2,
57+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
58+
}
1059
}
1160
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/ReadabilityRules/SA1121CSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.CSharp10.ReadabilityRules;
9+
using Xunit;
10+
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.ReadabilityRules.SA1121UseBuiltInTypeAlias,
13+
StyleCop.Analyzers.ReadabilityRules.SA1121CodeFixProvider>;
714

815
public partial class SA1121CSharp11UnitTests : SA1121CSharp10UnitTests
916
{
17+
// NOTE: This tests a fix for a c# 10 feature, but the Roslyn API used to solve it wasn't available in the version
18+
// we use in the c# 10 test project, so the test was added here instead.
19+
[Fact]
20+
[WorkItem(3594, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3594")]
21+
public async Task TestUsingNameChangeInGlobalUsingInAnotherFileAsync()
22+
{
23+
var source1 = @"
24+
global using MyDouble = System.Double;";
25+
26+
var oldSource2 = @"
27+
class TestClass
28+
{
29+
private [|MyDouble|] x;
30+
}";
31+
32+
var newSource2 = @"
33+
class TestClass
34+
{
35+
private double x;
36+
}";
37+
38+
await new CSharpTest()
39+
{
40+
TestSources = { source1, oldSource2 },
41+
FixedSources = { source1, newSource2 },
42+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
43+
}
44+
45+
[Fact]
46+
[WorkItem(3594, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3594")]
47+
public async Task TestUsingNameChangeInGlobalUsingInSameFileAsync()
48+
{
49+
var source = @"global using MyDouble = System.Double;
50+
class TestClass
51+
{
52+
private [|MyDouble|] x;
53+
}";
54+
55+
var newSource = @"global using MyDouble = System.Double;
56+
class TestClass
57+
{
58+
private double x;
59+
}";
60+
61+
await new CSharpTest()
62+
{
63+
TestSources = { source },
64+
FixedSources = { newSource },
65+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
66+
}
1067
}
1168
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp12.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.CSharp11.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp12UnitTests : IImportScopeWrapperCSharp11UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp13.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.CSharp12.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp13UnitTests : IImportScopeWrapperCSharp12UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp7.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp7UnitTests : IImportScopeWrapperUnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp8.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.CSharp7.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp8UnitTests : IImportScopeWrapperCSharp7UnitTests
9+
{
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.CSharp9.Lightup
5+
{
6+
using StyleCop.Analyzers.Test.CSharp8.Lightup;
7+
8+
public partial class IImportScopeWrapperCSharp9UnitTests : IImportScopeWrapperCSharp8UnitTests
9+
{
10+
}
11+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.Lightup
5+
{
6+
using System;
7+
using StyleCop.Analyzers.Lightup;
8+
using Xunit;
9+
10+
public class IImportScopeWrapperUnitTests
11+
{
12+
[Fact]
13+
public void TestNull()
14+
{
15+
object? obj = null;
16+
Assert.False(IImportScopeWrapper.IsInstance(obj!));
17+
var wrapper = IImportScopeWrapper.FromObject(obj!);
18+
Assert.Throws<NullReferenceException>(() => wrapper.Aliases);
19+
}
20+
21+
[Fact]
22+
public void TestIncompatibleInstance()
23+
{
24+
var obj = new object();
25+
Assert.False(IImportScopeWrapper.IsInstance(obj));
26+
Assert.Throws<InvalidCastException>(() => IImportScopeWrapper.FromObject(obj));
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)