示例#1
0
            public StringFormatInfo(Compilation compilation)
            {
                ImmutableDictionary <IMethodSymbol, Info> .Builder builder = ImmutableDictionary.CreateBuilder <IMethodSymbol, Info>();

                INamedTypeSymbol console = WellKnownTypes.Console(compilation);

                AddStringFormatMap(builder, console, "Write");
                AddStringFormatMap(builder, console, "WriteLine");

                INamedTypeSymbol @string = WellKnownTypes.String(compilation);

                AddStringFormatMap(builder, @string, "Format");

                _map = builder.ToImmutable();

                String = @string;
                Object = WellKnownTypes.Object(compilation);
            }
示例#2
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                INamedTypeSymbol localizableStateAttributeSymbol  = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation);
                INamedTypeSymbol conditionalAttributeSymbol       = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation);
                INamedTypeSymbol systemConsoleSymbol              = WellKnownTypes.Console(compilationContext.Compilation);
                ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation);

                compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod))
                    {
                        return;
                    }

                    var lazyValueContentResult = new Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> >(
                        valueFactory: ComputeValueContentAnalysisResult, isThreadSafe: false);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var argument = (IArgumentOperation)operationContext.Operation;
                        IMethodSymbol targetMethod = null;
                        switch (argument.Parent)
                        {
                        case IInvocationOperation invocation:
                            targetMethod = invocation.TargetMethod;
                            break;

                        case IObjectCreationOperation objectCreation:
                            targetMethod = objectCreation.Constructor;
                            break;
                        }

                        if (ShouldAnalyze(targetMethod))
                        {
                            AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic);
                        }
                    }, OperationKind.Argument);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var propertyReference = (IPropertyReferenceOperation)operationContext.Operation;
                        if (propertyReference.Parent is IAssignmentOperation assignment &&
                            assignment.Target == propertyReference &&
                            !propertyReference.Property.IsIndexer &&
                            propertyReference.Property.SetMethod?.Parameters.Length == 1 &&
                            ShouldAnalyze(propertyReference.Property))
                        {
                            IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0];
                            AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic);
                        }
                    }, OperationKind.PropertyReference);

                    return;

                    // Local functions
                    bool ShouldAnalyze(ISymbol symbol)
                    => symbol != null && !symbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken);

                    void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic)
                    {
                        if (ShouldBeLocalized(parameter.OriginalDefinition, containingPropertySymbolOpt?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore) &&
                            lazyValueContentResult.Value != null)
                        {
                            ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax];
                            if (stringContentValue.IsLiteralState)
                            {
                                Debug.Assert(stringContentValue.LiteralValues.Count > 0);

                                if (stringContentValue.LiteralValues.Any(l => !(l is string)))
                                {
                                    return;
                                }

                                var stringLiteralValues = stringContentValue.LiteralValues.Select(l => (string)l);

                                // 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.
                                var filteredStrings = stringLiteralValues.Where(literal => !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);
                                }
                            }
                        }
                    }

                    DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> ComputeValueContentAnalysisResult()
                    {
                        var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph();
                        if (cfg != null)
                        {
                            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                            return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider,
                                                                              operationBlockStartContext.Options, Rule, operationBlockStartContext.CancellationToken));
                        }

                        return(null);
                    }
                });
            });
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                INamedTypeSymbol localizableStateAttributeSymbol  = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation);
                INamedTypeSymbol conditionalAttributeSymbol       = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation);
                INamedTypeSymbol systemConsoleSymbol              = WellKnownTypes.Console(compilationContext.Compilation);
                ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation);

                compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext =>
                {
                    if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod))
                    {
                        return;
                    }

                    var lazyStringContentResult = new Lazy <DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> >(
                        valueFactory: ComputeStringContentAnalysisResult, isThreadSafe: false);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var argument = (IArgumentOperation)operationContext.Operation;
                        switch (argument.Parent?.Kind)
                        {
                        case OperationKind.Invocation:
                        case OperationKind.ObjectCreation:
                            AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic);
                            return;
                        }
                    }, OperationKind.Argument);

                    operationBlockStartContext.RegisterOperationAction(operationContext =>
                    {
                        var propertyReference = (IPropertyReferenceOperation)operationContext.Operation;
                        if (propertyReference.Parent is IAssignmentOperation assignment &&
                            assignment.Target == propertyReference &&
                            !propertyReference.Property.IsIndexer &&
                            propertyReference.Property.SetMethod?.Parameters.Length == 1)
                        {
                            IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0];
                            AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic);
                        }
                    }, OperationKind.PropertyReference);

                    void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic)
                    {
                        if (ShouldBeLocalized(parameter, containingPropertySymbolOpt, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore))
                        {
                            StringContentAbstractValue stringContentValue = lazyStringContentResult.Value[operation];
                            if (stringContentValue.IsLiteralState)
                            {
                                Debug.Assert(stringContentValue.LiteralValues.Count > 0);

                                // 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 == stringContentValue.LiteralValues.Single())
                                {
                                    return;
                                }

                                // FxCop compat: Do not fire if none of the string literals have any non-control character.
                                if (!LiteralValuesHaveNonControlCharacters(stringContentValue.LiteralValues))
                                {
                                    return;
                                }

                                // FxCop compat: Filter out xml string literals.
                                var filteredStrings = stringContentValue.LiteralValues.Where(literal => !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);
                                }
                            }
                        }
                    }

                    DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> ComputeStringContentAnalysisResult()
                    {
                        foreach (var operationRoot in operationBlockStartContext.OperationBlocks)
                        {
                            IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock();
                            if (topmostBlock != null)
                            {
                                var cfg = ControlFlowGraph.Create(topmostBlock);
                                var wellKnownTypeProvider  = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation);
                                var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider);
                                var copyAnalysisResult     = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResultOpt: pointsToAnalysisResult);
                                // Do another analysis pass to improve the results from PointsTo and Copy analysis.
                                pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResult, copyAnalysisResult);
                                return(StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, pointsToAnalysisResult));
                            }
                        }

                        return(null);
                    }
                });
            });
        }