private void Analyze(SyntaxNodeAnalysisContext context) { if (AllocationRules.IsIgnoredFile(context.Node.SyntaxTree.FilePath)) { return; } if (HasIgnoreAttribute(context)) { return; } var ids = SupportedDiagnostics.Select(x => x.Id).ToArray(); EnabledRules rules = AllocationRules.GetEnabledRules(ids); if (!rules.AnyEnabled) { return; } rules = HotPathAnalysis.GetEnabledRules(rules.All(), context); if (!rules.AnyEnabled) { return; } AnalyzeNode(context, rules); }
protected virtual void Analyze(SyntaxNodeAnalysisContext context, AttributeSyntax attributeSyntax) { var attributeLocation = attributeSyntax.GetLocation(); context.ReportDiagnostic(Diagnostic.Create( SupportedDiagnostics.First(), attributeLocation, attributeSyntax.Name.ToString())); }
private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; if (!(invocation.Expression is MemberAccessExpressionSyntax member)) { return; } var symbol = context.SemanticModel.GetSymbolInfo(member); if (symbol.Symbol == null) { return; } if (!(symbol.Symbol is IMethodSymbol method)) { return; } if (!IsReportable(method)) { return; } context.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics.First(), member.Name.GetLocation(), method.Name)); }
private void VerifyDiagnostics( IEnumerable <Diagnostic> actualDiagnostics, IEnumerable <Diagnostic> expectedDiagnostics, bool checkAdditionalLocations, CancellationToken cancellationToken = default) { int expectedCount = 0; int actualCount = 0; using (IEnumerator <Diagnostic> expectedEnumerator = expectedDiagnostics.OrderBy(f => f, DiagnosticComparer.SpanStart).GetEnumerator()) using (IEnumerator <Diagnostic> actualEnumerator = actualDiagnostics.OrderBy(f => f, DiagnosticComparer.SpanStart).GetEnumerator()) { if (!expectedEnumerator.MoveNext()) { throw new InvalidOperationException($"'{nameof(expectedDiagnostics)}' contains no elements."); } do { cancellationToken.ThrowIfCancellationRequested(); expectedCount++; Diagnostic expectedDiagnostic = expectedEnumerator.Current; if (SupportedDiagnostics.IndexOf(expectedDiagnostic.Descriptor, DiagnosticDescriptorComparer.Id) == -1) { Assert.True(false, $"Diagnostic \"{expectedDiagnostic.Id}\" is not supported by analyzer(s) {string.Join(", ", Analyzers.Select(f => f.GetType().Name))}."); } if (actualEnumerator.MoveNext()) { actualCount++; VerifyDiagnostic(actualEnumerator.Current, expectedDiagnostic, checkAdditionalLocations: checkAdditionalLocations); } else { while (expectedEnumerator.MoveNext()) { expectedCount++; } Assert.True(false, $"Mismatch between number of diagnostics returned, expected: {expectedCount} actual: {actualCount}{actualDiagnostics.ToDebugString()}"); } } while (expectedEnumerator.MoveNext()); if (actualEnumerator.MoveNext()) { actualCount++; while (actualEnumerator.MoveNext()) { actualCount++; } Assert.True(false, $"Mismatch between number of diagnostics returned, expected: {expectedCount} actual: {actualCount}{actualDiagnostics.ToDebugString()}"); } } }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.RegisterCompilationStartAction(compilationStartAnalysisContext => { if (compilationStartAnalysisContext.CancellationToken.IsCancellationRequested) { return; } var taskType = compilationStartAnalysisContext.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task"); var taskOfTType = compilationStartAnalysisContext.Compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1"); compilationStartAnalysisContext.RegisterCodeBlockStartAction <SyntaxKind>(codeBlockStartAnalysisContext => { if (codeBlockStartAnalysisContext.CancellationToken.IsCancellationRequested) { return; } if (codeBlockStartAnalysisContext.CodeBlock.SyntaxTree.IsGeneratedCode()) { return; } codeBlockStartAnalysisContext.RegisterSyntaxNodeAction(syntaxNodeAnalysisContext => { if (syntaxNodeAnalysisContext.CancellationToken.IsCancellationRequested) { return; } var identifierNameNode = (IdentifierNameSyntax)syntaxNodeAnalysisContext.Node; if (identifierNameNode.Identifier.Text != TaskMemberToDiagnose.Name) { return; } var symbolInfo = syntaxNodeAnalysisContext.SemanticModel.GetSymbolInfo(identifierNameNode, syntaxNodeAnalysisContext.CancellationToken); if (symbolInfo.Symbol == null || symbolInfo.Symbol.Kind != TaskMemberToDiagnose.SymbolKind) { return; } if (symbolInfo.Symbol.ContainingType.OriginalDefinition != taskType && symbolInfo.Symbol.ContainingType.OriginalDefinition != taskOfTType) { return; } syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics.First(), syntaxNodeAnalysisContext.Node.GetLocation())); }, SyntaxKind.IdentifierName); }); }); }
protected bool IsEnabled(AnalyzerOptions options) { if (analysisConfiguration.EnabledRules == null) { analysisConfiguration.Read(options); } if (analysisConfiguration.EnabledRules == null) { return(false); } return(SupportedDiagnostics.Any(d => analysisConfiguration.IsEnabled(d.Id))); }
public async Task VerifyNoDiagnosticAsync( string source, string[] additionalSources = null, CodeVerificationOptions options = null, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (SupportedDiagnostics.IndexOf(Descriptor, DiagnosticDescriptorComparer.Id) == -1) { Assert.True(false, $"Diagnostic \"{Descriptor.Id}\" is not supported by analyzer \"{Analyzer.GetType().Name}\"."); } using (Workspace workspace = new AdhocWorkspace()) { Project project = WorkspaceFactory.AddProject(workspace.CurrentSolution, options); Document document = WorkspaceFactory.AddDocument(project, source, additionalSources ?? Array.Empty <string>()); Compilation compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); ImmutableArray <Diagnostic> compilerDiagnostics = compilation.GetDiagnostics(cancellationToken); if (options == null) { options = Options; } VerifyCompilerDiagnostics(compilerDiagnostics, options); if (options.EnableDiagnosticsDisabledByDefault) { compilation = compilation.EnsureEnabled(Descriptor); } ImmutableArray <Diagnostic> analyzerDiagnostics = await compilation.GetAnalyzerDiagnosticsAsync(Analyzer, DiagnosticComparer.SpanStart, cancellationToken).ConfigureAwait(false); foreach (Diagnostic diagnostic in analyzerDiagnostics) { if (string.Equals(diagnostic.Id, Descriptor.Id, StringComparison.Ordinal)) { Assert.True(false, $"No diagnostic expected{analyzerDiagnostics.Where(f => string.Equals(f.Id, Descriptor.Id, StringComparison.Ordinal)).ToDebugString()}"); } } } }
private void CheckStructShouldImplementIEquatable(SyntaxNodeAnalysisContext context) { var declSyntax = (StructDeclarationSyntax)context.Node; var declSymbol = context.SemanticModel.GetDeclaredSymbol(declSyntax) as INamedTypeSymbol; bool foundIEquatableOfStruct = false; if (declSyntax.BaseList != null) { var baseList = declSyntax.BaseList.Types; var baseTypesSyntax = baseList.OfType <SimpleBaseTypeSyntax>(); foreach (var oneBaseTypeSyntax in baseTypesSyntax) { var baseTypeName = oneBaseTypeSyntax.ChildNodes(); foreach (var oneName in baseTypeName) { if (oneName is GenericNameSyntax) { var genericSymbolInfo = context.SemanticModel.GetSymbolInfo(oneName); var genericSymbol = genericSymbolInfo.Symbol as INamedTypeSymbol; if (genericSymbol != null && genericSymbol.ContainingNamespace.Name == "System" && genericSymbol.Name == "IEquatable") { foreach (var oneParameterType in genericSymbol.TypeArguments) { if (oneParameterType == declSymbol) { foundIEquatableOfStruct = true; } } } } } } } if (!foundIEquatableOfStruct) { var diagnostic = Diagnostic.Create(SupportedDiagnostics.First(), declSyntax.Identifier.GetLocation(), declSyntax.Identifier.ToString()); context.ReportDiagnostic(diagnostic); } }
protected void CheckComplexity <TSyntax>(SyntaxNodeAnalysisContext context, Func <TSyntax, SyntaxNode> nodeSelector, Func <TSyntax, Location> location, string declarationType) where TSyntax : SyntaxNode { var syntax = (TSyntax)context.Node; var nodeToAnalyze = nodeSelector(syntax); if (nodeToAnalyze == null) { return; } var complexity = GetComplexity(nodeToAnalyze); if (complexity > Maximum) { context.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics.First(), location(syntax), Maximum, complexity, declarationType)); } }
protected sealed override void Initialize(ParameterLoadingAnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( c => { var fieldDeclaration = (FieldDeclarationSyntax)c.Node; foreach (var name in fieldDeclaration.Declarators.SelectMany(v => v.Names).Where(n => n != null)) { var symbol = c.SemanticModel.GetDeclaredSymbol(name) as IFieldSymbol; if (symbol != null && IsCandidateSymbol(symbol) && !IsRegexMatch(symbol.Name, Pattern)) { c.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics.First(), name.GetLocation(), symbol.Name, Pattern)); } } }, SyntaxKind.FieldDeclaration); }
private void AnalyzeClassSyntax(SyntaxNodeAnalysisContext context) { var classDeclaration = (ClassDeclarationSyntax)context.Node; if (classDeclaration.IsDerived() && !classDeclaration.IsSealed()) { var methods = classDeclaration.Members.OfType <MethodDeclarationSyntax>(); foreach (var method in methods) { if (method.IsOverriden() && !method.IsSealed()) { var diagnostic = Diagnostic.Create(SupportedDiagnostics.First(), method.Identifier.GetLocation(), method.Identifier.ToString(), classDeclaration.Identifier.ToString()); context.ReportDiagnostic(diagnostic); } } } }
private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var invocation = context.Node as InvocationExpressionSyntax; if (invocation == null) { return; } var methodName = invocation.MethodName(); if (InvokeMethods.Contains(methodName)) { // check if the method is the one from UnityEngine var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation); var methodSymbol = symbolInfo.Symbol as IMethodSymbol; var fullTypeName = methodSymbol?.ContainingType.ToString(); if (fullTypeName == InvokeMethodTypeName && invocation.ArgumentList.Arguments.Count > 0) { var firstArgumentExpression = invocation.ArgumentList.Arguments[0]; var invokedMethodName = firstArgumentExpression.GetArgumentValue <string>(); var containingClassDeclaration = invocation.Ancestors().FirstOrDefault(a => a is ClassDeclarationSyntax) as ClassDeclarationSyntax; var allMethods = containingClassDeclaration?.Members.OfType <MethodDeclarationSyntax>(); var invokeEndPoint = allMethods.FirstOrDefault(m => m.Identifier.ValueText == invokedMethodName); if (invokeEndPoint == null) { var diagnostic = Diagnostic.Create(SupportedDiagnostics.First(), firstArgumentExpression.GetLocation(), methodName, invokedMethodName); context.ReportDiagnostic(diagnostic); } } } }
public async Task VerifyNoDiagnosticAsync( string source, IEnumerable <string> additionalSources = null, CodeVerificationOptions options = null, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); options ??= Options; if (SupportedDiagnostics.IndexOf(Descriptor, DiagnosticDescriptorComparer.Id) == -1) { Assert.True(false, $"Diagnostic \"{Descriptor.Id}\" is not supported by analyzer(s) {string.Join(", ", Analyzers.Select(f => f.GetType().Name))}."); } using (Workspace workspace = new AdhocWorkspace()) { Project project = WorkspaceFactory.AddProject(workspace.CurrentSolution, options); Document document = WorkspaceFactory.AddDocument(project, source, additionalSources); Compilation compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); ImmutableArray <Diagnostic> compilerDiagnostics = compilation.GetDiagnostics(cancellationToken); VerifyCompilerDiagnostics(compilerDiagnostics, options); compilation = UpdateCompilation(compilation); ImmutableArray <Diagnostic> analyzerDiagnostics = await compilation.GetAnalyzerDiagnosticsAsync(Analyzers, DiagnosticComparer.SpanStart, cancellationToken).ConfigureAwait(false); foreach (Diagnostic diagnostic in analyzerDiagnostics) { if (string.Equals(diagnostic.Id, Descriptor.Id, StringComparison.Ordinal)) { Assert.True(false, $"No diagnostic expected{analyzerDiagnostics.Where(f => string.Equals(f.Id, Descriptor.Id, StringComparison.Ordinal)).ToDebugString()}"); } } } }
protected void CheckComplexity <TSyntax>(SyntaxNodeAnalysisContext context, Func <TSyntax, Location> getLocationToReport, string declarationType, int threshold) where TSyntax : SyntaxNode { var syntax = (TSyntax)context.Node; var cognitiveWalker = new CognitiveComplexityWalker(); cognitiveWalker.Visit(syntax); if (cognitiveWalker.NestingLevel != 0) { throw new Exception($"There is a problem with the cognitive complexity walker. Expecting ending nesting to be '0' got '{cognitiveWalker.NestingLevel}'"); } if (cognitiveWalker.Complexity > Threshold) { context.ReportDiagnostic(Diagnostic.Create(SupportedDiagnostics.First(), getLocationToReport(syntax), cognitiveWalker.Flow.Select(x => x.Location), CreatePropertiesFromCognitiveTrace(cognitiveWalker.Flow), new object[] { declarationType, cognitiveWalker.Complexity, threshold })); } }
protected bool IsEnabled(AnalyzerOptions options) { analyzerConfiguration.Initialize(options); return(SupportedDiagnostics.Any(d => analyzerConfiguration.IsEnabled(d.Id))); }
public DeprecatedAnalyzer() { SupportedDiagnostics = GetDescriptors(); DescriptorById = SupportedDiagnostics.ToImmutableDictionary(d => d.Id); }
private ImmutableDictionary <string, ImmutableArray <DiagnosticDescriptor> > LoadSupportedDiagnosticsByPrefix() { return(SupportedDiagnostics .GroupBy(f => f, DiagnosticDescriptorComparer.IdPrefix) .ToImmutableDictionary(f => DiagnosticIdPrefix.GetPrefix(f.Key.Id), f => f.ToImmutableArray())); }