diff --git a/Directory.Packages.props b/Directory.Packages.props
index df3eb7f1..8e1c6513 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,15 +4,15 @@
-
+
-
-
+
+
-
+
@@ -22,17 +22,17 @@
-
-
+
+
-
+
-
-
-
+
+
+
diff --git a/src/Immediate.Handlers.Analyzers/BehaviorsAnalyzer.cs b/src/Immediate.Handlers.Analyzers/BehaviorsAnalyzer.cs
index 3eca3279..c9c96757 100644
--- a/src/Immediate.Handlers.Analyzers/BehaviorsAnalyzer.cs
+++ b/src/Immediate.Handlers.Analyzers/BehaviorsAnalyzer.cs
@@ -69,12 +69,7 @@ private void AnalyzeOperation(OperationAnalysisContext context)
if (context.Operation is not IAttributeOperation { Operation: IObjectCreationOperation attribute })
return;
- var behaviorsAttributeSymbol = context.Compilation.GetTypeByMetadataName("Immediate.Handlers.Shared.BehaviorsAttribute");
- if (behaviorsAttributeSymbol is null)
- return;
-
- token.ThrowIfCancellationRequested();
- if (!SymbolEqualityComparer.Default.Equals(attribute.Type?.OriginalDefinition, behaviorsAttributeSymbol))
+ if (!attribute.Type.IsBehaviorsAttribute())
return;
if (attribute.Arguments.Length != 1)
@@ -86,10 +81,22 @@ private void AnalyzeOperation(OperationAnalysisContext context)
token.ThrowIfCancellationRequested();
var array = attribute.Arguments[0].Value;
- var compilation = context.Compilation;
- var arrayTypeSymbol = compilation.CreateArrayTypeSymbol(compilation.GetTypeByMetadataName("System.Type")!, 1);
- if (!SymbolEqualityComparer.Default.Equals(array.Type, arrayTypeSymbol)
- || array.ChildOperations.Count != 2
+ if (array is not
+ {
+ Type: IArrayTypeSymbol
+ {
+ ElementType:
+ {
+ Name: "Type",
+ ContainingNamespace:
+ {
+ Name: "System",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ ChildOperations.Count: 2
+ }
|| array.ChildOperations.ElementAt(1) is not IArrayInitializerOperation aio)
{
// note: this will already be a compiler error anyway
@@ -117,7 +124,7 @@ private void AnalyzeOperation(OperationAnalysisContext context)
var location = toes.Type.GetLocation();
var originalDefinition = behaviorType.OriginalDefinition;
- if (!ImplementsBaseClass(originalDefinition, baseBehaviorSymbol))
+ if (!originalDefinition.ImplementsBehavior())
{
context.ReportDiagnostic(
Diagnostic.Create(
@@ -148,10 +155,4 @@ private void AnalyzeOperation(OperationAnalysisContext context)
}
}
}
-
- private static bool ImplementsBaseClass(INamedTypeSymbol typeSymbol, INamedTypeSymbol typeToCheck) =>
- SymbolEqualityComparer.Default.Equals(typeSymbol, typeToCheck)
- || (typeSymbol.BaseType is not null
- && ImplementsBaseClass(typeSymbol.BaseType.OriginalDefinition, typeToCheck)
- );
}
diff --git a/src/Immediate.Handlers.Analyzers/ITypeSymbolExtensions.cs b/src/Immediate.Handlers.Analyzers/ITypeSymbolExtensions.cs
new file mode 100644
index 00000000..031ac47a
--- /dev/null
+++ b/src/Immediate.Handlers.Analyzers/ITypeSymbolExtensions.cs
@@ -0,0 +1,86 @@
+using Microsoft.CodeAnalysis;
+
+namespace Immediate.Handlers.Analyzers;
+
+internal static class ITypeSymbolExtensions
+{
+ public static bool IsBehaviorsAttribute(this ITypeSymbol? typeSymbol) =>
+ typeSymbol is
+ {
+ Name: "BehaviorsAttribute",
+ ContainingNamespace:
+ {
+ Name: "Shared",
+ ContainingNamespace:
+ {
+ Name: "Handlers",
+ ContainingNamespace:
+ {
+ Name: "Immediate",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ };
+
+ public static bool IsRenderModeAttribute(this ITypeSymbol? typeSymbol) =>
+ typeSymbol is
+ {
+ Name: "RenderModeAttribute",
+ ContainingNamespace:
+ {
+ Name: "Shared",
+ ContainingNamespace:
+ {
+ Name: "Handlers",
+ ContainingNamespace:
+ {
+ Name: "Immediate",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ };
+
+ public static bool IsRenderMode(this ITypeSymbol? typeSymbol) =>
+ typeSymbol is
+ {
+ Name: "RenderMode",
+ ContainingNamespace:
+ {
+ Name: "Shared",
+ ContainingNamespace:
+ {
+ Name: "Handlers",
+ ContainingNamespace:
+ {
+ Name: "Immediate",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ };
+
+ public static bool IsBehavior2(this ITypeSymbol typeSymbol) =>
+ typeSymbol is
+ {
+ MetadataName: "Behavior`2",
+ ContainingNamespace:
+ {
+ Name: "Shared",
+ ContainingNamespace:
+ {
+ Name: "Handlers",
+ ContainingNamespace:
+ {
+ Name: "Immediate",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ };
+
+ public static bool ImplementsBehavior(this INamedTypeSymbol typeSymbol) =>
+ typeSymbol.IsBehavior2()
+ || (typeSymbol.BaseType is not null && ImplementsBehavior(typeSymbol.BaseType.OriginalDefinition));
+}
diff --git a/src/Immediate.Handlers.Analyzers/RenderModeAnalyzer.cs b/src/Immediate.Handlers.Analyzers/RenderModeAnalyzer.cs
index b421e713..7cb1d22f 100644
--- a/src/Immediate.Handlers.Analyzers/RenderModeAnalyzer.cs
+++ b/src/Immediate.Handlers.Analyzers/RenderModeAnalyzer.cs
@@ -44,18 +44,14 @@ private void AnalyzeOperation(OperationAnalysisContext context)
if (context.Operation is not IAttributeOperation { Operation: IObjectCreationOperation attribute })
return;
- var renderModeAttributeSymbol = context.Compilation.GetTypeByMetadataName("Immediate.Handlers.Shared.RenderModeAttribute");
-
- token.ThrowIfCancellationRequested();
- if (!SymbolEqualityComparer.Default.Equals(attribute.Type?.OriginalDefinition, renderModeAttributeSymbol))
+ if (!attribute.Type.IsRenderModeAttribute())
return;
token.ThrowIfCancellationRequested();
- var renderModeSymbol = context.Compilation.GetTypeByMetadataName("Immediate.Handlers.Shared.RenderMode");
if (attribute.Arguments.Length != 1
|| attribute.Arguments[0].Value is not IFieldReferenceOperation value
- || !SymbolEqualityComparer.Default.Equals(value.Type?.OriginalDefinition, renderModeSymbol)
+ || !value.Type.IsRenderMode()
|| value.Member.Name is "None")
{
context.ReportDiagnostic(Diagnostic.Create(
diff --git a/src/Immediate.Handlers.Generators/ITypeSymbolExtensions.cs b/src/Immediate.Handlers.Generators/ITypeSymbolExtensions.cs
new file mode 100644
index 00000000..2801a7a0
--- /dev/null
+++ b/src/Immediate.Handlers.Generators/ITypeSymbolExtensions.cs
@@ -0,0 +1,78 @@
+using Microsoft.CodeAnalysis;
+
+namespace Immediate.Handlers.Generators;
+
+internal static class ITypeSymbolExtensions
+{
+ public static bool IsBehavior2(this ITypeSymbol typeSymbol) =>
+ typeSymbol is
+ {
+ MetadataName: "Behavior`2",
+ ContainingNamespace:
+ {
+ Name: "Shared",
+ ContainingNamespace:
+ {
+ Name: "Handlers",
+ ContainingNamespace:
+ {
+ Name: "Immediate",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ },
+ };
+
+ public static bool ImplementsBehavior(this INamedTypeSymbol typeSymbol) =>
+ typeSymbol.IsBehavior2()
+ || (typeSymbol.BaseType is not null && ImplementsBehavior(typeSymbol.BaseType.OriginalDefinition));
+
+ public static bool IsValueTask1(this ITypeSymbol typeSymbol) =>
+ typeSymbol is INamedTypeSymbol
+ {
+ MetadataName: "ValueTask`1",
+ ContainingNamespace:
+ {
+ Name: "Tasks",
+ ContainingNamespace:
+ {
+ Name: "Threading",
+ ContainingNamespace:
+ {
+ Name: "System",
+ ContainingNamespace.IsGlobalNamespace: true
+ }
+ }
+ }
+ };
+
+ public static bool IsValueTask(this ITypeSymbol typeSymbol) =>
+ typeSymbol is INamedTypeSymbol
+ {
+ Name: "ValueTask",
+ ContainingNamespace:
+ {
+ Name: "Tasks",
+ ContainingNamespace:
+ {
+ Name: "Threading",
+ ContainingNamespace:
+ {
+ Name: "System",
+ ContainingNamespace.IsGlobalNamespace: true
+ }
+ }
+ }
+ };
+
+ public static bool IsIEquatable1(this ITypeSymbol typeSymbol) =>
+ typeSymbol is INamedTypeSymbol
+ {
+ MetadataName: "IEquatable`1",
+ ContainingNamespace:
+ {
+ Name: "System",
+ ContainingNamespace.IsGlobalNamespace: true
+ },
+ };
+}
diff --git a/src/Immediate.Handlers.Generators/Immediate.Handlers.Generators.csproj b/src/Immediate.Handlers.Generators/Immediate.Handlers.Generators.csproj
index 8909637d..d45335e5 100644
--- a/src/Immediate.Handlers.Generators/Immediate.Handlers.Generators.csproj
+++ b/src/Immediate.Handlers.Generators/Immediate.Handlers.Generators.csproj
@@ -4,11 +4,16 @@
netstandard2.0
true
true
+ $(NoWarn);CA1716
-
-
+
+
+
+
+
+
@@ -19,10 +24,6 @@
-
-
-
-
$(GetTargetPathDependsOn);GetDependencyTargetPaths
@@ -30,7 +31,6 @@
-
diff --git a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_Entrypoint.cs b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_Entrypoint.cs
index cd838f84..c3111c86 100644
--- a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_Entrypoint.cs
+++ b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_Entrypoint.cs
@@ -230,8 +230,7 @@ string GetVariableNameSuffix(string typeName)
private static bool ValidateType(string? type, GenericType implementedTypes) =>
type is null
- || implementedTypes.Implements
- .Contains(type);
+ || implementedTypes.Implements.Contains(type);
private static Template GetTemplate(string name)
{
diff --git a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformBehaviors.cs b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformBehaviors.cs
index 0a32b1d6..600aae3b 100644
--- a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformBehaviors.cs
+++ b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformBehaviors.cs
@@ -1,4 +1,3 @@
-using Immediate.Handlers.Shared;
using Microsoft.CodeAnalysis;
namespace Immediate.Handlers.Generators.ImmediateHandlers;
@@ -12,32 +11,35 @@ CancellationToken cancellationToken
{
cancellationToken.ThrowIfCancellationRequested();
- var semanticModel = context.SemanticModel;
- var compilation = semanticModel.Compilation;
- cancellationToken.ThrowIfCancellationRequested();
-
- return ParseBehaviors(context.Attributes[0], compilation, cancellationToken);
+ return ParseBehaviors(context.Attributes[0], cancellationToken);
}
private static EquatableReadOnlyList ParseBehaviors(
AttributeData attribute,
- Compilation compilation,
CancellationToken cancellationToken
)
{
cancellationToken.ThrowIfCancellationRequested();
- var behaviorType = typeof(Behavior<,>);
- var behaviorTypeSymbol = compilation.GetTypeByMetadataName(behaviorType.FullName!);
- if (behaviorTypeSymbol is null)
- return [];
if (attribute.ConstructorArguments.Length != 1)
return [];
var ca = attribute.ConstructorArguments[0];
- var arrayTypeSymbol = compilation.CreateArrayTypeSymbol(compilation.GetTypeByMetadataName("System.Type")!, 1);
- if (!SymbolEqualityComparer.Default.Equals(ca.Type, arrayTypeSymbol))
+ if (ca.Type is not IArrayTypeSymbol
+ {
+ ElementType:
+ {
+ Name: "Type",
+ ContainingNamespace:
+ {
+ Name: "System",
+ ContainingNamespace.IsGlobalNamespace: true,
+ },
+ },
+ })
+ {
return [];
+ }
cancellationToken.ThrowIfCancellationRequested();
return ca.Values
@@ -57,7 +59,7 @@ CancellationToken cancellationToken
if (originalDefinition.IsAbstract)
return null;
- if (!originalDefinition.ImplementsBaseClass(behaviorTypeSymbol))
+ if (!originalDefinition.ImplementsBehavior())
return null;
cancellationToken.ThrowIfCancellationRequested();
diff --git a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformHandler.cs b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformHandler.cs
index 054983e6..2189f63a 100644
--- a/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformHandler.cs
+++ b/src/Immediate.Handlers.Generators/ImmediateHandlers/ImmediateHandlersGenerator_TransformHandler.cs
@@ -26,10 +26,7 @@ CancellationToken cancellationToken
.GetMembers()
.OfType()
.Where(m => m.IsStatic)
- .Where(m =>
- m.Name.Equals("Handle", StringComparison.Ordinal)
- || m.Name.Equals("HandleAsync", StringComparison.Ordinal)
- )
+ .Where(m => m.Name is "Handle" or "HandleAsync")
.ToList() is not [var handleMethod])
{
return null;
@@ -45,17 +42,12 @@ CancellationToken cancellationToken
cancellationToken.ThrowIfCancellationRequested();
var requestType = BuildGenericType(handleMethod.Parameters[0].Type);
- var compilation = context.SemanticModel.Compilation;
- var taskSymbol = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask`1")!;
-
cancellationToken.ThrowIfCancellationRequested();
- var responseTypeSymbol = handleMethod.GetTaskReturnType(taskSymbol);
+ var responseTypeSymbol = handleMethod.GetTaskReturnType();
if (responseTypeSymbol is null)
{
- taskSymbol = compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask")!;
-
cancellationToken.ThrowIfCancellationRequested();
- if (!SymbolEqualityComparer.Default.Equals(handleMethod.ReturnType.OriginalDefinition, taskSymbol))
+ if (!handleMethod.ReturnType.IsValueTask())
return null;
}
@@ -75,7 +67,7 @@ CancellationToken cancellationToken
var renderMode = GetOverrideRenderMode(symbol);
cancellationToken.ThrowIfCancellationRequested();
- var behaviors = GetOverrideBehaviors(symbol, context.SemanticModel.Compilation, cancellationToken);
+ var behaviors = GetOverrideBehaviors(symbol, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
return new()
@@ -104,11 +96,10 @@ CancellationToken cancellationToken
private static EquatableReadOnlyList? GetOverrideBehaviors(
INamedTypeSymbol symbol,
- Compilation compilation,
CancellationToken cancellationToken) =>
symbol.GetAttribute("Immediate.Handlers.Shared.BehaviorsAttribute")
is { } ba
- ? ParseBehaviors(ba, compilation, cancellationToken)
+ ? ParseBehaviors(ba, cancellationToken)
: null;
[return: NotNullIfNotNull(nameof(type))]
@@ -131,11 +122,8 @@ CancellationToken cancellationToken
private static void AddBaseTypes(ITypeSymbol type, List implements)
{
- if (type.OriginalDefinition.ToString() is
- "object"
- or "System.Collections.IEnumerable"
- or "System.IEquatable"
- )
+ if (type.SpecialType is SpecialType.System_Object or SpecialType.System_Collections_IEnumerable
+ || type.IsIEquatable1())
{
return;
}
diff --git a/src/Immediate.Handlers.Generators/Utility.cs b/src/Immediate.Handlers.Generators/Utility.cs
index 3badf438..70a3aea9 100644
--- a/src/Immediate.Handlers.Generators/Utility.cs
+++ b/src/Immediate.Handlers.Generators/Utility.cs
@@ -4,14 +4,8 @@ namespace Immediate.Handlers.Generators;
internal static class Utility
{
- public static bool ImplementsBaseClass(this INamedTypeSymbol typeSymbol, INamedTypeSymbol typeToCheck) =>
- SymbolEqualityComparer.Default.Equals(typeSymbol, typeToCheck)
- || (typeSymbol.BaseType is not null
- && ImplementsBaseClass(typeSymbol.BaseType.OriginalDefinition, typeToCheck)
- );
-
- public static ITypeSymbol? GetTaskReturnType(this IMethodSymbol method, INamedTypeSymbol taskSymbol) =>
- SymbolEqualityComparer.Default.Equals(method.ReturnType.OriginalDefinition, taskSymbol)
+ public static ITypeSymbol? GetTaskReturnType(this IMethodSymbol method) =>
+ method.ReturnType.IsValueTask1()
? ((INamedTypeSymbol)method.ReturnType).TypeArguments.FirstOrDefault()
: null;
diff --git a/src/Immediate.Handlers.Shared/Immediate.Handlers.Shared.csproj b/src/Immediate.Handlers.Shared/Immediate.Handlers.Shared.csproj
index 6fbcaf3d..7b643f7b 100644
--- a/src/Immediate.Handlers.Shared/Immediate.Handlers.Shared.csproj
+++ b/src/Immediate.Handlers.Shared/Immediate.Handlers.Shared.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ net8.0
false
$(NoWarn);CA1716
diff --git a/src/Immediate.Handlers.Shared/RenderMode.cs b/src/Immediate.Handlers.Shared/RenderMode.cs
new file mode 100644
index 00000000..6d5979e4
--- /dev/null
+++ b/src/Immediate.Handlers.Shared/RenderMode.cs
@@ -0,0 +1,17 @@
+namespace Immediate.Handlers.Shared;
+
+///
+/// Specifies which type of handler should be rendered
+///
+public enum RenderMode
+{
+ ///
+ /// Represents an invalid entry, and should not be used.
+ ///
+ None,
+
+ ///
+ /// A common handler should be rendered.
+ ///
+ Normal,
+}
diff --git a/src/Immediate.Handlers.Shared/RenderModeAttribute.cs b/src/Immediate.Handlers.Shared/RenderModeAttribute.cs
index fc661de2..02b0caf1 100644
--- a/src/Immediate.Handlers.Shared/RenderModeAttribute.cs
+++ b/src/Immediate.Handlers.Shared/RenderModeAttribute.cs
@@ -1,21 +1,5 @@
namespace Immediate.Handlers.Shared;
-///
-/// Specifies which type of handler should be rendered
-///
-public enum RenderMode
-{
- ///
- /// Represents an invalid entry, and should not be used.
- ///
- None,
-
- ///
- /// A common handler should be rendered.
- ///
- Normal,
-}
-
///
/// Allows the specification of which type of handler should be rendered.
///
diff --git a/src/Immediate.Handlers/Immediate.Handlers.csproj b/src/Immediate.Handlers/Immediate.Handlers.csproj
index a53f3889..6ce4e4ad 100644
--- a/src/Immediate.Handlers/Immediate.Handlers.csproj
+++ b/src/Immediate.Handlers/Immediate.Handlers.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ net8.0
true
false
@@ -25,12 +25,11 @@
-
-
-
-
-
-
+
+
+
+
+
diff --git a/tests/Immediate.Handlers.Tests/GeneratorTests/GeneratorTestHelper.cs b/tests/Immediate.Handlers.Tests/GeneratorTests/GeneratorTestHelper.cs
index 05bce903..c0081e77 100644
--- a/tests/Immediate.Handlers.Tests/GeneratorTests/GeneratorTestHelper.cs
+++ b/tests/Immediate.Handlers.Tests/GeneratorTests/GeneratorTestHelper.cs
@@ -15,7 +15,7 @@ public static GeneratorDriver GetDriver(string source, DriverReferenceAssemblies
// Create a Roslyn compilation for the syntax tree.
var compilation = CSharpCompilation.Create(
assemblyName: "Tests",
- syntaxTrees: new[] { syntaxTree },
+ syntaxTrees: [syntaxTree],
references:
[
.. Basic.Reference.Assemblies.Net80.References.All,