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

            analysisContext.RegisterCompilationStartAction(compilationContext =>
            {
                var formatInfo = new StringFormatInfo(compilationContext.Compilation);

                compilationContext.RegisterOperationAction(operationContext =>
                {
                    var invocation = (IInvocationOperation)operationContext.Operation;

                    StringFormatInfo.Info info = formatInfo.TryGet(invocation.TargetMethod, operationContext);
                    if (info == null || invocation.Arguments.Length <= info.FormatStringIndex)
                    {
                        // not a target method
                        return;
                    }

                    IArgumentOperation formatStringArgument = invocation.Arguments[info.FormatStringIndex];
                    if (!object.Equals(formatStringArgument?.Value?.Type, formatInfo.String) ||
                        !(formatStringArgument?.Value?.ConstantValue.Value is string))
                    {
                        // wrong argument
                        return;
                    }

                    var stringFormat = (string)formatStringArgument.Value.ConstantValue.Value;
                    int expectedStringFormatArgumentCount = GetFormattingArguments(stringFormat);

                    // explict parameter case
                    if (info.ExpectedStringFormatArgumentCount >= 0)
                    {
                        // __arglist is not supported here
                        if (invocation.TargetMethod.IsVararg)
                        {
                            // can't deal with this for now.
                            return;
                        }

                        if (info.ExpectedStringFormatArgumentCount != expectedStringFormatArgumentCount)
                        {
                            operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
                        }

                        return;
                    }

                    // ensure argument is an array
                    IArgumentOperation paramsArgument = invocation.Arguments[info.FormatStringIndex + 1];
                    if (paramsArgument.ArgumentKind != ArgumentKind.ParamArray && paramsArgument.ArgumentKind != ArgumentKind.Explicit)
                    {
                        // wrong format
                        return;
                    }

                    var arrayCreation = paramsArgument.Value as IArrayCreationOperation;
                    var elementType   = arrayCreation.GetElementType();
                    if (elementType == null ||
                        !object.Equals(elementType, formatInfo.Object) ||
                        arrayCreation.DimensionSizes.Length != 1)
                    {
                        // wrong format
                        return;
                    }

                    // compiler generating object array for params case
                    IArrayInitializerOperation intializer = arrayCreation.Initializer;
                    if (intializer == null)
                    {
                        // unsupported format
                        return;
                    }

                    // REVIEW: "ElementValues" is a bit confusing where I need to double dot those to get number of elements
                    int actualArgumentCount = intializer.ElementValues.Length;
                    if (actualArgumentCount != expectedStringFormatArgumentCount)
                    {
                        operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
                    }
                }, OperationKind.Invocation);
            });
        }
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.RegisterCompilationStartAction(compilationContext =>
            {
                var formatInfo = new StringFormatInfo(compilationContext.Compilation);

                compilationContext.RegisterOperationAction(operationContext =>
                {
                    var invocation = (IInvocationExpression)operationContext.Operation;

                    StringFormatInfo.Info info = formatInfo.TryGet(invocation.TargetMethod);
                    if (info == null || invocation.ArgumentsInParameterOrder.Length <= info.FormatStringIndex)
                    {
                        // not a target method
                        return;
                    }

                    IArgument formatStringArgument = invocation.ArgumentsInParameterOrder[info.FormatStringIndex];
                    if (!object.Equals(formatStringArgument?.Value?.Type, formatInfo.String) ||
                        !(formatStringArgument?.Value?.ConstantValue.Value is string))
                    {
                        // wrong argument
                        return;
                    }

                    var stringFormat = (string)formatStringArgument.Value.ConstantValue.Value;
                    int expectedStringFormatArgumentCount = GetFormattingArguments(stringFormat);

                    // explict parameter case
                    if (info.ExpectedStringFormatArgumentCount >= 0)
                    {
                        // TODO: due to a bug - https://github.com/dotnet/roslyn/issues/7346
                        //       vararg case is disabled.
                        //       we might check this only for C# since __arglist is not supported in VB
                        //
                        //       we need to implement proper support for __arglist once the bug is fixed.
                        if (invocation.TargetMethod.IsVararg)
                        {
                            // can't deal with this for now.
                            return;
                        }

                        if (info.ExpectedStringFormatArgumentCount != expectedStringFormatArgumentCount)
                        {
                            operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
                        }

                        return;
                    }

                    // params case
                    IArgument paramsArgument = invocation.ArgumentsInParameterOrder[info.FormatStringIndex + 1];
                    if (paramsArgument.ArgumentKind != ArgumentKind.ParamArray)
                    {
                        // wrong format
                        return;
                    }

                    var arrayCreation = paramsArgument.Value as IArrayCreationExpression;
                    if (arrayCreation == null ||
                        !object.Equals(arrayCreation.ElementType, formatInfo.Object) ||
                        arrayCreation.DimensionSizes.Length != 1)
                    {
                        // wrong format
                        return;
                    }

                    // compiler generating object array for params case
                    IArrayInitializer intializer = arrayCreation.Initializer;
                    if (intializer == null)
                    {
                        // unsupported format
                        return;
                    }

                    // REVIEW: "ElementValues" is a bit confusing where I need to double dot those to get number of elements
                    int actualArgumentCount = intializer.ElementValues.Length;
                    if (actualArgumentCount != expectedStringFormatArgumentCount)
                    {
                        operationContext.ReportDiagnostic(operationContext.Operation.Syntax.CreateDiagnostic(Rule));
                    }
                }, OperationKind.InvocationExpression);
            });
        }