<commit_before>// Copyright 2015 The Noda Time Authors. All rights reserved.
// Use of this source code is governed by the Apache License 2.0,
// as found in the LICENSE.txt file.

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;

namespace NodaTime.CodeDiagnostics
{
    /// <summary>
    /// Diagnostic analyzer to ensure that InvokerParameterName is being used correctly - that
    /// all arguments to parameters with the attribute are in fact parameter names, using the
    /// nameof operator.
    /// </summary>
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class InvokerParameterNameDiagnosticAnalyzer : DiagnosticAnalyzer
    {

        internal static readonly DiagnosticDescriptor InvokerParameterName = Helpers.CreateWarning(
            "Argument should be a parameter using nameof",
            "Argument {0} of method {1} should be a parameter of the calling member, specified using the nameof operator",
            Category.Correctness);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
            ImmutableArray.Create(InvokerParameterName);

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterNodaTimeSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);
        }

        private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax) context.Node;
            var model = context.SemanticModel;
            var symbol = model.GetSymbolInfo(invocation).Symbol;
            var definition = symbol?.OriginalDefinition;
            if (definition?.Kind != SymbolKind.Method)
            {
                return;
            }
            var method = (IMethodSymbol) definition;
            // TODO: Handle named arguments etc
            var parameters = method.Parameters;
            for (int i = 0; i < parameters.Length; i++)
            {
                var parameter = parameters[i];
                if (!parameter.GetAttributes()
                        .Any(attr => attr.AttributeClass.Name == "InvokerParameterNameAttribute"))
                {
                    continue;
                }
                // TODO: Handle named arguments. (It's unclear how to get the argument that maps
                // to a particular parameter.)
                var argument = invocation.ArgumentList.Arguments[i];
                if (argument.Expression.CSharpKind() != SyntaxKind.NameOfExpression)
                {
                    context.ReportDiagnostic(InvokerParameterName, context.Node, i, method.Name);
                    return;
                }
                var nameOf = (NameOfExpressionSyntax) argument.Expression;
                // The same identifier might matches parameters, instance variables, method names, types etc.
                // We're fine so long as at least one of them is a parameter - if a parameter is one of the
                // candidates, then the compiler has found an in-scope parameter, and we're okay.
                var symbolInfo = model.GetSymbolInfo(nameOf.Argument);
                if (symbolInfo.Symbol?.Kind != SymbolKind.Parameter && !symbolInfo.CandidateSymbols.Select(cs => cs.Kind).Contains(SymbolKind.Parameter))
                {
                    context.ReportDiagnostic(InvokerParameterName, context.Node, i, method.Name);
                    return;
                }
            }
        }
    }
}
<commit_msg>Change InvokerParameterName diagnostic to highlight just the argument, not the whole node, and to remove the name in the message (as it'll be obvious from the location.)<commit_after>// Copyright 2015 The Noda Time Authors. All rights reserved.
// Use of this source code is governed by the Apache License 2.0,
// as found in the LICENSE.txt file.

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;

namespace NodaTime.CodeDiagnostics
{
    /// <summary>
    /// Diagnostic analyzer to ensure that InvokerParameterName is being used correctly - that
    /// all arguments to parameters with the attribute are in fact parameter names, using the
    /// nameof operator.
    /// </summary>
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public sealed class InvokerParameterNameDiagnosticAnalyzer : DiagnosticAnalyzer
    {

        internal static readonly DiagnosticDescriptor InvokerParameterName = Helpers.CreateWarning(
            "Argument should be a parameter using nameof",
            "Argument should be a parameter of the calling member, specified using the nameof operator",
            Category.Correctness);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
            ImmutableArray.Create(InvokerParameterName);

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterNodaTimeSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.InvocationExpression);
        }

        private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax) context.Node;
            var model = context.SemanticModel;
            var symbol = model.GetSymbolInfo(invocation).Symbol;
            var definition = symbol?.OriginalDefinition;
            if (definition?.Kind != SymbolKind.Method)
            {
                return;
            }
            var method = (IMethodSymbol) definition;
            // TODO: Handle named arguments etc
            var parameters = method.Parameters;
            for (int i = 0; i < parameters.Length; i++)
            {
                var parameter = parameters[i];
                if (!parameter.HasAttribute("InvokerParameterNameAttribute"))
                {
                    continue;
                }
                // TODO: Handle named arguments. (It's unclear how to get the argument that maps
                // to a particular parameter.)
                var argument = invocation.ArgumentList.Arguments[i];
                if (argument.Expression.CSharpKind() != SyntaxKind.NameOfExpression)
                {
                    context.ReportDiagnostic(InvokerParameterName, argument);
                    return;
                }

                var nameOf = (NameOfExpressionSyntax) argument.Expression;
                // The same identifier might matches parameters, instance variables, method names, types etc.
                // We're fine so long as at least one of them is a parameter - if a parameter is one of the
                // candidates, then the compiler has found an in-scope parameter, and we're okay.
                var symbolInfo = model.GetSymbolInfo(nameOf.Argument);
                if (symbolInfo.Symbol?.Kind != SymbolKind.Parameter && !symbolInfo.CandidateSymbols.Select(cs => cs.Kind).Contains(SymbolKind.Parameter))
                {
                    context.ReportDiagnostic(InvokerParameterName, argument);
                    return;
                }
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.07164694935531038, 'fraction_numerical': 0.002126811112588063, 'mean_word_length': 2.044921084581141, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1464824', 'n_tokens_mistral': 1758, 'n_tokens_neox': 1644, 'n_words': 535}