private static void ReportOnWeakIdentityObject(IOperation operation, OperationAnalysisContext context) { if (operation is IInstanceReferenceOperation instanceReference && instanceReference.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance) { context.ReportDiagnostic(operation.CreateDiagnostic(Rule, operation.Syntax.ToString())); }
private void AnalyzeFormatArgument(OperationAnalysisContext context, IOperation formatExpression, int paramsCount, bool argsIsArray, bool usingLoggerExtensionsTypes, IMethodSymbol methodSymbol) { var text = TryGetFormatText(formatExpression); if (text == null) { if (usingLoggerExtensionsTypes) { context.ReportDiagnostic(formatExpression.CreateDiagnostic(CA2254Rule, methodSymbol.ToDisplayString(GetLanguageSpecificFormat(formatExpression)))); } return; } LogValuesFormatter formatter; try { formatter = new LogValuesFormatter(text); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception) #pragma warning restore CA1031 // Do not catch general exception types { return; } foreach (var valueName in formatter.ValueNames) { if (int.TryParse(valueName, out _)) { context.ReportDiagnostic(formatExpression.CreateDiagnostic(CA2253Rule)); } else if (!string.IsNullOrEmpty(valueName) && char.IsLower(valueName[0])) { context.ReportDiagnostic(formatExpression.CreateDiagnostic(CA1727Rule)); } } var argsPassedDirectly = argsIsArray && paramsCount == 1; if (!argsPassedDirectly && paramsCount != formatter.ValueNames.Count) { context.ReportDiagnostic(formatExpression.CreateDiagnostic(CA2017Rule)); } }
void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol? containingPropertySymbol, IOperation operation, Action <Diagnostic> reportDiagnostic, bool useNamingHeuristic) { if (ShouldBeLocalized(parameter.OriginalDefinition, containingPropertySymbol?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore, useNamingHeuristic) && lazyValueContentResult.Value != null) { ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax]; if (stringContentValue.IsLiteralState) { Debug.Assert(!stringContentValue.LiteralValues.IsEmpty); if (stringContentValue.LiteralValues.Any(l => l is not string)) { return; } var stringLiteralValues = stringContentValue.LiteralValues.Cast <string?>(); // FxCop compat: Do not fire if the literal value came from a default parameter value if (stringContentValue.LiteralValues.Count == 1 && parameter.IsOptional && parameter.ExplicitDefaultValue is string defaultValue && defaultValue == stringLiteralValues.Single()) { return; } // FxCop compat: Do not fire if none of the string literals have any non-control character. if (!LiteralValuesHaveNonControlCharacters(stringLiteralValues)) { return; } // FxCop compat: Filter out xml string literals. IEnumerable <string> filteredStrings = stringLiteralValues.Where(literal => literal != null && !LooksLikeXmlTag(literal)) !; if (filteredStrings.Any()) { // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}". var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var arg3 = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg4 = FormatLiteralValues(filteredStrings); var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4); reportDiagnostic(diagnostic); } } } }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol?expectedExceptionType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionAttribute); INamedTypeSymbol?nunitAssertType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.NUnitFrameworkAssert); INamedTypeSymbol?xunitAssertType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.XunitAssert); INamedTypeSymbol?linqEnumerableType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemLinqEnumerable); compilationContext.RegisterOperationBlockStartAction(osContext => { if (osContext.OwningSymbol is not IMethodSymbol method) { return; } osContext.RegisterOperationAction(opContext => { IOperation expression = ((IExpressionStatementOperation)opContext.Operation).Operation; var userDefinedMethods = compilationContext.Options.GetAdditionalUseResultsMethodsOption(UserDefinedMethodRule, expression.Syntax.SyntaxTree, compilationContext.Compilation, compilationContext.CancellationToken); DiagnosticDescriptor?rule = null; string targetMethodName = ""; switch (expression.Kind) { case OperationKind.ObjectCreation: IMethodSymbol ctor = ((IObjectCreationOperation)expression).Constructor; if (ctor != null) { rule = ObjectCreationRule; targetMethodName = ctor.ContainingType.Name; } break; case OperationKind.Invocation: IInvocationOperation invocationExpression = (IInvocationOperation)expression; IMethodSymbol targetMethod = invocationExpression.TargetMethod; if (targetMethod.ReturnsVoid) { break; } if (IsStringCreatingMethod(targetMethod)) { rule = StringCreationRule; } else if (IsTryParseMethod(targetMethod)) { rule = TryParseRule; } else if (IsHResultOrErrorCodeReturningMethod(targetMethod)) { rule = HResultOrErrorCodeRule; } else if (IsPureMethod(targetMethod, opContext.Compilation)) { rule = PureMethodRule; } else if (targetMethod.ContainingType.Equals(linqEnumerableType)) { rule = LinqMethodRule; } else if (userDefinedMethods.Contains(targetMethod.OriginalDefinition)) { rule = UserDefinedMethodRule; } targetMethodName = targetMethod.Name; break; } if (rule != null) { if (ShouldSkipAnalyzing(opContext, expectedExceptionType, xunitAssertType, nunitAssertType)) { return; } Diagnostic diagnostic = expression.CreateDiagnostic(rule, method.Name, targetMethodName); opContext.ReportDiagnostic(diagnostic); } }, OperationKind.ExpressionStatement); }); }); }
public static Diagnostic CreateDiagnostic( this IOperation operation, DiagnosticDescriptor rule, params object[] args) => operation.CreateDiagnostic(rule, properties: null, args);
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemSecurityAuthenticationSslProtocols, out INamedTypeSymbol sslProtocolsSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IFieldReferenceOperation fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsReferencingSslProtocols( fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol)) { if (isDeprecatedProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( DeprecatedRule, fieldReferenceOperation.Field.Name)); } else if (isHardcodedOkayProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( HardcodedRule, fieldReferenceOperation.Field.Name)); } } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { IOperation valueOperation; switch (operationAnalysisContext.Operation) { case IAssignmentOperation assignmentOperation: // Make sure this is an assignment operation for a SslProtocols value. if (!sslProtocolsSymbol.Equals(assignmentOperation.Target.Type)) { return; } valueOperation = assignmentOperation.Value; break; case IArgumentOperation argumentOperation: if (!sslProtocolsSymbol.Equals(argumentOperation.Type)) { return; } valueOperation = argumentOperation.Value; break; case IReturnOperation returnOperation: if (returnOperation.ReturnedValue == null || !sslProtocolsSymbol.Equals(returnOperation.ReturnedValue.Type)) { return; } valueOperation = returnOperation.ReturnedValue; break; case IVariableInitializerOperation variableInitializerOperation: if (variableInitializerOperation.Value != null && !sslProtocolsSymbol.Equals(variableInitializerOperation.Value.Type)) { return; } valueOperation = variableInitializerOperation.Value; break; default: Debug.Fail("Unhandled IOperation " + operationAnalysisContext.Operation.Kind); return; } // Find the topmost operation with a bad bit set, unless we find an operation that would've been // flagged by the FieldReference callback above. IOperation foundDeprecatedOperation = null; bool foundDeprecatedReference = false; IOperation foundHardcodedOperation = null; bool foundHardcodedReference = false; foreach (IOperation childOperation in valueOperation.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSslProtocols( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardcodedOkayProtocol)) { if (isDeprecatedProtocol) { foundDeprecatedReference = true; } else if (isHardcodedOkayProtocol) { foundHardcodedReference = true; } if (foundDeprecatedReference && foundHardcodedReference) { return; } } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue) { if (foundDeprecatedOperation == null && // Only want the first. (integerValue & UnsafeBits) != 0) { foundDeprecatedOperation = childOperation; } if (foundHardcodedOperation == null && // Only want the first. (integerValue & HardcodedBits) != 0) { foundHardcodedOperation = childOperation; } } } if (foundDeprecatedOperation != null && !foundDeprecatedReference) { operationAnalysisContext.ReportDiagnostic( foundDeprecatedOperation.CreateDiagnostic( DeprecatedRule, foundDeprecatedOperation.ConstantValue)); } if (foundHardcodedOperation != null && !foundHardcodedReference) { operationAnalysisContext.ReportDiagnostic( foundHardcodedOperation.CreateDiagnostic( HardcodedRule, foundHardcodedOperation.ConstantValue)); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.Argument, OperationKind.Return, OperationKind.VariableInitializer); return; // Local function(s). bool IsReferencingSslProtocols( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardcodedOkayProtocol) { if (sslProtocolsSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardcodedSslProtocolsMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardcodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == "None") { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardcodedOkayProtocol = false; } return(true); } else { isHardcodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemNetSecurityProtocolType, out var securityProtocolTypeTypeSymbol) || !wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName( WellKnownTypeNames.SystemNetServicePointManager, out var servicePointManagerTypeSymbol)) { return; } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; // Make sure we're not inside an &= assignment like: // ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11) // cuz &= is at worst, disabling protocol versions. if (IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol) && null == fieldReferenceOperation.GetAncestor <ICompoundAssignmentOperation>( OperationKind.CompoundAssignment, IsAndEqualsServicePointManagerAssignment)) { if (isDeprecatedProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( DeprecatedRule, fieldReferenceOperation.Field.Name)); } else if (isHardCodedOkayProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( HardCodedRule, fieldReferenceOperation.Field.Name)); } } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation; // Make sure this is an assignment operation for a SecurityProtocolType, and not // an assignment like: // ServicePointManager.SecurityProtocol &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11) // cuz &= is at worst, disabling protocol versions. if (!securityProtocolTypeTypeSymbol.Equals(assignmentOperation.Target.Type) || (assignmentOperation is ICompoundAssignmentOperation compoundAssignmentOperation && IsAndEqualsServicePointManagerAssignment(compoundAssignmentOperation))) { return; } // Find the topmost operation with a bad bit set, unless we find an operation that would've been // flagged by the FieldReference callback above. IOperation foundDeprecatedOperation = null; bool foundDeprecatedReference = false; IOperation foundHardCodedOperation = null; bool foundHardCodedReference = false; foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol)) { if (isDeprecatedProtocol) { foundDeprecatedReference = true; } else if (isHardCodedOkayProtocol) { foundHardCodedReference = true; } if (foundDeprecatedReference && foundHardCodedReference) { return; } } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue) { if (foundDeprecatedOperation == null && // Only want the first. (integerValue & UnsafeBits) != 0) { foundDeprecatedOperation = childOperation; } if (foundHardCodedOperation == null && // Only want the first. (integerValue & HardCodedBits) != 0) { foundHardCodedOperation = childOperation; } } } if (foundDeprecatedOperation != null && !foundDeprecatedReference) { operationAnalysisContext.ReportDiagnostic( foundDeprecatedOperation.CreateDiagnostic( DeprecatedRule, foundDeprecatedOperation.ConstantValue)); } if (foundHardCodedOperation != null && !foundHardCodedReference) { operationAnalysisContext.ReportDiagnostic( foundHardCodedOperation.CreateDiagnostic( HardCodedRule, foundHardCodedOperation.ConstantValue)); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment); return; // Local function(s). bool IsReferencingSecurityProtocolType( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardCodedOkayProtocol) { if (securityProtocolTypeTypeSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardCodedSafeProtocolMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardCodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == SystemDefaultName) { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardCodedOkayProtocol = false; } return(true); } else { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } bool IsAndEqualsServicePointManagerAssignment(ICompoundAssignmentOperation compoundAssignmentOperation) { return(compoundAssignmentOperation.OperatorKind == BinaryOperatorKind.And && compoundAssignmentOperation.Target is IPropertyReferenceOperation targetPropertyReference && targetPropertyReference.Instance == null && servicePointManagerTypeSymbol.Equals(targetPropertyReference.Property.ContainingType) && targetPropertyReference.Property.MetadataName == "SecurityProtocol"); } }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } foreach (var operationRoot in operationBlockStartContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null && topmostBlock.HasAnyOperationDescendant(op => (op as IBinaryOperation)?.IsComparisonOperator() == true || op.Kind == OperationKind.Coalesce || op.Kind == OperationKind.ConditionalAccess)) { var cfg = ControlFlowGraph.Create(topmostBlock); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); var nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, nullAnalysisResult); var copyAnalysisResult = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, nullAnalysisResultOpt: nullAnalysisResult, pointsToAnalysisResultOpt: pointsToAnalysisResult); // Do another null analysis pass to improve the results from PointsTo and Copy analysis. nullAnalysisResult = NullAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, pointsToAnalysisResultOpt: pointsToAnalysisResult); var stringContentAnalysisResult = StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, nullAnalysisResult, pointsToAnalysisResult); operationBlockStartContext.RegisterOperationAction(operationContext => { PredicateValueKind GetPredicateKind(IBinaryOperation operation) { if (operation.IsComparisonOperator()) { PredicateValueKind binaryPredicateKind = nullAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } binaryPredicateKind = copyAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } binaryPredicateKind = stringContentAnalysisResult.GetPredicateKind(operation); if (binaryPredicateKind != PredicateValueKind.Unknown) { return(binaryPredicateKind); } ; } return(PredicateValueKind.Unknown); } var binaryOperation = (IBinaryOperation)operationContext.Operation; PredicateValueKind predicateKind = GetPredicateKind(binaryOperation); if (predicateKind != PredicateValueKind.Unknown && (!(binaryOperation.LeftOperand is IBinaryOperation leftBinary) || GetPredicateKind(leftBinary) == PredicateValueKind.Unknown) && (!(binaryOperation.RightOperand is IBinaryOperation rightBinary) || GetPredicateKind(rightBinary) == PredicateValueKind.Unknown)) { // '{0}' is always '{1}'. Remove or refactor the condition(s) to avoid dead code. var arg1 = binaryOperation.Syntax.ToString(); var arg2 = predicateKind == PredicateValueKind.AlwaysTrue ? (binaryOperation.Language == LanguageNames.VisualBasic ? "True" : "true") : (binaryOperation.Language == LanguageNames.VisualBasic ? "False" : "false"); var diagnostic = binaryOperation.CreateDiagnostic(AlwaysTrueFalseOrNullRule, arg1, arg2); operationContext.ReportDiagnostic(diagnostic); } }, OperationKind.BinaryOperator); operationBlockStartContext.RegisterOperationAction(operationContext => { IOperation nullCheckedOperation = operationContext.Operation.Kind == OperationKind.Coalesce ? ((ICoalesceOperation)operationContext.Operation).Value : ((IConditionalAccessOperation)operationContext.Operation).Operation; // '{0}' is always/never '{1}'. Remove or refactor the condition(s) to avoid dead code. DiagnosticDescriptor rule; switch (nullAnalysisResult[nullCheckedOperation]) { case NullAbstractValue.Null: rule = AlwaysTrueFalseOrNullRule; break; case NullAbstractValue.NotNull: rule = NeverNullRule; break; default: return; } var arg1 = nullCheckedOperation.Syntax.ToString(); var arg2 = nullCheckedOperation.Language == LanguageNames.VisualBasic ? "Nothing" : "null"; var diagnostic = nullCheckedOperation.CreateDiagnostic(rule, arg1, arg2); operationContext.ReportDiagnostic(diagnostic); }, OperationKind.Coalesce, OperationKind.ConditionalAccess); } } }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var securityProtocolTypeTypeSymbol = compilationStartAnalysisContext.Compilation.GetTypeByMetadataName(WellKnownTypeNames.SystemNetSecurityProtocolType); if (securityProtocolTypeTypeSymbol == null) { return; } bool IsReferencingSecurityProtocolType( IFieldReferenceOperation fieldReferenceOperation, out bool isDeprecatedProtocol, out bool isHardCodedOkayProtocol) { if (securityProtocolTypeTypeSymbol.Equals(fieldReferenceOperation.Field.ContainingType)) { if (HardCodedSafeProtocolMetadataNames.Contains(fieldReferenceOperation.Field.Name)) { isHardCodedOkayProtocol = true; isDeprecatedProtocol = false; } else if (fieldReferenceOperation.Field.Name == SystemDefaultName) { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; } else { isDeprecatedProtocol = true; isHardCodedOkayProtocol = false; } return(true); } else { isHardCodedOkayProtocol = false; isDeprecatedProtocol = false; return(false); } } compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var fieldReferenceOperation = (IFieldReferenceOperation)operationAnalysisContext.Operation; if (IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol)) { if (isDeprecatedProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( DeprecatedRule, fieldReferenceOperation.Field.Name)); } else if (isHardCodedOkayProtocol) { operationAnalysisContext.ReportDiagnostic( fieldReferenceOperation.CreateDiagnostic( HardCodedRule, fieldReferenceOperation.Field.Name)); } } }, OperationKind.FieldReference); compilationStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var assignmentOperation = (IAssignmentOperation)operationAnalysisContext.Operation; if (!securityProtocolTypeTypeSymbol.Equals(assignmentOperation.Target.Type)) { return; } // Find the topmost operation with a bad bit set, unless we find an operation that would've been // flagged by the FieldReference callback above. IOperation foundDeprecatedOperation = null; bool foundDeprecatedReference = false; IOperation foundHardCodedOperation = null; bool foundHardCodedReference = false; foreach (IOperation childOperation in assignmentOperation.Value.DescendantsAndSelf()) { if (childOperation is IFieldReferenceOperation fieldReferenceOperation && IsReferencingSecurityProtocolType( fieldReferenceOperation, out var isDeprecatedProtocol, out var isHardCodedOkayProtocol)) { if (isDeprecatedProtocol) { foundDeprecatedReference = true; } else if (isHardCodedOkayProtocol) { foundHardCodedReference = true; } if (foundDeprecatedReference && foundHardCodedReference) { return; } } if (childOperation.ConstantValue.HasValue && childOperation.ConstantValue.Value is int integerValue) { if (foundDeprecatedOperation == null && // Only want the first. (integerValue & UnsafeBits) != 0) { foundDeprecatedOperation = childOperation; } if (foundHardCodedOperation == null && // Only want the first. (integerValue & HardCodedBits) != 0) { foundHardCodedOperation = childOperation; } } } if (foundDeprecatedOperation != null && !foundDeprecatedReference) { operationAnalysisContext.ReportDiagnostic( foundDeprecatedOperation.CreateDiagnostic( DeprecatedRule, foundDeprecatedOperation.ConstantValue)); } if (foundHardCodedOperation != null && !foundHardCodedReference) { operationAnalysisContext.ReportDiagnostic( foundHardCodedOperation.CreateDiagnostic( HardCodedRule, foundHardCodedOperation.ConstantValue)); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment); }); }