コード例 #1
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                compilationContext.RegisterOperationBlockAction(operationBlockContext =>
                {
                    // Analyze externally visible methods with reference type parameters.
                    if (!(operationBlockContext.OwningSymbol is IMethodSymbol containingMethod) ||
                        !containingMethod.IsExternallyVisible() ||
                        !containingMethod.Parameters.Any(p => p.Type.IsReferenceType))
                    {
                        return;
                    }

                    // Bail out early if we have no parameter references in the method body.
                    if (!operationBlockContext.OperationBlocks.HasAnyOperationDescendant(OperationKind.ParameterReference))
                    {
                        return;
                    }

                    // Perform analysis of all direct/indirect parameter usages in the method to get all non-validated usages that can cause a null dereference.
                    ImmutableDictionary <IParameterSymbol, SyntaxNode> hazardousParameterUsages = null;
                    foreach (var operationBlock in operationBlockContext.OperationBlocks)
                    {
                        if (operationBlock is IBlockOperation topmostBlock)
                        {
                            hazardousParameterUsages = ParameterValidationAnalysis.GetOrComputeHazardousParameterUsages(
                                topmostBlock, operationBlockContext.Compilation, containingMethod,
                                operationBlockContext.Options, Rule, operationBlockContext.CancellationToken);
                            break;
                        }
                    }

                    if (hazardousParameterUsages != null)
                    {
                        foreach (var kvp in hazardousParameterUsages)
                        {
                            IParameterSymbol parameter = kvp.Key;
                            SyntaxNode node            = kvp.Value;

                            // In externally visible method '{0}', validate parameter '{1}' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.
                            var arg1       = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                            var arg2       = parameter.Name;
                            var diagnostic = node.CreateDiagnostic(Rule, arg1, arg2);
                            operationBlockContext.ReportDiagnostic(diagnostic);
                        }
                    }
                });
            });
        }
コード例 #2
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                compilationContext.RegisterOperationBlockAction(operationBlockContext =>
                {
                    // Analyze externally visible methods with reference type parameters.
                    if (operationBlockContext.OwningSymbol is not IMethodSymbol containingMethod ||
                        !containingMethod.IsExternallyVisible() ||
                        !containingMethod.Parameters.Any(p => p.Type.IsReferenceType) ||
                        operationBlockContext.Options.IsConfiguredToSkipAnalysis(Rule, containingMethod, operationBlockContext.Compilation))
                    {
                        return;
                    }

                    // Bail out for protected members of sealed classes if the entire overridden method chain
                    // is defined in the same assembly.
                    if (containingMethod.IsOverride &&
                        containingMethod.ContainingType.IsSealed)
                    {
                        var overriddenMethod    = containingMethod.OverriddenMethod;
                        var hasAssemblyMismatch = false;
                        while (overriddenMethod != null)
                        {
                            if (!Equals(overriddenMethod.ContainingAssembly, containingMethod.ContainingAssembly))
                            {
                                hasAssemblyMismatch = true;
                                break;
                            }

                            overriddenMethod = overriddenMethod.OverriddenMethod;
                        }

                        if (!hasAssemblyMismatch)
                        {
                            return;
                        }
                    }

                    // Bail out early if we have no parameter references in the method body.
                    if (!operationBlockContext.OperationBlocks.HasAnyOperationDescendant(OperationKind.ParameterReference))
                    {
                        return;
                    }

                    // Perform analysis of all direct/indirect parameter usages in the method to get all non-validated usages that can cause a null dereference.
                    ImmutableDictionary <IParameterSymbol, SyntaxNode>?hazardousParameterUsages = null;
                    foreach (var operationBlock in operationBlockContext.OperationBlocks)
                    {
                        if (operationBlock is IBlockOperation topmostBlock)
                        {
                            hazardousParameterUsages = ParameterValidationAnalysis.GetOrComputeHazardousParameterUsages(
                                topmostBlock, operationBlockContext.Compilation, containingMethod,
                                operationBlockContext.Options, Rule);
                            break;
                        }
                    }

                    if (hazardousParameterUsages != null)
                    {
                        foreach (var kvp in hazardousParameterUsages)
                        {
                            IParameterSymbol parameter = kvp.Key;
                            SyntaxNode node            = kvp.Value;

                            // Check if user has configured to skip extension method 'this' parameter analysis.
                            if (containingMethod.IsExtensionMethod &&
                                Equals(containingMethod.Parameters[0], parameter))
                            {
                                bool excludeThisParameterOption = operationBlockContext.Options.GetBoolOptionValue(
                                    optionName: EditorConfigOptionNames.ExcludeExtensionMethodThisParameter,
                                    rule: Rule,
                                    containingMethod,
                                    operationBlockContext.Compilation,
                                    defaultValue: false);
                                if (excludeThisParameterOption)
                                {
                                    continue;
                                }
                            }

                            // In externally visible method '{0}', validate parameter '{1}' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.
                            var arg1       = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
                            var arg2       = parameter.Name;
                            var diagnostic = node.CreateDiagnostic(Rule, arg1, arg2);
                            operationBlockContext.ReportDiagnostic(diagnostic);
                        }
                    }
                });
            });
        }