Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add DoNotPassStructToArgumentNullExceptionThrowIfNullAnalyzer#6815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
buyaa-n merged 11 commits intodotnet:mainfromCollinAlpert:issue_85154
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.NetCore.Analyzers.Usage;

namespace Microsoft.NetCore.CSharp.Analyzers.Usage
{
[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
public sealed class CSharpDoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullFixer : DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullFixer<InvocationExpressionSyntax>
{
protected override async Task<SyntaxNode> GetNewRootForNullableStructAsync(Document document, InvocationExpressionSyntax invocation, CancellationToken cancellationToken)
{
var editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var generator = editor.Generator;
var nullableStructExpression = invocation.ArgumentList.Arguments[0].Expression;
var condition = generator.LogicalNotExpression(generator.MemberAccessExpression(nullableStructExpression, HasValue));
var nameOfExpression = generator.NameOfExpression(nullableStructExpression);
var argumentNullException = generator.ObjectCreationExpression(generator.IdentifierName(ArgumentNullException), nameOfExpression);
var throwExpression = generator.ThrowStatement(argumentNullException);
var ifStatement = editor.Generator.IfStatement(condition, new[] { throwExpression });
if (invocation.Parent is not null)
{
editor.ReplaceNode(invocation.Parent, ifStatement);
}

return editor.GetChangedRoot();
}
}
}
2 changes: 2 additions & 0 deletionssrc/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,8 @@ CA1862 | Performance | Info | RecommendCaseInsensitiveStringComparison, [Documen
CA1863 | Performance | Hidden | UseCompositeFormatAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1862)
CA1864 | Performance | Info | PreferDictionaryTryAddValueOverGuardedAddAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1864)
CA2021 | Reliability | Warning | DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)
CA2262 | Usage | Warning | DoNotPassStructToArgumentNullExceptionThrowIfNullAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2262)
CA1869 | Performance | Info | DoNotPassStructToArgumentNullExceptionThrowIfNullAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1869)

### Removed Rules

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2129,4 +2129,28 @@ Widening and user defined conversions are not supported with generic types.</val
<data name="UseStringMethodCharOverloadWithSingleCharactersTitle" xml:space="preserve">
<value>Use char overload</value>
</data>
<data name="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullTitle" xml:space="preserve">
<value>Do not pass a non-nullable value to 'ArgumentNullException.ThrowIfNull'</value>
</data>
<data name="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullMessage" xml:space="preserve">
<value>Calling 'ArgumentNullException.ThrowIfNull' and passing a non-nullable value does nothing</value>
</data>
<data name="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullDescription" xml:space="preserve">
<value>'ArgumentNullException.ThrowIfNull' throws when the passed argument is 'null'. Certain constructs like non-nullable structs, 'nameof()' and 'new' expressions are known to never be null, so 'ArgumentNullException.ThrowIfNull' will never throw.</value>
</data>
<data name="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullCodeFixTitle" xml:space="preserve">
<value>Do not call 'ArgumentNullException.ThrowIfNull' with a non-nullable value</value>
</data>
<data name="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullTitle" xml:space="preserve">
<value>Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull'</value>
</data>
<data name="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullMessage" xml:space="preserve">
<value>Passing a nullable struct to 'ArgumentNullException.ThrowIfNull' may cause boxing</value>
</data>
<data name="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullDescription" xml:space="preserve">
<value>'ArgumentNullException.ThrowIfNull' accepts an 'object', so passing a nullable struct may cause the value to be boxed.</value>
</data>
<data name="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullCodeFixTitle" xml:space="preserve">
<value>Do not call 'ArgumentNullException.ThrowIfNull' with a struct</value>
</data>
</root>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

usingSystem;
usingSystem.Collections.Immutable;
usingSystem.Threading;
usingSystem.Threading.Tasks;
usingAnalyzer.Utilities;
usingMicrosoft.CodeAnalysis;
usingMicrosoft.CodeAnalysis.CodeActions;
usingMicrosoft.CodeAnalysis.CodeFixes;

