private void RegisterActions(CompilationStartAnalysisContext compilationStartContext) { // We register following actions in the compilation: // 1. A symbol action for member symbols to ensure the member's unused state is initialized to true for every private member symbol. // 2. Operation actions for member references, invocations and object creations to detect member usages, i.e. read or read reference taken. // 3. Operation action for field initializers to detect non-constant initialization. // 4. Operation action for invalid operations to bail out on erroneous code. // 5. A symbol start/end action for named types to report diagnostics for candidate members that have no usage in executable code. // // Note that we need to register separately for OperationKind.Invocation and OperationKind.ObjectCreation due to https://github.com/dotnet/roslyn/issues/26206 compilationStartContext.RegisterSymbolAction(AnalyzeSymbolDeclaration, SymbolKind.Method, SymbolKind.Field, SymbolKind.Property, SymbolKind.Event); Action <ISymbol, ValueUsageInfo> onSymbolUsageFound = OnSymbolUsage; compilationStartContext.RegisterSymbolStartAction(symbolStartContext => { var hasInvalidOrDynamicOperation = false; symbolStartContext.RegisterOperationAction(AnalyzeMemberReferenceOperation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, OperationKind.EventReference); symbolStartContext.RegisterOperationAction(AnalyzeFieldInitializer, OperationKind.FieldInitializer); symbolStartContext.RegisterOperationAction(AnalyzeInvocationOperation, OperationKind.Invocation); symbolStartContext.RegisterOperationAction(AnalyzeNameOfOperation, OperationKind.NameOf); symbolStartContext.RegisterOperationAction(AnalyzeObjectCreationOperation, OperationKind.ObjectCreation); symbolStartContext.RegisterOperationAction(_ => hasInvalidOrDynamicOperation = true, OperationKind.Invalid, OperationKind.DynamicIndexerAccess, OperationKind.DynamicInvocation, OperationKind.DynamicMemberReference, OperationKind.DynamicObjectCreation); symbolStartContext.RegisterSymbolEndAction(symbolEndContext => OnSymbolEnd(symbolEndContext, hasInvalidOrDynamicOperation)); // Register custom language-specific actions, if any. _analyzer.HandleNamedTypeSymbolStart(symbolStartContext, onSymbolUsageFound); }, SymbolKind.NamedType); }
private void RegisterActions(CompilationStartAnalysisContext compilationStartContext) { // We register following actions in the compilation: // 1. A symbol action for member symbols to ensure the member's unused state is initialized to true for every private member symbol. // 2. Operation actions for member references, invocations and object creations to detect member usages, i.e. read or read reference taken. // 3. Operation action for field initializers to detect non-constant initialization. // 4. Operation action for invalid operations to bail out on erroneous code. // 5. A symbol start/end action for named types to report diagnostics for candidate members that have no usage in executable code. // // Note that we need to register separately for OperationKind.Invocation and OperationKind.ObjectCreation due to https://github.com/dotnet/roslyn/issues/26206 compilationStartContext.RegisterSymbolAction(AnalyzeSymbolDeclaration, SymbolKind.Method, SymbolKind.Field, SymbolKind.Property, SymbolKind.Event); Action <ISymbol, ValueUsageInfo> onSymbolUsageFound = OnSymbolUsage; compilationStartContext.RegisterSymbolStartAction(symbolStartContext => { var hasUnsupportedOperation = false; symbolStartContext.RegisterOperationAction(AnalyzeMemberReferenceOperation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, OperationKind.EventReference); symbolStartContext.RegisterOperationAction(AnalyzeFieldInitializer, OperationKind.FieldInitializer); symbolStartContext.RegisterOperationAction(AnalyzeInvocationOperation, OperationKind.Invocation); symbolStartContext.RegisterOperationAction(AnalyzeNameOfOperation, OperationKind.NameOf); symbolStartContext.RegisterOperationAction(AnalyzeObjectCreationOperation, OperationKind.ObjectCreation); // We bail out reporting diagnostics for named types if it contains following kind of operations: // 1. Invalid operations, i.e. erroneous code: // We do so to ensure that we don't report false positives during editing scenarios in the IDE, where the user // is still editing code and fixing unresolved references to symbols, such as overload resolution errors. // 2. Dynamic operations, where we do not know the exact member being referenced at compile time. // 3. Operations with OperationKind.None which are not operation root nodes. Attributes // generate operation blocks with root operation with OperationKind.None, and we don't want to bail out for them. symbolStartContext.RegisterOperationAction(_ => hasUnsupportedOperation = true, OperationKind.Invalid, OperationKind.DynamicIndexerAccess, OperationKind.DynamicInvocation, OperationKind.DynamicMemberReference, OperationKind.DynamicObjectCreation); symbolStartContext.RegisterOperationAction(AnalyzeOperationNone, OperationKind.None); symbolStartContext.RegisterSymbolEndAction(symbolEndContext => OnSymbolEnd(symbolEndContext, hasUnsupportedOperation)); // Register custom language-specific actions, if any. _analyzer.HandleNamedTypeSymbolStart(symbolStartContext, onSymbolUsageFound); return; void AnalyzeOperationNone(OperationAnalysisContext context) { if (context.Operation.Kind == OperationKind.None && context.Operation.Parent != null) { hasUnsupportedOperation = true; } } }, SymbolKind.NamedType); }