Skip to content

Commit

Permalink
Remove HasMatchingScope from Execute for SyntaxNode (#8396)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastien-marichal authored Nov 24, 2023
1 parent fe74751 commit 3c62b3b
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,15 @@ protected override void Initialize(SonarAnalysisContext context) =>
return;
}

context.RegisterNodeAction(
c.RegisterNodeAction(
VisitStringExpressions,
SyntaxKind.StringLiteralExpression,
SyntaxKind.InterpolatedStringExpression,
SyntaxKindEx.Utf8StringLiteralExpression);

context.RegisterNodeAction(VisitObjectCreation, SyntaxKind.ObjectCreationExpression, SyntaxKindEx.ImplicitObjectCreationExpression);
context.RegisterNodeAction(VisitInvocationExpression, SyntaxKind.InvocationExpression);
context.RegisterNodeAction(VisitAssignments, SyntaxKind.SimpleAssignmentExpression);
c.RegisterNodeAction(VisitObjectCreation, SyntaxKind.ObjectCreationExpression, SyntaxKindEx.ImplicitObjectCreationExpression);
c.RegisterNodeAction(VisitInvocationExpression, SyntaxKind.InvocationExpression);
c.RegisterNodeAction(VisitAssignments, SyntaxKind.SimpleAssignmentExpression);
});