namespaceMicrosoft.NetCore.Analyzers.Usage
{
publicabstractclassDoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullFixer<TInvocationExpression>:CodeFixProvider
whereTInvocationExpression:SyntaxNode
{
protectedconststringHasValue=nameof(Nullable<int>.HasValue);
protectedconststringArgumentNullException=nameof(System.ArgumentNullException);

publicoverrideasyncTaskRegisterCodeFixesAsync(CodeFixContextcontext)
{
foreach(vardiagnosticincontext.Diagnostics)
{
varroot=awaitcontext.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if(root.FindNode(context.Span,getInnermostNodeForTie:true)is notTInvocationExpressioninvocation)
{
continue;
}

if(diagnostic.Id==DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull.NonNullableValueRuleId&&invocation.Parentis notnull)
{
varcodeAction=CodeAction.Create(
MicrosoftNetCoreAnalyzersResources.DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullCodeFixTitle,
_=>
{
varnewRoot=root.RemoveNode(invocation.Parent,SyntaxRemoveOptions.KeepNoTrivia);
if(newRootisnull)
{
returnTask.FromResult(context.Document);
}

returnTask.FromResult(context.Document.WithSyntaxRoot(newRoot));
},diagnostic.Id);
context.RegisterCodeFix(codeAction,diagnostic);
}
elseif(diagnostic.Id==DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull.NullableStructRuleId)
{
varcodeAction=CodeAction.Create(
MicrosoftNetCoreAnalyzersResources.DoNotPassNullableStructToArgumentNullExceptionThrowIfNullCodeFixTitle,
async ct=>
{
varnewRoot=awaitGetNewRootForNullableStructAsync(context.Document,invocation,ct).ConfigureAwait(false);
if(newRootisnull)
{
returncontext.Document;
}

returncontext.Document.WithSyntaxRoot(newRoot);
},diagnostic.Id);
context.RegisterCodeFix(codeAction,diagnostic);
}
}
}

protectedabstractTask<SyntaxNode>GetNewRootForNullableStructAsync(Documentdocument,TInvocationExpressioninvocation,CancellationTokencancellationToken);

publicoverrideFixAllProviderGetFixAllProvider()=>WellKnownFixAllProviders.BatchFixer;

publicoverrideImmutableArray<string>FixableDiagnosticIds{get;}=ImmutableArray.Create(
DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull.NonNullableValueRuleId,
DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull.NullableStructRuleId
);
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Linq;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using static Microsoft.NetCore.Analyzers.MicrosoftNetCoreAnalyzersResources;

namespace Microsoft.NetCore.Analyzers.Usage
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull : DiagnosticAnalyzer
{
internal const string NonNullableValueRuleId = "CA2262";
internal const string NullableStructRuleId = "CA1869";

internal static readonly DiagnosticDescriptor DoNotPassNonNullableValueDiagnostic = DiagnosticDescriptorHelper.Create(
NonNullableValueRuleId,
CreateLocalizableResourceString(nameof(DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullTitle)),
CreateLocalizableResourceString(nameof(DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullMessage)),
DiagnosticCategory.Usage,
RuleLevel.BuildWarning,
CreateLocalizableResourceString(nameof(DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullDescription)),
isPortedFxCopRule: false,
isDataflowRule: false);

internal static readonly DiagnosticDescriptor DoNotPassNullableStructDiagnostic = DiagnosticDescriptorHelper.Create(
NullableStructRuleId,
CreateLocalizableResourceString(nameof(DoNotPassNullableStructToArgumentNullExceptionThrowIfNullTitle)),
CreateLocalizableResourceString(nameof(DoNotPassNullableStructToArgumentNullExceptionThrowIfNullMessage)),
DiagnosticCategory.Performance,
RuleLevel.IdeSuggestion,
CreateLocalizableResourceString(nameof(DoNotPassNullableStructToArgumentNullExceptionThrowIfNullDescription)),
isPortedFxCopRule: false,
isDataflowRule: false);

public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(static context =>
{
var typeProvider = WellKnownTypeProvider.GetOrCreate(context.Compilation);
var throwIfNullMethod = typeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemArgumentNullException)
?.GetMembers("ThrowIfNull")
.FirstOrDefault(m => m is IMethodSymbol { Parameters: [{ Type.SpecialType: SpecialType.System_Object }, _] });
if (throwIfNullMethod is null)
{
return;
}

context.RegisterOperationAction(ctx => AnalyzeInvocation(ctx, (IMethodSymbol)throwIfNullMethod), OperationKind.Invocation);
});
}

private static void AnalyzeInvocation(OperationAnalysisContext context, IMethodSymbol throwIfNullMethod)
{
var invocation = (IInvocationOperation)context.Operation;
if (invocation.TargetMethod.Equals(throwIfNullMethod, SymbolEqualityComparer.Default))
{
if (invocation.Arguments[0].Value.WalkDownConversion().Type.IsNonNullableValueType()
|| invocation.Arguments[0].Value.WalkDownConversion().Kind is OperationKind.NameOf or OperationKind.ObjectCreation or OperationKind.ObjectOrCollectionInitializer)
{
context.ReportDiagnostic(invocation.CreateDiagnostic(DoNotPassNonNullableValueDiagnostic));
}

if (invocation.Arguments[0].Value.WalkDownConversion().Type.IsNullableValueType())
{
context.ReportDiagnostic(invocation.CreateDiagnostic(DoNotPassNullableStructDiagnostic));
}
}
}

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(DoNotPassNonNullableValueDiagnostic, DoNotPassNullableStructDiagnostic);
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -843,6 +843,46 @@ Obecné přetypování (IL unbox.any) používané sekvencí vrácenou metodou E
<target state="translated">Nepředávejte literály jako lokalizované parametry</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullCodeFixTitle">
<source>Do not call 'ArgumentNullException.ThrowIfNull' with a non-nullable value</source>
<target state="new">Do not call 'ArgumentNullException.ThrowIfNull' with a non-nullable value</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullDescription">
<source>'ArgumentNullException.ThrowIfNull' throws when the passed argument is 'null'. Certain constructs like non-nullable structs, 'nameof()' and 'new' expressions are known to never be null, so 'ArgumentNullException.ThrowIfNull' will never throw.</source>
<target state="new">'ArgumentNullException.ThrowIfNull' throws when the passed argument is 'null'. Certain constructs like non-nullable structs, 'nameof()' and 'new' expressions are known to never be null, so 'ArgumentNullException.ThrowIfNull' will never throw.</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullMessage">
<source>Calling 'ArgumentNullException.ThrowIfNull' and passing a non-nullable value does nothing</source>
<target state="new">Calling 'ArgumentNullException.ThrowIfNull' and passing a non-nullable value does nothing</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNullTitle">
<source>Do not pass a non-nullable value to 'ArgumentNullException.ThrowIfNull'</source>
<target state="new">Do not pass a non-nullable value to 'ArgumentNullException.ThrowIfNull'</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullCodeFixTitle">
<source>Do not call 'ArgumentNullException.ThrowIfNull' with a struct</source>
<target state="new">Do not call 'ArgumentNullException.ThrowIfNull' with a struct</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullDescription">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

❓ Do we really need this? SharpLab suggests that release builds will not box a non-null value in this case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Can you share an example? I can see thebox instructionhere.

<source>'ArgumentNullException.ThrowIfNull' accepts an 'object', so passing a nullable struct may cause the value to be boxed.</source>
<target state="new">'ArgumentNullException.ThrowIfNull' accepts an 'object', so passing a nullable struct may cause the value to be boxed.</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullMessage">
<source>Passing a nullable struct to 'ArgumentNullException.ThrowIfNull' may cause boxing</source>
<target state="new">Passing a nullable struct to 'ArgumentNullException.ThrowIfNull' may cause boxing</target>
<note />
</trans-unit>
<trans-unit id="DoNotPassNullableStructToArgumentNullExceptionThrowIfNullTitle">
<source>Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull'</source>
<target state="new">Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull'</target>
<note />
</trans-unit>
<trans-unit id="DoNotRaiseReservedExceptionTypesDescription">
<source>An exception of type that is not sufficiently specific or reserved by the runtime should never be raised by user code. This makes the original error difficult to detect and debug. If this exception instance might be thrown, use a different exception type.</source>
<target state="translated">Uživatelský kód by nikdy neměl vyvolat výjimku typu, který není dostatečně konkrétní nebo je rezervovaný modulem runtime. V takovém případě je totiž obtížné zjistit a ladit původní chybu. Pokud může dojít k vyvolání této instance výjimky, použijte jiný typ výjimky.</target>
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp