public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.RegisterOperationAction( ctx => { var invoke = (IInvocationOperation)ctx.Operation; bool hasAnyConstant = invoke.Arguments.Any(x => x.Value.ConstantValue.HasValue); if (!hasAnyConstant) { return; } if (!FormatStringHelper.TryGetFormattingParameters(invoke, out var formatArgument, out var formatArguments, null, ctx.CancellationToken)) { return; } var format = (string)formatArgument.Value.ConstantValue.Value; var parsingResult = new CompositeFormatStringParser().Parse(format); CheckSegments(ctx, parsingResult.Segments, formatArgument.Syntax.SpanStart + 1, formatArguments); var argUsed = new HashSet <int>(); foreach (var item in parsingResult.Segments) { if (!(item is FormatItem fi)) { continue; } argUsed.Add(fi.Index); } var text = GettextCatalog.GetString("Argument is not used in format string"); for (int i = 0; i < formatArguments.Count; i++) { if (!argUsed.Contains(i)) { ctx.ReportDiagnostic(Diagnostic.Create( descriptor, formatArguments[i].Syntax.GetLocation(), text )); } } }, OperationKind.Invocation ); }
void AnalyzeInvocation(SyntaxNodeAnalysisContext ctx) { var invocationExpression = (InvocationExpressionSyntax)ctx.Node; // Speed up the inspector by discarding some invocations early var hasEligibleArgument = invocationExpression.ArgumentList.Arguments.Any(argument => { var primitiveArg = argument.Expression as LiteralExpressionSyntax; return(primitiveArg != null && primitiveArg.Token.IsKind(SyntaxKind.StringLiteralToken)); }); if (!hasEligibleArgument) { return; } var invocationResolveResult = ctx.SemanticModel.GetSymbolInfo(invocationExpression); if (invocationResolveResult.Symbol == null) { return; } ExpressionSyntax formatArgument; IList <ExpressionSyntax> formatArguments; if (!FormatStringHelper.TryGetFormattingParameters(ctx.SemanticModel, invocationExpression, out formatArgument, out formatArguments, null, ctx.CancellationToken)) { return; } var primitiveArgument = formatArgument as LiteralExpressionSyntax; if (primitiveArgument == null || !primitiveArgument.Token.IsKind(SyntaxKind.StringLiteralToken)) { return; } var format = primitiveArgument.Token.ValueText; var parsingResult = new CompositeFormatStringParser().Parse(format); CheckSegments(ctx, parsingResult.Segments, formatArgument.SpanStart + 1, formatArguments, invocationExpression); var argUsed = new HashSet <int> (); foreach (var item in parsingResult.Segments) { var fi = item as FormatItem; if (fi == null) { continue; } argUsed.Add(fi.Index); } for (int i = 0; i < formatArguments.Count; i++) { if (!argUsed.Contains(i)) { ctx.ReportDiagnostic(Diagnostic.Create( descriptor, formatArguments[i].GetLocation(), GettextCatalog.GetString("Argument is not used in format string") )); } } }