private static void VisitObjectCreation(SonarSyntaxNodeReportingContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ public DisablingCsrfProtection(IAnalyzerConfiguration configuration) : base(conf

protected override void Initialize(SonarAnalysisContext context) =>
context.RegisterCompilationStartAction(
ccc =>
c =>
{
if (!IsEnabled(ccc.Options))
if (!IsEnabled(c.Options))
{
return;
}

context.RegisterNodeAction(
c.RegisterNodeAction(
CheckIgnoreAntiforgeryTokenAttribute,
SyntaxKind.Attribute,
SyntaxKind.ObjectCreationExpression,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ protected override void Initialize(SonarAnalysisContext context)
{
base.Initialize(context);

context.RegisterCompilationStartAction(compilationContext =>
context.RegisterCompilationStartAction(c =>
{
if (IsEnabled(compilationContext.Options))
if (IsEnabled(c.Options))
{
context.RegisterNodeAction(VisitAttribute, SyntaxKind.Attribute);
c.RegisterNodeAction(VisitAttribute, SyntaxKind.Attribute);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override void Initialize(SonarAnalysisContext context) =>
{
if (c.Compilation.GetTypeByMetadataName(KnownType.Microsoft_JSInterop_JSInvokable) is not null)
{
context.RegisterNodeAction(CheckMethod, SyntaxKind.MethodDeclaration);
c.RegisterNodeAction(CheckMethod, SyntaxKind.MethodDeclaration);
}
});

Expand Down
6 changes: 3 additions & 3 deletions analyzers/src/SonarAnalyzer.CSharp/Rules/UseStringCreate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ public sealed class UseStringCreate : SonarDiagnosticAnalyzer
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

protected override void Initialize(SonarAnalysisContext context) =>
context.RegisterCompilationStartAction(start =>
context.RegisterCompilationStartAction(c =>
{
if (!CompilationTargetsValidNetVersion(start.Compilation))
if (!CompilationTargetsValidNetVersion(c.Compilation))
{
return;
}

context.RegisterNodeAction(c =>
c.RegisterNodeAction(c =>
{
var node = (InvocationExpressionSyntax)c.Node;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace SonarAnalyzer.AnalysisContext;

public class SonarAnalysisContext
{
internal ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }

private readonly HashSet<string> rulesDisabledForRazor = new()
{
"S103",
Expand All @@ -37,7 +39,6 @@ public class SonarAnalysisContext
};

private readonly RoslynAnalysisContext analysisContext;
private readonly ImmutableArray<DiagnosticDescriptor> supportedDiagnostics;

/// <summary>
/// This delegate is called on all specific contexts, after the registration to the <see cref="RoslynAnalysisContext"/>, to
Expand Down Expand Up @@ -71,10 +72,10 @@ public class SonarAnalysisContext
internal SonarAnalysisContext(RoslynAnalysisContext analysisContext, ImmutableArray<DiagnosticDescriptor> supportedDiagnostics)
{
this.analysisContext = analysisContext ?? throw new ArgumentNullException(nameof(analysisContext));
this.supportedDiagnostics = supportedDiagnostics;
SupportedDiagnostics = supportedDiagnostics;
}

private protected SonarAnalysisContext(SonarAnalysisContext context) : this(context.analysisContext, context.supportedDiagnostics) { }
private protected SonarAnalysisContext(SonarAnalysisContext context) : this(context.analysisContext, context.SupportedDiagnostics) { }

public bool TryGetValue<TValue>(SourceText text, SourceTextValueProvider<TValue> valueProvider, out TValue value) =>
analysisContext.TryGetValue(text, valueProvider, out value);
Expand Down Expand Up @@ -110,8 +111,8 @@ public void RegisterSymbolAction(Action<SonarSymbolReportingContext> action, par

public void RegisterNodeAction<TSyntaxKind>(GeneratedCodeRecognizer generatedCodeRecognizer, Action<SonarSyntaxNodeReportingContext> action, params TSyntaxKind[] syntaxKinds)
where TSyntaxKind : struct =>
analysisContext.RegisterSyntaxNodeAction(
c => Execute<SonarSyntaxNodeReportingContext, SyntaxNodeAnalysisContext>(new(this, c), action, c.Node.SyntaxTree, generatedCodeRecognizer), syntaxKinds);
RegisterCompilationStartAction(
c => c.RegisterNodeAction(generatedCodeRecognizer, action, syntaxKinds));

public void RegisterSemanticModelAction(GeneratedCodeRecognizer generatedCodeRecognizer, Action<SonarSemanticModelReportingContext> action) =>
analysisContext.RegisterSemanticModelAction(
Expand All @@ -132,6 +133,12 @@ public void RegisterTreeAction(GeneratedCodeRecognizer generatedCodeRecognizer,
public void RegisterNodeActionInAllFiles<TSyntaxKind>(Action<SonarSyntaxNodeReportingContext> action, params TSyntaxKind[] syntaxKinds) where TSyntaxKind : struct =>
analysisContext.RegisterSyntaxNodeAction(c => action(new(this, c)), syntaxKinds);

internal bool ShouldAnalyzeRazorFile(SyntaxTree sourceTree) =>
!GeneratedCodeRecognizer.IsRazorGeneratedFile(sourceTree)
|| !SupportedDiagnostics.Any(x => (x.CustomTags.Count() == 1 && x.CustomTags.Contains(DiagnosticDescriptorFactory.TestSourceScopeTag))
|| rulesDisabledForRazor.Contains(x.Id));

/// This method will be replaced by <see cref="SonarCompilationStartAnalysisContext.Execute"/> in the future.
/// <param name="sourceTree">Tree that is definitely known to be analyzed. Pass 'null' if the context doesn't know a specific tree to be analyzed, like a CompilationContext.</param>
private void Execute<TSonarContext, TRoslynContext>(TSonarContext context, Action<TSonarContext> action, SyntaxTree sourceTree, GeneratedCodeRecognizer generatedCodeRecognizer = null)
where TSonarContext : SonarAnalysisContextBase<TRoslynContext>
Expand All @@ -140,17 +147,12 @@ private void Execute<TSonarContext, TRoslynContext>(TSonarContext context, Actio
// First, we need to ensure the rule does apply to the current scope (main vs test source).
// Second, we call an external delegate (set by legacy SonarLint for VS) to ensure the rule should be run (usually
// the decision is made on based on whether the project contains the analyzer as NuGet).
if (context.HasMatchingScope(supportedDiagnostics)
if (context.HasMatchingScope(SupportedDiagnostics)
&& context.ShouldAnalyzeTree(sourceTree, generatedCodeRecognizer)
&& LegacyIsRegisteredActionEnabled(supportedDiagnostics, sourceTree)
&& ShoulAnalyzeRazorFile(sourceTree))
&& LegacyIsRegisteredActionEnabled(SupportedDiagnostics, sourceTree)
&& ShouldAnalyzeRazorFile(sourceTree))
{
action(context);
}
}

private bool ShoulAnalyzeRazorFile(SyntaxTree sourceTree) =>
!GeneratedCodeRecognizer.IsRazorGeneratedFile(sourceTree)
|| !supportedDiagnostics.Any(x => (x.CustomTags.Count() == 1 && x.CustomTags.Contains(DiagnosticDescriptorFactory.TestSourceScopeTag))
|| rulesDisabledForRazor.Contains(x.Id));
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ public void RegisterSemanticModelAction(Action<SonarSemanticModelReportingContex
Context.RegisterSemanticModelAction(x => action(new(AnalysisContext, x)));

public void RegisterNodeAction<TSyntaxKind>(GeneratedCodeRecognizer generatedCodeRecognizer, Action<SonarSyntaxNodeReportingContext> action, params TSyntaxKind[] syntaxKinds)
where TSyntaxKind : struct =>
AnalysisContext.RegisterNodeAction(generatedCodeRecognizer, action, syntaxKinds);
where TSyntaxKind : struct
{
if (HasMatchingScope(AnalysisContext.SupportedDiagnostics))
{
Context.RegisterSyntaxNodeAction(x =>
Execute<SonarSyntaxNodeReportingContext, SyntaxNodeAnalysisContext>(
new(AnalysisContext, x), action, x.Node.SyntaxTree, generatedCodeRecognizer),
syntaxKinds);
}
}

/// <inheritdoc cref="SonarAnalysisContext.Execute" />
private void Execute<TSonarContext, TRoslynContext>(TSonarContext context, Action<TSonarContext> action, SyntaxTree sourceTree, GeneratedCodeRecognizer generatedCodeRecognizer = null)
where TSonarContext : SonarAnalysisContextBase<TRoslynContext>
{
if (ShouldAnalyzeTree(sourceTree, generatedCodeRecognizer)
&& SonarAnalysisContext.LegacyIsRegisteredActionEnabled(AnalysisContext.SupportedDiagnostics, sourceTree)
&& AnalysisContext.ShouldAnalyzeRazorFile(sourceTree))
{
action(context);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ public abstract class DateAndTimeShouldNotBeUsedasTypeForPrimaryKeyBase<TSyntaxK
protected DateAndTimeShouldNotBeUsedasTypeForPrimaryKeyBase() : base(DiagnosticId) { }

protected override void Initialize(SonarAnalysisContext context) =>
context.RegisterCompilationStartAction(c =>
context.RegisterCompilationStartAction(startContext =>
{
if (ShouldRegisterAction(c.Compilation))
if (ShouldRegisterAction(startContext.Compilation))
{
context.RegisterNodeAction(Language.GeneratedCodeRecognizer, context =>
startContext.RegisterNodeAction(Language.GeneratedCodeRecognizer, nodeContext =>
{
foreach (var propertyType in TypeNodesOfTemporalKeyProperties(context))
foreach (var propertyType in TypeNodesOfTemporalKeyProperties(nodeContext))
{
context.ReportIssue(Diagnostic.Create(Rule, propertyType.GetLocation(), Language.Syntax.NodeIdentifier(propertyType)));
nodeContext.ReportIssue(Diagnostic.Create(Rule, propertyType.GetLocation(), Language.Syntax.NodeIdentifier(propertyType)));
}
}, Language.SyntaxKind.ClassDeclaration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ public abstract class DoNotCallMethodsBase<TSyntaxKind, TInvocationExpressionSyn
protected DoNotCallMethodsBase(string diagnosticId) : base(diagnosticId) { }

protected override void Initialize(SonarAnalysisContext context) =>
context.RegisterCompilationStartAction(start =>
context.RegisterCompilationStartAction(c =>
{
if (!ShouldRegisterAction(start.Compilation))
if (!ShouldRegisterAction(c.Compilation))
{
return;
}
context.RegisterNodeAction(Language.GeneratedCodeRecognizer, AnalyzeInvocation, Language.SyntaxKind.InvocationExpression);
c.RegisterNodeAction(Language.GeneratedCodeRecognizer, AnalyzeInvocation, Language.SyntaxKind.InvocationExpression);
});

private void AnalyzeInvocation(SonarSyntaxNodeReportingContext analysisContext)
Expand Down
22 changes: 11 additions & 11 deletions analyzers/src/SonarAnalyzer.Common/Rules/UseUnixEpochBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,33 @@ public abstract class UseUnixEpochBase<TSyntaxKind, TLiteralExpression, TMemberA
protected abstract bool IsZeroTimeOffset(SyntaxNode node);

protected sealed override void Initialize(SonarAnalysisContext context) =>
context.RegisterCompilationStartAction(start =>
context.RegisterCompilationStartAction(c =>
{
if (!IsUnixEpochSupported(start.Compilation))
if (!IsUnixEpochSupported(c.Compilation))
{
return;
}

context.RegisterNodeAction(
c.RegisterNodeAction(
Language.GeneratedCodeRecognizer,
c =>
cc =>
{
var arguments = Language.Syntax.ArgumentExpressions(c.Node);
var arguments = Language.Syntax.ArgumentExpressions(cc.Node);
var literalsArguments = arguments.OfType<TLiteralExpression>();

if (literalsArguments.Any(x => IsValueEqualTo(x, EpochYear)
&& literalsArguments.Count(x => IsValueEqualTo(x, EpochMonth)) == 2)
&& CheckAndGetTypeName(c.Node, c.SemanticModel) is { } name
&& IsEpochCtor(c.Node, c.SemanticModel))
&& CheckAndGetTypeName(cc.Node, cc.SemanticModel) is { } name
&& IsEpochCtor(cc.Node, cc.SemanticModel))
{
c.ReportIssue(Diagnostic.Create(Rule, c.Node.GetLocation(), name));
cc.ReportIssue(Diagnostic.Create(Rule, cc.Node.GetLocation(), name));
}
else if (arguments.Count() == 1
&& ((literalsArguments.Count() == 1 && IsValueEqualTo(literalsArguments.First(), EpochTicks))
|| (Language.FindConstantValue(c.SemanticModel, arguments.First()) is long ticks && ticks == EpochTicks))
&& CheckAndGetTypeName(c.Node, c.SemanticModel) is { } typeName)
|| (Language.FindConstantValue(cc.SemanticModel, arguments.First()) is long ticks && ticks == EpochTicks))
&& CheckAndGetTypeName(cc.Node, cc.SemanticModel) is { } typeName)
{
c.ReportIssue(Diagnostic.Create(Rule, c.Node.GetLocation(), typeName));
cc.ReportIssue(Diagnostic.Create(Rule, cc.Node.GetLocation(), typeName));
}
},
Language.SyntaxKind.ObjectCreationExpressions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ public void RegisterNodeAction_UnchangedFiles_SonarAnalysisContext(string unchan
public void RegisterNodeAction_UnchangedFiles_SonarParametrizedAnalysisContext(string unchangedFileName, bool expected)
{
var context = new DummyAnalysisContext(TestContext, unchangedFileName);
var sut = new SonarParametrizedAnalysisContext(new(context, DummyMainDescriptor));
var sonarContext = new SonarAnalysisContext(context, DummyMainDescriptor);
var sut = new SonarParametrizedAnalysisContext(sonarContext);
sut.RegisterNodeAction<SyntaxKind>(CSharpGeneratedCodeRecognizer.Instance, context.DelegateAction);
sonarContext.RegisterCompilationStartAction(c => sut.ExecutePostponedActions(c));

context.AssertDelegateInvoked(expected);
}
Expand Down Expand Up @@ -237,7 +239,7 @@ public void SonarCompilationStartAnalysisContext_RegisterNodeAction()
var sut = new SonarCompilationStartAnalysisContext(new(context, DummyMainDescriptor), startContext);
sut.RegisterNodeAction<SyntaxKind>(CSharpGeneratedCodeRecognizer.Instance, _ => { });

startContext.AssertExpectedInvocationCounts(expectedNodeCount: 0); // RegisterNodeAction doesn't use DummyCompilationStartAnalysisContext to register but a newly created context
startContext.AssertExpectedInvocationCounts(expectedNodeCount: 1);
}

[TestMethod]
Expand Down

0 comments on commit 3c62b3b

Please sign in to comment.