From ab36f60f4855bb77b57f3e48764fd42d6da33581 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 14 Apr 2020 07:46:37 -0700 Subject: [PATCH 1/8] ArgumentException analyzer updates and fixer implementation --- .../Core/AnalyzerReleases.Unshipped.md | 3 +- .../MicrosoftNetCoreAnalyzersResources.resx | 8 +- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 112 ++++++- .../InstantiateArgumentExceptionsCorrectly.cs | 45 ++- .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 14 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 14 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 14 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 14 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 14 +- ...antiateArgumentExceptionsCorrectlyTests.cs | 279 ++++++++++++++++-- 18 files changed, 551 insertions(+), 78 deletions(-) diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md index 7afb2e455d..26485d7937 100644 --- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -7,4 +7,5 @@ CA1069 | Design | Info | EnumShouldNotHaveDuplicatedValues, [Documentation](http CA2011 | Reliability | Info | AvoidInfiniteRecursion, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2011) CA2012 | Reliability | Hidden | UseValueTasksCorrectlyAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2012) CA2013 | Reliability | Warning | DoNotUseReferenceEqualsWithValueTypesAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2013) -CA2014 | Reliability | Warning | DoNotUseStackallocInLoopsAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2014) \ No newline at end of file +CA2014 | Reliability | Warning | DoNotUseStackallocInLoopsAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2014) +CA2208 | Usage | Info | InstantiateArgumentExceptionsCorrectlyAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2208) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 18c335c233..82c4d10e42 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -460,7 +460,7 @@ A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. - Call the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. @@ -1251,4 +1251,10 @@ Potential stack overflow. Move the stackalloc out of the loop. + + Change to call the two argument constructor, pass null for the message. + + + Swap the arguments order + diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs index e9e983ae71..bb12b37780 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs @@ -1,8 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Globalization; +using System.Linq; +using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; namespace Microsoft.NetCore.Analyzers.Runtime { @@ -11,19 +18,110 @@ namespace Microsoft.NetCore.Analyzers.Runtime /// public abstract class InstantiateArgumentExceptionsCorrectlyFixer : CodeFixProvider { - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Empty; + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(InstantiateArgumentExceptionsCorrectlyAnalyzer.RuleId); - public sealed override FixAllProvider GetFixAllProvider() + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers - return WellKnownFixAllProviders.BatchFixer; + SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var diagnostic = context.Diagnostics.First(); + string messagePositionString = diagnostic.Properties.GetValueOrDefault(InstantiateArgumentExceptionsCorrectlyAnalyzer.MessagePosition); + if (messagePositionString != null) + { + var diagnosticSpan = diagnostic.Location.SourceSpan; + SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true); + if (node is ObjectCreationExpressionSyntax creation) + { + int messagePosition = int.Parse(messagePositionString, CultureInfo.InvariantCulture); + switch (creation.ArgumentList.Arguments.Count) + { + case 1: // Add null message + context.RegisterCodeFix( + CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument, + createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument), + diagnostic); + break; + case 2: // Swap message and paramete name + context.RegisterCodeFix( + CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, + createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, messagePosition, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder), + diagnostic); + break; + case 3: // 3 parameter, message can be 1st or 3rd parameter + context.RegisterCodeFix( + CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, + createChangedDocument: c => SwapArgumentsOrderThreeParameters(context.Document, creation, messagePosition, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder), + diagnostic); + break; + + } + } + } } - public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + private static async Task SwapArgumentsOrder(Document document, ObjectCreationExpressionSyntax creation, int messagePosition, CancellationToken token) { - // Fixer not yet implemented. - return Task.CompletedTask; + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[messagePosition].Expression, editor.Generator); + SyntaxNode newCreation; + if (messagePosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[0]); + } + editor.ReplaceNode(creation, newCreation); + return editor.GetChangedDocument(); + } + private static async Task SwapArgumentsOrderThreeParameters(Document document, ObjectCreationExpressionSyntax creation, int messagePosition, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[messagePosition].Expression, editor.Generator); + SyntaxNode newCreation; + if (messagePosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter, creation.ArgumentList.Arguments[2]); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[1], creation.ArgumentList.Arguments[0]); + } + editor.ReplaceNode(creation, newCreation); + return editor.GetChangedDocument(); } + + private static async Task AddNullMessageToArgumentList(Document document, ObjectCreationExpressionSyntax creation, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode argument = AddNameOfIfLiteral(creation.ArgumentList.Arguments.First().Expression, editor.Generator); + SyntaxNode newCreation = editor.Generator.ObjectCreationExpression( + creation.Type, + editor.Generator.Argument(editor.Generator.NullLiteralExpression()), + argument); + editor.ReplaceNode(creation, newCreation); + return editor.GetChangedDocument(); + } + + private static SyntaxNode AddNameOfIfLiteral(ExpressionSyntax expression, SyntaxGenerator generator) + { + if (expression is LiteralExpressionSyntax literal) + { + return GetNameOfExpression(generator, literal.Token.ValueText); + } + return expression; + } + + private static SyntaxNode GetNameOfExpression(SyntaxGenerator generator, string identifierNameArgument) => + generator.NameOfExpression(generator.IdentifierName(identifierNameArgument)); } } \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index 4ee5aba4d2..7df4c9e792 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Globalization; using Analyzer.Utilities; using Analyzer.Utilities.Extensions; using Microsoft.CodeAnalysis; @@ -16,6 +17,7 @@ namespace Microsoft.NetCore.Analyzers.Runtime public sealed class InstantiateArgumentExceptionsCorrectlyAnalyzer : DiagnosticAnalyzer { internal const string RuleId = "CA2208"; + internal const string MessagePosition = nameof(MessagePosition); private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyTitle), MicrosoftNetCoreAnalyzersResources.ResourceManager, typeof(MicrosoftNetCoreAnalyzersResources)); @@ -28,7 +30,7 @@ public sealed class InstantiateArgumentExceptionsCorrectlyAnalyzer : DiagnosticA s_localizableTitle, s_localizableMessageNoArguments, DiagnosticCategory.Usage, - RuleLevel.IdeHidden_BulkConfigurable, + RuleLevel.IdeSuggestion, description: s_localizableDescription, isPortedFxCopRule: true, isDataflowRule: false); @@ -37,7 +39,7 @@ public sealed class InstantiateArgumentExceptionsCorrectlyAnalyzer : DiagnosticA s_localizableTitle, s_localizableMessageIncorrectMessage, DiagnosticCategory.Usage, - RuleLevel.IdeHidden_BulkConfigurable, + RuleLevel.IdeSuggestion, description: s_localizableDescription, isPortedFxCopRule: true, isDataflowRule: false); @@ -46,7 +48,7 @@ public sealed class InstantiateArgumentExceptionsCorrectlyAnalyzer : DiagnosticA s_localizableTitle, s_localizableMessageIncorrectParameterName, DiagnosticCategory.Usage, - RuleLevel.IdeHidden_BulkConfigurable, + RuleLevel.IdeSuggestion, description: s_localizableDescription, isPortedFxCopRule: true, isDataflowRule: false); @@ -91,7 +93,7 @@ private static void AnalyzeObjectCreation( if (creation.Arguments.Length == 0) { - if (HasMessageOrParameterNameConstructor(creation.Type)) + if (HasParameters(owningSymbol) && HasMessageOrParameterNameConstructor(creation.Type)) { // Call the {0} constructor that contains a message and/ or paramName parameter context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(RuleNoArguments, creation.Type.Name)); @@ -99,24 +101,37 @@ private static void AnalyzeObjectCreation( } else { + Diagnostic? diagnostic = null; foreach (IArgumentOperation argument in creation.Arguments) { if (argument.Parameter.Type.SpecialType != SpecialType.System_String) { continue; } - string? value = argument.Value.ConstantValue.HasValue ? argument.Value.ConstantValue.Value as string : null; if (value == null) { continue; } - - CheckArgument(owningSymbol, creation, argument.Parameter, value, context); + diagnostic = CheckArgument(owningSymbol, creation, argument.Parameter, value, context); + if (diagnostic != null && !diagnostic.Properties.IsEmpty) + { + break; + } + } + if (diagnostic != null) + { + context.ReportDiagnostic(diagnostic); } } } - private static void CheckArgument( + + private static bool HasParameters(ISymbol owningSymbol) + { + return owningSymbol.GetParameters().Length > 0; + } + + private static Diagnostic? CheckArgument( ISymbol targetSymbol, IObjectCreationOperation creation, IParameterSymbol parameter, @@ -125,26 +140,28 @@ private static void CheckArgument( { bool matchesParameter = MatchesParameter(targetSymbol, creation, stringArgument); DiagnosticDescriptor? rule = null; + var dictBuilder = ImmutableDictionary.CreateBuilder(); if (IsMessage(parameter) && matchesParameter) { rule = RuleIncorrectMessage; + dictBuilder.Add(MessagePosition, parameter.Ordinal.ToString(CultureInfo.InvariantCulture)); } - else if (IsParameterName(parameter) && !matchesParameter) + else if (HasParameters(targetSymbol) && IsParameterName(parameter) && !matchesParameter) { // Allow argument exceptions in accessors to use the associated property symbol name. - if (MatchesAssociatedSymbol(targetSymbol, stringArgument)) + if (!MatchesAssociatedSymbol(targetSymbol, stringArgument)) { - return; + rule = RuleIncorrectParameterName; } - - rule = RuleIncorrectParameterName; } if (rule != null) { - context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(rule, targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name)); + return context.Operation.Syntax.CreateDiagnostic(rule, dictBuilder.ToImmutable(), targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); } + + return null; } private static bool IsMessage(IParameterSymbol parameter) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index c1158444bb..2b6674c960 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1012,11 +1012,21 @@ Inicializujte statická pole typu hodnot jako vložená + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Zavolal se výchozí konstruktor (bez parametrů) typu výjimky, který je třídou ArgumentException nebo je z ní odvozený, nebo se do jeho konstruktoru s parametry předal nesprávný argument řetězce. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. Metoda {0} předává název parametru {1} jako argument {2} konstruktoru {3}. Nahraďte tento argument popisnou zprávou a předejte název parametru na správné pozici. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Zavolejte konstruktor {0}, který obsahuje zprávu a/nebo parametr paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Zavolejte konstruktor {0}, který obsahuje zprávu a/nebo parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 09bd8601d8..99f6359375 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1012,11 +1012,21 @@ Statische Felder für Werttyp inline initialisieren + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Ein Aufruf erfolgt an den (parameterlosen) Standardkonstruktur eines Ausnahmetyps, der einer ArgumentException entspricht oder von dieser ableitet, oder ein falsches Zeichenfolgenargument wurde an einen parametrisierten Konstruktor eines Ausnahmetyps übergeben, der einer ArgumentException entspricht oder von dieser ableitet. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. Die Methode "{0}" übergibt den Parameternamen "{1}" als {2}-Argument an einen {3}-Konstruktor. Ersetzen Sie dieses Argument durch eine aussagekräftige Nachricht, und übergeben Sie den Parameternamen an der richtigen Position. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Rufen Sie den Konstruktur "{0}" auf, der eine Nachricht und/oder einen paramName-Parameter enthält. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Rufen Sie den Konstruktur "{0}" auf, der eine Nachricht und/oder einen paramName-Parameter enthält. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index f99aa5936c..57cc650cf4 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1012,11 +1012,21 @@ Inicializar campos estáticos de tipo de valor insertados + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Se realiza una llamada al constructor predeterminado (sin parámetros) de un tipo de excepción que es o se deriva de ArgumentException, o se pasa un argumento de cadena incorrecto a un constructor con parámetros de un tipo de excepción que es o se deriva de ArgumentException. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. El método {0} pasa un nombre de parámetro "{1}" como argumento {2} a un constructor {3}. Reemplace este argumento por un mensaje descriptivo y pase el nombre del parámetro en la posición correcta. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Llame al constructor {0} que contiene un mensaje o un parámetro paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Llame al constructor {0} que contiene un mensaje o un parámetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 0475845839..4d72315d52 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1012,11 +1012,21 @@ Initialiser les champs static de type valeur inline + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Le constructeur par défaut (sans paramètre) d'un type d'exception qui correspond à ou dérive de ArgumentException est appelé. Ou bien, un argument de chaîne incorrect est passé à un constructeur paramétré d'un type d'exception qui correspond à ou dérive de ArgumentException. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. La méthode {0} passe le nom de paramètre '{1}' en tant qu'argument {2} à un constructeur {3}. Remplacez cet argument par un message descriptif, et passez le nom de paramètre à l'emplacement approprié. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Appelez le constructeur {0} qui contient un message et/ou un paramètre paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Appelez le constructeur {0} qui contient un message et/ou un paramètre paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 642704f6a8..595b84f554 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1012,11 +1012,21 @@ Inizializzare inline i campi statici di tipo valore + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Viene effettuata una chiamata al costruttore predefinito (senza parametri) di un tipo di eccezione che corrisponde a o deriva da ArgumentException oppure viene passato un argomento stringa non corretto a un costruttore con parametri di un tipo di eccezione che corrisponde a o deriva da ArgumentException. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. Il metodo {0} passa il nome di parametro '{1}' come argomento di {2} a un costruttore {3}. Sostituire questo argomento con un messaggio descrittivo e passare il nome di parametro nella posizione corretta. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Chiamare il costruttore {0} che contiene un messaggio e/o il parametro paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Chiamare il costruttore {0} che contiene un messaggio e/o il parametro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index eda0249670..a9bcc3b1f6 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1012,11 +1012,21 @@ 値型の静的フィールドをインラインで初期化します + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. ArgumentException またはそれから派生した例外の種類の既定の (パラメーターのない) コンストラクターに対して呼び出しが行われます。または、正しくない文字列引数が、ArgumentException またはそれから派生した例外の種類のパラメーター化されたコンストラクターに渡されます。 + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. メソッド {0} は、パラメーター名 '{1}' を {2} 引数として {3} コンストラクターに渡します。この引数を説明メッセージに置き換え、正しい位置にパラメーター名を渡してください。 @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - メッセージおよび paramName パラメーターまたはそのいずれかを含む {0} コンストラクターを呼び出します。 + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + メッセージおよび paramName パラメーターまたはそのいずれかを含む {0} コンストラクターを呼び出します。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 81ec6207e3..75dae1a4e4 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1012,11 +1012,21 @@ 값 형식 정적 필드 인라인을 초기화하세요. + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. 예외 형식의 매개 변수가 없는 기본 생성자에 발생하는 호출은 ArgumentException이거나 ArgumentException에서 파생됩니다. 즉, 올바르지 않은 문자열 인수는 ArgumentException이거나 ArgumentException에서 파생된 예외 형식의 매개 변수가 있는 생성자로 전달됩니다. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. {0} 메서드가 매개 변수 이름 '{1}'을(를) {3} 생성자에 {2} 인수로 전달합니다. 이 인수를 자세한 설명이 있는 메시지로 바꾸고 매개 변수 이름을 올바른 위치에 전달하세요. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - 메시지 및/또는 paramName 매개 변수를 포함하는 {0} 생성자를 호출하세요. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + 메시지 및/또는 paramName 매개 변수를 포함하는 {0} 생성자를 호출하세요. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index ec9d31a2cc..1d3dd756f8 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1013,11 +1013,21 @@ Zainicjuj pola statyczne typu wartości w deklaracji pól + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Wywołano domyślny (bezparametrowy) konstruktor typu wyjątku ArgumentException lub typu pochodzącego od niego albo przekazano niepoprawny argument ciągu do konstruktora parametryzowanego typu wyjątku ArgumentException lub typu pochodzącego od niego. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. Metoda {0} przekazuje nazwę parametru „{1}” jako argument {2} do konstruktora {3}. Zastąp ten argument opisowym komunikatem i przekaż nazwę parametru na poprawnej pozycji. @@ -1029,8 +1039,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Wywołaj konstruktor {0}, który zawiera komunikat i/lub parametr paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Wywołaj konstruktor {0}, który zawiera komunikat i/lub parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 44f3b8854b..ec5f15cd31 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1012,11 +1012,21 @@ Inicializar campos estáticos de tipo de valor embutido + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. É feita uma chamada para o construtor padrão (sem parâmetro) de um tipo de exceção que é ArgumentException ou derivado dele, ou então um argumento de cadeia de caracteres incorreto é passado para um construtor parametrizado de um tipo de exceção que é ArgumentException ou derivado dele. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. O método {0} passa o nome de parâmetro '{1}' como o argumento {2} para um construtor {3}. Substitua este argumento por uma mensagem descritiva e passe o nome do parâmetro na posição correta. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Chame o construtor {0} que contém uma mensagem e/ou um parâmetro paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Chame o construtor {0} que contém uma mensagem e/ou um parâmetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 32f8c634bf..331e96761c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1012,11 +1012,21 @@ Используйте встроенную инициализацию статических полей типов значений + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. Выполняется вызов конструктора по умолчанию (без параметров) для типа исключения, который является ArgumentException или производным от него, либо в параметризованный конструктор для типа исключения, который является ArgumentException или производным от него, передается неправильный строковый аргумент. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. Метод {0} передает имя параметра "{1}" в качестве аргумента {2} в конструктор {3}. Замените этот аргумент описательным сообщением и передайте имя этого параметра в правильном положении. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Вызывайте конструктор {0}, который содержит сообщение и (или) параметр paramName. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Вызывайте конструктор {0}, который содержит сообщение и (или) параметр paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 6862c4f4c3..24fc6ea68a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1012,11 +1012,21 @@ Değer türünde statik alanları satır içi olarak başlatın + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. ArgumentException olan veya bundan türetilen bir özel durum türünün varsayılan (parametresiz) oluşturucusuna bir çağrı yapıldı veya ArgumentException olan veya bundan türetilen bir özel durum türünün parametreli oluşturucusuna yanlış bir dize bağımsız değişkeni geçirildi. + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. {0} yöntemi, bir {3} oluşturucusuna {2} bağımsız değişkeni olarak '{1}' parametre adını geçiriyor. Bu bağımsız değişkeni açıklayıcı bir iletiyle değiştirin ve parametre adını doğru konumda geçirin. @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - Bir iletiyi ve/veya paramName parametresini içeren {0} oluşturucusunu çağırın. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Bir iletiyi ve/veya paramName parametresini içeren {0} oluşturucusunu çağırın. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index bc0bf21010..f6d19503a0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1012,11 +1012,21 @@ 以内联方式初始化值类型的静态字段 + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. 调用了 ArgumentException 异常类型或其派生异常类型的默认(无参数)构造函数,或将不正确的字符串参数传递给 ArgumentException. 异常类型或其派生异常类型的参数化构造函数。 + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. 方法 {0} 将参数名“{1}”作为变量 {2} 传递给构造函数 {3}。请将此参数替换为一则说明性消息并在正确的位置传递参数名。 @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - 调用 {0} 构造函数,该函数包含 message 和/或 paramName 参数。 + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + 调用 {0} 构造函数,该函数包含 message 和/或 paramName 参数。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 255f534d7d..47b24855b8 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1012,11 +1012,21 @@ 初始化實值型別靜態欄位內嵌 + + Change to call the two argument constructor, pass null for the message. + Change to call the two argument constructor, pass null for the message. + + A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. 已呼叫例外狀況類型為 ArgumentException 或由其衍生的預設 (無參數) 建構函式; 或將不正確的字串引數傳遞到例外狀況類型為 ArgumentException 或由其衍生的參數化建構函式。 + + Swap the arguments order + Swap the arguments order + + Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. 方法 {0} 會將參數名稱 '{1}' 以 {2} 引數傳遞到 {3} 建構函式。請以描述性訊息取代此引數,並將該參數名稱傳遞到正確的位置。 @@ -1028,8 +1038,8 @@ - Call the {0} constructor that contains a message and/or paramName parameter. - 請呼叫包含 message 及 (或) paramName 參數的 {0} 建構函式。 + Please use overload of the {0} constructor that contains a message and/or paramName parameter. + 請呼叫包含 message 及 (或) paramName 參數的 {0} 建構函式。 diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index f9cf7f5768..f709a306a5 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -106,9 +106,9 @@ End Sub } [Fact] - public async Task ArgumentException_ParameterNameAsMessage_Warns() + public async Task ArgumentException_ParameterNameAsMessage_WarnsAndCodeFixesWithNameOf() { - await VerifyCS.VerifyAnalyzerAsync(@" + await VerifyCS.VerifyCodeFixAsync(@" public class Class { public void Test(string first) @@ -116,7 +116,15 @@ public void Test(string first) throw new System.ArgumentException(""first""); } }", - GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException")); + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(null, nameof(first)); + } + }" + ); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -124,13 +132,14 @@ Public Sub Test(first As String) Throw New System.ArgumentException(""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") + ); } [Fact] - public async Task ArgumentException_ReversedArguments_Warns() + public async Task ArgumentException_ReversedArguments_WarnsAndCodeFixesWithNameOf() { - await VerifyCS.VerifyAnalyzerAsync(@" + await VerifyCS.VerifyCodeFixAsync(@" public class Class { public void Test(string first) @@ -138,8 +147,15 @@ public void Test(string first) throw new System.ArgumentException(""first"", ""first is incorrect""); } }", - GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException"), - GetCSharpIncorrectParameterNameExpectedResult(6, 31, "Test", "first is incorrect", "paramName", "ArgumentException")); + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(""first is incorrect"", nameof(first)); + } + }" + ); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -147,8 +163,84 @@ Public Sub Test(first As String) Throw New System.ArgumentException(""first"", ""first is incorrect"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException"), - GetBasicIncorrectParameterNameExpectedResult(4, 31, "Test", "first is incorrect", "paramName", "ArgumentException")); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") + ); + } + + [Fact] + public async Task ArgumentException_ParameterWithNameofAsMessage_WarnsAndCodeFixes() + { + await VerifyCS.VerifyCodeFixAsync(@" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(nameof(first)); + } + }", + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException") + , @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(null, nameof(first)); + } + }" + ); + } + + [Fact] + public async Task ArgumentException_ReversedArgumentsWithNameof_WarnsAndCodeFixes() + { + await VerifyCS.VerifyCodeFixAsync(@" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(nameof(first), ""first is incorrect""); + } + }", + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(""first is incorrect"", nameof(first)); + } + }" + ); + } + + [Fact] + public async Task ArgumentException_Reversed3Arguments_WarnsAndCodeFixes() + { + await VerifyCS.VerifyCodeFixAsync(@" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(""first"", ""first is incorrect"", null); + } + }", + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentException(""first is incorrect"", nameof(first), null); + } + }" + ); + + await VerifyVB.VerifyAnalyzerAsync(@" + Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first"", ""first is incorrect"", Nothing) + End Sub + End Class", + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") + ); } [Fact] @@ -170,7 +262,7 @@ Public Sub Test(first As String) Throw New System.ArgumentNullException() End Sub End Class", - GetBasicNoArgumentsExpectedResult(4, 31, "ArgumentNullException")); + GetBasicNoArgumentsExpectedResult(4, 31, "ArgumentNullException")); } [Fact] @@ -188,9 +280,9 @@ public void Test(string first) } [Fact] - public async Task ArgumentNullException_ReversedArguments_Warns() + public async Task ArgumentNullException_ReversedArguments_WarnsAndCodeFixes() { - await VerifyCS.VerifyAnalyzerAsync(@" + await VerifyCS.VerifyCodeFixAsync(@" public class Class { public void Test(string first) @@ -198,8 +290,15 @@ public void Test(string first) throw new System.ArgumentNullException(""first is null"", ""first""); } }", - GetCSharpIncorrectParameterNameExpectedResult(6, 31, "Test", "first is null", "paramName", "ArgumentNullException"), - GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentNullException")); + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentNullException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentNullException(nameof(first), ""first is null""); + } + }" + ); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -207,8 +306,8 @@ Public Sub Test(first As String) Throw New System.ArgumentNullException(""first is null"", ""first"") End Sub End Class", - GetBasicIncorrectParameterNameExpectedResult(4, 31, "Test", "first is null", "paramName", "ArgumentNullException"), - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentNullException")); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentNullException") + ); } [Fact] @@ -256,9 +355,9 @@ End Sub } [Fact] - public async Task ArgumentOutOfRangeException_ReversedArguments_Warns() + public async Task ArgumentOutOfRangeException_ReversedArguments_WarnsAndCodeFixes() { - await VerifyCS.VerifyAnalyzerAsync(@" + await VerifyCS.VerifyCodeFixAsync(@" public class Class { public void Test(string first) @@ -266,8 +365,15 @@ public void Test(string first) throw new System.ArgumentOutOfRangeException(""first is out of range"", ""first""); } }", - GetCSharpIncorrectParameterNameExpectedResult(6, 31, "Test", "first is out of range", "paramName", "ArgumentOutOfRangeException"), - GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "ArgumentOutOfRangeException"), @" + public class Class + { + public void Test(string first) + { + throw new System.ArgumentOutOfRangeException(nameof(first), ""first is out of range""); + } + }" + ); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -275,8 +381,41 @@ Public Sub Test(first As String) Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") End Sub End Class", - GetBasicIncorrectParameterNameExpectedResult(4, 31, "Test", "first is out of range", "paramName", "ArgumentOutOfRangeException"), - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException") + ); + } + + [Fact] + public async Task ArgumentOutOfRangeException_Reversed3Arguments_WarnsAndCodeFixes() + { + await VerifyCS.VerifyCodeFixAsync(@" + public class Class + { + public void Test(string first) + { + var val = new object(); + throw new System.ArgumentOutOfRangeException(""first is incorrect"", val, ""first""); + } + }", + GetCSharpIncorrectMessageExpectedResult(7, 31, "Test", "first", "message", "ArgumentOutOfRangeException"), @" + public class Class + { + public void Test(string first) + { + var val = new object(); + throw new System.ArgumentOutOfRangeException(nameof(first), val, ""first is out of range""); + } + }" + ); + + await VerifyVB.VerifyAnalyzerAsync(@" + Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") + End Sub + End Class", + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException") + ); } [Fact] @@ -324,9 +463,9 @@ End Sub } [Fact] - public async Task DuplicateWaitObjectException_ReversedArguments_Warns() + public async Task DuplicateWaitObjectException_ReversedArguments_WarnsAndCodeFixes() { - await VerifyCS.VerifyAnalyzerAsync(@" + await VerifyCS.VerifyCodeFixAsync(@" public class Class { public void Test(string first) @@ -334,8 +473,15 @@ public void Test(string first) throw new System.DuplicateWaitObjectException(""first is duplicate"", ""first""); } }", - GetCSharpIncorrectParameterNameExpectedResult(6, 31, "Test", "first is duplicate", "parameterName", "DuplicateWaitObjectException"), - GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "DuplicateWaitObjectException")); + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "first", "message", "DuplicateWaitObjectException"), @" + public class Class + { + public void Test(string first) + { + throw new System.DuplicateWaitObjectException(nameof(first), ""first is duplicate""); + } + }" + ); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -343,10 +489,71 @@ Public Sub Test(first As String) Throw New System.DuplicateWaitObjectException(""first is duplicate"", ""first"") End Sub End Class", - GetBasicIncorrectParameterNameExpectedResult(4, 31, "Test", "first is duplicate", "parameterName", "DuplicateWaitObjectException"), - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "DuplicateWaitObjectException")); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "DuplicateWaitObjectException") + ); + } + + [Fact] + public async Task ArgumentNullException_ParentHasNoParameter_Not_Warns() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + public void Test() + { + throw new System.ArgumentNullException(""Invalid argument""); + } + }" + ); + } + + [Fact] + public async Task ArgumentException_ParentHasNoParameter_Not_Warns() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + public void Test() + { + throw new System.ArgumentException(""Invalid argument"", ""test""); + } + }" + ); } + [Fact] + public async Task ArgumentException_VariableUsed_Not_Warns() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + public void Test(string paramName, string message) + { + throw new System.ArgumentException(paramName, message); + } + }" + ); + } + + [Fact] + public async Task ArgumentException_NoArgumentss_ParentMethod_HasNoParameter_DoesNotWarn() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + public void Test() + { + throw new System.ArgumentException(); + } + }"); + + await VerifyVB.VerifyAnalyzerAsync(@" + Public Class [MyClass] + Public Sub Test() + Throw New System.ArgumentException() + End Sub + End Class"); + } [Fact] public async Task ArgumentException_CorrectMessage_DoesNotWarn() @@ -408,6 +615,20 @@ End Sub End Class"); } + [Fact] + public async Task ArgumentNullException_VariableUsed_Not_Warns() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + string str = ""Hi there""; + public void Test(string first) + { + throw new System.ArgumentNullException(str); + } + }" + ); + } [Fact] From 21147990af373c867a93b2e3b8c6d73d8520c520 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 14 Apr 2020 10:10:22 -0700 Subject: [PATCH 2/8] Typo fix, moved code to sharp fixer --- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 79 +++++++++++++ .../MicrosoftNetCoreAnalyzersResources.resx | 2 +- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 104 +----------------- .../InstantiateArgumentExceptionsCorrectly.cs | 2 + .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 2 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 2 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 2 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 2 +- ...antiateArgumentExceptionsCorrectlyTests.cs | 75 +++++-------- ...ntiateArgumentExceptionsCorrectly.Fixer.vb | 3 + 19 files changed, 132 insertions(+), 159 deletions(-) diff --git a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs index 17e6d2a96e..3201b99687 100644 --- a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs +++ b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs @@ -1,9 +1,16 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Composition; +using System.Globalization; using Microsoft.NetCore.Analyzers.Runtime; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editing; +using System.Threading; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.NetCore.Analyzers; +using System.Threading.Tasks; namespace Microsoft.NetCore.CSharp.Analyzers.Runtime { @@ -13,5 +20,77 @@ namespace Microsoft.NetCore.CSharp.Analyzers.Runtime [ExportCodeFixProvider(LanguageNames.CSharp), Shared] public sealed class CSharpInstantiateArgumentExceptionsCorrectlyFixer : InstantiateArgumentExceptionsCorrectlyFixer { + protected override void PopulateCodeFix(CodeFixContext context, Diagnostic diagnostic, string paramPositionString, SyntaxNode node) + { + if (node is ObjectCreationExpressionSyntax creation) + { + int paramPosition = int.Parse(paramPositionString, CultureInfo.InvariantCulture); + CodeAction? codeAction = null; + if (creation.ArgumentList.Arguments.Count == 1) + { // Add null message + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument, + createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument); + } + else + { // Swap message and paramete name + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, + createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, paramPosition, creation.ArgumentList.Arguments.Count, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder); + } + context.RegisterCodeFix(codeAction, diagnostic); + } + } + + private static async Task SwapArgumentsOrder(Document document, ObjectCreationExpressionSyntax creation, int paramPosition, int argumentCount, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[paramPosition].Expression, editor.Generator); + SyntaxNode newCreation; + if (argumentCount == 2) + { + if (paramPosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[0]); + } + } + else // 3 arguments + { + if (paramPosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter, creation.ArgumentList.Arguments[2]); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[1], creation.ArgumentList.Arguments[0]); + } + } + editor.ReplaceNode(creation, newCreation); + return editor.GetChangedDocument(); + } + + private static async Task AddNullMessageToArgumentList(Document document, ObjectCreationExpressionSyntax creation, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode argument = AddNameOfIfLiteral(creation.ArgumentList.Arguments.First().Expression, editor.Generator); + SyntaxNode newCreation = editor.Generator.ObjectCreationExpression(creation.Type, editor.Generator.Argument(editor.Generator.NullLiteralExpression()), argument); + editor.ReplaceNode(creation, newCreation); + return editor.GetChangedDocument(); + } + + private static SyntaxNode AddNameOfIfLiteral(ExpressionSyntax expression, SyntaxGenerator generator) + { + if (expression is LiteralExpressionSyntax literal) + { + return generator.NameOfExpression(generator.IdentifierName(literal.Token.ValueText)); + } + return expression; + } } } \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 82c4d10e42..2db2030178 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -460,7 +460,7 @@ A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs index bb12b37780..453d249630 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs @@ -1,15 +1,11 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; -using System.Globalization; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; + namespace Microsoft.NetCore.Analyzers.Runtime { @@ -24,104 +20,16 @@ public abstract class InstantiateArgumentExceptionsCorrectlyFixer : CodeFixProvi public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); - string messagePositionString = diagnostic.Properties.GetValueOrDefault(InstantiateArgumentExceptionsCorrectlyAnalyzer.MessagePosition); - if (messagePositionString != null) + string paramPositionString = diagnostic.Properties.GetValueOrDefault(InstantiateArgumentExceptionsCorrectlyAnalyzer.MessagePosition); + if (paramPositionString != null) { - var diagnosticSpan = diagnostic.Location.SourceSpan; + SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true); - if (node is ObjectCreationExpressionSyntax creation) - { - int messagePosition = int.Parse(messagePositionString, CultureInfo.InvariantCulture); - switch (creation.ArgumentList.Arguments.Count) - { - case 1: // Add null message - context.RegisterCodeFix( - CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument, - createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument), - diagnostic); - break; - case 2: // Swap message and paramete name - context.RegisterCodeFix( - CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, - createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, messagePosition, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder), - diagnostic); - break; - case 3: // 3 parameter, message can be 1st or 3rd parameter - context.RegisterCodeFix( - CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, - createChangedDocument: c => SwapArgumentsOrderThreeParameters(context.Document, creation, messagePosition, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder), - diagnostic); - break; - - } - } - } - } - - private static async Task SwapArgumentsOrder(Document document, ObjectCreationExpressionSyntax creation, int messagePosition, CancellationToken token) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); - SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[messagePosition].Expression, editor.Generator); - SyntaxNode newCreation; - if (messagePosition == 0) - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter); - } - else - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[0]); - } - editor.ReplaceNode(creation, newCreation); - return editor.GetChangedDocument(); - } - - private static async Task SwapArgumentsOrderThreeParameters(Document document, ObjectCreationExpressionSyntax creation, int messagePosition, CancellationToken token) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); - SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[messagePosition].Expression, editor.Generator); - SyntaxNode newCreation; - if (messagePosition == 0) - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter, creation.ArgumentList.Arguments[2]); - } - else - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[1], creation.ArgumentList.Arguments[0]); - } - editor.ReplaceNode(creation, newCreation); - return editor.GetChangedDocument(); - } - - private static async Task AddNullMessageToArgumentList(Document document, ObjectCreationExpressionSyntax creation, CancellationToken token) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); - SyntaxNode argument = AddNameOfIfLiteral(creation.ArgumentList.Arguments.First().Expression, editor.Generator); - SyntaxNode newCreation = editor.Generator.ObjectCreationExpression( - creation.Type, - editor.Generator.Argument(editor.Generator.NullLiteralExpression()), - argument); - editor.ReplaceNode(creation, newCreation); - return editor.GetChangedDocument(); - } - - private static SyntaxNode AddNameOfIfLiteral(ExpressionSyntax expression, SyntaxGenerator generator) - { - if (expression is LiteralExpressionSyntax literal) - { - return GetNameOfExpression(generator, literal.Token.ValueText); + PopulateCodeFix(context, diagnostic, paramPositionString, node); } - return expression; } - private static SyntaxNode GetNameOfExpression(SyntaxGenerator generator, string identifierNameArgument) => - generator.NameOfExpression(generator.IdentifierName(identifierNameArgument)); + protected abstract void PopulateCodeFix(CodeFixContext context, Diagnostic diagnostic, string paramPositionString, SyntaxNode node); } } \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index 7df4c9e792..1edb1d2945 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -108,11 +108,13 @@ private static void AnalyzeObjectCreation( { continue; } + string? value = argument.Value.ConstantValue.HasValue ? argument.Value.ConstantValue.Value as string : null; if (value == null) { continue; } + diagnostic = CheckArgument(owningSymbol, creation, argument.Parameter, value, context); if (diagnostic != null && !diagnostic.Properties.IsEmpty) { diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index 2b6674c960..10562ab763 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Zavolejte konstruktor {0}, který obsahuje zprávu a/nebo parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 99f6359375..c2fa0c7358 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Rufen Sie den Konstruktur "{0}" auf, der eine Nachricht und/oder einen paramName-Parameter enthält. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 57cc650cf4..7621ac4dca 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Llame al constructor {0} que contiene un mensaje o un parámetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 4d72315d52..94c8c0e37a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Appelez le constructeur {0} qui contient un message et/ou un paramètre paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 595b84f554..4fb565faed 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Chiamare il costruttore {0} che contiene un messaggio e/o il parametro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index a9bcc3b1f6..ee7145959d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. メッセージおよび paramName パラメーターまたはそのいずれかを含む {0} コンストラクターを呼び出します。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 75dae1a4e4..b748a4884b 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. 메시지 및/또는 paramName 매개 변수를 포함하는 {0} 생성자를 호출하세요. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index 1d3dd756f8..263f46879c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1039,7 +1039,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Wywołaj konstruktor {0}, który zawiera komunikat i/lub parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index ec5f15cd31..51b0578019 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Chame o construtor {0} que contém uma mensagem e/ou um parâmetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 331e96761c..af2dcaf4be 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Вызывайте конструктор {0}, который содержит сообщение и (или) параметр paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 24fc6ea68a..809f9518ed 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. Bir iletiyi ve/veya paramName parametresini içeren {0} oluşturucusunu çağırın. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index f6d19503a0..6200f29ccf 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. 调用 {0} 构造函数,该函数包含 message 和/或 paramName 参数。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 47b24855b8..c1ef45cb75 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1038,7 +1038,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Please use overload of the {0} constructor that contains a message and/or paramName parameter. 請呼叫包含 message 及 (或) paramName 參數的 {0} 建構函式。 diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index f709a306a5..acc87d7340 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -34,7 +34,7 @@ Public Sub Test(first As String) Throw New System.ArgumentException() End Sub End Class", - GetBasicNoArgumentsExpectedResult(4, 31, "ArgumentException")); + GetBasicNoArgumentsExpectedResult(4, 31, "ArgumentException")); } [Fact] @@ -123,8 +123,7 @@ public void Test(string first) { throw new System.ArgumentException(null, nameof(first)); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -132,8 +131,7 @@ Public Sub Test(first As String) Throw New System.ArgumentException(""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); } [Fact] @@ -154,8 +152,7 @@ public void Test(string first) { throw new System.ArgumentException(""first is incorrect"", nameof(first)); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -163,8 +160,7 @@ Public Sub Test(first As String) Throw New System.ArgumentException(""first"", ""first is incorrect"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); } [Fact] @@ -186,8 +182,7 @@ public void Test(string first) { throw new System.ArgumentException(null, nameof(first)); } - }" - ); + }"); } [Fact] @@ -208,8 +203,7 @@ public void Test(string first) { throw new System.ArgumentException(""first is incorrect"", nameof(first)); } - }" - ); + }"); } [Fact] @@ -230,8 +224,7 @@ public void Test(string first) { throw new System.ArgumentException(""first is incorrect"", nameof(first), null); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -239,8 +232,7 @@ Public Sub Test(first As String) Throw New System.ArgumentException(""first"", ""first is incorrect"", Nothing) End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); } [Fact] @@ -297,8 +289,7 @@ public void Test(string first) { throw new System.ArgumentNullException(nameof(first), ""first is null""); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -306,8 +297,7 @@ Public Sub Test(first As String) Throw New System.ArgumentNullException(""first is null"", ""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentNullException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentNullException")); } [Fact] @@ -372,8 +362,7 @@ public void Test(string first) { throw new System.ArgumentOutOfRangeException(nameof(first), ""first is out of range""); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -381,8 +370,7 @@ Public Sub Test(first As String) Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); } [Fact] @@ -394,7 +382,7 @@ public class Class public void Test(string first) { var val = new object(); - throw new System.ArgumentOutOfRangeException(""first is incorrect"", val, ""first""); + throw new System.ArgumentOutOfRangeException(""first is out of range"", val, ""first""); } }", GetCSharpIncorrectMessageExpectedResult(7, 31, "Test", "first", "message", "ArgumentOutOfRangeException"), @" @@ -405,17 +393,16 @@ public void Test(string first) var val = new object(); throw new System.ArgumentOutOfRangeException(nameof(first), val, ""first is out of range""); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] Public Sub Test(first As String) - Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") + Dim val = New Object() + Throw New System.ArgumentOutOfRangeException(""first is out of range"", val, ""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException") - ); + GetBasicIncorrectMessageExpectedResult(5, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); } [Fact] @@ -480,8 +467,7 @@ public void Test(string first) { throw new System.DuplicateWaitObjectException(nameof(first), ""first is duplicate""); } - }" - ); + }"); await VerifyVB.VerifyAnalyzerAsync(@" Public Class [MyClass] @@ -489,12 +475,11 @@ Public Sub Test(first As String) Throw New System.DuplicateWaitObjectException(""first is duplicate"", ""first"") End Sub End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "DuplicateWaitObjectException") - ); + GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "DuplicateWaitObjectException")); } [Fact] - public async Task ArgumentNullException_ParentHasNoParameter_Not_Warns() + public async Task ArgumentNullException_ParentHasNoParameter_DoesNotWarn() { await VerifyCS.VerifyAnalyzerAsync(@" public class Class @@ -503,12 +488,11 @@ public void Test() { throw new System.ArgumentNullException(""Invalid argument""); } - }" - ); + }"); } [Fact] - public async Task ArgumentException_ParentHasNoParameter_Not_Warns() + public async Task ArgumentException_ParentHasNoParameter_DoesNotWarn() { await VerifyCS.VerifyAnalyzerAsync(@" public class Class @@ -517,12 +501,11 @@ public void Test() { throw new System.ArgumentException(""Invalid argument"", ""test""); } - }" - ); + }"); } [Fact] - public async Task ArgumentException_VariableUsed_Not_Warns() + public async Task ArgumentException_VariableUsed_DoesNotWarn() { await VerifyCS.VerifyAnalyzerAsync(@" public class Class @@ -531,8 +514,7 @@ public void Test(string paramName, string message) { throw new System.ArgumentException(paramName, message); } - }" - ); + }"); } [Fact] @@ -616,7 +598,7 @@ End Sub } [Fact] - public async Task ArgumentNullException_VariableUsed_Not_Warns() + public async Task ArgumentNullException_VariableUsed_DoesNotWarn() { await VerifyCS.VerifyAnalyzerAsync(@" public class Class @@ -626,8 +608,7 @@ public void Test(string first) { throw new System.ArgumentNullException(str); } - }" - ); + }"); } [Fact] diff --git a/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb b/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb index e86b1eb327..e410f626a7 100644 --- a/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb +++ b/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb @@ -13,5 +13,8 @@ Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime Public NotInheritable Class BasicInstantiateArgumentExceptionsCorrectlyFixer Inherits InstantiateArgumentExceptionsCorrectlyFixer + Protected Overrides Sub PopulateCodeFix(context As CodeFixContext, diagnostic As Diagnostic, paramPositionString As String, node As SyntaxNode) + Throw New NotImplementedException() + End Sub End Class End Namespace From 960e8516cf43188d9a66aec1b47f6a91c6bfc4b8 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 16 Apr 2020 17:03:12 -0700 Subject: [PATCH 3/8] Applying feedback --- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 96 ------------ .../MicrosoftNetCoreAnalyzersResources.resx | 6 +- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 89 ++++++++++- .../InstantiateArgumentExceptionsCorrectly.cs | 2 +- .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 6 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 6 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 6 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 6 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 6 +- ...antiateArgumentExceptionsCorrectlyTests.cs | 142 +++++++++++------- ...ntiateArgumentExceptionsCorrectly.Fixer.vb | 20 --- 19 files changed, 217 insertions(+), 216 deletions(-) delete mode 100644 src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs delete mode 100644 src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb diff --git a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs deleted file mode 100644 index 3201b99687..0000000000 --- a/src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Runtime/CSharpInstantiateArgumentExceptionsCorrectly.Fixer.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Composition; -using System.Globalization; -using Microsoft.NetCore.Analyzers.Runtime; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editing; -using System.Threading; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.NetCore.Analyzers; -using System.Threading.Tasks; - -namespace Microsoft.NetCore.CSharp.Analyzers.Runtime -{ - /// - /// CA2208: Instantiate argument exceptions correctly - /// - [ExportCodeFixProvider(LanguageNames.CSharp), Shared] - public sealed class CSharpInstantiateArgumentExceptionsCorrectlyFixer : InstantiateArgumentExceptionsCorrectlyFixer - { - protected override void PopulateCodeFix(CodeFixContext context, Diagnostic diagnostic, string paramPositionString, SyntaxNode node) - { - if (node is ObjectCreationExpressionSyntax creation) - { - int paramPosition = int.Parse(paramPositionString, CultureInfo.InvariantCulture); - CodeAction? codeAction = null; - if (creation.ArgumentList.Arguments.Count == 1) - { // Add null message - codeAction = CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument, - createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgument); - } - else - { // Swap message and paramete name - codeAction = CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder, - createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, paramPosition, creation.ArgumentList.Arguments.Count, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrder); - } - context.RegisterCodeFix(codeAction, diagnostic); - } - } - - private static async Task SwapArgumentsOrder(Document document, ObjectCreationExpressionSyntax creation, int paramPosition, int argumentCount, CancellationToken token) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); - SyntaxNode parameter = AddNameOfIfLiteral(creation.ArgumentList.Arguments[paramPosition].Expression, editor.Generator); - SyntaxNode newCreation; - if (argumentCount == 2) - { - if (paramPosition == 0) - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter); - } - else - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[0]); - } - } - else // 3 arguments - { - if (paramPosition == 0) - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.ArgumentList.Arguments[1], parameter, creation.ArgumentList.Arguments[2]); - } - else - { - newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.ArgumentList.Arguments[1], creation.ArgumentList.Arguments[0]); - } - } - editor.ReplaceNode(creation, newCreation); - return editor.GetChangedDocument(); - } - - private static async Task AddNullMessageToArgumentList(Document document, ObjectCreationExpressionSyntax creation, CancellationToken token) - { - DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); - SyntaxNode argument = AddNameOfIfLiteral(creation.ArgumentList.Arguments.First().Expression, editor.Generator); - SyntaxNode newCreation = editor.Generator.ObjectCreationExpression(creation.Type, editor.Generator.Argument(editor.Generator.NullLiteralExpression()), argument); - editor.ReplaceNode(creation, newCreation); - return editor.GetChangedDocument(); - } - - private static SyntaxNode AddNameOfIfLiteral(ExpressionSyntax expression, SyntaxGenerator generator) - { - if (expression is LiteralExpressionSyntax literal) - { - return generator.NameOfExpression(generator.IdentifierName(literal.Token.ValueText)); - } - return expression; - } - } -} \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 99079a2e9b..e8918d6934 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -460,7 +460,7 @@ A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Method {0} passes parameter name '{1}' as the {2} argument to a {3} constructor. Replace this argument with a descriptive message and pass the parameter name in the correct position. @@ -1275,10 +1275,10 @@ Potential stack overflow. Move the stackalloc out of the loop. - + Change to call the two argument constructor, pass null for the message. - + Swap the arguments order diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs index 453d249630..58befb2110 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs @@ -1,18 +1,24 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Composition; +using System.Globalization; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; - +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Operations; namespace Microsoft.NetCore.Analyzers.Runtime { /// /// CA2208: Instantiate argument exceptions correctly /// - public abstract class InstantiateArgumentExceptionsCorrectlyFixer : CodeFixProvider + [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared] + public sealed class InstantiateArgumentExceptionsCorrectlyFixer : CodeFixProvider { public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(InstantiateArgumentExceptionsCorrectlyAnalyzer.RuleId); @@ -26,10 +32,85 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true); - PopulateCodeFix(context, diagnostic, paramPositionString, node); + await PopulateCodeFixAsync(context, diagnostic, paramPositionString, node).ConfigureAwait(false); + } + } + + private static async Task PopulateCodeFixAsync(CodeFixContext context, Diagnostic diagnostic, string paramPositionString, SyntaxNode node) + { + SemanticModel model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); + var operation = model.GetOperation(node, context.CancellationToken); + if (operation is IObjectCreationOperation creation) + { + int paramPosition = int.Parse(paramPositionString, CultureInfo.InvariantCulture); + CodeAction? codeAction = null; + if (creation.Arguments.Length == 1) + { + // Add null message + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle, + createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle); + } + else + { + // Swap message and paramete name + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle, + createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, paramPosition, creation.Arguments.Length, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle); + } + context.RegisterCodeFix(codeAction, diagnostic); + } + } + + private static async Task SwapArgumentsOrder(Document document, IObjectCreationOperation creation, int paramPosition, int argumentCount, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode parameter = AddNameOfIfLiteral(creation.Arguments[paramPosition].Value, editor.Generator); + SyntaxNode newCreation; + if (argumentCount == 2) + { + if (paramPosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.Arguments[1].Syntax, parameter); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.Arguments[0].Syntax); + } + } + else // 3 arguments + { + if (paramPosition == 0) + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.Arguments[1].Syntax, parameter, creation.Arguments[2].Syntax); + } + else + { + newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.Arguments[1].Syntax, creation.Arguments[0].Syntax); + } } + editor.ReplaceNode(creation.Syntax, newCreation); + return editor.GetChangedDocument(); + } + + private static async Task AddNullMessageToArgumentList(Document document, IObjectCreationOperation creation, CancellationToken token) + { + DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); + SyntaxNode argument = AddNameOfIfLiteral(creation.Arguments[0].Value, editor.Generator); + SyntaxNode newCreation = editor.Generator.ObjectCreationExpression(creation.Type, editor.Generator.Argument(editor.Generator.NullLiteralExpression()), argument); + editor.ReplaceNode(creation.Syntax, newCreation); + return editor.GetChangedDocument(); } - protected abstract void PopulateCodeFix(CodeFixContext context, Diagnostic diagnostic, string paramPositionString, SyntaxNode node); + private static SyntaxNode AddNameOfIfLiteral(IOperation expression, SyntaxGenerator generator) + { + if (expression is ILiteralOperation literal) + { + return generator.NameOfExpression(generator.IdentifierName(literal.ConstantValue.Value.ToString())); + } + return expression.Syntax; + } } } \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index 1edb1d2945..ffd39d27b0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -160,7 +160,7 @@ private static bool HasParameters(ISymbol owningSymbol) if (rule != null) { - return context.Operation.Syntax.CreateDiagnostic(rule, dictBuilder.ToImmutable(), targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); + return context.Operation.CreateDiagnostic(rule, dictBuilder.ToImmutable(), targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); } return null; diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index e410a8d440..e0332e2edd 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1027,7 +1027,7 @@ Inicializujte statická pole typu hodnot jako vložená - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Zavolal se výchozí konstruktor (bez parametrů) typu výjimky, který je třídou ArgumentException nebo je z ní odvozený, nebo se do jeho konstruktoru s parametry předal nesprávný argument řetězce. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Zavolejte konstruktor {0}, který obsahuje zprávu a/nebo parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index e7c8de518e..bd56402bf3 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1027,7 +1027,7 @@ Statische Felder für Werttyp inline initialisieren - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Ein Aufruf erfolgt an den (parameterlosen) Standardkonstruktur eines Ausnahmetyps, der einer ArgumentException entspricht oder von dieser ableitet, oder ein falsches Zeichenfolgenargument wurde an einen parametrisierten Konstruktor eines Ausnahmetyps übergeben, der einer ArgumentException entspricht oder von dieser ableitet. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Rufen Sie den Konstruktur "{0}" auf, der eine Nachricht und/oder einen paramName-Parameter enthält. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 3c4a86408d..4b3760732a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1027,7 +1027,7 @@ Inicializar campos estáticos de tipo de valor insertados - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Se realiza una llamada al constructor predeterminado (sin parámetros) de un tipo de excepción que es o se deriva de ArgumentException, o se pasa un argumento de cadena incorrecto a un constructor con parámetros de un tipo de excepción que es o se deriva de ArgumentException. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Llame al constructor {0} que contiene un mensaje o un parámetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index d934dfb950..98d29df64c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1027,7 +1027,7 @@ Initialiser les champs static de type valeur inline - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Le constructeur par défaut (sans paramètre) d'un type d'exception qui correspond à ou dérive de ArgumentException est appelé. Ou bien, un argument de chaîne incorrect est passé à un constructeur paramétré d'un type d'exception qui correspond à ou dérive de ArgumentException. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Appelez le constructeur {0} qui contient un message et/ou un paramètre paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 1360586530..6031bb5b31 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1027,7 +1027,7 @@ Inizializzare inline i campi statici di tipo valore - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Viene effettuata una chiamata al costruttore predefinito (senza parametri) di un tipo di eccezione che corrisponde a o deriva da ArgumentException oppure viene passato un argomento stringa non corretto a un costruttore con parametri di un tipo di eccezione che corrisponde a o deriva da ArgumentException. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Chiamare il costruttore {0} che contiene un messaggio e/o il parametro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index 6d8991d828..aba1ab5fcc 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1027,7 +1027,7 @@ 値型の静的フィールドをインラインで初期化します - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ ArgumentException またはそれから派生した例外の種類の既定の (パラメーターのない) コンストラクターに対して呼び出しが行われます。または、正しくない文字列引数が、ArgumentException またはそれから派生した例外の種類のパラメーター化されたコンストラクターに渡されます。 - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. メッセージおよび paramName パラメーターまたはそのいずれかを含む {0} コンストラクターを呼び出します。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 82a2a9c991..21a0cd8f6f 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1027,7 +1027,7 @@ 값 형식 정적 필드 인라인을 초기화하세요. - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ 예외 형식의 매개 변수가 없는 기본 생성자에 발생하는 호출은 ArgumentException이거나 ArgumentException에서 파생됩니다. 즉, 올바르지 않은 문자열 인수는 ArgumentException이거나 ArgumentException에서 파생된 예외 형식의 매개 변수가 있는 생성자로 전달됩니다. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. 메시지 및/또는 paramName 매개 변수를 포함하는 {0} 생성자를 호출하세요. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index 4f4e7aa70a..6573cc0303 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1028,7 +1028,7 @@ Zainicjuj pola statyczne typu wartości w deklaracji pól - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1038,7 +1038,7 @@ Wywołano domyślny (bezparametrowy) konstruktor typu wyjątku ArgumentException lub typu pochodzącego od niego albo przekazano niepoprawny argument ciągu do konstruktora parametryzowanego typu wyjątku ArgumentException lub typu pochodzącego od niego. - + Swap the arguments order Swap the arguments order @@ -1054,7 +1054,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Wywołaj konstruktor {0}, który zawiera komunikat i/lub parametr paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 7644628712..726eab813e 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1027,7 +1027,7 @@ Inicializar campos estáticos de tipo de valor embutido - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ É feita uma chamada para o construtor padrão (sem parâmetro) de um tipo de exceção que é ArgumentException ou derivado dele, ou então um argumento de cadeia de caracteres incorreto é passado para um construtor parametrizado de um tipo de exceção que é ArgumentException ou derivado dele. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Chame o construtor {0} que contém uma mensagem e/ou um parâmetro paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 23dab3a7f9..621246776c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1027,7 +1027,7 @@ Используйте встроенную инициализацию статических полей типов значений - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ Выполняется вызов конструктора по умолчанию (без параметров) для типа исключения, который является ArgumentException или производным от него, либо в параметризованный конструктор для типа исключения, который является ArgumentException или производным от него, передается неправильный строковый аргумент. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Вызывайте конструктор {0}, который содержит сообщение и (или) параметр paramName. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index f2b43d0de1..323d0a2286 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1027,7 +1027,7 @@ Değer türünde statik alanları satır içi olarak başlatın - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ ArgumentException olan veya bundan türetilen bir özel durum türünün varsayılan (parametresiz) oluşturucusuna bir çağrı yapıldı veya ArgumentException olan veya bundan türetilen bir özel durum türünün parametreli oluşturucusuna yanlış bir dize bağımsız değişkeni geçirildi. - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. Bir iletiyi ve/veya paramName parametresini içeren {0} oluşturucusunu çağırın. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index 102887f1f9..c4ee419063 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1027,7 +1027,7 @@ 以内联方式初始化值类型的静态字段 - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ 调用了 ArgumentException 异常类型或其派生异常类型的默认(无参数)构造函数,或将不正确的字符串参数传递给 ArgumentException. 异常类型或其派生异常类型的参数化构造函数。 - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. 调用 {0} 构造函数,该函数包含 message 和/或 paramName 参数。 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 863574f156..694071cab0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1027,7 +1027,7 @@ 初始化實值型別靜態欄位內嵌 - + Change to call the two argument constructor, pass null for the message. Change to call the two argument constructor, pass null for the message. @@ -1037,7 +1037,7 @@ 已呼叫例外狀況類型為 ArgumentException 或由其衍生的預設 (無參數) 建構函式; 或將不正確的字串引數傳遞到例外狀況類型為 ArgumentException 或由其衍生的參數化建構函式。 - + Swap the arguments order Swap the arguments order @@ -1053,7 +1053,7 @@ - Please use overload of the {0} constructor that contains a message and/or paramName parameter. + Call the {0} constructor that contains a message and/or paramName parameter. 請呼叫包含 message 及 (或) paramName 參數的 {0} 建構函式。 diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index acc87d7340..c23d834d2b 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -6,10 +6,10 @@ using Xunit; using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyAnalyzer, - Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpInstantiateArgumentExceptionsCorrectlyFixer>; + Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyFixer>; using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyAnalyzer, - Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicInstantiateArgumentExceptionsCorrectlyFixer>; + Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyFixer>; namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests { @@ -125,13 +125,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.ArgumentException(""first"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "ArgumentException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(Nothing, NameOf(first)) + End Sub +End Class"); } [Fact] @@ -154,13 +159,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.ArgumentException(""first"", ""first is incorrect"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first"", ""first is incorrect"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "ArgumentException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first is incorrect"", NameOf(first)) + End Sub +End Class"); } [Fact] @@ -226,13 +236,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.ArgumentException(""first"", ""first is incorrect"", Nothing) - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first"", ""first is incorrect"", Nothing) + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "ArgumentException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentException(""first is incorrect"", NameOf(first), Nothing) + End Sub +End Class"); } [Fact] @@ -291,13 +306,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.ArgumentNullException(""first is null"", ""first"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentNullException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentNullException(""first is null"", ""first"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "ArgumentNullException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentNullException(NameOf(first), ""first is null"") + End Sub +End Class"); } [Fact] @@ -364,13 +384,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentOutOfRangeException(""first is out of range"", ""first"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "ArgumentOutOfRangeException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.ArgumentOutOfRangeException(NameOf(first), ""first is out of range"") + End Sub +End Class"); } [Fact] @@ -395,14 +420,20 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Dim val = New Object() - Throw New System.ArgumentOutOfRangeException(""first is out of range"", val, ""first"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(5, 31, "Test", "first", "message", "ArgumentOutOfRangeException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Dim val = New Object() + Throw New System.ArgumentOutOfRangeException(""first is out of range"", val, ""first"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(5, 15, "Test", "first", "message", "ArgumentOutOfRangeException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Dim val = New Object() + Throw New System.ArgumentOutOfRangeException(NameOf(first), val, ""first is out of range"") + End Sub +End Class"); } [Fact] @@ -469,13 +500,18 @@ public void Test(string first) } }"); - await VerifyVB.VerifyAnalyzerAsync(@" - Public Class [MyClass] - Public Sub Test(first As String) - Throw New System.DuplicateWaitObjectException(""first is duplicate"", ""first"") - End Sub - End Class", - GetBasicIncorrectMessageExpectedResult(4, 31, "Test", "first", "message", "DuplicateWaitObjectException")); + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.DuplicateWaitObjectException(""first is duplicate"", ""first"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "first", "message", "DuplicateWaitObjectException"), @" +Public Class [MyClass] + Public Sub Test(first As String) + Throw New System.DuplicateWaitObjectException(NameOf(first), ""first is duplicate"") + End Sub +End Class"); } [Fact] @@ -518,7 +554,7 @@ public void Test(string paramName, string message) } [Fact] - public async Task ArgumentException_NoArgumentss_ParentMethod_HasNoParameter_DoesNotWarn() + public async Task ArgumentException_NoArguments_ParentMethod_HasNoParameter_DoesNotWarn() { await VerifyCS.VerifyAnalyzerAsync(@" public class Class diff --git a/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb b/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb deleted file mode 100644 index e410f626a7..0000000000 --- a/src/NetAnalyzers/VisualBasic/Microsoft.NetCore.Analyzers/Runtime/BasicInstantiateArgumentExceptionsCorrectly.Fixer.vb +++ /dev/null @@ -1,20 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports System.Composition -Imports Microsoft.NetCore.Analyzers.Runtime -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeFixes - -Namespace Microsoft.NetCore.VisualBasic.Analyzers.Runtime - ''' - ''' CA2208: Instantiate argument exceptions correctly - ''' - - Public NotInheritable Class BasicInstantiateArgumentExceptionsCorrectlyFixer - Inherits InstantiateArgumentExceptionsCorrectlyFixer - - Protected Overrides Sub PopulateCodeFix(context As CodeFixContext, diagnostic As Diagnostic, paramPositionString As String, node As SyntaxNode) - Throw New NotImplementedException() - End Sub - End Class -End Namespace From 7874fe1f43f5b6220fffe64cb6a06b39afe5fa75 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Tue, 21 Apr 2020 23:01:58 -0700 Subject: [PATCH 4/8] Adding api surface option and allowing generic type paremeter name --- .../InstantiateArgumentExceptionsCorrectly.cs | 22 +++- ...antiateArgumentExceptionsCorrectlyTests.cs | 105 ++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index ffd39d27b0..d874904645 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -86,7 +86,7 @@ private static void AnalyzeObjectCreation( ITypeSymbol argumentExceptionType) { var creation = (IObjectCreationOperation)context.Operation; - if (!creation.Type.Inherits(argumentExceptionType)) + if (!creation.Type.Inherits(argumentExceptionType) || !MatchesConfiguredVisibility(owningSymbol, context)) { return; } @@ -121,6 +121,7 @@ private static void AnalyzeObjectCreation( break; } } + if (diagnostic != null) { context.ReportDiagnostic(diagnostic); @@ -128,6 +129,11 @@ private static void AnalyzeObjectCreation( } } + private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) + { // Should add for all rules? + return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); + } + private static bool HasParameters(ISymbol owningSymbol) { return owningSymbol.GetParameters().Length > 0; @@ -241,6 +247,20 @@ private static bool MatchesParameterCore(ISymbol? symbol, string stringArgumentV } } + if (symbol is IMethodSymbol method) + { + if (method.IsGenericMethod) + { + foreach (ITypeParameterSymbol parameter in method.TypeParameters) + { + if (parameter.Name == stringArgumentValue) + { + return true; + } + } + } + + } return false; } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index c23d834d2b..88547ebea6 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -593,6 +593,111 @@ End Sub End Class"); } + [Fact] + public async Task ArgumentException_GenericParameterName_DoesNotWarn() + { + await VerifyCS.VerifyAnalyzerAsync(@" + public class Class + { + public void Test(TEnum first) + { + throw new System.ArgumentException(""first is incorrect"", nameof(TEnum)); + } + }"); + + await VerifyVB.VerifyAnalyzerAsync(@" + Public Class [MyClass] + Public Sub Test(Of TEnum)(ByVal first As TEnum) + Throw New System.ArgumentException(""first is incorrect"", NameOf(TEnum)) + End Sub + End Class"); + } + + + [Theory] + [InlineData("public", "dotnet_code_quality.api_surface = private", false)] + [InlineData("private", "dotnet_code_quality.api_surface = internal, public", false)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = private, piblic", true)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = internal, private", false)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = Friend, Private", false)] + [InlineData("public", @"dotnet_code_quality.api_surface = all + dotnet_code_quality.CA2208.api_surface = private", false)] + [InlineData("public", "dotnet_code_quality.api_surface = public", true)] + [InlineData("public", "dotnet_code_quality.api_surface = internal, public", true)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = public", true)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = all", true)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = public, private", true)] + [InlineData("public", @"dotnet_code_quality.api_surface = internal + dotnet_code_quality.CA2208.api_surface = public", true)] + public async Task EditorConfigConfiguration_ApiSurfaceOption_CsTest(string accessibility, string editorConfigText, bool expectDiagnostic) + { + var exception = expectDiagnostic ? @"[|new System.ArgumentNullException(""first is null"")|]" : @"new System.ArgumentNullException(""first is null"")"; + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + $@" +public class C +{{ + {accessibility} void Test(string first) + {{ + throw {exception}; + }} +}}" + }, + AdditionalFiles = { (".editorconfig", editorConfigText) } + }, + MarkupOptions = MarkupOptions.UseFirstDescriptor + }.RunAsync(); + + exception = expectDiagnostic ? @"[|New System.ArgumentNullException(""first is null"")|]" : @"New System.ArgumentNullException(""first is null"")"; + + await new VerifyVB.Test + { + TestState = + { + Sources = + { + $@" + Public Class C + {accessibility} Sub Test(first As String) + Throw {exception} + End Sub + End Class" + }, + AdditionalFiles = { (".editorconfig", editorConfigText) } + }, + MarkupOptions = MarkupOptions.UseFirstDescriptor + }.RunAsync(); + } + + [Fact] + public async Task EditorConfigConfiguration_Private_MethodArgumentException_DoesNotWarn() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + $@" + public class C + {{ + private void Mmmmmm(string fisrt) + {{ + throw new System.ArgumentNullException(); + }} + }}" + }, + AdditionalFiles = { (".editorconfig", "dotnet_code_quality.CA2208.api_surface = public") } + }, + MarkupOptions = MarkupOptions.UseFirstDescriptor + }.RunAsync(); + } + [Fact] public async Task ArgumentException_CorrectMessageAndParameterName_DoesNotWarn() { From 7a27e7ff2be45f1d7aec53203c2a0ed6317bfa19 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Wed, 22 Apr 2020 11:10:23 -0700 Subject: [PATCH 5/8] Apply feedback --- .../InstantiateArgumentExceptionsCorrectly.cs | 2 +- .../InstantiateArgumentExceptionsCorrectlyTests.cs | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index d874904645..6b325e1670 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -130,7 +130,7 @@ private static void AnalyzeObjectCreation( } private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) - { // Should add for all rules? + { return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index 88547ebea6..f80ccd3575 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -617,7 +617,7 @@ End Sub [Theory] [InlineData("public", "dotnet_code_quality.api_surface = private", false)] [InlineData("private", "dotnet_code_quality.api_surface = internal, public", false)] - [InlineData("public", "dotnet_code_quality.CA2208.api_surface = private, piblic", true)] + [InlineData("public", "dotnet_code_quality.CA2208.api_surface = private, public", true)] [InlineData("public", "dotnet_code_quality.CA2208.api_surface = internal, private", false)] [InlineData("public", "dotnet_code_quality.CA2208.api_surface = Friend, Private", false)] [InlineData("public", @"dotnet_code_quality.api_surface = all @@ -629,7 +629,7 @@ End Sub [InlineData("public", "dotnet_code_quality.CA2208.api_surface = public, private", true)] [InlineData("public", @"dotnet_code_quality.api_surface = internal dotnet_code_quality.CA2208.api_surface = public", true)] - public async Task EditorConfigConfiguration_ApiSurfaceOption_CsTest(string accessibility, string editorConfigText, bool expectDiagnostic) + public async Task EditorConfigConfiguration_ApiSurfaceOption_Test(string accessibility, string editorConfigText, bool expectDiagnostic) { var exception = expectDiagnostic ? @"[|new System.ArgumentNullException(""first is null"")|]" : @"new System.ArgumentNullException(""first is null"")"; @@ -675,7 +675,7 @@ End Class" } [Fact] - public async Task EditorConfigConfiguration_Private_MethodArgumentException_DoesNotWarn() + public async Task EditorConfigConfiguredPublic_PrivateMethods_TriggeringOtherRules_DoesNotWarn() { await new VerifyCS.Test { @@ -686,10 +686,15 @@ public async Task EditorConfigConfiguration_Private_MethodArgumentException_Does $@" public class C {{ - private void Mmmmmm(string fisrt) + private void Test(string first) {{ throw new System.ArgumentNullException(); }} + + private void TestFlipped(string first) + {{ + throw new System.ArgumentException(nameof(first), ""message""); + }} }}" }, AdditionalFiles = { (".editorconfig", "dotnet_code_quality.CA2208.api_surface = public") } From 3ea6d4f4614328385658c0f320e517c591748468 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Wed, 22 Apr 2020 14:21:23 -0700 Subject: [PATCH 6/8] typo, styling update --- .../InstantiateArgumentExceptionsCorrectly.cs | 15 +++++---------- ...InstantiateArgumentExceptionsCorrectlyTests.cs | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index 6b325e1670..56269a3e88 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -131,7 +131,8 @@ private static void AnalyzeObjectCreation( private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) { - return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); + return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, + context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); } private static bool HasParameters(ISymbol owningSymbol) @@ -147,28 +148,22 @@ private static bool HasParameters(ISymbol owningSymbol) OperationAnalysisContext context) { bool matchesParameter = MatchesParameter(targetSymbol, creation, stringArgument); - DiagnosticDescriptor? rule = null; - var dictBuilder = ImmutableDictionary.CreateBuilder(); if (IsMessage(parameter) && matchesParameter) { - rule = RuleIncorrectMessage; + var dictBuilder = ImmutableDictionary.CreateBuilder(); dictBuilder.Add(MessagePosition, parameter.Ordinal.ToString(CultureInfo.InvariantCulture)); + return context.Operation.CreateDiagnostic(RuleIncorrectMessage, dictBuilder.ToImmutable(), targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); } else if (HasParameters(targetSymbol) && IsParameterName(parameter) && !matchesParameter) { // Allow argument exceptions in accessors to use the associated property symbol name. if (!MatchesAssociatedSymbol(targetSymbol, stringArgument)) { - rule = RuleIncorrectParameterName; + return context.Operation.CreateDiagnostic(RuleIncorrectParameterName, targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); } } - if (rule != null) - { - return context.Operation.CreateDiagnostic(rule, dictBuilder.ToImmutable(), targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name); - } - return null; } diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index f80ccd3575..e64ff83270 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -9,7 +9,7 @@ Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyFixer>; using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyAnalyzer, - Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyFixer>; + Microsoft.NetCore.Analyzers.Runtime.InstantiateArgumentExceptionsCorrectlyFixer>; namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests { From 8ff32986eb0c7b39ba5843f0d711f5bcec20f23f Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Wed, 22 Apr 2020 15:14:14 -0700 Subject: [PATCH 7/8] fix formatting --- .../Runtime/InstantiateArgumentExceptionsCorrectly.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index 56269a3e88..f334d4d491 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -131,7 +131,7 @@ private static void AnalyzeObjectCreation( private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) { - return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, + return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); } From e7a0879b0fa8af3d9d3ba5c8eaa149649fb2f381 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 23 Apr 2020 16:18:46 -0700 Subject: [PATCH 8/8] Applying feedback --- .../Core/AnalyzerReleases.Unshipped.md | 8 ++- ...ntiateArgumentExceptionsCorrectly.Fixer.cs | 50 +++++++++++-------- .../InstantiateArgumentExceptionsCorrectly.cs | 17 +++---- ...antiateArgumentExceptionsCorrectlyTests.cs | 37 ++++++++++++++ 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md index 796497840b..72eb7b2d13 100644 --- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -18,6 +18,10 @@ CA2011 | Reliability | Info | AvoidInfiniteRecursion, [Documentation](https://do CA2012 | Reliability | Hidden | UseValueTasksCorrectlyAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2012) CA2013 | Reliability | Warning | DoNotUseReferenceEqualsWithValueTypesAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2013) CA2014 | Reliability | Warning | DoNotUseStackallocInLoopsAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2014) -CA2208 | Usage | Info | InstantiateArgumentExceptionsCorrectlyAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2208) CA2015 | Reliability | Warning | DoNotDefineFinalizersForTypesDerivedFromMemoryManager, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2015) -CA2247 | Usage | Warning | DoNotCreateTaskCompletionSourceWithWrongArguments, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2247) \ No newline at end of file +CA2247 | Usage | Warning | DoNotCreateTaskCompletionSourceWithWrongArguments, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2247) + +### Changed Rules +Rule ID | New Category | New Severity | Old Category | Old Severity | Notes +--------|--------------|--------------|--------------|--------------|------- +CA2208 | Usage | Info | Usage | Hidden | InstantiateArgumentExceptionsCorrectlyAnalyzer, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca2208) \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs index 58befb2110..544a6a51e7 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.Fixer.cs @@ -2,10 +2,10 @@ using System.Collections.Immutable; using System.Composition; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; @@ -32,7 +32,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); SyntaxNode node = root.FindNode(context.Span, getInnermostNodeForTie: true); - await PopulateCodeFixAsync(context, diagnostic, paramPositionString, node).ConfigureAwait(false); + if (node != null) + { + await PopulateCodeFixAsync(context, diagnostic, paramPositionString, node).ConfigureAwait(false); + } } } @@ -42,29 +45,31 @@ private static async Task PopulateCodeFixAsync(CodeFixContext context, Diagnosti var operation = model.GetOperation(node, context.CancellationToken); if (operation is IObjectCreationOperation creation) { - int paramPosition = int.Parse(paramPositionString, CultureInfo.InvariantCulture); - CodeAction? codeAction = null; - if (creation.Arguments.Length == 1) - { - // Add null message - codeAction = CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle, - createChangedDocument: c => AddNullMessageToArgumentList(context.Document, creation, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle); - } - else + if (int.TryParse(paramPositionString, out int paramPosition)) { - // Swap message and paramete name - codeAction = CodeAction.Create( - title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle, - createChangedDocument: c => SwapArgumentsOrder(context.Document, creation, paramPosition, creation.Arguments.Length, c), - equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle); + CodeAction? codeAction = null; + if (creation.Arguments.Length == 1) + { + // Add null message + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle, + createChangedDocument: c => AddNullMessageToArgumentListAsync(context.Document, creation, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyChangeToTwoArgumentCodeFixTitle); + } + else + { + // Swap message and paramete name + codeAction = CodeAction.Create( + title: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle, + createChangedDocument: c => SwapArgumentsOrderAsync(context.Document, creation, paramPosition, creation.Arguments.Length, c), + equivalenceKey: MicrosoftNetCoreAnalyzersResources.InstantiateArgumentExceptionsCorrectlyFlipArgumentOrderCodeFixTitle); + } + context.RegisterCodeFix(codeAction, diagnostic); } - context.RegisterCodeFix(codeAction, diagnostic); } } - private static async Task SwapArgumentsOrder(Document document, IObjectCreationOperation creation, int paramPosition, int argumentCount, CancellationToken token) + private static async Task SwapArgumentsOrderAsync(Document document, IObjectCreationOperation creation, int paramPosition, int argumentCount, CancellationToken token) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); SyntaxNode parameter = AddNameOfIfLiteral(creation.Arguments[paramPosition].Value, editor.Generator); @@ -80,8 +85,9 @@ private static async Task SwapArgumentsOrder(Document document, IObjec newCreation = editor.Generator.ObjectCreationExpression(creation.Type, parameter, creation.Arguments[0].Syntax); } } - else // 3 arguments + else { + Debug.Assert(argumentCount == 3); if (paramPosition == 0) { newCreation = editor.Generator.ObjectCreationExpression(creation.Type, creation.Arguments[1].Syntax, parameter, creation.Arguments[2].Syntax); @@ -95,7 +101,7 @@ private static async Task SwapArgumentsOrder(Document document, IObjec return editor.GetChangedDocument(); } - private static async Task AddNullMessageToArgumentList(Document document, IObjectCreationOperation creation, CancellationToken token) + private static async Task AddNullMessageToArgumentListAsync(Document document, IObjectCreationOperation creation, CancellationToken token) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false); SyntaxNode argument = AddNameOfIfLiteral(creation.Arguments[0].Value, editor.Generator); diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs index f334d4d491..67491def79 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectly.cs @@ -116,7 +116,9 @@ private static void AnalyzeObjectCreation( } diagnostic = CheckArgument(owningSymbol, creation, argument.Parameter, value, context); - if (diagnostic != null && !diagnostic.Properties.IsEmpty) + + // RuleIncorrectMessage is the highest priority rule, no need to check other rules + if (diagnostic != null && diagnostic.Descriptor.Equals(RuleIncorrectMessage)) { break; } @@ -129,16 +131,11 @@ private static void AnalyzeObjectCreation( } } - private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) - { - return owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, - context.Compilation, context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); - } + private static bool MatchesConfiguredVisibility(ISymbol owningSymbol, OperationAnalysisContext context) => + owningSymbol.MatchesConfiguredVisibility(context.Options, RuleIncorrectParameterName, context.Compilation, + context.CancellationToken, defaultRequiredVisibility: SymbolVisibilityGroup.All); - private static bool HasParameters(ISymbol owningSymbol) - { - return owningSymbol.GetParameters().Length > 0; - } + private static bool HasParameters(ISymbol owningSymbol) => owningSymbol.GetParameters().Length > 0; private static Diagnostic? CheckArgument( ISymbol targetSymbol, diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs index e64ff83270..919263e8f3 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/InstantiateArgumentExceptionsCorrectlyTests.cs @@ -613,6 +613,39 @@ End Sub End Class"); } + [Fact] + public async Task ArgumentException_GenericParameterName_WrongPosition_WarnsAndCodeFixes() + { + await VerifyCS.VerifyCodeFixAsync(@" + public class Class + { + public void Test(TEnum first) + { + throw new System.ArgumentException(""TEnum""); + } + }", + GetCSharpIncorrectMessageExpectedResult(6, 31, "Test", "TEnum", "message", "ArgumentException"), @" + public class Class + { + public void Test(TEnum first) + { + throw new System.ArgumentException(null, nameof(TEnum)); + } + }"); + + await VerifyVB.VerifyCodeFixAsync(@" +Public Class [MyClass] + Public Sub Test(Of TEnum)(ByVal first As TEnum) + Throw New System.ArgumentException(""TEnum"") + End Sub +End Class", + GetBasicIncorrectMessageExpectedResult(4, 15, "Test", "TEnum", "message", "ArgumentException"), @" +Public Class [MyClass] + Public Sub Test(Of TEnum)(ByVal first As TEnum) + Throw New System.ArgumentException(Nothing, NameOf(TEnum)) + End Sub +End Class"); + } [Theory] [InlineData("public", "dotnet_code_quality.api_surface = private", false)] @@ -629,6 +662,10 @@ End Sub [InlineData("public", "dotnet_code_quality.CA2208.api_surface = public, private", true)] [InlineData("public", @"dotnet_code_quality.api_surface = internal dotnet_code_quality.CA2208.api_surface = public", true)] + [InlineData("public", "", true)] + [InlineData("protected", "", true)] + [InlineData("private", "", true)] + [InlineData("protected", "dotnet_code_quality.CA2208.api_surface = public", true)] public async Task EditorConfigConfiguration_ApiSurfaceOption_Test(string accessibility, string editorConfigText, bool expectDiagnostic) { var exception = expectDiagnostic ? @"[|new System.ArgumentNullException(""first is null"")|]" : @"new System.ArgumentNullException(""first is null"")";