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

Commit55a4724

Browse files
committed
Provide analyzer for removing unneeded public partial class Program
1 parent109c0d4 commit55a4724

File tree

5 files changed

+285
-27
lines changed

5 files changed

+285
-27
lines changed

‎src/Framework/AspNetCoreAnalyzers/src/Analyzers/DiagnosticDescriptors.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,13 @@ internal static class DiagnosticDescriptors
223223
DiagnosticSeverity.Warning,
224224
isEnabledByDefault:true,
225225
helpLinkUri:"https://aka.ms/aspnet/analyzers");
226+
227+
internalstaticreadonlyDiagnosticDescriptorPublicPartialProgramClassNotRequired=new(
228+
"ASP0027",
229+
newLocalizableResourceString(nameof(Resources.Analyzer_PublicPartialProgramClass_Title),Resources.ResourceManager,typeof(Resources)),
230+
newLocalizableResourceString(nameof(Resources.Analyzer_PublicPartialProgramClass_Message),Resources.ResourceManager,typeof(Resources)),
231+
"Security",
232+
DiagnosticSeverity.Info,
233+
isEnabledByDefault:true,
234+
helpLinkUri:"https://aka.ms/aspnet/analyzers");
226235
}

‎src/Framework/AspNetCoreAnalyzers/src/Analyzers/Resources.resx

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3-
<!--
4-
Microsoft ResX Schema
5-
3+
<!--
4+
Microsoft ResX Schema
5+
66
Version 2.0
7-
8-
The primary goals of this format is to allow a simple XML format
9-
that is mostly human readable. The generation and parsing of the
10-
various data types are done through the TypeConverter classes
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
1111
associated with the data types.
12-
12+
1313
Example:
14-
14+
1515
... ado.net/XML headers & schema ...
1616
<resheader name="resmimetype">text/microsoft-resx</resheader>
1717
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
2626
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
2727
<comment>This is a comment</comment>
2828
</data>
29-
30-
There are any number of "resheader" rows that contain simple
29+
30+
There are any number of "resheader" rows that contain simple
3131
name/value pairs.
32-
33-
Each data row contains a name, and value. The row also contains a
34-
type or mimetype. Type corresponds to a .NET class that support
35-
text/value conversion through the TypeConverter architecture.
36-
Classes that don't support this are serialized and stored with the
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
3737
mimetype set.
38-
39-
The mimetype is used for serialized objects, and tells the
40-
ResXResourceReader how to depersist the object. This is currently not
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
4141
extensible. For a given mimetype the value must be set accordingly:
42-
43-
Note - application/x-microsoft.net.object.binary.base64 is the format
44-
that the ResXResourceWriter will generate, however the reader can
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
4545
read any of the formats listed below.
46-
46+
4747
mimetype: application/x-microsoft.net.object.binary.base64
48-
value : The object must be serialized with
48+
value : The object must be serialized with
4949
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
5050
: and then encoded with base64 encoding.
51-
51+
5252
mimetype: application/x-microsoft.net.object.soap.base64
53-
value : The object must be serialized with
53+
value : The object must be serialized with
5454
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
5555
: and then encoded with base64 encoding.
5656
5757
mimetype: application/x-microsoft.net.object.bytearray.base64
58-
value : The object must be serialized into a byte array
58+
value : The object must be serialized into a byte array
5959
: using a System.ComponentModel.TypeConverter
6060
: and then encoded with base64 encoding.
6161
-->
@@ -321,4 +321,10 @@
321321
<dataname="Analyzer_OverriddenAuthorizeAttribute_Title"xml:space="preserve">
322322
<value>[Authorize] overridden by [AllowAnonymous] from farther away</value>
323323
</data>
324+
<dataname="Analyzer_PublicPartialProgramClass_Message"xml:space="preserve">
325+
<value>Using public partial class Program { } to make generated Program class public is no longer required. See https://aka.ms/aspnetcore-warnings/ASP0027 for more details.</value>
326+
</data>
327+
<dataname="Analyzer_PublicPartialProgramClass_Title"xml:space="preserve">
328+
<value>Explicit class declaration not required</value>
329+
</data>
324330
</root>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
usingSystem.Collections.Immutable;
5+
usingMicrosoft.CodeAnalysis;
6+
usingMicrosoft.CodeAnalysis.CSharp;
7+
usingMicrosoft.CodeAnalysis.CSharp.Syntax;
8+
usingMicrosoft.CodeAnalysis.Diagnostics;
9+
10+
namespaceMicrosoft.AspNetCore.Analyzers;
11+
12+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
13+
publicsealedclassPublicPartialProgramClassAnalyzer:DiagnosticAnalyzer
14+
{
15+
publicoverrideImmutableArray<DiagnosticDescriptor>SupportedDiagnostics=>ImmutableArray.Create(DiagnosticDescriptors.PublicPartialProgramClassNotRequired);
16+
17+
publicoverridevoidInitialize(AnalysisContextcontext)
18+
{
19+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
20+
context.EnableConcurrentExecution();
21+
context.RegisterSyntaxNodeAction(context=>
22+
{
23+
varsyntaxNode=context.Node;
24+
if(IsPublicPartialClassProgram(syntaxNode))
25+
{
26+
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.PublicPartialProgramClassNotRequired,syntaxNode.GetLocation()));
27+
}
28+
},SyntaxKind.ClassDeclaration);
29+
}
30+
31+
privatestaticboolIsPublicPartialClassProgram(SyntaxNodesyntaxNode)
32+
{
33+
returnsyntaxNodeisClassDeclarationSyntax{Modifiers:{}modifiers}classDeclaration
34+
&&modifiersis{Count:>1}
35+
&&modifiers.Any(SyntaxKind.PublicKeyword)
36+
&&modifiers.Any(SyntaxKind.PartialKeyword)
37+
&&classDeclarationis{Identifier.ValueText:"Program"};
38+
}
39+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
usingSystem.Collections.Immutable;
5+
usingSystem.Composition;
6+
usingSystem.Threading.Tasks;
7+
usingMicrosoft.AspNetCore.Analyzers;
8+
usingMicrosoft.CodeAnalysis;
9+
usingMicrosoft.CodeAnalysis.CodeActions;
10+
usingMicrosoft.CodeAnalysis.CodeFixes;
11+
usingMicrosoft.CodeAnalysis.CSharp.Syntax;
12+
usingMicrosoft.CodeAnalysis.Editing;
13+
14+
namespaceMicrosoft.AspNetCore.Fixers;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp),Shared]
17+
publicclassPublicPartialProgramClassFixer:CodeFixProvider
18+
{
19+
publicoverrideImmutableArray<string>FixableDiagnosticIds{get;}=[DiagnosticDescriptors.PublicPartialProgramClassNotRequired.Id];
20+
21+
publicsealedoverrideFixAllProviderGetFixAllProvider()=>WellKnownFixAllProviders.BatchFixer;
22+
23+
publicsealedoverrideTaskRegisterCodeFixesAsync(CodeFixContextcontext)
24+
{
25+
foreach(vardiagnosticincontext.Diagnostics)
26+
{
27+
context.RegisterCodeFix(
28+
CodeAction.Create("Fix unnecessary public partial class Program",
29+
async cancellationToken=>
30+
{
31+
vareditor=awaitDocumentEditor.CreateAsync(context.Document,cancellationToken).ConfigureAwait(false);
32+
varroot=context.Document.GetSyntaxRootAsync(cancellationToken).Result;
33+
if(rootisnull)
34+
{
35+
returncontext.Document;
36+
}
37+
38+
varclassDeclaration=root.FindNode(diagnostic.Location.SourceSpan)
39+
.FirstAncestorOrSelf<ClassDeclarationSyntax>();
40+
if(classDeclarationisnull)
41+
{
42+
returncontext.Document;
43+
}
44+
editor.RemoveNode(classDeclaration,SyntaxRemoveOptions.KeepNoTrivia);
45+
returneditor.GetChangedDocument();
46+
},
47+
equivalenceKey:DiagnosticDescriptors.PublicPartialProgramClassNotRequired.Id),
48+
diagnostic);
49+
}
50+
51+
returnTask.CompletedTask;
52+
}
53+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
usingMicrosoft.CodeAnalysis.Testing;
5+
usingVerifyCS=Microsoft.AspNetCore.Analyzers.Verifiers.CSharpCodeFixVerifier<
6+
Microsoft.AspNetCore.Analyzers.PublicPartialProgramClassAnalyzer,
7+
Microsoft.AspNetCore.Fixers.PublicPartialProgramClassFixer>;
8+
9+
namespaceMicrosoft.AspNetCore.Analyzers;
10+
11+
publicclassPublicPartialProgramClassTest
12+
{
13+
[Fact]
14+
publicasyncTaskDoesNothingWhenNoDeclarationIsFound()
15+
{
16+
// Arrange
17+
varsource="""
18+
using Microsoft.AspNetCore.Builder;
19+
20+
var app = WebApplication.Create();
21+
22+
app.MapGet("/", () => "Hello, World!");
23+
24+
app.Run();
25+
""";
26+
27+
// Assert
28+
awaitVerifyCS.VerifyCodeFixAsync(source,source);
29+
}
30+
31+
[Fact]
32+
publicasyncTaskRemovesDeclarationIfItIsFound()
33+
{
34+
// Arrange
35+
varsource="""
36+
using Microsoft.AspNetCore.Builder;
37+
38+
var app = WebApplication.Create();
39+
40+
app.MapGet("/", () => "Hello, World!");
41+
42+
app.Run();
43+
44+
{|#0:public partial class Program { }|}
45+
""";
46+
47+
vardiagnostic=newDiagnosticResult(DiagnosticDescriptors.PublicPartialProgramClassNotRequired)
48+
.WithLocation(0);
49+
50+
varfixedSource="""
51+
using Microsoft.AspNetCore.Builder;
52+
53+
var app = WebApplication.Create();
54+
55+
app.MapGet("/", () => "Hello, World!");
56+
57+
app.Run();
58+
59+
""";
60+
61+
// Assert
62+
awaitVerifyCS.VerifyCodeFixAsync(source,[diagnostic],fixedSource);
63+
}
64+
65+
[Fact]
66+
publicasyncTaskDoesNotGeneratesSource_IfProgramDeclaresExplicitInternalAccess()
67+
{
68+
varsource="""
69+
using Microsoft.AspNetCore.Builder;
70+
71+
var app = WebApplication.Create();
72+
73+
app.MapGet("/", () => "Hello, World!");
74+
75+
app.Run();
76+
77+
internal partial class Program { }
78+
""";
79+
80+
awaitVerifyCS.VerifyCodeFixAsync(source,source);
81+
}
82+
83+
[Fact]
84+
publicasyncTaskDoesNotFix_ExplicitPublicProgramClass()
85+
{
86+
varsource="""
87+
using Microsoft.AspNetCore.Builder;
88+
89+
public class Program
90+
{
91+
public static void Main()
92+
{
93+
var app = WebApplication.Create();
94+
95+
app.MapGet("/", () => "Hello, World!");
96+
97+
app.Run();
98+
}
99+
}
100+
""";
101+
102+
awaitVerifyCS.VerifyCodeFixAsync(source,source);
103+
}
104+
105+
[Fact]
106+
publicasyncTaskDoesNotFix_ExplicitInternalProgramClass()
107+
{
108+
varsource="""
109+
using Microsoft.AspNetCore.Builder;
110+
111+
internal class Program
112+
{
113+
public static void Main()
114+
{
115+
var app = WebApplication.Create();
116+
117+
app.MapGet("/", () => "Hello, World!");
118+
119+
app.Run();
120+
}
121+
}
122+
""";
123+
124+
awaitVerifyCS.VerifyCodeFixAsync(source,source);
125+
}
126+
127+
[Theory]
128+
[InlineData("interface")]
129+
[InlineData("struct")]
130+
publicasyncTaskDoesNotFix_ExplicitInternalProgramType(stringtype)
131+
{
132+
varsource=$$"""
133+
using Microsoft.AspNetCore.Builder;
134+
135+
internal{{type}} Program
136+
{
137+
public static void Main(string[] args)
138+
{
139+
var app = WebApplication.Create();
140+
141+
app.MapGet("/", () => "Hello, World!");
142+
143+
app.Run();
144+
}
145+
}
146+
""";
147+
148+
awaitVerifyCS.VerifyCodeFixAsync(source,source);
149+
}
150+
}
151+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp