Skip to content

Commit 53f05c6

Browse files
authored
MSTEST0024: Do not store TestContext in static members (#2597)
1 parent 03a0054 commit 53f05c6

20 files changed

+351
-0
lines changed

src/Analyzers/MSTest.Analyzers/AnalyzerReleases.Unshipped.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ MSTEST0020 | Design | Disabled | PreferConstructorOverTestInitializeAnalyzer, [D
1010
MSTEST0021 | Design | Disabled | PreferDisposeOverTestCleanupAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0021)
1111
MSTEST0022 | Design | Disabled | PreferTestCleanupOverDisposeAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0022)
1212
MSTEST0023 | Usage | Info | DoNotNegateBooleanAssertionAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0023)
13+
MSTEST0024 | Usage | Info | DoNotStoreStaticTestContextAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/mstest0024)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Collections.Immutable;
5+
6+
using Analyzer.Utilities.Extensions;
7+
8+
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.Diagnostics;
10+
using Microsoft.CodeAnalysis.Operations;
11+
12+
using MSTest.Analyzers.Helpers;
13+
14+
namespace MSTest.Analyzers;
15+
16+
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
17+
public sealed class DoNotStoreStaticTestContextAnalyzer : DiagnosticAnalyzer
18+
{
19+
private static readonly LocalizableResourceString Title = new(nameof(Resources.DoNotStoreStaticTestContextAnalyzerTitle), Resources.ResourceManager, typeof(Resources));
20+
private static readonly LocalizableResourceString MessageFormat = new(nameof(Resources.DoNotStoreStaticTestContextAnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
21+
22+
internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
23+
DiagnosticIds.DoNotStoreStaticTestContextAnalyzerRuleId,
24+
Title,
25+
MessageFormat,
26+
null,
27+
Category.Usage,
28+
DiagnosticSeverity.Info,
29+
isEnabledByDefault: true);
30+
31+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
32+
= ImmutableArray.Create(Rule);
33+
34+
public override void Initialize(AnalysisContext context)
35+
{
36+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
37+
context.EnableConcurrentExecution();
38+
39+
context.RegisterCompilationStartAction(context =>
40+
{
41+
if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestContext, out var testContextSymbol))
42+
{
43+
context.RegisterOperationAction(context => AnalyzeOperation(context, testContextSymbol), OperationKind.SimpleAssignment);
44+
}
45+
});
46+
}
47+
48+
private static void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol testContextSymbol)
49+
{
50+
ISimpleAssignmentOperation assignmentOperation = (ISimpleAssignmentOperation)context.Operation;
51+
52+
if (assignmentOperation.Target is IMemberReferenceOperation memberReferenceOperation
53+
&& memberReferenceOperation.Instance is null
54+
&& assignmentOperation.Value is IParameterReferenceOperation parameterReferenceOperation
55+
&& SymbolEqualityComparer.Default.Equals(parameterReferenceOperation.Type, testContextSymbol))
56+
{
57+
context.ReportDiagnostic(assignmentOperation.CreateDiagnostic(Rule));
58+
}
59+
}
60+
}

src/Analyzers/MSTest.Analyzers/Helpers/DiagnosticIds.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ internal static class DiagnosticIds
2727
public const string PreferDisposeOverTestCleanupRuleId = "MSTEST0021";
2828
public const string PreferTestCleanupOverDisposeRuleId = "MSTEST0022";
2929
public const string DoNotNegateBooleanAssertionRuleId = "MSTEST0023";
30+
public const string DoNotStoreStaticTestContextAnalyzerRuleId = "MSTEST0024";
3031
}

src/Analyzers/MSTest.Analyzers/Resources.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Analyzers/MSTest.Analyzers/Resources.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,12 @@
307307
<data name="DoNotNegateBooleanAssertionTitle" xml:space="preserve">
308308
<value>Do not negate boolean assertions</value>
309309
</data>
310+
<data name="DoNotStoreStaticTestContextAnalyzerMessageFormat" xml:space="preserve">
311+
<value>Do not store TestContext in a static member</value>
312+
</data>
313+
<data name="DoNotStoreStaticTestContextAnalyzerTitle" xml:space="preserve">
314+
<value>Do not store TestContext in a static member</value>
315+
</data>
310316
<data name="PreferConstructorOverTestInitializeMessageFormat" xml:space="preserve">
311317
<value>Prefer constructors over TestInitialize methods</value>
312318
</data>

src/Analyzers/MSTest.Analyzers/xlf/Resources.cs.xlf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,16 @@
333333
<target state="new">Do not negate boolean assertions</target>
334334
<note />
335335
</trans-unit>
336+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerMessageFormat">
337+
<source>Do not store TestContext in a static member</source>
338+
<target state="new">Do not store TestContext in a static member</target>
339+
<note />
340+
</trans-unit>
341+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerTitle">
342+
<source>Do not store TestContext in a static member</source>
343+
<target state="new">Do not store TestContext in a static member</target>
344+
<note />
345+
</trans-unit>
336346
<trans-unit id="PreferConstructorOverTestInitializeMessageFormat">
337347
<source>Prefer constructors over TestInitialize methods</source>
338348
<target state="new">Prefer constructors over TestInitialize methods</target>

src/Analyzers/MSTest.Analyzers/xlf/Resources.de.xlf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@
329329
<target state="new">Do not negate boolean assertions</target>
330330
<note />
331331
</trans-unit>
332+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerMessageFormat">
333+
<source>Do not store TestContext in a static member</source>
334+
<target state="new">Do not store TestContext in a static member</target>
335+
<note />
336+
</trans-unit>
337+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerTitle">
338+
<source>Do not store TestContext in a static member</source>
339+
<target state="new">Do not store TestContext in a static member</target>
340+
<note />
341+
</trans-unit>
332342
<trans-unit id="PreferConstructorOverTestInitializeMessageFormat">
333343
<source>Prefer constructors over TestInitialize methods</source>
334344
<target state="new">Prefer constructors over TestInitialize methods</target>

src/Analyzers/MSTest.Analyzers/xlf/Resources.es.xlf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@
329329
<target state="new">Do not negate boolean assertions</target>
330330
<note />
331331
</trans-unit>
332+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerMessageFormat">
333+
<source>Do not store TestContext in a static member</source>
334+
<target state="new">Do not store TestContext in a static member</target>
335+
<note />
336+
</trans-unit>
337+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerTitle">
338+
<source>Do not store TestContext in a static member</source>
339+
<target state="new">Do not store TestContext in a static member</target>
340+
<note />
341+
</trans-unit>
332342
<trans-unit id="PreferConstructorOverTestInitializeMessageFormat">
333343
<source>Prefer constructors over TestInitialize methods</source>
334344
<target state="new">Prefer constructors over TestInitialize methods</target>

src/Analyzers/MSTest.Analyzers/xlf/Resources.fr.xlf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@
329329
<target state="new">Do not negate boolean assertions</target>
330330
<note />
331331
</trans-unit>
332+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerMessageFormat">
333+
<source>Do not store TestContext in a static member</source>
334+
<target state="new">Do not store TestContext in a static member</target>
335+
<note />
336+
</trans-unit>
337+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerTitle">
338+
<source>Do not store TestContext in a static member</source>
339+
<target state="new">Do not store TestContext in a static member</target>
340+
<note />
341+
</trans-unit>
332342
<trans-unit id="PreferConstructorOverTestInitializeMessageFormat">
333343
<source>Prefer constructors over TestInitialize methods</source>
334344
<target state="new">Prefer constructors over TestInitialize methods</target>

src/Analyzers/MSTest.Analyzers/xlf/Resources.it.xlf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,16 @@
329329
<target state="new">Do not negate boolean assertions</target>
330330
<note />
331331
</trans-unit>
332+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerMessageFormat">
333+
<source>Do not store TestContext in a static member</source>
334+
<target state="new">Do not store TestContext in a static member</target>
335+
<note />
336+
</trans-unit>
337+
<trans-unit id="DoNotStoreStaticTestContextAnalyzerTitle">
338+
<source>Do not store TestContext in a static member</source>
339+
<target state="new">Do not store TestContext in a static member</target>
340+
<note />
341+
</trans-unit>
332342
<trans-unit id="PreferConstructorOverTestInitializeMessageFormat">
333343
<source>Prefer constructors over TestInitialize methods</source>
334344
<target state="new">Prefer constructors over TestInitialize methods</target>

0 commit comments

Comments
 (0)