-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add additional generator tests * Add MissingHandlerAttribute analyzer * Add Invalid [Authorize] and [AllowAnonymous] analyzers * Clean up Test facts
- Loading branch information
1 parent
d9887aa
commit a3f1952
Showing
25 changed files
with
825 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## Release 1.0 | ||
|
||
### New Rules | ||
|
||
Rule ID | Category | Severity | Notes | ||
--------|----------|----------|-------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
### New Rules | ||
|
||
Rule ID | Category | Severity | Notes | ||
--------|----------|----------|------- | ||
IAPI0001 | ImmediateApis | Error | InvalidHandlerAttributeAnalyzer | ||
IAPI0002 | ImmediateApis | Error | InvalidAuthorizeAttributeAnalyzer | ||
IAPI0003 | ImmediateApis | Warning | InvalidAuthorizeAttributeAnalyzer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Immediate.Apis.Analyzers; | ||
|
||
internal static class DiagnosticIds | ||
{ | ||
public const string IAPI0001MissingHandlerAttribute = "IAPI0001"; | ||
public const string IAPI0002InvalidAuthorizeParameter = "IAPI0002"; | ||
public const string IAPI0003UsedBothAuthorizeAndAnonymous = "IAPI0003"; | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Immediate.Apis.Analyzers/Immediate.Apis.Analyzers.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.0</TargetFramework> | ||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> | ||
<IsRoslynComponent>true</IsRoslynComponent> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="All" /> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" /> | ||
<PackageReference Include="MinVer" PrivateAssets="all" /> | ||
</ItemGroup> | ||
|
||
<PropertyGroup Label="MinVer"> | ||
<MinVerAutoIncrement>minor</MinVerAutoIncrement> | ||
<MinVerDefaultPreReleaseIdentifiers>preview.0</MinVerDefaultPreReleaseIdentifiers> | ||
<MinVerTagPrefix>v</MinVerTagPrefix> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Immediate.Api.Analyzers | ||
|
||
## IAPI0001: [Handler] must be used | ||
|
||
The `[Handler]` attribute must be applied for registrations to be generated by `Immediate.Apis`. | ||
|
||
| Item | Value | | ||
|----------|------------------| | ||
| Category | ImmediateHandler | | ||
| Enabled | True | | ||
| Severity | Error | | ||
| CodeFix | False | | ||
--- |
108 changes: 108 additions & 0 deletions
108
src/Immediate.Apis.Analyzers/InvalidAuthorizeAttributeAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Immediate.Apis.Analyzers; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class InvalidAuthorizeAttributeAnalyzer : DiagnosticAnalyzer | ||
{ | ||
public static readonly DiagnosticDescriptor InvalidAuthorizeParameter = | ||
new( | ||
id: DiagnosticIds.IAPI0002InvalidAuthorizeParameter, | ||
title: "Must use `Policies` parameter for [Authorize]", | ||
messageFormat: "[Authorize] was used with invalid parameter {0}", | ||
category: "ImmediateApis", | ||
defaultSeverity: DiagnosticSeverity.Error, | ||
isEnabledByDefault: true, | ||
description: "Only policy authorization is supported with Immediate.Apis." | ||
); | ||
|
||
public static readonly DiagnosticDescriptor UsedBothAuthorizeAndAnonymous = | ||
new( | ||
id: DiagnosticIds.IAPI0003UsedBothAuthorizeAndAnonymous, | ||
title: "Only use one of [AllowAnonymous] and [Authorize]", | ||
messageFormat: "Both [AllowAnonymous] and [Authorize] were used, but only one will be applied to the endpoint", | ||
category: "ImmediateApis", | ||
defaultSeverity: DiagnosticSeverity.Warning, | ||
isEnabledByDefault: true, | ||
description: "Only one of [AllowAnonymous] and [Authorize] can be used for a single endpoint." | ||
); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = | ||
ImmutableArray.Create( | ||
[ | ||
InvalidAuthorizeParameter, | ||
UsedBothAuthorizeAndAnonymous, | ||
]); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
if (context == null) | ||
throw new ArgumentNullException(nameof(context)); | ||
|
||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
|
||
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType); | ||
} | ||
|
||
private static void AnalyzeSymbol(SymbolAnalysisContext context) | ||
{ | ||
var token = context.CancellationToken; | ||
token.ThrowIfCancellationRequested(); | ||
|
||
if (context.Symbol is not INamedTypeSymbol namedTypeSymbol) | ||
return; | ||
|
||
var attributeNames = namedTypeSymbol | ||
.GetAttributes() | ||
.Select(a => a.AttributeClass?.ToString() ?? "") | ||
.ToList(); | ||
|
||
if (!attributeNames.Any(x => Utility.ValidAttributes.Contains(x))) | ||
{ | ||
return; | ||
} | ||
|
||
token.ThrowIfCancellationRequested(); | ||
|
||
var allowAnonymous = attributeNames.Contains("Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute"); | ||
|
||
var authorizeIndex = attributeNames.IndexOf("Microsoft.AspNetCore.Authorization.AuthorizeAttribute"); | ||
var authorize = authorizeIndex >= 0; | ||
|
||
if (allowAnonymous && authorize) | ||
{ | ||
context.ReportDiagnostic( | ||
Diagnostic.Create( | ||
UsedBothAuthorizeAndAnonymous, | ||
namedTypeSymbol.Locations[0] | ||
) | ||
); | ||
} | ||
|
||
if (authorize) | ||
{ | ||
var authorizeAttribute = namedTypeSymbol.GetAttributes()[authorizeIndex]; | ||
if (authorizeAttribute.NamedArguments.Length > 0) | ||
{ | ||
foreach (var argument in authorizeAttribute.NamedArguments) | ||
{ | ||
if (argument.Key != "Policy") | ||
{ | ||
context.ReportDiagnostic( | ||
Diagnostic.Create( | ||
InvalidAuthorizeParameter, | ||
authorizeAttribute.ApplicationSyntaxReference | ||
?.GetSyntax() | ||
.GetLocation(), | ||
argument.Key | ||
) | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
src/Immediate.Apis.Analyzers/MissingHandlerAttributeAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Immediate.Apis.Analyzers; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class MissingHandlerAttributeAnalyzer : DiagnosticAnalyzer | ||
{ | ||
public static readonly DiagnosticDescriptor MissingHandlerAttribute = | ||
new( | ||
id: DiagnosticIds.IAPI0001MissingHandlerAttribute, | ||
title: "[Handler] must be used", | ||
messageFormat: "Handler `{0}` must be marked with [Handler]", | ||
category: "ImmediateApis", | ||
defaultSeverity: DiagnosticSeverity.Error, | ||
isEnabledByDefault: true, | ||
description: "An endpoint registration can only be generated for an Immediate.Handlers handler." | ||
); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = | ||
ImmutableArray.Create( | ||
[ | ||
MissingHandlerAttribute, | ||
]); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
if (context == null) | ||
throw new ArgumentNullException(nameof(context)); | ||
|
||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
|
||
context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType); | ||
} | ||
|
||
private static void AnalyzeSymbol(SymbolAnalysisContext context) | ||
{ | ||
var token = context.CancellationToken; | ||
token.ThrowIfCancellationRequested(); | ||
|
||
if (context.Symbol is not INamedTypeSymbol namedTypeSymbol) | ||
return; | ||
|
||
if (!namedTypeSymbol | ||
.GetAttributes() | ||
.Any(x => Utility.ValidAttributes.Contains(x.AttributeClass?.ToString())) | ||
) | ||
{ | ||
return; | ||
} | ||
|
||
token.ThrowIfCancellationRequested(); | ||
|
||
if (!namedTypeSymbol | ||
.GetAttributes() | ||
.Any(x => x.AttributeClass?.ToString() == "Immediate.Handlers.Shared.HandlerAttribute") | ||
) | ||
{ | ||
context.ReportDiagnostic( | ||
Diagnostic.Create( | ||
MissingHandlerAttribute, | ||
namedTypeSymbol.Locations[0], | ||
namedTypeSymbol.Name | ||
) | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"profiles": { | ||
"Immediate.Apis.FunctionalTests": { | ||
"commandName": "DebugRoslynComponent", | ||
"targetProject": "../../tests/Immediate.Apis.FunctionalTests/Immediate.Apis.FunctionalTests.csproj" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace Immediate.Apis.Analyzers; | ||
internal static class Utility | ||
{ | ||
public static readonly string[] ValidAttributes = | ||
[ | ||
"Immediate.Apis.Shared.MapGetAttribute", | ||
"Immediate.Apis.Shared.MapPostAttribute", | ||
"Immediate.Apis.Shared.MapPutAttribute", | ||
"Immediate.Apis.Shared.MapPatchAttribute", | ||
"Immediate.Apis.Shared.MapDeleteAttribute", | ||
]; | ||
} |
33 changes: 33 additions & 0 deletions
33
tests/Immediate.Apis.Tests/AnalyzerTests/AnalyzerTestHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using Microsoft.CodeAnalysis.CSharp.Testing; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis.Testing; | ||
|
||
namespace Immediate.Apis.Tests.AnalyzerTests; | ||
|
||
public static class AnalyzerTestHelpers | ||
{ | ||
public static CSharpAnalyzerTest<TAnalyzer, DefaultVerifier> CreateAnalyzerTest<TAnalyzer>( | ||
string inputSource | ||
) | ||
where TAnalyzer : DiagnosticAnalyzer, new() | ||
{ | ||
var csTest = new CSharpAnalyzerTest<TAnalyzer, DefaultVerifier> | ||
{ | ||
TestState = | ||
{ | ||
Sources = { inputSource }, | ||
ReferenceAssemblies = new ReferenceAssemblies( | ||
"net8.0", | ||
new PackageIdentity( | ||
"Microsoft.NETCore.App.Ref", | ||
"8.0.0"), | ||
Path.Combine("ref", "net8.0")), | ||
}, | ||
}; | ||
|
||
csTest.TestState.AdditionalReferences | ||
.AddRange(Utility.GetMetadataReferences()); | ||
|
||
return csTest; | ||
} | ||
} |
Oops, something went wrong.