public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterCodeBlockStartAction <SyntaxKind>(startCodeBlockContext => { // We only care about method bodies. if (startCodeBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. IMethodSymbol method = (IMethodSymbol)startCodeBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Initialize local mutable state in the start action. UnusedParametersAnalyzer analyzer = new UnusedParametersAnalyzer(method); // Register an intermediate non-end action that accesses and modifies the state. startCodeBlockContext.RegisterSyntaxNodeAction(analyzer.AnalyzeSyntaxNode, SyntaxKind.IdentifierName); // Register an end action to report diagnostics based on the final state. startCodeBlockContext.RegisterCodeBlockEndAction(analyzer.CodeBlockEndAction); }); }
public override void Initialize(AnalysisContext context) { context.RegisterCodeBlockStartAction<SyntaxKind>(startCodeBlockContext => { // We only care about method bodies. if (startCodeBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startCodeBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method); // Register an intermediate non-end action that accesses and modifies the state. startCodeBlockContext.RegisterSyntaxNodeAction(analyzer.AnalyzeSyntaxNode, SyntaxKind.IdentifierName); // Register an end action to report diagnostics based on the final state. startCodeBlockContext.RegisterCodeBlockEndAction(analyzer.CodeBlockEndAction); }); }
public override void Initialize(AnalysisContext context) { // TODO: Consider making this analyzer thread-safe. //context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol obsoleteAttribute = WellKnownTypes.ObsoleteAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create( conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute, obsoleteAttribute); UnusedParameterDictionary unusedMethodParameters = new ConcurrentDictionary <IMethodSymbol, ISet <IParameterSymbol> >(); ISet <IMethodSymbol> methodsUsedAsDelegates = new HashSet <IMethodSymbol>(); // Create a list of functions to exclude from analysis. We assume that any function that is used in an IMethodBindingExpression // cannot have its signature changed, and add it to the list of methods to be excluded from analysis. compilationStartContext.RegisterOperationActionInternal(operationContext => { var methodBinding = (IMethodBindingExpression)operationContext.Operation; methodsUsedAsDelegates.Add(methodBinding.Method.OriginalDefinition); }, OperationKind.MethodBindingExpression); compilationStartContext.RegisterOperationBlockStartActionInternal(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMember() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Ignore methods that were used as delegates if (methodsUsedAsDelegates.Contains(method)) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method, unusedMethodParameters); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationActionInternal(analyzer.AnalyzeOperation, OperationKind.ParameterReferenceExpression); // Register an end action to add unused parameters to the unusedMethodParameters dictionary startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); // Register a compilation end action to filter all methods used as delegates and report any diagnostics compilationStartContext.RegisterCompilationEndAction(compilationAnalysisContext => { // Report diagnostics for unused parameters. var unusedParameters = unusedMethodParameters.Where(kvp => !methodsUsedAsDelegates.Contains(kvp.Key)).SelectMany(kvp => kvp.Value); foreach (var parameter in unusedParameters) { var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], parameter.Name, parameter.ContainingSymbol.Name); compilationAnalysisContext.ReportDiagnostic(diagnostic); } }); }); }
public override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction(compilationStartContext => { var eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) var conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') var onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); var onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); var onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); var onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); var attributeSetForMethodsToIgnore = ImmutableHashSet.Create(conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMethod() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeOperation, OperationKind.ParameterReferenceExpression); // Register an end action to report diagnostics based on the final state. startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); }); }
public override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create(conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMethod() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeOperation, OperationKind.ParameterReferenceExpression); // Register an end action to report diagnostics based on the final state. startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); }); }
private static void AnalyzeMethod( IMethodSymbol method, OperationBlockStartAnalysisContext startOperationBlockContext, UnusedParameterDictionary unusedMethodParameters, INamedTypeSymbol eventsArgSymbol, ISet <IMethodSymbol> methodsUsedAsDelegates, ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore) { // We only care about methods with parameters. if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, extern methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsExtern || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMember() || method.IsFinalizer()) { return; } // Ignore property accessors. if (method.IsPropertyAccessor()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Ignore methods that were used as delegates if (methodsUsedAsDelegates.Contains(method)) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method, unusedMethodParameters); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeParameterReference, OperationKind.ParameterReference); // Register an end action to add unused parameters to the unusedMethodParameters dictionary startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }
private static void AnalyzeMethod( IMethodSymbol method, OperationBlockStartAnalysisContext startOperationBlockContext, UnusedParameterDictionary unusedMethodParameters, INamedTypeSymbol?eventsArgSymbol, ISet <IMethodSymbol> methodsUsedAsDelegates, ImmutableHashSet <INamedTypeSymbol?> attributeSetForMethodsToIgnore) { // We only care about methods with parameters. if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, extern methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsExtern || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMember() || method.IsFinalizer()) { return; } // Ignore property accessors. if (method.IsPropertyAccessor()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && // UWP has specific EventArgs not inheriting from System.EventArgs. It was decided to go for a suffix match rather than a whitelist. (method.Parameters[1].Type.Inherits(eventsArgSymbol) || method.Parameters[1].Type.Name.EndsWith("EventArgs", StringComparison.Ordinal))) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Ignore methods that were used as delegates if (methodsUsedAsDelegates.Contains(method)) { return; } // Bail out if user has configured to skip analysis for the method. if (!method.MatchesConfiguredVisibility( startOperationBlockContext.Options, Rule, startOperationBlockContext.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All)) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method, unusedMethodParameters); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeParameterReference, OperationKind.ParameterReference); // Register an end action to add unused parameters to the unusedMethodParameters dictionary startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }