mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 00:42:51 +08:00
70 lines
2.9 KiB
C#
70 lines
2.9 KiB
C#
namespace Spectre.Console.Analyzer;
|
|
|
|
/// <summary>
|
|
/// Analyzer to detect calls to live renderables within a live renderable context.
|
|
/// </summary>
|
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
[Shared]
|
|
public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer
|
|
{
|
|
private static readonly DiagnosticDescriptor _diagnosticDescriptor =
|
|
Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables;
|
|
|
|
/// <inheritdoc />
|
|
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
|
|
ImmutableArray.Create(_diagnosticDescriptor);
|
|
|
|
/// <inheritdoc />
|
|
protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext)
|
|
{
|
|
compilationStartContext.RegisterOperationAction(
|
|
context =>
|
|
{
|
|
var invocationOperation = (IInvocationOperation)context.Operation;
|
|
var methodSymbol = invocationOperation.TargetMethod;
|
|
|
|
const string StartMethod = "Start";
|
|
if (methodSymbol.Name != StartMethod)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var liveTypes = Constants.LiveRenderables
|
|
.Select(i => context.Compilation.GetTypeByMetadataName(i))
|
|
.ToImmutableArray();
|
|
|
|
if (liveTypes.All(i => !SymbolEqualityComparer.Default.Equals(i, methodSymbol.ContainingType)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
#pragma warning disable RS1030 // Do not invoke Compilation.GetSemanticModel() method within a diagnostic analyzer
|
|
var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree);
|
|
#pragma warning restore RS1030 // Do not invoke Compilation.GetSemanticModel() method within a diagnostic analyzer
|
|
var parentInvocations = invocationOperation
|
|
.Syntax.Ancestors()
|
|
.OfType<InvocationExpressionSyntax>()
|
|
.Select(i => model.GetOperation(i))
|
|
.OfType<IInvocationOperation>()
|
|
.ToList();
|
|
|
|
if (parentInvocations.All(parent =>
|
|
parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var displayString = SymbolDisplay.ToDisplayString(
|
|
methodSymbol,
|
|
SymbolDisplayFormat.CSharpShortErrorMessageFormat
|
|
.WithParameterOptions(SymbolDisplayParameterOptions.None)
|
|
.WithGenericsOptions(SymbolDisplayGenericsOptions.None));
|
|
|
|
context.ReportDiagnostic(
|
|
Diagnostic.Create(
|
|
_diagnosticDescriptor,
|
|
invocationOperation.Syntax.GetLocation(),
|
|
displayString));
|
|
}, OperationKind.Invocation);
|
|
}
|
|
} |