Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule registration: "SonarTreeReportingContextBase.ReportIssue" assumes ShouldAnalyzeTree was called before #8876

Open
martin-strecker-sonarsource opened this issue Mar 6, 2024 · 0 comments
Labels
Area: C# C# rules related issues. Area: VB.NET VB.NET rules related issues. Type: Improvement Making existing code better.

Comments

@martin-strecker-sonarsource
Copy link
Contributor

martin-strecker-sonarsource commented Mar 6, 2024

There are two implementations of "ReportIssue":

SonarTreeReportingContextBase

public void ReportIssue(Diagnostic diagnostic) =>
ReportIssueCore(diagnostic);

SonarCompilationReportingContextBase

public void ReportIssue(GeneratedCodeRecognizer generatedCodeRecognizer, Diagnostic diagnostic)
{
if (ShouldAnalyzeTree(diagnostic.Location.SourceTree, generatedCodeRecognizer))
{
ReportIssueCore(diagnostic);
}
}

These classes are derived from SonarTreeReportingContextBase

  • SonarCodeBlockReportingContext
  • SonarSemanticModelReportingContext
  • SonarSyntaxNodeReportingContext
  • SonarSyntaxTreeReportingContext

If the reporting happens through one of these contexts, ShouldAnalyzeTree is not checked. The reasoning is, that the check was done via "Execute" like in SonarAnalysisContext:

public void RegisterSemanticModelAction(GeneratedCodeRecognizer generatedCodeRecognizer, Action<SonarSemanticModelReportingContext> action) =>
analysisContext.RegisterSemanticModelAction(
c => Execute<SonarSemanticModelReportingContext, SemanticModelAnalysisContext>(new(this, c), action, c.SemanticModel.SyntaxTree, generatedCodeRecognizer));

private void Execute<TSonarContext, TRoslynContext>(TSonarContext context, Action<TSonarContext> action, SyntaxTree sourceTree, GeneratedCodeRecognizer generatedCodeRecognizer = null)
where TSonarContext : SonarAnalysisContextBase<TRoslynContext>
{
// For each action registered on context we need to do some pre-processing before actually calling the rule.
// 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)
&& context.ShouldAnalyzeTree(sourceTree, generatedCodeRecognizer)
&& LegacyIsRegisteredActionEnabled(SupportedDiagnostics, sourceTree)
&& ShouldAnalyzeRazorFile(sourceTree))
{
action(context);
}
}

But in the other "Start" contexts this check is missing:

public void RegisterNodeAction(Action<SonarSyntaxNodeReportingContext> action, params TSyntaxKind[] symbolKinds) =>
Context.RegisterSyntaxNodeAction(x => action(new(AnalysisContext, x)), symbolKinds);

public void RegisterSymbolAction(Action<SonarSymbolReportingContext> action, params SymbolKind[] symbolKinds) =>
Context.RegisterSymbolAction(x => action(new(AnalysisContext, x)), symbolKinds);
public void RegisterCompilationEndAction(Action<SonarCompilationReportingContext> action) =>
Context.RegisterCompilationEndAction(x => action(new(AnalysisContext, x)));
public void RegisterSemanticModelAction(Action<SonarSemanticModelReportingContext> action) =>
Context.RegisterSemanticModelAction(x => action(new(AnalysisContext, x)));

.. and the new SymbolStartAnalysisContext of #8799

public void RegisterCodeBlockAction(Action<SonarCodeBlockReportingContext> action) =>
Context.RegisterCodeBlockAction(x => action(new(AnalysisContext, x)));
public void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<SonarCodeBlockStartAnalysisContext<TLanguageKindEnum>> action) where TLanguageKindEnum : struct =>
Context.RegisterCodeBlockStartAction<TLanguageKindEnum>(x => action(new(AnalysisContext, x)));
public void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds) =>
throw new NotImplementedException("SonarOperationAnalysisContext wrapper type not implemented.");
public void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action) =>
throw new NotImplementedException("SonarOperationBlockAnalysisContext wrapper type not implemented.");
public void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action) =>
throw new NotImplementedException("SonarOperationBlockStartAnalysisContext wrapper type not implemented.");
public void RegisterSymbolEndAction(Action<SonarSymbolReportingContext> action) =>
Context.RegisterSymbolEndAction(x => action(new(AnalysisContext, x)));
public void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SonarSyntaxNodeReportingContext> action, params TLanguageKindEnum[] syntaxKinds) where TLanguageKindEnum : struct =>
Context.RegisterSyntaxNodeAction(x => action(new(AnalysisContext, x)), syntaxKinds);

as a result, we raise in generated code in these registrations.

See also:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: C# C# rules related issues. Area: VB.NET VB.NET rules related issues. Type: Improvement Making existing code better.
Projects
None yet
Development

No branches or pull requests

1 participant