diff --git a/Directory.Build.props b/Directory.Build.props index 24c0e06..16361d7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -44,6 +44,7 @@ $(BaseIntermediateOutputPath)$(MSBuildProjectName).xml portable true + Readme.md @@ -56,6 +57,7 @@ + diff --git a/Durian.sln b/Durian.sln index 73ef784..9b84887 100644 --- a/Durian.sln +++ b/Durian.sln @@ -190,6 +190,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Durian.Samples.CopyFrom", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Durian.GlobalScope", "src\Durian.GlobalScope\Durian.GlobalScope.csproj", "{643FFE0C-B641-4504-8F6A-0EA694F3DEF7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GlobalScope", "GlobalScope", "{A04BF577-5DEB-477A-A22C-3557852AC25B}" + ProjectSection(SolutionItems) = preProject + docs\GlobalScope\DUR0501.md = docs\GlobalScope\DUR0501.md + docs\GlobalScope\DUR0502.md = docs\GlobalScope\DUR0502.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -485,6 +491,7 @@ Global {072AEE81-1199-4446-B2D5-54384D23DAE0} = {BA3DE2E2-7B32-4612-8219-24FBCF850813} {9C383ACD-8C9E-4C24-B2EA-4326C7553866} = {D98DD137-AADE-4474-86EF-9F0874607687} {643FFE0C-B641-4504-8F6A-0EA694F3DEF7} = {74D7ECF9-D1F6-46FA-B8D8-D34F86F713EA} + {A04BF577-5DEB-477A-A22C-3557852AC25B} = {BA3DE2E2-7B32-4612-8219-24FBCF850813} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {09524C45-0D6D-4456-B89D-9673853B9FA0} diff --git a/docs/GlobalScope/DUR0501.md b/docs/GlobalScope/DUR0501.md new file mode 100644 index 0000000..becdb3a --- /dev/null +++ b/docs/GlobalScope/DUR0501.md @@ -0,0 +1,22 @@ +# DUR0501 - Error +### Type marked with the GlobalScopeAttribute must be static. + +## Example 1 + +### Code with diagnostic: +```csharp +using Durian; + +// DUR0501 +[GlobalScope] +public class Test +{ + public static void DoStuff() + { + } +} + +``` +## + +*\(Written by Piotr Stenke\)* \ No newline at end of file diff --git a/docs/GlobalScope/DUR0502.md b/docs/GlobalScope/DUR0502.md new file mode 100644 index 0000000..1428557 --- /dev/null +++ b/docs/GlobalScope/DUR0502.md @@ -0,0 +1,22 @@ +# DUR0502 - Error +### Type marked with the GlobalScopeAttribute cannot be a nested type. + +## Example 1 + +### Code with diagnostic: +```csharp +using Durian; + +public static class Test +{ + // DUR0502 + [GlobalScope] + public static class Inner + { + } +} + +``` +## + +*\(Written by Piotr Stenke\)* \ No newline at end of file diff --git a/durian.json b/durian.json index f89d241..b8468d4 100644 --- a/durian.json +++ b/durian.json @@ -1,159 +1,181 @@ { "modules": [ - { - "name": "Core", - "packages": [ - { - "name": "Main", - "version": "3.0.0", - "type": [ - "Unspecified" - ] - }, - { - "name": "Core", - "version": "3.0.0", - "type": [ - "Library" - ] - }, - { - "name": "CoreAnalyzer", - "version": "3.0.0", - "type": [ - "Analyzer" - ] - } - ], - "diagnosticIdPrefix": "00", - "diagnosticFiles": [ - "src/Durian.Core.Analyzer/DurianDiagnostics.cs" - ], - "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/Core", - "includedTypes": [ - "Durian.Generator.EnableModuleAttribute", - "Durian.Generator.DurianGeneratedAttribute", - "Durian.PartialNameAttribute", - "Durian.UsingsAttribute" - ] - }, - { - "name": "Development", - "packages": [ - { - "name": "AnalysisServices", - "version": "3.0.0", - "type": [ - "Library" - ] - }, - { - "name": "TestServices", - "version": "3.0.0", - "type": [ - "Library" - ] - } - ] - }, - { - "name": "DefaultParam", - "packages": [ - { - "name": "DefaultParam", - "version": "3.0.0", - "type": [ - "Analyzer", - "CodeFixLibrary", - "StaticGenerator", - "SyntaxBasedGenerator" - ] - } - ], - "includedTypes": [ - "Durian.DefaultParamAttribute", - "Durian.Configuration.DefaultParamConfigurationAttribute", - "Durian.Configuration.DefaultParamScopedConfigurationAttribute", - "Durian.Configuration.DPMethodConvention", - "Durian.Configuration.DPTypeConvention" - ], - "diagnosticIdPrefix": "01", - "diagnosticFiles": [ - "src/Durian.DefaultParam/DefaultParamDiagnostics.cs" - ], - "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam" - }, - { - "name": "FriendClass", - "packages": [ - { - "name": "FriendClass", - "version": "2.0.0", - "type": [ - "Analyzer", - "CodeFixLibrary", - "StaticGenerator" - ] - } - ], - "includedTypes": [ - "Durian.FriendClassAttribute", - "Durian.Configuration.FriendClassConfigurationAttribute" - ], - "diagnosticIdPrefix": "03", - "diagnosticFiles": [ - "src/Durian.FriendClass/FriendClassDiagnostics.cs" - ], - "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass" - }, - { - "name": "InterfaceTargets", - "packages": [ - { - "name": "InterfaceTargets", - "version": "2.0.0", - "type": [ - "Analyzer", - "StaticGenerator" - ] - } - ], - "includedTypes": [ - "Durian.InterfaceTargets", - "Durian.InterfaceTargetsAttribute" - ], - "diagnosticIdPrefix": "04", - "diagnosticFiles": [ - "src/Durian.InterfaceTargets/InterfaceTargetsDiagnostics.cs" - ], - "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets" - }, - { - "name": "CopyFrom", - "packages": [ - { - "name": "CopyFrom", - "version": "1.0.0", - "type": [ - "Analyzer", - "StaticGenerator", - "SyntaxBasedGenerator", - "CodeFixLibrary" - ] - } - ], - "includedTypes": [ - "Durian.CopyFromTypeAttribute", - "Durian.CopyFromMethodAttribute", - "Durian.Configuration.CopyFromAdditionalNodes", - "Durian.PatternAttribute", - "Durian.PartialNameAttribute" - ], - "diagnosticIdPrefix": "02", - "diagnosticFiles": [ - "src/Durian.CopyFrom/CopyFromDiagnostics.cs" - ], - "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom" - } + { + "name": "Core", + "packages": [ + { + "name": "Main", + "version": "3.0.0", + "type": [ + "Unspecified" + ] + }, + { + "name": "Core", + "version": "3.0.0", + "type": [ + "Library" + ] + }, + { + "name": "CoreAnalyzer", + "version": "3.0.0", + "type": [ + "Analyzer" + ] + } + ], + "diagnosticIdPrefix": "00", + "diagnosticFiles": [ + "src/Durian.Core.Analyzer/DurianDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/Core", + "includedTypes": [ + "Durian.Generator.EnableModuleAttribute", + "Durian.Generator.DurianGeneratedAttribute", + "Durian.PartialNameAttribute", + "Durian.UsingsAttribute" + ] + }, + { + "name": "Development", + "packages": [ + { + "name": "AnalysisServices", + "version": "3.0.0", + "type": [ + "Library" + ] + }, + { + "name": "TestServices", + "version": "3.0.0", + "type": [ + "Library" + ] + } + ] + }, + { + "name": "DefaultParam", + "packages": [ + { + "name": "DefaultParam", + "version": "3.0.0", + "type": [ + "Analyzer", + "CodeFixLibrary", + "StaticGenerator", + "SyntaxBasedGenerator" + ] + } + ], + "includedTypes": [ + "Durian.DefaultParamAttribute", + "Durian.Configuration.DefaultParamConfigurationAttribute", + "Durian.Configuration.DefaultParamScopedConfigurationAttribute", + "Durian.Configuration.DPMethodConvention", + "Durian.Configuration.DPTypeConvention" + ], + "diagnosticIdPrefix": "01", + "diagnosticFiles": [ + "src/Durian.DefaultParam/DefaultParamDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam" + }, + { + "name": "FriendClass", + "packages": [ + { + "name": "FriendClass", + "version": "2.0.0", + "type": [ + "Analyzer", + "CodeFixLibrary", + "StaticGenerator" + ] + } + ], + "includedTypes": [ + "Durian.FriendClassAttribute", + "Durian.Configuration.FriendClassConfigurationAttribute" + ], + "diagnosticIdPrefix": "03", + "diagnosticFiles": [ + "src/Durian.FriendClass/FriendClassDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass" + }, + { + "name": "InterfaceTargets", + "packages": [ + { + "name": "InterfaceTargets", + "version": "2.0.0", + "type": [ + "Analyzer", + "StaticGenerator" + ] + } + ], + "includedTypes": [ + "Durian.InterfaceTargets", + "Durian.InterfaceTargetsAttribute" + ], + "diagnosticIdPrefix": "04", + "diagnosticFiles": [ + "src/Durian.InterfaceTargets/InterfaceTargetsDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets" + }, + { + "name": "CopyFrom", + "packages": [ + { + "name": "CopyFrom", + "version": "1.0.0", + "type": [ + "Analyzer", + "StaticGenerator", + "SyntaxBasedGenerator", + "CodeFixLibrary" + ] + } + ], + "includedTypes": [ + "Durian.CopyFromTypeAttribute", + "Durian.CopyFromMethodAttribute", + "Durian.Configuration.CopyFromAdditionalNodes", + "Durian.PatternAttribute", + "Durian.PartialNameAttribute" + ], + "diagnosticIdPrefix": "02", + "diagnosticFiles": [ + "src/Durian.CopyFrom/CopyFromDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom" + }, + { + "name": "GlobalScope", + "packages": [ + { + "name": "GlobalScope", + "version": "1.0.0", + "type": [ + "Analyzer", + "StaticGenerator", + "SyntaxBasedGenerator" + ] + } + ], + "includedTypes": [ + "Durian.GlobalScopeAttribute" + ], + "diagnosticIdPrefix": "05", + "diagnosticFiles": [ + "src/Durian.GlobalScope/GlobalScopeDiagnostics.cs" + ], + "documentation": "https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope" + } ] } \ No newline at end of file diff --git a/internal/GenerateModuleRepository/Program.cs b/internal/GenerateModuleRepository/Program.cs index a118806..66923e4 100644 --- a/internal/GenerateModuleRepository/Program.cs +++ b/internal/GenerateModuleRepository/Program.cs @@ -288,7 +288,8 @@ public static PackageIdentity {package.Name} builder.Append( @" } -}"); +} +"); } @@ -359,7 +360,8 @@ public static TypeIdentity {type.Name} builder.Append( @" } -}"); +} +"); } private static void WriteModuleRepository(StringBuilder builder, List configurations) @@ -389,7 +391,8 @@ public static class ModuleRepository builder.AppendLine( $@" }} -}}"); +}} +"); } private static void WriteModuleIdentity(StringBuilder builder, ModuleConfiguration config) diff --git a/src/Durian.AnalysisServices/AnalysisUtilities.cs b/src/Durian.AnalysisServices/AnalysisUtilities.cs index 742527b..47355c6 100644 --- a/src/Durian.AnalysisServices/AnalysisUtilities.cs +++ b/src/Durian.AnalysisServices/AnalysisUtilities.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; -using Durian.Analysis.Extensions; using Durian.Info; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/Durian.AnalysisServices/Extensions/AttributeDataExtensions.cs b/src/Durian.AnalysisServices/AttributeDataExtensions.cs similarity index 97% rename from src/Durian.AnalysisServices/Extensions/AttributeDataExtensions.cs rename to src/Durian.AnalysisServices/AttributeDataExtensions.cs index 42fd4e3..33ca171 100644 --- a/src/Durian.AnalysisServices/Extensions/AttributeDataExtensions.cs +++ b/src/Durian.AnalysisServices/AttributeDataExtensions.cs @@ -1,673 +1,673 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Durian.Analysis.Extensions; - -/// -/// Contains various extension methods for the class. -/// -public static class AttributeDataExtensions -{ - /// - /// Returns a representing the named argument at the specified . - /// - /// to get the from. - /// Position where the target argument is to be found. - public static TypedConstant GetConstructorArgument(this AttributeData attribute, int position) - { - attribute.TryGetConstructorArgument(position, out TypedConstant value); - return value; - } - - /// - /// Returns an of s representing the value of the constructor argument at the specified . - /// - /// to get the values from. - /// Position where the target argument is to be found. - public static ImmutableArray GetConstructorArgumentArrayValue(this AttributeData attribute, int position) - { - attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray array); - return array; - } - - /// - /// Returns an of s representing the value of the constructor argument at the specified . - /// - /// Type of array's elements. - /// to get the values from. - /// Position where the target argument is to be found. - public static ImmutableArray GetConstructorArgumentArrayValue(this AttributeData attribute, int position) - { - attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray array); - return array; - } - - /// - /// Returns the enum value of the constructor argument at the specified . - /// - /// Type of enum value to return. - /// to get the value from. - /// Position where the target argument is to be found. - /// Type size mismatch. - public static TEnum GetConstructorArgumentEnumValue(this AttributeData attribute, int position) where TEnum : unmanaged, Enum - { - attribute.TryGetConstructorArgumentEnumValue(position, out TEnum value); - return value; - } - - /// - /// Returns the enum value of the constructor argument at the specified . - /// - /// Type of enum value to return. - /// Type the type extends. - /// to get the value from. - /// Position where the target argument is to be found. - /// Type size mismatch. - public static TEnum GetConstructorArgumentEnumValue(this AttributeData attribute, int position) - where TEnum : unmanaged, Enum - where TType : unmanaged - { - attribute.TryGetConstructorArgumentEnumValue(position, out TEnum value); - return value; - } - - /// - /// Returns location of attribute argument at the specified - /// or location of the is no appropriate argument was found. - /// If for some reason source syntax of the is not accessible, is returned instead. - /// - /// to get the location of argument of. - /// Position of argument to get. - public static Location? GetConstructorArgumentLocation(this AttributeData attribute, int position) - { - if (attribute.ApplicationSyntaxReference is null) - { - return null; - } - - SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); - - if (node is not AttributeSyntax attr) - { - return node.GetLocation(); - } - - return attr.GetArgumentLocation(position); - } - - /// - /// Returns a representing the value of the constructor argument at the specified . - /// - /// Type of to return. - /// to get the value from. - /// Position where the target argument is to be found. - public static T? GetConstructorArgumentTypeValue(this AttributeData attribute, int position) where T : ITypeSymbol - { - attribute.TryGetConstructorArgumentTypeValue(position, out T? symbol); - return symbol; - } - - /// - /// Returns the value of the constructor argument at the specified . - /// - /// Type of value to return. - /// to get the value from. - /// Position where the target argument is to be found. - public static T? GetConstructorArgumentValue(this AttributeData attribute, int position) - { - attribute.TryGetConstructorArgumentValue(position, out T? value); - return value; - } - - /// - /// Returns the of the specified . - /// - public static Location? GetLocation(this AttributeData attribute) - { - if (attribute.ApplicationSyntaxReference is null) - { - return null; - } - - return Location.Create(attribute.ApplicationSyntaxReference.SyntaxTree, attribute.ApplicationSyntaxReference.Span); - } - - /// - /// Returns a representing the named argument with the specified . - /// - /// to get the from. - /// Name of the argument to get the of. - public static TypedConstant GetNamedArgument(this AttributeData attribute, string argumentName) - { - attribute.TryGetNamedArgument(argumentName, out TypedConstant value); - return value; - } - - /// - /// Returns an of s representing the value of the named argument with the specified . - /// - /// to get the values from. - /// Name of the argument to get the values of. - public static ImmutableArray GetNamedArgumentArrayValue(this AttributeData attribute, string argumentName) - { - attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray array); - return array; - } - - /// - /// Returns an of s representing the value of the named argument with the specified . - /// - /// Type of array's elements. - /// to get the values from. - /// Name of the argument to get the values of. - public static ImmutableArray GetNamedArgumentArrayValue(this AttributeData attribute, string argumentName) - { - attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray array); - return array; - } - - /// - /// Returns the enum value of the named argument with the specified . - /// - /// Type of enum value to return. - /// to get the value from. - /// Name of the argument to get the values of. - /// Type size mismatch. - public static TEnum GetNamedArgumentEnumValue(this AttributeData attribute, string argumentName) where TEnum : unmanaged, Enum - { - attribute.TryGetNamedArgumentEnumValue(argumentName, out TEnum value); - return value; - } - - /// - /// Returns the enum value of the named argument with the specified . - /// - /// Type of enum value to return. - /// Type the type extends. - /// to get the value from. - /// Name of the argument to get the values of. - /// Type size mismatch. - public static TEnum GetNamedArgumentEnumValue(this AttributeData attribute, string argumentName) - where TEnum : unmanaged, Enum - where TType : unmanaged - { - attribute.TryGetNamedArgumentEnumValue(argumentName, out TEnum value); - return value; - } - - /// - /// Returns location of attribute argument with the specified - /// or location of the if no argument with the was found. - /// If for some reason source syntax of the is not accessible, is returned instead. - /// - /// to get the location of argument of. - /// Name of argument to get the location of. - public static Location? GetNamedArgumentLocation(this AttributeData attribute, string argumentName) - { - if (attribute.ApplicationSyntaxReference is null) - { - return null; - } - - SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); - - if (node is not AttributeSyntax attr) - { - return node.GetLocation(); - } - - return attr.GetArgumentLocation(argumentName); - } - - /// - /// Returns a representing the value of the named argument with the specified . - /// - /// Type of to return. - /// to get the value from. - /// Name of the argument to get the value of. - public static T? GetNamedArgumentTypeValue(this AttributeData attribute, string argumentName) where T : ITypeSymbol - { - attribute.TryGetNamedArgumentTypeValue(argumentName, out T? symbol); - return symbol; - } - - /// - /// Returns the value of the named argument with the specified . - /// - /// Type of value to return. - /// to get the value from. - /// Name of the argument to get the value of. - public static T? GetNamedArgumentValue(this AttributeData attribute, string argumentName) - { - attribute.TryGetNamedArgumentValue(argumentName, out T? value); - return value; - } - - /// - /// Returns the kind of this represents. - /// - /// to get the kind of. - public static NullableAnnotationAttribute GetNullableAnnotationAttributeKind(this AttributeData attribute) - { - return attribute.AttributeClass?.GetNullableAnnotationAttributeKind() ?? default; - } - - /// - /// Returns the kind of this represents. - /// - /// to get the kind of. - public static SpecialAttribute GetSpecialAttributeKind(this AttributeData attribute) - { - return attribute.AttributeClass?.GetSpecialAttributeKind() ?? default; - } - - /// - /// Returns target of the specified . - /// - /// to get the target of. - public static AttributeTarget GetTarget(this AttributeData attribute) - { - if (attribute.ApplicationSyntaxReference?.GetSyntax() is not AttributeSyntax node || node.Parent is not AttributeListSyntax list || list.Target is not AttributeTargetSpecifierSyntax target) - { - return AttributeTarget.None; - } - - return target.Identifier.ValueText switch - { - "assembly" => AttributeTarget.Assembly, - "return" => AttributeTarget.Return, - "field" => AttributeTarget.Field, - "event" => AttributeTarget.Event, - "method" => AttributeTarget.Method, - "type" => AttributeTarget.Type, - "property" => AttributeTarget.Property, - "param" => AttributeTarget.Param, - "module" => AttributeTarget.Module, - "typevar" => AttributeTarget.TypeVar, - _ => AttributeTarget.None - }; - } - - /// - /// Checks if the target has a constructor argument at the specified . If so, also returns a that represents that argument. - /// - /// to get the from. - /// Position where the target argument is to be found. - /// Returned that represents the argument with at the specified . - public static bool TryGetConstructorArgument(this AttributeData attribute, int position, out TypedConstant value) - { - ImmutableArray arguments = attribute.ConstructorArguments; - - if (arguments.Length == 0 || arguments.Length <= position) - { - value = default; - return false; - } - - value = arguments[position]; - return true; - } - - /// - /// Checks if the target defines a constructor argument at the specified . If so, also returns the of contained within the argument's array value. - /// - /// to get the values from. - /// Position where the target argument is to be found. - /// Values contained within array value of the argument. - public static bool TryGetConstructorArgumentArrayValue(this AttributeData attribute, int position, out ImmutableArray values) - { - if (attribute.TryGetConstructorArgument(position, out TypedConstant constant)) - { - if (constant.Values.IsDefault) - { - values = ImmutableArray.Create(); - } - else - { - values = constant.Values; - } - - return true; - } - - values = ImmutableArray.Create(); - return false; - } - - /// - /// Checks if the target defines a constructor argument at the specified . If so, also returns the of contained within the argument's array value. - /// - /// Type of array's elements. - /// to get the values from. - /// Position where the target argument is to be found. - /// Values contained within array value of the argument. - public static bool TryGetConstructorArgumentArrayValue(this AttributeData attribute, int position, out ImmutableArray values) - { - if (!attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray constants)) - { - values = ImmutableArray.Create(); - return false; - } - - int length = constants.Length; - - if (length == 0) - { - values = ImmutableArray.Create(); - return true; - } - - T[] array = new T[length]; - - for (int i = 0; i < length; i++) - { - if (constants[i].Value is T t) - { - array[i] = t; - } - else - { - array[i] = default!; - } - } - - values = ImmutableArray.Create(array); - return true; - } - - /// - /// Checks if the target defines a constructor argument at specified . If so, also returns the enum value of that argument. - /// - /// Type of enum value to return. - /// to get the value from. - /// Position where the target argument is to be found. - /// Returned enum value. - /// Type size mismatch. - public static bool TryGetConstructorArgumentEnumValue(this AttributeData attribute, int position, out TEnum value) where TEnum : unmanaged, Enum - { - return attribute.TryGetConstructorArgumentEnumValue(position, out value); - } - - /// - /// Checks if the target defines a constructor argument at specified . If so, also returns the enum value of that argument. - /// - /// Type of enum value to return. - /// Type the type extends. - /// to get the value from. - /// Position where the target argument is to be found. - /// Returned enum value. - /// Type size mismatch. - public static unsafe bool TryGetConstructorArgumentEnumValue(this AttributeData attribute, int position, out TEnum value) - where TEnum : unmanaged, Enum - where TType : unmanaged - { - if (sizeof(TType) != sizeof(TEnum)) - { - throw new InvalidOperationException($"Type size mismatch. TEnum is {sizeof(TEnum)}, while TType is {sizeof(TType)}"); - } - - if (attribute.TryGetConstructorArgumentValue(position, out TType n)) - { - // For some reason this line causes assembly version conflicts. - //value = Unsafe.As(ref n); - - value = (TEnum)(object)n; - return true; - } - - value = default; - return false; - } - - /// - /// Checks if the target defines a constructor argument at specified . If so, also returns the represented by value of that argument. - /// - /// Type of to return. - /// to get the value from. - /// Position where the target argument is to be found. - /// Symbol that represents the value of the argument. - public static bool TryGetConstructorArgumentTypeValue(this AttributeData attribute, int position, out TType? symbol) where TType : ITypeSymbol - { - if (attribute.TryGetConstructorArgument(position, out TypedConstant value)) - { - if (value.Value is TType t) - { - symbol = t; - } - else - { - symbol = default; - } - - return true; - } - - symbol = default; - return false; - } - - /// - /// Checks if the target has a constructor argument at the specified . If so, also returns the of that argument. - /// - /// Type of value to return. - /// to get the from. - /// Position where the target argument is to be found. - /// Value of the argument. - public static bool TryGetConstructorArgumentValue(this AttributeData attribute, int position, out T? value) - { - if (attribute.TryGetConstructorArgument(position, out TypedConstant arg)) - { - if (arg.Value is T t) - { - value = t; - } - else - { - value = default; - } - - return true; - } - - value = default; - return false; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns a that represents that argument. - /// - /// to get the from. - /// Name of the argument to get the of. - /// Returned that represents the argument with the specified . - public static bool TryGetNamedArgument(this AttributeData attribute, string argumentName, out TypedConstant value) - { - foreach (KeyValuePair arg in attribute.NamedArguments) - { - if (arg.Key == argumentName) - { - value = arg.Value; - return true; - } - } - - value = default; - return false; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the of contained within the argument's array value. - /// - /// to get the values from. - /// Name of the argument to get the values of. - /// Values contained within array value of the argument. - public static bool TryGetNamedArgumentArrayValue(this AttributeData attribute, string argumentName, out ImmutableArray values) - { - foreach (KeyValuePair arg in attribute.NamedArguments) - { - if (arg.Key == argumentName) - { - if (arg.Value.Values.IsDefault) - { - values = ImmutableArray.Create(); - } - else - { - values = arg.Value.Values; - } - - return true; - } - } - - values = ImmutableArray.Create(); - return false; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the of contained within the argument's array value. - /// - /// Type of array's elements. - /// to get the values from. - /// Name of the argument to get the values of. - /// Values contained within array value of the argument. - public static bool TryGetNamedArgumentArrayValue(this AttributeData attribute, string argumentName, out ImmutableArray values) - { - if (!attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray constants)) - { - values = ImmutableArray.Create(); - return false; - } - - int length = constants.Length; - - if (length == 0) - { - values = ImmutableArray.Create(); - return true; - } - - T[] array = new T[length]; - - for (int i = 0; i < length; i++) - { - if (constants[i].Value is T t) - { - array[i] = t; - } - else - { - array[i] = default!; - } - } - - values = ImmutableArray.Create(array); - return true; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the enum of that argument. - /// - /// Type of enum value to return. - /// to get the value from. - /// Name of the argument to get the of. - /// Returned enum value. - /// Type size mismatch. - public static bool TryGetNamedArgumentEnumValue(this AttributeData attribute, string argumentName, out TEnum value) where TEnum : unmanaged, Enum - { - return attribute.TryGetNamedArgumentEnumValue(argumentName, out value); - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the enum of that argument. - /// - /// Type of enum value to return. - /// Type the type extends. - /// to get the value from. - /// Name of the argument to get the of. - /// Returned enum value. - /// Type size mismatch. - public static unsafe bool TryGetNamedArgumentEnumValue(this AttributeData attribute, string argumentName, out TEnum value) - where TEnum : unmanaged, Enum - where TType : unmanaged - { - if (sizeof(TType) != sizeof(TEnum)) - { - throw new InvalidOperationException($"Type size mismatch. TEnum is {sizeof(TEnum)}, while TType is {sizeof(TType)}"); - } - - if (attribute.TryGetNamedArgumentValue(argumentName, out TType n)) - { - // For some reason this line causes assembly version conflicts. - //value = Unsafe.As(ref n); - - value = (TEnum)(object)n; - return true; - } - - value = default; - return false; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the represented by value of that argument. - /// - /// Type of to return. - /// to get the value from. - /// Name of the argument to get the value of. - /// Symbol that represents the value of the argument. - public static bool TryGetNamedArgumentTypeValue(this AttributeData attribute, string argumentName, out T? symbol) where T : ITypeSymbol - { - foreach (KeyValuePair arg in attribute.NamedArguments) - { - if (arg.Key == argumentName) - { - if (arg.Value.Value is T t) - { - symbol = t; - } - else - { - symbol = default; - } - - return true; - } - } - - symbol = default; - return false; - } - - /// - /// Checks if the target defines a named argument with the specified . If so, also returns the of that argument. - /// - /// Type of value to return. - /// to get the from. - /// Name of the argument to get the of. - /// Value of the argument. - public static bool TryGetNamedArgumentValue(this AttributeData attribute, string argumentName, out T? value) - { - foreach (KeyValuePair arg in attribute.NamedArguments) - { - if (arg.Key == argumentName) - { - if (arg.Value.Value is T t) - { - value = t; - } - else - { - value = default!; - } - - return true; - } - } - - value = default!; - return false; - } -} +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Durian.Analysis; + +/// +/// Contains various extension methods for the class. +/// +public static class AttributeDataExtensions +{ + /// + /// Returns a representing the named argument at the specified . + /// + /// to get the from. + /// Position where the target argument is to be found. + public static TypedConstant GetConstructorArgument(this AttributeData attribute, int position) + { + attribute.TryGetConstructorArgument(position, out TypedConstant value); + return value; + } + + /// + /// Returns an of s representing the value of the constructor argument at the specified . + /// + /// to get the values from. + /// Position where the target argument is to be found. + public static ImmutableArray GetConstructorArgumentArrayValue(this AttributeData attribute, int position) + { + attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray array); + return array; + } + + /// + /// Returns an of s representing the value of the constructor argument at the specified . + /// + /// Type of array's elements. + /// to get the values from. + /// Position where the target argument is to be found. + public static ImmutableArray GetConstructorArgumentArrayValue(this AttributeData attribute, int position) + { + attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray array); + return array; + } + + /// + /// Returns the enum value of the constructor argument at the specified . + /// + /// Type of enum value to return. + /// to get the value from. + /// Position where the target argument is to be found. + /// Type size mismatch. + public static TEnum GetConstructorArgumentEnumValue(this AttributeData attribute, int position) where TEnum : unmanaged, Enum + { + attribute.TryGetConstructorArgumentEnumValue(position, out TEnum value); + return value; + } + + /// + /// Returns the enum value of the constructor argument at the specified . + /// + /// Type of enum value to return. + /// Type the type extends. + /// to get the value from. + /// Position where the target argument is to be found. + /// Type size mismatch. + public static TEnum GetConstructorArgumentEnumValue(this AttributeData attribute, int position) + where TEnum : unmanaged, Enum + where TType : unmanaged + { + attribute.TryGetConstructorArgumentEnumValue(position, out TEnum value); + return value; + } + + /// + /// Returns location of attribute argument at the specified + /// or location of the is no appropriate argument was found. + /// If for some reason source syntax of the is not accessible, is returned instead. + /// + /// to get the location of argument of. + /// Position of argument to get. + public static Location? GetConstructorArgumentLocation(this AttributeData attribute, int position) + { + if (attribute.ApplicationSyntaxReference is null) + { + return null; + } + + SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); + + if (node is not AttributeSyntax attr) + { + return node.GetLocation(); + } + + return attr.GetArgumentLocation(position); + } + + /// + /// Returns a representing the value of the constructor argument at the specified . + /// + /// Type of to return. + /// to get the value from. + /// Position where the target argument is to be found. + public static T? GetConstructorArgumentTypeValue(this AttributeData attribute, int position) where T : ITypeSymbol + { + attribute.TryGetConstructorArgumentTypeValue(position, out T? symbol); + return symbol; + } + + /// + /// Returns the value of the constructor argument at the specified . + /// + /// Type of value to return. + /// to get the value from. + /// Position where the target argument is to be found. + public static T? GetConstructorArgumentValue(this AttributeData attribute, int position) + { + attribute.TryGetConstructorArgumentValue(position, out T? value); + return value; + } + + /// + /// Returns the of the specified . + /// + public static Location? GetLocation(this AttributeData attribute) + { + if (attribute.ApplicationSyntaxReference is null) + { + return null; + } + + return Location.Create(attribute.ApplicationSyntaxReference.SyntaxTree, attribute.ApplicationSyntaxReference.Span); + } + + /// + /// Returns a representing the named argument with the specified . + /// + /// to get the from. + /// Name of the argument to get the of. + public static TypedConstant GetNamedArgument(this AttributeData attribute, string argumentName) + { + attribute.TryGetNamedArgument(argumentName, out TypedConstant value); + return value; + } + + /// + /// Returns an of s representing the value of the named argument with the specified . + /// + /// to get the values from. + /// Name of the argument to get the values of. + public static ImmutableArray GetNamedArgumentArrayValue(this AttributeData attribute, string argumentName) + { + attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray array); + return array; + } + + /// + /// Returns an of s representing the value of the named argument with the specified . + /// + /// Type of array's elements. + /// to get the values from. + /// Name of the argument to get the values of. + public static ImmutableArray GetNamedArgumentArrayValue(this AttributeData attribute, string argumentName) + { + attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray array); + return array; + } + + /// + /// Returns the enum value of the named argument with the specified . + /// + /// Type of enum value to return. + /// to get the value from. + /// Name of the argument to get the values of. + /// Type size mismatch. + public static TEnum GetNamedArgumentEnumValue(this AttributeData attribute, string argumentName) where TEnum : unmanaged, Enum + { + attribute.TryGetNamedArgumentEnumValue(argumentName, out TEnum value); + return value; + } + + /// + /// Returns the enum value of the named argument with the specified . + /// + /// Type of enum value to return. + /// Type the type extends. + /// to get the value from. + /// Name of the argument to get the values of. + /// Type size mismatch. + public static TEnum GetNamedArgumentEnumValue(this AttributeData attribute, string argumentName) + where TEnum : unmanaged, Enum + where TType : unmanaged + { + attribute.TryGetNamedArgumentEnumValue(argumentName, out TEnum value); + return value; + } + + /// + /// Returns location of attribute argument with the specified + /// or location of the if no argument with the was found. + /// If for some reason source syntax of the is not accessible, is returned instead. + /// + /// to get the location of argument of. + /// Name of argument to get the location of. + public static Location? GetNamedArgumentLocation(this AttributeData attribute, string argumentName) + { + if (attribute.ApplicationSyntaxReference is null) + { + return null; + } + + SyntaxNode node = attribute.ApplicationSyntaxReference.GetSyntax(); + + if (node is not AttributeSyntax attr) + { + return node.GetLocation(); + } + + return attr.GetArgumentLocation(argumentName); + } + + /// + /// Returns a representing the value of the named argument with the specified . + /// + /// Type of to return. + /// to get the value from. + /// Name of the argument to get the value of. + public static T? GetNamedArgumentTypeValue(this AttributeData attribute, string argumentName) where T : ITypeSymbol + { + attribute.TryGetNamedArgumentTypeValue(argumentName, out T? symbol); + return symbol; + } + + /// + /// Returns the value of the named argument with the specified . + /// + /// Type of value to return. + /// to get the value from. + /// Name of the argument to get the value of. + public static T? GetNamedArgumentValue(this AttributeData attribute, string argumentName) + { + attribute.TryGetNamedArgumentValue(argumentName, out T? value); + return value; + } + + /// + /// Returns the kind of this represents. + /// + /// to get the kind of. + public static NullableAnnotationAttribute GetNullableAnnotationAttributeKind(this AttributeData attribute) + { + return attribute.AttributeClass?.GetNullableAnnotationAttributeKind() ?? default; + } + + /// + /// Returns the kind of this represents. + /// + /// to get the kind of. + public static SpecialAttribute GetSpecialAttributeKind(this AttributeData attribute) + { + return attribute.AttributeClass?.GetSpecialAttributeKind() ?? default; + } + + /// + /// Returns target of the specified . + /// + /// to get the target of. + public static AttributeTarget GetTarget(this AttributeData attribute) + { + if (attribute.ApplicationSyntaxReference?.GetSyntax() is not AttributeSyntax node || node.Parent is not AttributeListSyntax list || list.Target is not AttributeTargetSpecifierSyntax target) + { + return AttributeTarget.None; + } + + return target.Identifier.ValueText switch + { + "assembly" => AttributeTarget.Assembly, + "return" => AttributeTarget.Return, + "field" => AttributeTarget.Field, + "event" => AttributeTarget.Event, + "method" => AttributeTarget.Method, + "type" => AttributeTarget.Type, + "property" => AttributeTarget.Property, + "param" => AttributeTarget.Param, + "module" => AttributeTarget.Module, + "typevar" => AttributeTarget.TypeVar, + _ => AttributeTarget.None + }; + } + + /// + /// Checks if the target has a constructor argument at the specified . If so, also returns a that represents that argument. + /// + /// to get the from. + /// Position where the target argument is to be found. + /// Returned that represents the argument with at the specified . + public static bool TryGetConstructorArgument(this AttributeData attribute, int position, out TypedConstant value) + { + ImmutableArray arguments = attribute.ConstructorArguments; + + if (arguments.Length == 0 || arguments.Length <= position) + { + value = default; + return false; + } + + value = arguments[position]; + return true; + } + + /// + /// Checks if the target defines a constructor argument at the specified . If so, also returns the of contained within the argument's array value. + /// + /// to get the values from. + /// Position where the target argument is to be found. + /// Values contained within array value of the argument. + public static bool TryGetConstructorArgumentArrayValue(this AttributeData attribute, int position, out ImmutableArray values) + { + if (attribute.TryGetConstructorArgument(position, out TypedConstant constant)) + { + if (constant.Values.IsDefault) + { + values = ImmutableArray.Create(); + } + else + { + values = constant.Values; + } + + return true; + } + + values = ImmutableArray.Create(); + return false; + } + + /// + /// Checks if the target defines a constructor argument at the specified . If so, also returns the of contained within the argument's array value. + /// + /// Type of array's elements. + /// to get the values from. + /// Position where the target argument is to be found. + /// Values contained within array value of the argument. + public static bool TryGetConstructorArgumentArrayValue(this AttributeData attribute, int position, out ImmutableArray values) + { + if (!attribute.TryGetConstructorArgumentArrayValue(position, out ImmutableArray constants)) + { + values = ImmutableArray.Create(); + return false; + } + + int length = constants.Length; + + if (length == 0) + { + values = ImmutableArray.Create(); + return true; + } + + T[] array = new T[length]; + + for (int i = 0; i < length; i++) + { + if (constants[i].Value is T t) + { + array[i] = t; + } + else + { + array[i] = default!; + } + } + + values = ImmutableArray.Create(array); + return true; + } + + /// + /// Checks if the target defines a constructor argument at specified . If so, also returns the enum value of that argument. + /// + /// Type of enum value to return. + /// to get the value from. + /// Position where the target argument is to be found. + /// Returned enum value. + /// Type size mismatch. + public static bool TryGetConstructorArgumentEnumValue(this AttributeData attribute, int position, out TEnum value) where TEnum : unmanaged, Enum + { + return attribute.TryGetConstructorArgumentEnumValue(position, out value); + } + + /// + /// Checks if the target defines a constructor argument at specified . If so, also returns the enum value of that argument. + /// + /// Type of enum value to return. + /// Type the type extends. + /// to get the value from. + /// Position where the target argument is to be found. + /// Returned enum value. + /// Type size mismatch. + public static unsafe bool TryGetConstructorArgumentEnumValue(this AttributeData attribute, int position, out TEnum value) + where TEnum : unmanaged, Enum + where TType : unmanaged + { + if (sizeof(TType) != sizeof(TEnum)) + { + throw new InvalidOperationException($"Type size mismatch. TEnum is {sizeof(TEnum)}, while TType is {sizeof(TType)}"); + } + + if (attribute.TryGetConstructorArgumentValue(position, out TType n)) + { + // For some reason this line causes assembly version conflicts. + //value = Unsafe.As(ref n); + + value = (TEnum)(object)n; + return true; + } + + value = default; + return false; + } + + /// + /// Checks if the target defines a constructor argument at specified . If so, also returns the represented by value of that argument. + /// + /// Type of to return. + /// to get the value from. + /// Position where the target argument is to be found. + /// Symbol that represents the value of the argument. + public static bool TryGetConstructorArgumentTypeValue(this AttributeData attribute, int position, out TType? symbol) where TType : ITypeSymbol + { + if (attribute.TryGetConstructorArgument(position, out TypedConstant value)) + { + if (value.Value is TType t) + { + symbol = t; + } + else + { + symbol = default; + } + + return true; + } + + symbol = default; + return false; + } + + /// + /// Checks if the target has a constructor argument at the specified . If so, also returns the of that argument. + /// + /// Type of value to return. + /// to get the from. + /// Position where the target argument is to be found. + /// Value of the argument. + public static bool TryGetConstructorArgumentValue(this AttributeData attribute, int position, out T? value) + { + if (attribute.TryGetConstructorArgument(position, out TypedConstant arg)) + { + if (arg.Value is T t) + { + value = t; + } + else + { + value = default; + } + + return true; + } + + value = default; + return false; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns a that represents that argument. + /// + /// to get the from. + /// Name of the argument to get the of. + /// Returned that represents the argument with the specified . + public static bool TryGetNamedArgument(this AttributeData attribute, string argumentName, out TypedConstant value) + { + foreach (KeyValuePair arg in attribute.NamedArguments) + { + if (arg.Key == argumentName) + { + value = arg.Value; + return true; + } + } + + value = default; + return false; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the of contained within the argument's array value. + /// + /// to get the values from. + /// Name of the argument to get the values of. + /// Values contained within array value of the argument. + public static bool TryGetNamedArgumentArrayValue(this AttributeData attribute, string argumentName, out ImmutableArray values) + { + foreach (KeyValuePair arg in attribute.NamedArguments) + { + if (arg.Key == argumentName) + { + if (arg.Value.Values.IsDefault) + { + values = ImmutableArray.Create(); + } + else + { + values = arg.Value.Values; + } + + return true; + } + } + + values = ImmutableArray.Create(); + return false; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the of contained within the argument's array value. + /// + /// Type of array's elements. + /// to get the values from. + /// Name of the argument to get the values of. + /// Values contained within array value of the argument. + public static bool TryGetNamedArgumentArrayValue(this AttributeData attribute, string argumentName, out ImmutableArray values) + { + if (!attribute.TryGetNamedArgumentArrayValue(argumentName, out ImmutableArray constants)) + { + values = ImmutableArray.Create(); + return false; + } + + int length = constants.Length; + + if (length == 0) + { + values = ImmutableArray.Create(); + return true; + } + + T[] array = new T[length]; + + for (int i = 0; i < length; i++) + { + if (constants[i].Value is T t) + { + array[i] = t; + } + else + { + array[i] = default!; + } + } + + values = ImmutableArray.Create(array); + return true; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the enum of that argument. + /// + /// Type of enum value to return. + /// to get the value from. + /// Name of the argument to get the of. + /// Returned enum value. + /// Type size mismatch. + public static bool TryGetNamedArgumentEnumValue(this AttributeData attribute, string argumentName, out TEnum value) where TEnum : unmanaged, Enum + { + return attribute.TryGetNamedArgumentEnumValue(argumentName, out value); + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the enum of that argument. + /// + /// Type of enum value to return. + /// Type the type extends. + /// to get the value from. + /// Name of the argument to get the of. + /// Returned enum value. + /// Type size mismatch. + public static unsafe bool TryGetNamedArgumentEnumValue(this AttributeData attribute, string argumentName, out TEnum value) + where TEnum : unmanaged, Enum + where TType : unmanaged + { + if (sizeof(TType) != sizeof(TEnum)) + { + throw new InvalidOperationException($"Type size mismatch. TEnum is {sizeof(TEnum)}, while TType is {sizeof(TType)}"); + } + + if (attribute.TryGetNamedArgumentValue(argumentName, out TType n)) + { + // For some reason this line causes assembly version conflicts. + //value = Unsafe.As(ref n); + + value = (TEnum)(object)n; + return true; + } + + value = default; + return false; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the represented by value of that argument. + /// + /// Type of to return. + /// to get the value from. + /// Name of the argument to get the value of. + /// Symbol that represents the value of the argument. + public static bool TryGetNamedArgumentTypeValue(this AttributeData attribute, string argumentName, out T? symbol) where T : ITypeSymbol + { + foreach (KeyValuePair arg in attribute.NamedArguments) + { + if (arg.Key == argumentName) + { + if (arg.Value.Value is T t) + { + symbol = t; + } + else + { + symbol = default; + } + + return true; + } + } + + symbol = default; + return false; + } + + /// + /// Checks if the target defines a named argument with the specified . If so, also returns the of that argument. + /// + /// Type of value to return. + /// to get the from. + /// Name of the argument to get the of. + /// Value of the argument. + public static bool TryGetNamedArgumentValue(this AttributeData attribute, string argumentName, out T? value) + { + foreach (KeyValuePair arg in attribute.NamedArguments) + { + if (arg.Key == argumentName) + { + if (arg.Value.Value is T t) + { + value = t; + } + else + { + value = default!; + } + + return true; + } + } + + value = default!; + return false; + } +} diff --git a/src/Durian.AnalysisServices/Cache/CachedAnalyzer`1.cs b/src/Durian.AnalysisServices/Cache/CachedAnalyzer`1.cs index 59bdefc..874a892 100644 --- a/src/Durian.AnalysisServices/Cache/CachedAnalyzer`1.cs +++ b/src/Durian.AnalysisServices/Cache/CachedAnalyzer`1.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.ComponentModel; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -18,20 +19,21 @@ protected CachedAnalyzer() { } + /// + public abstract void Register(IDurianAnalysisContext context, ConcurrentDictionary cached); + /// #pragma warning disable CS0809 // Obsolete member overrides non-obsolete member [Obsolete("This method shouldn't be used directly - use Register(IDurianAnalysisContext, ConcurrentDictionary) instead.")] - public sealed override void Register(IDurianAnalysisContext context) + [EditorBrowsable(EditorBrowsableState.Never)] + protected sealed override void Register(IDurianAnalysisContext context) #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member { ConcurrentDictionary dict = new(); Register(context, dict); } - /// - public abstract void Register(IDurianAnalysisContext context, ConcurrentDictionary cached); - void ICachedAnalyzer.Register(IDurianAnalysisContext context, CSharpCompilation compilation, ConcurrentDictionary cached) { Register(context, cached); diff --git a/src/Durian.AnalysisServices/Cache/CachedAnalyzer`2.cs b/src/Durian.AnalysisServices/Cache/CachedAnalyzer`2.cs index d0d6b18..c636e70 100644 --- a/src/Durian.AnalysisServices/Cache/CachedAnalyzer`2.cs +++ b/src/Durian.AnalysisServices/Cache/CachedAnalyzer`2.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.ComponentModel; using Durian.Analysis.Data; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -22,25 +23,26 @@ protected CachedAnalyzer() { } + /// + /// Registers actions to be performed by the analyzer and caches the result of analysis. + /// + /// used to register the actions to be performed. + /// Compilation to be used during the analysis. + /// A that contains the cached values. + public abstract void Register(IDurianAnalysisContext context, TCompilation compilation, ConcurrentDictionary cached); + #pragma warning disable CS0809 // Obsolete member overrides non-obsolete member /// [Obsolete("This method shouldn't be used directly - use Register(IDurianAnalysisContext, TCompilation, ConcurrentDictionary) instead.")] - public sealed override void Register(IDurianAnalysisContext context, TCompilation compilation) + [EditorBrowsable(EditorBrowsableState.Never)] + protected sealed override void Register(IDurianAnalysisContext context, TCompilation compilation) #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member { ConcurrentDictionary dict = new(); Register(context, compilation, dict); } - /// - /// Registers actions to be performed by the analyzer and caches the result of analysis. - /// - /// used to register the actions to be performed. - /// Compilation to be used during the analysis. - /// A that contains the cached values. - public abstract void Register(IDurianAnalysisContext context, TCompilation compilation, ConcurrentDictionary cached); - void ICachedAnalyzer.Register(IDurianAnalysisContext context, CSharpCompilation compilation, ConcurrentDictionary cached) { TCompilation c = CreateCompilation(compilation, _diagnosticReceiver); diff --git a/src/Durian.AnalysisServices/CodeBuilder.cs b/src/Durian.AnalysisServices/CodeBuilder.cs index 3888c4d..9aff8f3 100644 --- a/src/Durian.AnalysisServices/CodeBuilder.cs +++ b/src/Durian.AnalysisServices/CodeBuilder.cs @@ -3,7 +3,6 @@ using System.Runtime.CompilerServices; using System.Text; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis; diff --git a/src/Durian.AnalysisServices/CodeBuilder.symbols.cs b/src/Durian.AnalysisServices/CodeBuilder.symbols.cs index 3005a52..0dd6c3e 100644 --- a/src/Durian.AnalysisServices/CodeBuilder.symbols.cs +++ b/src/Durian.AnalysisServices/CodeBuilder.symbols.cs @@ -4,9 +4,7 @@ using System.Globalization; using System.Reflection.Metadata; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Durian.Analysis; diff --git a/src/Durian.AnalysisServices/CodeFixes/CodeFixUtility.cs b/src/Durian.AnalysisServices/CodeFixes/CodeFixUtility.cs index 5f23d2c..19566d3 100644 --- a/src/Durian.AnalysisServices/CodeFixes/CodeFixUtility.cs +++ b/src/Durian.AnalysisServices/CodeFixes/CodeFixUtility.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`1.cs b/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`1.cs index 3dadbde..ce8088b 100644 --- a/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`1.cs +++ b/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`1.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`2.cs b/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`2.cs index 00c75b5..962dd02 100644 --- a/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`2.cs +++ b/src/Durian.AnalysisServices/CodeFixes/ReplaceNodeCodeFix`2.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/CodeGeneration/LiteralWriter.cs b/src/Durian.AnalysisServices/CodeGeneration/LiteralWriter.cs index a56c742..70a6f10 100644 --- a/src/Durian.AnalysisServices/CodeGeneration/LiteralWriter.cs +++ b/src/Durian.AnalysisServices/CodeGeneration/LiteralWriter.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; using System.Text; -using Durian.Analysis.Extensions; namespace Durian.Analysis.CodeGeneration; diff --git a/src/Durian.AnalysisServices/Extensions/CompilationExtensions.cs b/src/Durian.AnalysisServices/CompilationExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/CompilationExtensions.cs rename to src/Durian.AnalysisServices/CompilationExtensions.cs index 343f2d4..b8c677a 100644 --- a/src/Durian.AnalysisServices/Extensions/CompilationExtensions.cs +++ b/src/Durian.AnalysisServices/CompilationExtensions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for the class. diff --git a/src/Durian.AnalysisServices/Data/CompilationWithImportedTypes.cs b/src/Durian.AnalysisServices/Data/CompilationWithImportedTypes.cs index 3650471..d8e3750 100644 --- a/src/Durian.AnalysisServices/Data/CompilationWithImportedTypes.cs +++ b/src/Durian.AnalysisServices/Data/CompilationWithImportedTypes.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Generator; using Durian.Info; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/DataHelpers.cs b/src/Durian.AnalysisServices/Data/DataHelpers.cs index 6e1dafa..b83bc00 100644 --- a/src/Durian.AnalysisServices/Data/DataHelpers.cs +++ b/src/Durian.AnalysisServices/Data/DataHelpers.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.CompilerServices; using Durian.Analysis.Data.FromSource; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/AccessorData.cs b/src/Durian.AnalysisServices/Data/FromSource/AccessorData.cs index 80a9ff7..33591e9 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/AccessorData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/AccessorData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/ConstructorData.cs b/src/Durian.AnalysisServices/Data/FromSource/ConstructorData.cs index a643fa9..906e250 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/ConstructorData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/ConstructorData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/ConversionOperatorData.cs b/src/Durian.AnalysisServices/Data/FromSource/ConversionOperatorData.cs index 847ac9f..1006c4c 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/ConversionOperatorData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/ConversionOperatorData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/DestructorData.cs b/src/Durian.AnalysisServices/Data/FromSource/DestructorData.cs index 292e5a3..349ed09 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/DestructorData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/DestructorData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/EnumData.cs b/src/Durian.AnalysisServices/Data/FromSource/EnumData.cs index 044c1f9..f82ddb1 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/EnumData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/EnumData.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Immutable; using System.ComponentModel; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/EventData.cs b/src/Durian.AnalysisServices/Data/FromSource/EventData.cs index 46cdd9b..7664890 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/EventData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/EventData.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/FieldData.cs b/src/Durian.AnalysisServices/Data/FromSource/FieldData.cs index a6d0954..97987e2 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/FieldData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/FieldData.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/IndexerData.cs b/src/Durian.AnalysisServices/Data/FromSource/IndexerData.cs index 7a8ef27..792d075 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/IndexerData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/IndexerData.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/InterfaceData.cs b/src/Durian.AnalysisServices/Data/FromSource/InterfaceData.cs index 8f151aa..745ac0e 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/InterfaceData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/InterfaceData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/LambdaData.cs b/src/Durian.AnalysisServices/Data/FromSource/LambdaData.cs index 55e6deb..4ed3730 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/LambdaData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/LambdaData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/LocalFunctionData.cs b/src/Durian.AnalysisServices/Data/FromSource/LocalFunctionData.cs index 1c20eae..ffe6ccd 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/LocalFunctionData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/LocalFunctionData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/MemberData.cs b/src/Durian.AnalysisServices/Data/FromSource/MemberData.cs index 3129183..c3b242f 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/MemberData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/MemberData.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/MethodData.cs b/src/Durian.AnalysisServices/Data/FromSource/MethodData.cs index 6e32da5..a286c13 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/MethodData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/MethodData.cs @@ -2,7 +2,6 @@ using System.ComponentModel; using System.Linq; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/NamespaceData.cs b/src/Durian.AnalysisServices/Data/FromSource/NamespaceData.cs index 42f8f5d..8c14ee6 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/NamespaceData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/NamespaceData.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/NamespaceOrTypeData.cs b/src/Durian.AnalysisServices/Data/FromSource/NamespaceOrTypeData.cs index 2123e40..4980a7f 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/NamespaceOrTypeData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/NamespaceOrTypeData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/OperatorData.cs b/src/Durian.AnalysisServices/Data/FromSource/OperatorData.cs index d269969..cfb2206 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/OperatorData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/OperatorData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/PropertyData.cs b/src/Durian.AnalysisServices/Data/FromSource/PropertyData.cs index 36f9bb3..2adec7d 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/PropertyData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/PropertyData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/RecordData.cs b/src/Durian.AnalysisServices/Data/FromSource/RecordData.cs index e2ec816..b3edafe 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/RecordData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/RecordData.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/FromSource/TypeData.cs b/src/Durian.AnalysisServices/Data/FromSource/TypeData.cs index b90ba6d..447d518 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/TypeData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/TypeData.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Data/FromSource/TypeParameterData.cs b/src/Durian.AnalysisServices/Data/FromSource/TypeParameterData.cs index 8b6e429..749fed6 100644 --- a/src/Durian.AnalysisServices/Data/FromSource/TypeParameterData.cs +++ b/src/Durian.AnalysisServices/Data/FromSource/TypeParameterData.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/Data/SymbolOrMemberWrapper.cs b/src/Durian.AnalysisServices/Data/SymbolOrMemberWrapper.cs index ea33841..efdef3c 100644 --- a/src/Durian.AnalysisServices/Data/SymbolOrMemberWrapper.cs +++ b/src/Durian.AnalysisServices/Data/SymbolOrMemberWrapper.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.Data; diff --git a/src/Durian.AnalysisServices/Extensions/DiagnosticReceiverExtensions.cs b/src/Durian.AnalysisServices/DiagnosticReceiverExtensions.cs similarity index 98% rename from src/Durian.AnalysisServices/Extensions/DiagnosticReceiverExtensions.cs rename to src/Durian.AnalysisServices/DiagnosticReceiverExtensions.cs index 687a7c4..4be239f 100644 --- a/src/Durian.AnalysisServices/Extensions/DiagnosticReceiverExtensions.cs +++ b/src/Durian.AnalysisServices/DiagnosticReceiverExtensions.cs @@ -2,7 +2,7 @@ using System.Linq; using Microsoft.CodeAnalysis; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains extension methods for the interface. diff --git a/src/Durian.AnalysisServices/DurianAnalyzer.cs b/src/Durian.AnalysisServices/DurianAnalyzer.cs index 1619598..c37e08f 100644 --- a/src/Durian.AnalysisServices/DurianAnalyzer.cs +++ b/src/Durian.AnalysisServices/DurianAnalyzer.cs @@ -46,9 +46,6 @@ public override void Initialize(AnalysisContext context) Register(c); } - /// - public abstract void Register(IDurianAnalysisContext context); - IEnumerable IDurianAnalyzer.GetSupportedDiagnostics() { return SupportedDiagnostics; @@ -59,6 +56,10 @@ void IDurianAnalyzer.Register(IDurianAnalysisContext context, CSharpCompilation Register(context, compilation); } + + /// + protected abstract void Register(IDurianAnalysisContext context); + /// protected virtual void Register(IDurianAnalysisContext context, CSharpCompilation compilation) { diff --git a/src/Durian.AnalysisServices/DurianAnalyzer`1.cs b/src/Durian.AnalysisServices/DurianAnalyzer`1.cs index 226f500..63ce964 100644 --- a/src/Durian.AnalysisServices/DurianAnalyzer`1.cs +++ b/src/Durian.AnalysisServices/DurianAnalyzer`1.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using Durian.Analysis.Data; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -53,7 +54,8 @@ public sealed override void Initialize(AnalysisContext context) /// [Obsolete("Implementation of this method was removed - use Register(IDurianAnalysisContext, TCompilation) instead.")] - public sealed override void Register(IDurianAnalysisContext context) + [EditorBrowsable(EditorBrowsableState.Never)] + protected sealed override void Register(IDurianAnalysisContext context) #pragma warning restore CS0809 // Obsolete member overrides non-obsolete member { // Do nothing @@ -64,14 +66,7 @@ public sealed override void Register(IDurianAnalysisContext context) /// /// to register the actions to. /// to be used during the analysis. - public abstract void Register(IDurianAnalysisContext context, TCompilation compilation); - - /// - /// Creates a new based on the specified . - /// - /// to create the from. - /// to report diagnostics to. - protected abstract TCompilation CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver); + protected abstract void Register(IDurianAnalysisContext context, TCompilation compilation); /// protected sealed override void Register(IDurianAnalysisContext context, CSharpCompilation compilation) @@ -87,6 +82,13 @@ protected sealed override void Register(IDurianAnalysisContext context, CSharpCo ReportInitializationDiagnostics(context, diagnosticReceiver); } + /// + /// Creates a new based on the specified . + /// + /// to create the from. + /// to report diagnostics to. + protected abstract TCompilation CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver); + private static void ReportInitializationDiagnostics(IDurianAnalysisContext context, DiagnosticBag diagnosticReceiver) { if (diagnosticReceiver.Count > 0) diff --git a/src/Durian.AnalysisServices/DurianGeneratorBase.cs b/src/Durian.AnalysisServices/DurianGeneratorBase.cs index 48278a8..111d94a 100644 --- a/src/Durian.AnalysisServices/DurianGeneratorBase.cs +++ b/src/Durian.AnalysisServices/DurianGeneratorBase.cs @@ -6,7 +6,6 @@ using System.Text; using System.Threading; using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Extensions; using Durian.Analysis.Logging; using Durian.Info; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/DurianGeneratorWithBuilder.cs b/src/Durian.AnalysisServices/DurianGeneratorWithBuilder.cs index e30d073..f08988f 100644 --- a/src/Durian.AnalysisServices/DurianGeneratorWithBuilder.cs +++ b/src/Durian.AnalysisServices/DurianGeneratorWithBuilder.cs @@ -3,7 +3,6 @@ using System.Text; using Durian.Analysis.CodeGeneration; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Logging; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/Durian.AnalysisServices/DurianIncrementalGenerator.cs b/src/Durian.AnalysisServices/DurianIncrementalGenerator.cs index a310870..0fb75f1 100644 --- a/src/Durian.AnalysisServices/DurianIncrementalGenerator.cs +++ b/src/Durian.AnalysisServices/DurianIncrementalGenerator.cs @@ -1,5 +1,6 @@ -using System.Text; -using System.Threading; +using System; +using System.Text; +using Durian.Analysis.Logging; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; @@ -11,6 +12,38 @@ namespace Durian.Analysis; /// public abstract class DurianIncrementalGenerator : DurianGeneratorBase, IIncrementalGenerator { + /// + /// Initializes a new instance of the class. + /// + protected DurianIncrementalGenerator() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Service that handles log files for this generator. + /// is . + protected DurianIncrementalGenerator(IGeneratorLogHandler logHandler) : base(logHandler) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Configures how this generator is initialized. + protected DurianIncrementalGenerator(in GeneratorLogCreationContext context) : base(in context) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Determines how the source generator should behave when logging information. + protected DurianIncrementalGenerator(LoggingConfiguration? loggingConfiguration) : base(loggingConfiguration) + { + } + /// public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -24,14 +57,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return compilation; }, context.ReportDiagnostic)); - Register(context); + Register(compilation, context); } /// /// Adds generator-specific logic to the . /// + /// Current compilation. /// The to register callbacks on - protected abstract void Register(IncrementalGeneratorInitializationContext context); + protected abstract void Register(IncrementalValueProvider compilation, IncrementalGeneratorInitializationContext context); /// /// Adds the specified to the . diff --git a/src/Durian.AnalysisServices/Extensions/EnumExtensions.cs b/src/Durian.AnalysisServices/EnumExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/EnumExtensions.cs rename to src/Durian.AnalysisServices/EnumExtensions.cs index 03b937a..38e772f 100644 --- a/src/Durian.AnalysisServices/Extensions/EnumExtensions.cs +++ b/src/Durian.AnalysisServices/EnumExtensions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains extension methods for various enum types. diff --git a/src/Durian.AnalysisServices/Extensions/GeneratorExtensions.cs b/src/Durian.AnalysisServices/GeneratorExtensions.cs similarity index 98% rename from src/Durian.AnalysisServices/Extensions/GeneratorExtensions.cs rename to src/Durian.AnalysisServices/GeneratorExtensions.cs index 9db6f25..5d877c7 100644 --- a/src/Durian.AnalysisServices/Extensions/GeneratorExtensions.cs +++ b/src/Durian.AnalysisServices/GeneratorExtensions.cs @@ -1,7 +1,7 @@ using Durian.Analysis.Logging; using Microsoft.CodeAnalysis; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for s. diff --git a/src/Durian.AnalysisServices/GeneratorPassContext.cs b/src/Durian.AnalysisServices/GeneratorPassContext.cs index 4b36333..efe9fef 100644 --- a/src/Durian.AnalysisServices/GeneratorPassContext.cs +++ b/src/Durian.AnalysisServices/GeneratorPassContext.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Logging; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Logging/GeneratorLogCreationContext.cs b/src/Durian.AnalysisServices/Logging/GeneratorLogCreationContext.cs index 8c6627c..d91b94c 100644 --- a/src/Durian.AnalysisServices/Logging/GeneratorLogCreationContext.cs +++ b/src/Durian.AnalysisServices/Logging/GeneratorLogCreationContext.cs @@ -30,7 +30,7 @@ namespace Durian.Analysis.Logging; public static GeneratorLogCreationContext Runtime => new(); /// - /// Determines whether to try to create a based on one of the . + /// Determines whether to try to create a based on one of the . /// public bool CheckForConfigurationAttribute { get; } diff --git a/src/Durian.AnalysisServices/Extensions/MemberDataExtensions.cs b/src/Durian.AnalysisServices/MemberDataExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/MemberDataExtensions.cs rename to src/Durian.AnalysisServices/MemberDataExtensions.cs index 4957adf..f0001eb 100644 --- a/src/Durian.AnalysisServices/Extensions/MemberDataExtensions.cs +++ b/src/Durian.AnalysisServices/MemberDataExtensions.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for the interface. diff --git a/src/Durian.AnalysisServices/Extensions/ModuleUtilities.cs b/src/Durian.AnalysisServices/ModuleUtilities.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/ModuleUtilities.cs rename to src/Durian.AnalysisServices/ModuleUtilities.cs index 49ea22d..d94567d 100644 --- a/src/Durian.AnalysisServices/Extensions/ModuleUtilities.cs +++ b/src/Durian.AnalysisServices/ModuleUtilities.cs @@ -7,7 +7,7 @@ using Durian.Info; using Microsoft.CodeAnalysis; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various -related extension methods for the class and interface. diff --git a/src/Durian.AnalysisServices/Extensions/PackageUtilities.cs b/src/Durian.AnalysisServices/PackageUtilities.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/PackageUtilities.cs rename to src/Durian.AnalysisServices/PackageUtilities.cs index 7e72805..d939ac4 100644 --- a/src/Durian.AnalysisServices/Extensions/PackageUtilities.cs +++ b/src/Durian.AnalysisServices/PackageUtilities.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis; using static Durian.Info.PackageIdentity; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various -related extension methods for the class. diff --git a/src/Durian.AnalysisServices/Extensions/SemanticModelExtensions.cs b/src/Durian.AnalysisServices/SemanticModelExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/SemanticModelExtensions.cs rename to src/Durian.AnalysisServices/SemanticModelExtensions.cs index d223cf2..a24c757 100644 --- a/src/Durian.AnalysisServices/Extensions/SemanticModelExtensions.cs +++ b/src/Durian.AnalysisServices/SemanticModelExtensions.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for the class. diff --git a/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.InnerContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.InnerContainer.cs index 9f08282..b4c58d3 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.InnerContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.InnerContainer.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers; diff --git a/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.cs index 6996b31..f0afdd2 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/LeveledSymbolContainer.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers; diff --git a/src/Durian.AnalysisServices/SymbolContainers/ReturnOrderEnumerable.cs b/src/Durian.AnalysisServices/SymbolContainers/ReturnOrderEnumerable.cs index 6d7fded..033fdd7 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/ReturnOrderEnumerable.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/ReturnOrderEnumerable.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Durian.Analysis.Extensions; namespace Durian.Analysis.SymbolContainers; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerMemberContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerMemberContainer.cs index 501cf6f..802bbd4 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerMemberContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerMemberContainer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerTypeContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerTypeContainer.cs index 2bb98c0..cb7812a 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerTypeContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/InnerTypeContainer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/LocalFunctionContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/LocalFunctionContainer.cs index 1e06371..70e6e1d 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/LocalFunctionContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/LocalFunctionContainer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/MethodOverloadContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/MethodOverloadContainer.cs index babbb35..14e0045 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/MethodOverloadContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/MethodOverloadContainer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/NamespaceOrTypeContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/NamespaceOrTypeContainer.cs index 25327e2..c8d1c90 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/NamespaceOrTypeContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/NamespaceOrTypeContainer.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Runtime.CompilerServices; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/Specialized/SubNamespaceContainer.cs b/src/Durian.AnalysisServices/SymbolContainers/Specialized/SubNamespaceContainer.cs index fb2b8f5..a5e6b5f 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/Specialized/SubNamespaceContainer.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/Specialized/SubNamespaceContainer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers.Specialized; diff --git a/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerBase.cs b/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerBase.cs index 7b82295..777471c 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerBase.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerBase.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Runtime.CompilerServices; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis.SymbolContainers; diff --git a/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerFactory.cs b/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerFactory.cs index 0b4ed2c..5a7bf30 100644 --- a/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerFactory.cs +++ b/src/Durian.AnalysisServices/SymbolContainers/SymbolContainerFactory.cs @@ -6,7 +6,6 @@ using System.Runtime.CompilerServices; using System.Text; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers.Specialized; using Microsoft.CodeAnalysis; diff --git a/src/Durian.AnalysisServices/Extensions/SymbolExtensions.cs b/src/Durian.AnalysisServices/SymbolExtensions.cs similarity index 97% rename from src/Durian.AnalysisServices/Extensions/SymbolExtensions.cs rename to src/Durian.AnalysisServices/SymbolExtensions.cs index 3c207a7..cd7ba39 100644 --- a/src/Durian.AnalysisServices/Extensions/SymbolExtensions.cs +++ b/src/Durian.AnalysisServices/SymbolExtensions.cs @@ -1,3709 +1,3709 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection.Metadata; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; -using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Data; -using Durian.Analysis.Data.FromSource; -using Durian.Analysis.SymbolContainers; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Durian.Analysis.Extensions; - -/// -/// Contains various extension methods for the -derived interfaces. -/// -public static class SymbolExtensions -{ - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this INamedTypeSymbol type) - { - TypeSyntax syntax; - - if (type.IsGenericType) - { - List arguments = new(type.TypeArguments.Length); - - foreach (ITypeSymbol t in type.TypeArguments) - { - arguments.Add(t.CreateTypeSyntax()); - } - - syntax = SyntaxFactory.GenericName( - SyntaxFactory.Identifier(type.GetVerbatimName()), - SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(arguments))); - } - else if (type.GetPredefineTypeSyntax() is PredefinedTypeSyntax predefined) - { - syntax = predefined; - } - else - { - syntax = SyntaxFactory.IdentifierName(type.GetVerbatimName()); - } - - return ApplyAnnotation(syntax, NullableAnnotation.Annotated); - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this IArrayTypeSymbol type) - { - ITypeSymbol[] elementTypes = type.GetElementTypes().ToArray(); - TypeSyntax elementSyntax = elementTypes[0].CreateTypeSyntax(); - - List ranks = new(elementTypes.Length - 1); - - for (int i = 1; i < elementTypes.Length; i++) - { - IArrayTypeSymbol array = (IArrayTypeSymbol)elementTypes[i]; - ranks.Add(GetArrayRank(array)); - - if (array.NullableAnnotation == NullableAnnotation.Annotated) - { - elementSyntax = SyntaxFactory.NullableType(SyntaxFactory.ArrayType(elementSyntax, SyntaxFactory.List(ranks))); - ranks.Clear(); - } - } - - ranks.Add(GetArrayRank(type)); - - return ApplyAnnotation(SyntaxFactory.ArrayType(elementSyntax, SyntaxFactory.List(ranks)), type.NullableAnnotation); - - static ArrayRankSpecifierSyntax GetArrayRank(IArrayTypeSymbol array) - { - return SyntaxFactory.ArrayRankSpecifier(SyntaxFactory.SeparatedList( - array.Sizes.Select(s => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(s))))); - } - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this IFunctionPointerTypeSymbol functionPointer) - { - IMethodSymbol signature = functionPointer.Signature; - - FunctionPointerCallingConventionSyntax? callingConvention; - - if (signature.CallingConvention == SignatureCallingConvention.Unmanaged) - { - FunctionPointerUnmanagedCallingConventionListSyntax? list = signature.UnmanagedCallingConventionTypes.Length > 0 ? - SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(SyntaxFactory.SeparatedList(signature.UnmanagedCallingConventionTypes.Select(u => - SyntaxFactory.FunctionPointerUnmanagedCallingConvention(SyntaxFactory.Identifier(u.Name))))) - : default; - - callingConvention = SyntaxFactory.FunctionPointerCallingConvention(SyntaxFactory.Token(SyntaxKind.UnmanagedKeyword), list); - } - else - { - callingConvention = default; - } - - List parameters = new(signature.Parameters.Length + 1); - - foreach (IParameterSymbol parameter in signature.Parameters) - { - TypeSyntax parameterType = parameter.Type.CreateTypeSyntax(); - parameters.Add(GetParameterSyntax(parameterType, parameter.RefKind, false)); - } - - parameters.Add(GetParameterSyntax(signature.ReturnType.CreateTypeSyntax(), signature.RefKind, true)); - - return SyntaxFactory.FunctionPointerType(callingConvention, SyntaxFactory.FunctionPointerParameterList(SyntaxFactory.SeparatedList(parameters))); - - static FunctionPointerParameterSyntax GetParameterSyntax(TypeSyntax parameterType, RefKind refKind, bool allowRefReadonly) - { - switch (refKind) - { - case RefKind.None: - return SyntaxFactory.FunctionPointerParameter(parameterType); - - case RefKind.RefReadOnly: - - if (!allowRefReadonly) - { - goto default; - } - - return SyntaxFactory.FunctionPointerParameter(default, SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), parameterType); - - default: - SyntaxKind kind = refKind.GetSyntaxKind(); - return SyntaxFactory.FunctionPointerParameter(default, SyntaxFactory.TokenList(SyntaxFactory.Token(kind)), parameterType); - } - } - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this IDynamicTypeSymbol type) - { - return ApplyAnnotation(SyntaxFactory.IdentifierName("dynamic"), type.NullableAnnotation); - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this ITypeParameterSymbol typeParameter) - { - return ApplyAnnotation(SyntaxFactory.IdentifierName(typeParameter.GetVerbatimName()), typeParameter.NullableAnnotation); - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this IPointerTypeSymbol pointer) - { - return SyntaxFactory.PointerType(pointer.PointedAtType.CreateTypeSyntax()); - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this ITypeSymbol type) - { - return type switch - { - INamedTypeSymbol named => named.CreateTypeSyntax(), - IDynamicTypeSymbol dynamic => dynamic.CreateTypeSyntax(), - IArrayTypeSymbol array => array.CreateTypeSyntax(), - ITypeParameterSymbol typeParameter => typeParameter.CreateTypeSyntax(), - IPointerTypeSymbol pointer => pointer.CreateTypeSyntax(), - IFunctionPointerTypeSymbol functionPointer => functionPointer.CreateTypeSyntax(), - _ => ApplyAnnotation(SyntaxFactory.IdentifierName(type.GetVerbatimName()), type.NullableAnnotation), - }; - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this ISymbol symbol) - { - if (symbol is ITypeSymbol type) - { - return type.CreateTypeSyntax(); - } - - if (symbol is IMethodSymbol method) - { - return method.CreateTypeSyntax(); - } - - return SyntaxFactory.IdentifierName(symbol.GetVerbatimName()); - } - - /// - /// Creates a representing the specified . - /// - /// to get the for. - public static TypeSyntax CreateTypeSyntax(this IMethodSymbol method) - { - if (!method.IsGenericMethod) - { - return SyntaxFactory.IdentifierName(method.GetVerbatimName()); - } - - List arguments = new(method.TypeArguments.Length); - - foreach (ITypeSymbol type in method.TypeArguments) - { - arguments.Add(type.CreateTypeSyntax()); - } - - return SyntaxFactory.GenericName( - SyntaxFactory.Identifier(method.GetVerbatimName()), - SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(arguments))); - } - - /// - /// Returns the kind of accessor the specified represents. - /// - /// to get the accessor kind of. - public static AccessorKind GetAccessorKind(this IMethodSymbol method) - { - return method.MethodKind.GetAccessorKind(); - } - - /// - /// Returns a collection of all inner types of the specified . - /// - /// to get the inner types of. - /// Determines whether to include the in the returned collection if its a . - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetAllInnerTypes(this INamespaceOrTypeSymbol type, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ChildToParent); - - IEnumerable Yield() - { - const int CAPACITY = 32; - - if (includeSelf && type is INamedTypeSymbol named) - { - yield return named; - } - - ImmutableArray array = type.GetTypeMembers(); - - if (array.Length == 0) - { - yield break; - } - - Stack innerTypes = new(array.Length > CAPACITY ? array.Length : CAPACITY); - - PushReverse(ref array, innerTypes); - - while (innerTypes.Count > 0) - { - INamedTypeSymbol t = innerTypes.Pop(); - yield return t; - - array = t.GetTypeMembers(); - - if (array.Length == 0) - { - continue; - } - - PushReverse(ref array, innerTypes); - } - } - } - - /// - public static IReturnOrderEnumerable GetAllMembers(this INamedTypeSymbol type, ReturnOrder order = ReturnOrder.ParentToChild) - { - return GetBaseTypes_Internal(type, true).SelectMany(t => t.GetMembers()).OrderBy(order, ReturnOrder.ChildToParent); - } - - /// - /// Returns all members of the specified including the members that are declared in base types of this . - /// - /// to get the members of. - /// Name of the members to find. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetAllMembers(this INamedTypeSymbol type, string name, ReturnOrder order = ReturnOrder.ParentToChild) - { - return GetBaseTypes_Internal(type, true).SelectMany(t => t.GetMembers(name)).OrderBy(order, ReturnOrder.ChildToParent); - } - - /// - /// Returns an associated with the and defined on the specified . - /// - /// Target . - /// Type of attribute to look for. - /// The associated with the and defined on the specified . -or- if no such found. - public static AttributeData? GetAttribute(this ISymbol symbol, INamedTypeSymbol attrSymbol) - { - return symbol.GetAttributes() - .FirstOrDefault(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attrSymbol)); - } - - /// - /// Returns an associated with the defined on the specified . - /// - /// Target . - /// to get the data of. - /// The associated with the . -or- if no such found. - public static AttributeData? GetAttribute(this ISymbol symbol, AttributeSyntax syntax) - { - foreach (AttributeData attr in symbol.GetAttributes()) - { - SyntaxReference? reference = attr.ApplicationSyntaxReference; - - if (reference is null) - { - continue; - } - - if (reference.Span == syntax.Span) - { - return attr; - } - } - - return null; - } - - /// - /// Returns a collection of s associated with the and defined on the specified . - /// - /// Target . - /// Type of attributes to look for. - public static IEnumerable GetAttributes(this ISymbol symbol, INamedTypeSymbol attrSymbol) - { - foreach (AttributeData attr in symbol.GetAttributes()) - { - if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attrSymbol)) - { - yield return attr; - } - } - } - - /// - /// Returns the that is accessed by using the specified in the context of the given . - /// - /// to get the attribute target symbol of. - /// Kind of attribute target. - /// Note: In actual code the target applied to an event refers to both the and accessors. In such case, this method returns the event itself. - public static ISymbol? GetAttributeTarget(this ISymbol symbol, AttributeTarget target) - { - switch (target) - { - case AttributeTarget.Assembly: - return symbol as IAssemblySymbol; - - case AttributeTarget.Return: - { - if (symbol is IMethodSymbol method) - { - if (!method.IsConstructor() && method.MethodKind != MethodKind.Destructor) - { - return method.ReturnType; - } - } - else if (symbol is INamedTypeSymbol type) - { - if (type.DelegateInvokeMethod is not null) - { - return type.DelegateInvokeMethod.ReturnType; - } - } - - return default; - } - - case AttributeTarget.Field: - { - if (symbol is IPropertySymbol property) - { - if (property.GetBackingField() is IFieldSymbol backingField) - { - return backingField; - } - } - else if (symbol is IEventSymbol @event) - { - if (@event.GetBackingField() is IFieldSymbol backingField) - { - return backingField; - } - } - - return symbol as IFieldSymbol; - } - - case AttributeTarget.Method: - return symbol is IMethodSymbol or IEventSymbol ? symbol : default; - - case AttributeTarget.Property: - return symbol as IPropertySymbol; - - case AttributeTarget.Event: - return symbol as IEventSymbol; - - case AttributeTarget.Type: - return symbol as INamedTypeSymbol; - - case AttributeTarget.Param: - { - if (symbol is IMethodSymbol method && method.MethodKind is MethodKind.PropertySet or MethodKind.EventAdd or MethodKind.EventRemove) - { - return method.Parameters[0]; - } - - return symbol as IParameterSymbol; - } - - case AttributeTarget.Module: - return symbol as IModuleSymbol; - - case AttributeTarget.TypeVar: - return symbol as ITypeParameterSymbol; - - default: - return default; - } - } - - /// - /// Returns the that is accessed by using an attribute target if the specified in the context of the given . - /// - /// to get the attribute target symbol of. - /// Kind of attribute target. - /// Note: In actual code the target applied to an event refers to both the and accessors. In such case, this method returns the event itself. - public static ISymbol? GetAttributeTarget(this ISymbol symbol, AttributeTargetKind kind) - { - return symbol switch - { - IAssemblySymbol => ThisOrDefault(), - IFieldSymbol => ThisOrDefault(), - IMethodSymbol method => kind switch - { - AttributeTargetKind.This => method.SupportsAttributeTargets() ? method : default, - AttributeTargetKind.Value => method.SupportsAlternativeAttributeTargets() ? method.ReturnType : default, - AttributeTargetKind.Handler when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => method.Parameters[0], - _ => default - }, - IPropertySymbol property => kind switch - { - AttributeTargetKind.This => property, - AttributeTargetKind.Value => property.GetBackingField(), - _ => default - }, - IEventSymbol @event => kind switch - { - AttributeTargetKind.This => @event, - AttributeTargetKind.Value => @event.GetBackingField(), - AttributeTargetKind.Handler when @event.IsFieldEvent() => @event, - _ => default - }, - INamedTypeSymbol type => kind switch - { - AttributeTargetKind.This => type, - AttributeTargetKind.Value when type.DelegateInvokeMethod is IMethodSymbol method => method.ReturnType, - _ => default - }, - IParameterSymbol => ThisOrDefault(), - ITypeParameterSymbol => ThisOrDefault(), - IModuleSymbol => ThisOrDefault(), - _ => default - }; - - ISymbol? ThisOrDefault() - { - return kind == AttributeTargetKind.This ? symbol : default; - } - } - - /// - /// Determines the kind of the specified attribute used in context of the given . - /// - /// to get the kind of attribute target of. - /// Attribute target to get the kind of. - public static AttributeTargetKind GetAttributeTargetKind(this ISymbol symbol, AttributeTarget target) - { - return target switch - { - AttributeTarget.Assembly => symbol is IAssemblySymbol ? AttributeTargetKind.This : default, - AttributeTarget.Field => symbol switch - { - IFieldSymbol => AttributeTargetKind.This, - IPropertySymbol property => property.IsAutoProperty() ? AttributeTargetKind.Value : default, - IEventSymbol @event when @event.IsFieldEvent() => AttributeTargetKind.Value, - _ => default - }, - AttributeTarget.Return => symbol switch - { - IMethodSymbol method => method.SupportsAlternativeAttributeTargets() ? AttributeTargetKind.Value : default, - INamedTypeSymbol type when type.SupportsAlternativeAttributeTargets() => AttributeTargetKind.Value, - _ => default - }, - AttributeTarget.Method => symbol switch - { - IMethodSymbol => AttributeTargetKind.This, - IEventSymbol @event when @event.IsFieldEvent() => AttributeTargetKind.Handler, - _ => default - }, - AttributeTarget.Property => symbol is IPropertySymbol ? AttributeTargetKind.This : default, - AttributeTarget.Event => symbol is IEventSymbol ? AttributeTargetKind.This : default, - AttributeTarget.Type => symbol is INamedTypeSymbol ? AttributeTargetKind.This : default, - AttributeTarget.Param => symbol switch - { - IParameterSymbol => AttributeTargetKind.This, - IMethodSymbol method when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => AttributeTargetKind.Handler, - _ => default - }, - AttributeTarget.TypeVar => symbol is ITypeParameterSymbol ? AttributeTargetKind.This : default, - AttributeTarget.Module => symbol is IModuleSymbol ? AttributeTargetKind.This : default, - _ => default - }; - } - - /// - /// Returns an attribute target keyword used to refer to the specified inside an attribute list. - /// - /// to get the associated attribute target keyword of. - /// Determines which keyword to return when there is more than one option (e.g '' and '' for methods). - public static AttributeTarget GetAttributeTargetKind(this ISymbol symbol, AttributeTargetKind kind = AttributeTargetKind.This) - { - return symbol switch - { - IAssemblySymbol => ThisOrDefault(AttributeTarget.Assembly), - IFieldSymbol => ThisOrDefault(AttributeTarget.Field), - IMethodSymbol method => kind switch - { - AttributeTargetKind.This => method.SupportsAttributeTargets() ? AttributeTarget.Method : default, - AttributeTargetKind.Value => method.SupportsAlternativeAttributeTargets() && method.MethodKind != MethodKind.PropertySet ? AttributeTarget.Return : default, - AttributeTargetKind.Handler when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => AttributeTarget.Param, - _ => default - }, - IPropertySymbol property => kind switch - { - AttributeTargetKind.This => AttributeTarget.Property, - AttributeTargetKind.Value when property.IsAutoProperty() => AttributeTarget.Field, - _ => default - }, - IEventSymbol @event => kind switch - { - AttributeTargetKind.This => AttributeTarget.Event, - AttributeTargetKind.Value => @event.IsFieldEvent() ? AttributeTarget.Field : default, - AttributeTargetKind.Handler when @event.IsFieldEvent() => AttributeTarget.Method, - _ => default - }, - INamedTypeSymbol type => kind switch - { - AttributeTargetKind.This => AttributeTarget.Type, - AttributeTargetKind.Value when type.SupportsAlternativeAttributeTargets() => AttributeTarget.Return, - _ => default - }, - IParameterSymbol => ThisOrDefault(AttributeTarget.Param), - ITypeParameterSymbol => ThisOrDefault(AttributeTarget.TypeVar), - IModuleSymbol => ThisOrDefault(AttributeTarget.Module), - _ => default, - }; - - AttributeTarget ThisOrDefault(AttributeTarget @this) - { - return kind == AttributeTargetKind.This ? @this : default; - } - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - /// Determines whether to return even if the is or . - public static AutoPropertyKind GetAutoPropertyKind(this IPropertySymbol property, bool includeAbstract = false) - { - if (includeAbstract) - { - if (property.GetMethod is null) - { - if (property.SetMethod is not null) - { - if (property.SetMethod.IsInitOnly) - { - return AutoPropertyKind.InitOnly; - } - - return AutoPropertyKind.SetOnly; - } - - return default; - } - } - else if (property.IsAbstract || property.IsExtern || !property.IsAutoProperty() || property.GetMethod is null) - { - return default; - } - - if (property.SetMethod is null) - { - return AutoPropertyKind.GetOnly; - } - - if (property.SetMethod.IsInitOnly) - { - return AutoPropertyKind.GetInit; - } - - return AutoPropertyKind.GetSet; - } - - /// - /// Returns the type of result of awaiting on the specified . - /// - /// to get the type of result of awaiting on. - public static ITypeSymbol? GetAwaitResult(this INamedTypeSymbol type) - { - bool hasIsCompleted = false; - bool hasGetResult = false; - - ITypeSymbol? resultType = default; - - if (!type.IsINotifyCompletion()) - { - foreach (IMethodSymbol method in type.GetAllMembers().OfType()) - { - if (method.IsGetAwaiterRaw(out INamedTypeSymbol? returnType) && HandleAwaiterType(type)) - { - return resultType; - } - } - - return default; - } - - List awaiters = new(); - - foreach (ISymbol symbol in type.GetAllMembers()) - { - bool? handleResultType = HandleResultType(symbol); - - if (handleResultType.HasValue) - { - if (handleResultType.Value) - { - return resultType; - } - } - else if (symbol is IMethodSymbol method && method.IsGetAwaiterRaw(out INamedTypeSymbol? awaiter)) - { - awaiters.Add(awaiter); - } - } - - foreach (INamedTypeSymbol awaiter in awaiters) - { - if (HandleAwaiterType(awaiter)) - { - return resultType; - } - } - - return default; - - bool HandleAwaiterType(INamedTypeSymbol type) - { - if (!type.IsINotifyCompletion()) - { - return false; - } - - resultType = default; - - hasIsCompleted = false; - hasGetResult = false; - - foreach (ISymbol symbol in type.GetAllMembers()) - { - bool? handleResultType = HandleResultType(symbol); - - if (handleResultType == true) - { - return true; - } - } - - return false; - } - - bool? HandleResultType(ISymbol symbol) - { - if (!hasIsCompleted && symbol.IsSpecialMember(SpecialMember.IsCompleted)) - { - if (hasGetResult) - { - return true; - } - - hasIsCompleted = true; - - return false; - } - else if (!hasGetResult && symbol.IsSpecialMember(SpecialMember.GetResult)) - { - IMethodSymbol method = (symbol as IMethodSymbol)!; - resultType = method.ReturnsVoid ? default : method.ReturnType; - - if (hasIsCompleted) - { - return true; - } - - hasGetResult = true; - - return false; - } - - return default; - } - } - - /// - /// Returns the backing field of the specified or if the is not auto-implemented. - /// - /// to get the backing field of. - public static IFieldSymbol? GetBackingField(this IPropertySymbol property) - { - if (property.IsIndexer || property.IsAbstract || property.IsExtern) - { - return default; - } - - return property.ContainingType? - .GetMembers() - .OfType() - .FirstOrDefault(f => SymbolEqualityComparer.Default.Equals(f.AssociatedSymbol, property)); - } - - /// - /// Returns the backing field of the specified or if the is not a field-like event. - /// - /// to get the backing field of. - public static IFieldSymbol? GetBackingField(this IEventSymbol @event) - { - return @event.ContainingType? - .GetMembers() - .OfType() - .FirstOrDefault(f => SymbolEqualityComparer.Default.Equals(f.AssociatedSymbol, @event)); - } - - /// - /// Returns the kind of the of the specified . - /// - /// to get the of. - public static BackingFieldKind GetBackingFieldKind(this IFieldSymbol field) - { - return field.AssociatedSymbol switch - { - IPropertySymbol => BackingFieldKind.Property, - IEventSymbol => BackingFieldKind.Event, - _ => default - }; - } - - /// - /// Returns the kind of the backing field of the specified . - /// - /// to get the kind of the backing field of. - public static BackingFieldKind GetBackingFieldKind(this ISymbol symbol) - { - return symbol switch - { - IFieldSymbol field => field.GetBackingFieldKind(), - IPropertySymbol => BackingFieldKind.Property, - IEventSymbol => BackingFieldKind.Event, - _ => default - }; - } - - /// - /// Returns all types the specified inherits from. - /// - /// to get the base types of. - /// Determines whether to include the in the returned collection. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetBaseTypes(this INamedTypeSymbol type, bool includeSelf = false, ReturnOrder order = ReturnOrder.ChildToParent) - { - return GetBaseTypes_Internal(type, includeSelf).OrderBy(order, ReturnOrder.ParentToChild); - } - - /// - /// Returns the compiler condition applied to the through the . - /// - /// to get the compiler condition of. - public static string? GetCompilerCondition(this IMethodSymbol method) - { - AttributeData? attribute = method.GetSpecialAttribute(SpecialAttribute.Conditional); - return attribute?.GetConstructorArgumentValue(0); - } - - /// - /// Returns the compiler condition applied to the through the . - /// - /// to get the compiler condition of. - public static string? GetCompilerCondition(this INamedTypeSymbol type) - { - AttributeData? attribute = type.GetSpecialAttribute(SpecialAttribute.Conditional); - return attribute?.GetConstructorArgumentValue(0); - } - - /// - /// Returns generic constraints applied to type parameters of the specified . - /// - /// to get the generic constraints of. - /// - /// If a is constrained to another , - /// determines whether to also include constraints of that 's base parameter. - /// - public static GenericConstraint[] GetConstraints(this IMethodSymbol method, bool includeParentParameters = false) - { - if (!method.IsGenericMethod) - { - return Array.Empty(); - } - - return method.TypeParameters.Select(p => p.GetConstraints(includeParentParameters)).ToArray(); - } - - /// - /// Returns generic constraints applied to type parameters of the specified . - /// - /// to get the generic constraints of. - /// - /// If a is constrained to another , - /// determines whether to also include constraints of that 's base parameter. - /// - public static GenericConstraint[] GetConstraints(this INamedTypeSymbol type, bool includeParentParameters = false) - { - if (!type.IsGenericType) - { - return Array.Empty(); - } - - return type.TypeParameters.Select(p => p.GetConstraints(includeParentParameters)).ToArray(); - } - - /// - /// Returns generic constraints applied to the specified . - /// - /// to get the generic constraint of. - /// - /// If the is constrained to another , - /// determines whether to also include constraints of the 's base parameter. - /// - public static GenericConstraint GetConstraints(this ITypeParameterSymbol parameter, bool includeParentParameter = false) - { - GenericConstraint constraint = default; - - if (parameter.HasReferenceTypeConstraint) - { - constraint |= GenericConstraint.Class; - } - - if (parameter.HasValueTypeConstraint) - { - constraint |= GenericConstraint.Struct; - } - - if (parameter.HasUnmanagedTypeConstraint) - { - constraint |= GenericConstraint.Unmanaged; - } - - if (parameter.HasConstructorConstraint) - { - constraint |= GenericConstraint.New; - } - - if (parameter.HasNotNullConstraint) - { - constraint |= GenericConstraint.NotNull; - } - - if (parameter.ConstraintTypes.Length > 0) - { - constraint |= GenericConstraint.Type; - - if (includeParentParameter && parameter.ConstraintTypes.FirstOrDefault(p => p.TypeKind == TypeKind.TypeParameter) is ITypeParameterSymbol baseParameter) - { - constraint |= baseParameter.GetConstraints(true); - } - } - - return constraint; - } - - /// - /// Returns value representing special kind of the specified . - /// - /// to get the special constructor kind of. - public static SpecialConstructor GetConstructorKind(this IMethodSymbol method) - { - if (method.MethodKind == MethodKind.StaticConstructor) - { - return SpecialConstructor.Static; - } - - if (method.IsVararg) - { - return default; - } - - if (method.Parameters.Length == 0) - { - return method.IsImplicitlyDeclared ? SpecialConstructor.Default : SpecialConstructor.Parameterless; - } - - if (method.Parameters.Length == 1 && method.Parameters[0].RefKind == RefKind.None && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, method.ContainingType)) - { - return SpecialConstructor.Copy; - } - - return default; - } - - /// - /// Returns all s that contain the target . - /// - /// to get the parent namespaces of. - /// Determines whether to return the global namespace as well. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetContainingNamespaces(this ISymbol symbol, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - IEnumerable namespaces = Yield(symbol); - - if (!includeGlobal) - { - namespaces = namespaces.Where(n => !n.IsGlobalNamespace); - } - - return namespaces.OrderBy(order, ReturnOrder.ParentToChild); - - static IEnumerable Yield(ISymbol symbol) - { - INamespaceSymbol parent = symbol.ContainingNamespace; - - if (parent is not null) - { - yield return parent; - - while ((parent = parent!.ContainingNamespace) is not null) - { - yield return parent; - } - } - } - } - - /// - /// Returns all s contain the target in namespace-first order. - /// - /// to get the parent types and namespaces of. - /// Determines whether to return the global namespace as well - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetContainingNamespacesAndTypes(this ISymbol symbol, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - IEnumerable first; - IEnumerable second; - - if (order == ReturnOrder.ParentToChild) - { - first = symbol.GetContainingNamespaces(includeGlobal, order); - second = symbol.GetContainingTypes(false, order); - } - else - { - first = symbol.GetContainingTypes(false, order); - second = symbol.GetContainingNamespaces(includeGlobal, order); - } - - return first.Concat(second).OrderBy(order, GetNoReverseFlag(order)); - } - - /// - /// Returns all s that contain the target . - /// - /// to get the parent types of. - /// Determines whether to include the in the returned collection if its a . - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetContainingTypes(this ISymbol symbol, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield(symbol, includeSelf).OrderBy(order, ReturnOrder.ParentToChild); - - static IEnumerable Yield(ISymbol symbol, bool includeSelf) - { - if (includeSelf && symbol is INamedTypeSymbol t) - { - yield return t; - } - - INamedTypeSymbol parent = symbol.ContainingType; - - if (parent is not null) - { - yield return parent; - - while ((parent = parent!.ContainingType) is not null) - { - yield return parent; - } - } - } - } - - /// - /// Returns the custom offset applied to the field through a or -1 if no custom offset applied. - /// - /// to get the custom offset of. - public static int GetCustomOffset(this IFieldSymbol field) - { - AttributeData? attribute = field.GetSpecialAttribute(SpecialAttribute.FieldOffset); - - if (attribute is null) - { - return -1; - } - - return attribute.TryGetConstructorArgumentValue(0, out int value) ? value : -1; - } - - /// - /// Returns a keyword used to declare the specified (e.g. , ). - /// - /// to get the keyword of. - public static string? GetDeclaredKeyword(this ISymbol symbol) - { - return symbol switch - { - INamedTypeSymbol type => type.GetDeclaredKeyword(), - IEventSymbol => "event", - IMethodSymbol method when method.IsOperator() => "operator", - _ => default - }; - } - - /// - /// Returns a keyword used to declare the specified (e.g. , ). - /// - /// to get the keyword of. - /// Determines whether to include the keyword for record classes. - public static string? GetDeclaredKeyword(this INamedTypeSymbol type, bool includeSecondary = false) - { - return type.TypeKind switch - { - TypeKind.Class => type.IsRecord ? (includeSecondary ? "record class" : "record") : "class", - TypeKind.Struct => type.IsRecord ? "record struct" : "struct", - TypeKind.Interface => "interface", - TypeKind.Enum => "enum", - TypeKind.Delegate => "delegate", - _ => default - }; - } - - /// - /// Returns the default in the context of the specified , that is: - /// - /// For top-level types: . - /// For interface members other than partial methods: . - /// For property/event accessors: accessibility of the parent property/event. - /// For all other members: . - /// - /// - /// to get the default accessibility of. - /// Determines whether accessibility of an associated member of the (e.g. parent property of an accessor) should be treated as default. - public static Accessibility GetDefaultAccessibility(this ISymbol symbol, bool includeAssociated = true) - { - if (symbol.IsTopLevel()) - { - return Accessibility.Internal; - } - - if (symbol.ContainingSymbol is INamedTypeSymbol type && type.TypeKind == TypeKind.Interface) - { - if (symbol is IMethodSymbol intfMethod && intfMethod.IsPartial(true)) - { - return Accessibility.Private; - } - - return Accessibility.Public; - } - - if (includeAssociated && symbol is IMethodSymbol method && method.IsAccessor()) - { - return method.AssociatedSymbol!.DeclaredAccessibility; - } - - return Accessibility.Private; - } - - /// - /// Returns all interface members that have default implementations. - /// - /// of an interface to get the default implementations of. - /// Determines whether to also include default implementations from the implemented interfaces. - public static IEnumerable GetDefaultImplementations(this INamedTypeSymbol type, bool baseInterfaces = false) - { - if (type.TypeKind != TypeKind.Interface) - { - return Array.Empty(); - } - - IEnumerable members = baseInterfaces - ? type.GetAllMembers() - : type.GetMembers(); - - return members.Where(m => m.IsDefaultImplementation()); - } - - /// - /// Returns the effective of the specified . - /// - /// to get the effective of. - public static Accessibility GetEffectiveAccessibility(this ISymbol symbol) - { - ISymbol? s = symbol; - Accessibility lowest = Accessibility.Public; - - while (s is not null) - { - Accessibility current = s.DeclaredAccessibility; - - if (current == Accessibility.Private) - { - return current; - } - - if (current != Accessibility.NotApplicable && current < lowest) - { - lowest = current; - } - - s = s.ContainingSymbol; - } - - return lowest; - } - - /// - /// Returns the effective underlaying element type of the specified . - /// - /// to get the effective underlaying type of. - public static ITypeSymbol? GetEffectiveElementType(this ITypeSymbol type) - { - return type switch - { - IArrayTypeSymbol array => array.GetEffectiveElementType(), - IPointerTypeSymbol pointer => pointer.GetEffectiveElementType(), - _ => type.GetNullableUnderlayingType() is ITypeSymbol nullable ? nullable : default, - }; - } - - /// - /// Returns the effective underlaying element type of the . - /// - /// to get the effective underlaying type of. - public static ITypeSymbol GetEffectiveElementType(this IArrayTypeSymbol array) - { - return array.GetEffectiveElementType(out _); - } - - /// - /// Returns the effective underlaying element type of the . - /// - /// to get the effective underlaying type of. - /// Number of inner s (including the itself). - public static ITypeSymbol GetEffectiveElementType(this IArrayTypeSymbol array, out int nestingLevel) - { - int count = 0; - ITypeSymbol? a = array; - - while (a is IArrayTypeSymbol t) - { - a = t.ElementType; - count++; - } - - nestingLevel = count; - return a; - } - - /// - /// Returns the effective underlaying type the . - /// - /// to get the effective underlaying type of. - public static ITypeSymbol GetEffectiveElementType(this IPointerTypeSymbol pointer) - { - return pointer.GetEffectiveElementType(out _); - } - - /// - /// Returns the effective underlaying type the . - /// - /// to get the effective underlaying type of. - /// Number of inner s (including the itself). - public static ITypeSymbol GetEffectiveElementType(this IPointerTypeSymbol pointer, out int nestingLevel) - { - ITypeSymbol? p = pointer; - int count = 0; - - while (p is IPointerTypeSymbol t) - { - p = t.PointedAtType; - count++; - } - - nestingLevel = count; - return p; - } - - /// - /// Returns all underlaying element types of the specified . - /// - /// to get the element types of. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetElementTypes(this IArrayTypeSymbol array, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ChildToParent); - - IEnumerable Yield() - { - ITypeSymbol element = array.ElementType; - - yield return element; - - while (element is IArrayTypeSymbol array) - { - yield return array.ElementType; - element = array.ElementType; - } - } - } - - /// - /// Returns all underlaying element types of the specified . - /// - /// to get the element types of. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetElementTypes(this IPointerTypeSymbol pointer, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ChildToParent); - - IEnumerable Yield() - { - ITypeSymbol element = pointer.PointedAtType; - - yield return element; - - while (element is IPointerTypeSymbol pointer) - { - yield return pointer.PointedAtType; - element = pointer.PointedAtType; - } - } - } - - /// - /// Returns a representing a C# keyword associated with the of the specified . - /// - /// to get the keyword associated with. - public static TypeKeyword GetEnumUnderlayingTypeKeyword(this INamedTypeSymbol type) - { - return type.EnumUnderlyingType?.GetTypeKeywordKind() ?? default; - } - - /// - /// Returns formatted name of the specified . - /// - /// to get the formatted name of. - /// format to apply. - public static string GetFormattedName(this ISymbol symbol, SymbolName format) - { - CodeBuilder builder = new(false); - builder.Name(symbol, format); - return builder.ToString(); - } - - /// - /// Returns fully qualified name of the specified . - /// - /// to get the fully qualified name of. - /// Determines format of the returned qualified name. - public static string GetFullyQualifiedName(this ISymbol symbol, QualifiedName format = default) - { - if (format == QualifiedName.Metadata) - { - return symbol.ToString(); - } - - CodeBuilder builder = new(false); - builder.QualifiedName(symbol); - string value = builder.ToString(); - - if (format == QualifiedName.Xml) - { - return AnalysisUtilities.ToXmlCompatible(value); - } - - return value; - } - - /// - /// Returns a containing generic identifier of the specified or name of the if it is not an or . - /// - /// to get the generic name of. - /// Determines whether to use type arguments instead of type parameters. - public static string GetGenericName(this ISymbol symbol, bool substituted = false) - { - CodeBuilder builder = new(false); - builder.Name(symbol, substituted ? SymbolName.Substituted : SymbolName.Generic); - return builder.ToString(); - } - - /// - /// Returns a containing generic identifier of the specified . - /// - /// to get the generic name of. - /// Determines whether to use type arguments instead of type parameters. - public static string GetGenericName(this IMethodSymbol method, bool substituted = false) - { - CodeBuilder builder = new(false); - builder.Name(method, substituted ? SymbolName.Substituted : SymbolName.Generic); - return builder.ToString(); - } - - /// - /// Returns a containing generic identifier of the specified . - /// - /// to get the generic name of. - /// Determines whether to use type arguments instead of type parameters. - public static string GetGenericName(this INamedTypeSymbol type, bool substituted = false) - { - CodeBuilder builder = new(false); - builder.Name(type, substituted ? SymbolName.Substituted : SymbolName.Generic); - return builder.ToString(); - } - - /// - /// Returns a containing the generic part of an identifier created from the collection of . - /// - /// Type parameters. - /// Determines whether to include variance of the . - /// Pointers can't be used as generic arguments. - public static string GetGenericName(this IEnumerable typeParameters, bool includeVariance = false) - { - return typeParameters.GetGenericName(null, includeVariance); - } - - /// - /// Returns a containing generic identifier combined of the specified and the collection of . - /// - /// Type parameters. - /// Actual member identifier. - /// Determines whether to include variance of the . - public static string GetGenericName(this IEnumerable typeParameters, string? name, bool includeVariance = false) - { - if (includeVariance) - { - return AnalysisUtilities.GetGenericName(typeParameters.Select(p => - { - if (p.Variance == VarianceKind.Out || p.Variance == VarianceKind.In) - { - return $"{p.Variance.ToString().ToLower()} {p.GetVerbatimName()}"; - } - - return p.GetVerbatimName(); - }), - name); - } - - return AnalysisUtilities.GetGenericName(typeParameters.Select(p => p.GetVerbatimName()), name); - } - - /// - /// Returns a containing the generic part of an identifier created from the collection of . - /// - /// Type arguments. - public static string GetGenericName(this IEnumerable typeArguments) - { - CodeBuilder builder = new(false); - builder.TypeArgumentList(typeArguments); - return builder.ToString(); - } - - /// - /// Returns a containing generic identifier combined of the specified and the collection of . - /// - /// Type arguments. - /// Actual member identifier. - public static string GetGenericName(this IEnumerable typeArguments, string? name) - { - CodeBuilder builder = new(false); - - if (!string.IsNullOrWhiteSpace(name)) - { - builder.Write(name!); - } - - builder.TypeArgumentList(typeArguments); - return builder.ToString(); - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this ISymbol symbol) - { - return symbol switch - { - INamedTypeSymbol type => type.GetHiddenSymbol(), - IMethodSymbol method => method.GetHiddenSymbol(), - IPropertySymbol property => property.GetHiddenSymbol(), - IFieldSymbol field => field.GetHiddenSymbol(), - IEventSymbol @event => @event.GetHiddenSymbol(), - _ => default - }; - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this IMethodSymbol method) - { - if (method.MethodKind != MethodKind.Ordinary || method.ContainingType is null) - { - return default; - } - - if (method.Arity == 0) - { - return method.ContainingType - .GetAllMembers(method.Name) - .FirstOrDefault(member => member switch - { - INamedTypeSymbol type => type.Arity == 0, - IMethodSymbol other => method.CanHideSymbol(other), - IPropertySymbol property => !property.IsIndexer, - IFieldSymbol or IFieldSymbol => true, - _ => false - }); - } - - return method.ContainingType - .GetAllMembers(method.Name) - .FirstOrDefault(member => member switch - { - INamedTypeSymbol type => type.Arity == method.Arity, - IMethodSymbol other => method.CanHideSymbol(other), - _ => false - }); - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this INamedTypeSymbol type) - { - if (type.ContainingType is null || !type.IsDeclarationKind()) - { - return default; - } - - if (type.Arity == 0) - { - return GetHiddenSymbol_Internal(type); - } - - return type.ContainingType - .GetAllMembers(type.GetVerbatimName()) - .FirstOrDefault(member => member switch - { - INamedTypeSymbol other => other.Arity == type.Arity, - IMethodSymbol method => method.Arity == type.Arity, - _ => false - }); - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this IPropertySymbol property) - { - if (property.ContainingType is null) - { - return default; - } - - if (property.IsIndexer) - { - return property.ContainingType - .GetAllMembers() - .OfType() - .FirstOrDefault(p => p.IsIndexer && SymbolFacts.ParametersAreEquivalent(property.Parameters, p.Parameters)); - } - - return GetHiddenSymbol_Internal(property); - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this IFieldSymbol field) - { - if (field.ContainingType is null) - { - return default; - } - - return GetHiddenSymbol_Internal(field); - } - - /// - /// Returns the hidden by the specified using the keyword. - /// - /// to get the symbol hidden by. - public static ISymbol? GetHiddenSymbol(this IEventSymbol @event) - { - if (@event.ContainingType is null) - { - return default; - } - - return @event.ContainingType - .GetAllMembers(@event.GetVerbatimName()) - .FirstOrDefault(member => member switch - { - INamedTypeSymbol type => type.Arity == 0, - IMethodSymbol method => method.Arity == 0, - IPropertySymbol property => !property.IsIndexer, - IFieldSymbol or IEventSymbol => true, - _ => false - }); - } - - /// - /// Returns a collection of all s implicitly implemented by the specified . - /// - /// to get the implicitly implemented s of. - public static IEnumerable GetImplicitImplementations(this ISymbol symbol) - { - return symbol switch - { - IMethodSymbol method => method.GetImplicitImplementations(), - IPropertySymbol property => property.GetImplicitImplementations(), - IEventSymbol @event => @event.GetImplicitImplementations(), - INamedTypeSymbol type => type.GetImplicitImplementations(), - _ => Array.Empty() - }; - } - - /// - /// Returns a collection of all s implicitly implemented by the specified . - /// - /// to get the implicitly implemented s by. - public static IEnumerable GetImplicitImplementations(this IPropertySymbol property) - { - if (property.IsImplementedExplicitly()) - { - return Array.Empty(); - } - - return GetImplicitImplementations_Internal(property); - } - - /// - /// Returns a collection of all s implicitly implemented by the specified . - /// - /// to get the implicitly implemented s by. - public static IEnumerable GetImplicitImplementations(this IMethodSymbol method) - { - if (method.IsImplementedExplicitly()) - { - return Array.Empty(); - } - - return GetImplicitImplementations_Internal(method); - } - - /// - /// Returns a collection of all s implicitly implemented by the specified . - /// - /// to get the implicitly implemented s by. - public static IEnumerable GetImplicitImplementations(this IEventSymbol @event) - { - if (@event.IsImplementedExplicitly()) - { - return Array.Empty(); - } - - return GetImplicitImplementations_Internal(@event); - } - - /// - /// Returns a collection of all s implicitly implemented by the specified . - /// - /// to get the implicitly implemented s by. - public static IEnumerable GetImplicitImplementations(this INamedTypeSymbol type) - { - return type.AllInterfaces - .SelectMany(m => m.GetMembers()) - .Where(m => type.FindImplementationForInterfaceMember(m) is not null); - } - - /// - /// Returns a collection of all s of the given implicitly implemented by the specified . - /// - /// to get the implicitly implemented s by. - /// to get the implicitly implemented s of. - public static IEnumerable GetImplicitImplementations(this INamedTypeSymbol type, INamedTypeSymbol @interface) - { - return @interface.GetMembers() - .Where(m => type.FindImplementationForInterfaceMember(m) is not null); - } - - /// - /// Creates an <inheritdoc/> tag from the specified . - /// - /// to get the <inheritdoc/> tag from. - /// Determines whether to return the <inheritdoc/> event if it cannot be referenced by other symbols. - /// A containing the created <inheritdoc/> tag -or- if has no documentation comment. - public static string? GetInheritdocIfHasDocumentation(this ISymbol symbol, bool forceUnsupported = false) - { - if (forceUnsupported) - { - if (!symbol.HasDocumentation()) - { - return default; - } - } - else if (!symbol.HasInheritableDocumentation()) - { - return default; - } - - CodeBuilder builder = new(false); - - foreach (INamedTypeSymbol type in symbol.GetContainingTypes()) - { - builder.XmlName(type); - builder.Write('.'); - } - - builder.XmlName(symbol); - - return AutoGenerated.GetInheritdoc(builder.ToString()); - } - - /// - /// Returns a collection of all local functions of the specified . - /// - /// to get the local functions of. - /// Determines whether to include the itself. - /// Determines whether to include nested local functions. - /// Specifies ordering of the returned members. - public static IEnumerable GetLocalFunctions(this IMethodSymbol method, bool includeSelf = false, bool includeNested = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - IEnumerable collection; - - if (includeNested) - { - collection = GetFuncs(method); - } - else - { - collection = GetNested(); - } - - if (includeSelf) - { - collection = new[] { method }.Concat(collection); - } - - return GetNested().OrderBy(order, ReturnOrder.ChildToParent); - - IEnumerable GetFuncs(IMethodSymbol method) - { - return method.ContainingType - .GetMembers() - .OfType() - .Where(m => m.MethodKind == MethodKind.LocalFunction && SymbolEqualityComparer.Default.Equals(method, m.ContainingSymbol)); - } - - IEnumerable GetNested() - { - const int CAPACITY = 8; - - ImmutableArray array = GetFuncs(method).ToImmutableArray(); - - if (array.Length == 0) - { - yield break; - } - - Stack subs = new(array.Length > CAPACITY ? array.Length : CAPACITY); - - PushReverse(ref array, subs); - - while (subs.Count > 0) - { - IMethodSymbol local = subs.Pop(); - yield return local; - - array = GetFuncs(local).ToImmutableArray(); - - if (array.Length == 0) - { - continue; - } - - PushReverse(ref array, subs); - } - } - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this ISymbol symbol) - { - return symbol switch - { - INamedTypeSymbol type => type.GetModifiers(), - IMethodSymbol method => method.GetModifiers(), - IPropertySymbol property => property.GetModifiers(), - IFieldSymbol field => field.GetModifiers(), - IEventSymbol @event => @event.GetModifiers(), - _ => Array.Empty() - }; - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this IFieldSymbol field) - { - List modifiers = new(4); - - AddAccessibilityModifiers(modifiers, field.DeclaredAccessibility); - - if (field.IsConst) - { - modifiers.Add("const"); - } - else if (field.IsStatic) - { - modifiers.Add("static"); - } - - if (field.IsReadOnly) - { - modifiers.Add("readonly"); - } - - if (field.IsUnsafe()) - { - modifiers.Add("unsafe"); - } - - if (field.IsVolatile) - { - modifiers.Add("volatile"); - } - - if (field.IsFixedSizeBuffer) - { - modifiers.Add("fixed"); - } - - return modifiers.ToArray(); - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this ILocalSymbol local) - { - List modifiers = new(2); - - if (local.IsConst) - { - modifiers.Add("const"); - } - - switch (local.RefKind) - { - case RefKind.Ref: - modifiers.Add("ref"); - break; - - case RefKind.RefReadOnly: - modifiers.Add("ref"); - modifiers.Add("readonly"); - break; - } - - return modifiers.ToArray(); - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this IParameterSymbol parameter) - { - List modifiers = new(2); - - if (parameter.IsThis) - { - modifiers.Add("this"); - } - - if (parameter.RefKind.GetText() is string refKind) - { - modifiers.Add(refKind); - } - - if (parameter.IsParams) - { - modifiers.Add("params"); - } - - return modifiers.ToArray(); - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this IPropertySymbol property) - { - List modifiers = new(8); - - AddAccessibilityModifiers(modifiers, property.DeclaredAccessibility); - AddBasicMethodModifiers(modifiers, property); - - if (property.IsReadOnly) - { - CheckAccessor(property.GetMethod); - } - else if (property.IsWriteOnly) - { - CheckAccessor(property.SetMethod); - } - else if (property.IsReadOnlyContext()) - { - modifiers.Add("readonly"); - } - - if (property.IsUnsafe()) - { - modifiers.Add("unsafe"); - } - - return modifiers.ToArray(); - - void CheckAccessor(IMethodSymbol? accessor) - { - if (accessor is not null && accessor.IsReadOnly) - { - modifiers.Add("readonly"); - } - } - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this IEventSymbol @event) - { - List modifiers = new(8); - - AddAccessibilityModifiers(modifiers, @event.DeclaredAccessibility); - AddBasicMethodModifiers(modifiers, @event); - - if (@event.IsReadOnlyContext()) - { - modifiers.Add("readonly"); - } - - if (@event.IsUnsafe()) - { - modifiers.Add("unsafe"); - } - - return modifiers.ToArray(); - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this IMethodSymbol method) - { - List modifiers = new(8); - - AddAccessibilityModifiers(modifiers, method.DeclaredAccessibility); - AddBasicMethodModifiers(modifiers, method); - - if (method.IsReadOnly) - { - modifiers.Add("readonly"); - } - - if (method.IsUnsafe()) - { - modifiers.Add("unsafe"); - } - - if (method.IsAsync) - { - modifiers.Add("async"); - } - - if (method.IsPartial(true)) - { - modifiers.Add("partial"); - } - - return modifiers.ToArray(); - } - - /// - /// Returns modifiers applied to the target . - /// - /// to get the modifiers of. - public static string[] GetModifiers(this INamedTypeSymbol type) - { - List modifiers = new(8); - - AddAccessibilityModifiers(modifiers, type.DeclaredAccessibility); - - if (type.IsStatic) - { - modifiers.Add("static"); - } - - if (type.IsNew()) - { - modifiers.Add("new"); - } - - if (type.IsAbstract) - { - modifiers.Add("abstract"); - } - else if (type.IsRefLikeType) - { - modifiers.Add("ref"); - } - else if (type.IsSealed) - { - modifiers.Add("sealed"); - } - - if (type.IsReadOnly) - { - modifiers.Add("readonly"); - } - - if (type.IsUnsafe()) - { - modifiers.Add("unsafe"); - } - - if (type.IsPartial()) - { - modifiers.Add("partial"); - } - - return modifiers.ToArray(); - } - - /// - /// Returns the defined on the specified that is of the given . - /// - /// to get the of. - /// to check for. - public static AttributeData? GetNullableAnnotationAttribute(this ISymbol symbol, NullableAnnotationAttribute attributeKind) - { - string? name = attributeKind.GetAttributeName(); - - if (name is null) - { - return default; - } - - string? @namespace = attributeKind.GetNamespaceName(); - - if (@namespace is null) - { - return default; - } - - return symbol.GetAttributes().FirstOrDefault(attr => - attr.AttributeClass is not null && - attr.AttributeClass.Name == name && - attr.AttributeClass.IsWithinNamespace(@namespace, @namespace != "System") - ); - } - - /// - /// Returns the kind of this represents. - /// - /// to get the kind of. - public static NullableAnnotationAttribute GetNullableAnnotationAttributeKind(this INamedTypeSymbol type) - { - return MapToNullableAnnotationAttribute(type.Name, toReturn => type.IsWithinNamespace("System.Diagnostics.CodeAnalysis", true) ? toReturn : default); - } - - /// - /// Returns the underlaying of a nullable . - /// - /// to get the underlaying of. - public static ITypeSymbol? GetNullableUnderlayingType(this ITypeSymbol type) - { - if (type.NullableAnnotation == NullableAnnotation.Annotated) - { - return type; - } - - if (type is not INamedTypeSymbol named || !named.IsValueType || named.ConstructedFrom is null || named.ConstructedFrom.SpecialType != SpecialType.System_Nullable_T) - { - return default; - } - - ImmutableArray arguments = named.TypeArguments; - - if (arguments.Length != 1) - { - return default; - } - - return arguments[0]; - } - - /// - /// Returns kind of operator this overloads. - /// - /// to get the kind of the overloaded operator. - public static OverloadableOperator GetOperatorKind(this IMethodSymbol method) - { - if (method.MethodKind != MethodKind.UserDefinedOperator && method.MethodKind != MethodKind.BuiltinOperator) - { - return default; - } - - return AnalysisUtilities.GetOperatorType(method.Name); - } - - /// - /// Returns text of operator this overloads. - /// - /// to get the kind of the overloaded operator. - public static string? GetOperatorToken(this IMethodSymbol method) - { - if (method.MethodKind != MethodKind.UserDefinedOperator && method.MethodKind != MethodKind.BuiltinOperator) - { - return default; - } - - return AnalysisUtilities.GetOperatorText(method.Name); - } - - /// - /// Returns collection of overloads of the specified . - /// - /// to get the overloads of. - /// Determines whether to also include inherited overloads. - /// Determines whether to also include methods with different arity than the . - public static IEnumerable GetOverloads(this IMethodSymbol method, bool includeInherited = true, bool ignoreArity = false) - { - if (method.MethodKind != MethodKind.Ordinary) - { - return Array.Empty(); - } - - IEnumerable overloads = method.ContainingType - .GetMembers(method.Name) - .OfType(); - - if (ignoreArity) - { - overloads = overloads.Where(m => method.Arity == m.Arity); - } - - if (!includeInherited || !method.ContainingType.HasExplicitBaseType()) - { - return overloads; - } - - IMethodSymbol[] array = overloads.ToArray(); - - List inheritedMethods = new(array.Length * 4); - List overrides = new(inheritedMethods.Count); - - inheritedMethods.Add(method); - - if (method.IsOverride) - { - overrides.Add(method); - } - - foreach (INamedTypeSymbol type in method.ContainingType.GetBaseTypes()) - { - // These two values allow to skip methods that were added to the lists during this loop pass. - - int currentOverrideLength = overrides.Count; - int currentRegistryLength = inheritedMethods.Count; - - foreach (IMethodSymbol inheritedMethod in type.GetMembers(method.Name).OfType()) - { - if (!CheckVirtuality(inheritedMethod, currentOverrideLength, out bool addOverride)) - { - continue; - } - - if (!CheckNewModifier(inheritedMethod, currentRegistryLength)) - { - continue; - } - - inheritedMethods.Add(inheritedMethod); - - if (addOverride) - { - overrides.Add(inheritedMethod); - } - } - } - - return overloads.Concat(inheritedMethods); - - bool CheckVirtuality(IMethodSymbol inheritedMethod, int length, out bool addOverride) - { - Virtuality virtuality = inheritedMethod.GetVirtuality(); - - switch (virtuality) - { - case Virtuality.Sealed: - addOverride = true; - break; - - case Virtuality.Abstract: - case Virtuality.Virtual: - - for (int i = 0; i < length; i++) - { - if (SymbolEqualityComparer.Default.Equals(overrides[i], inheritedMethod)) - { - addOverride = false; - return false; - } - } - - break; - } - - addOverride = false; - return true; - } - - bool CheckNewModifier(IMethodSymbol inheritedMethod, int length) - { - for (int i = 0; i < length; i++) - { - IMethodSymbol registered = inheritedMethods[i]; - - if (registered.CanHideSymbol_Internal(inheritedMethod, ignoreArity)) - { - return false; - } - } - - return true; - } - } - - /// - /// Returns the overridden by the specified . - /// - /// to get the symbol overridden by. - public static ISymbol? GetOverriddenSymbol(this ISymbol symbol) - { - return symbol switch - { - IMethodSymbol method => method.OverriddenMethod, - IPropertySymbol property => property.OverriddenProperty, - IEventSymbol @event => @event.OverriddenEvent, - _ => default - }; - } - - /// - /// Returns all s overridden by the specified . - /// - /// to get the methods overridden by. - public static IEnumerable GetOverriddenSymbols(this IMethodSymbol method) - { - IMethodSymbol? m = method; - - while ((m = m!.OverriddenMethod) is not null) - { - yield return m; - } - } - - /// - /// Returns all s overridden by the specified . - /// - /// to get the properties overridden by. - public static IEnumerable GetOverriddenSymbols(this IPropertySymbol property) - { - IPropertySymbol? p = property; - - while ((p = p!.OverriddenProperty) is not null) - { - yield return p; - } - } - - /// - /// Returns all s overridden by the specified . - /// - /// to get the events overridden by. - public static IEnumerable GetOverriddenSymbols(this IEventSymbol @event) - { - IEventSymbol? e = @event; - - while ((e = e!.OverriddenEvent) is not null) - { - yield return e; - } - } - - /// - /// Returns all s overridden by the specified . - /// - /// to get the symbols overridden by. - public static IEnumerable GetOverriddenSymbols(this ISymbol symbol) - { - return symbol switch - { - IMethodSymbol method => method.GetOverriddenSymbols(), - IPropertySymbol property => property.GetOverriddenSymbols(), - IEventSymbol @event => @event.GetOverriddenSymbols(), - _ => Array.Empty() - }; - } - - /// - /// Returns all es of the specified . - /// - /// to get the es of. - /// that specifies if the operation should be canceled. - public static IEnumerable GetPartialDeclarations(this INamedTypeSymbol type, CancellationToken cancellationToken = default) where T : TypeDeclarationSyntax - { - return type.DeclaringSyntaxReferences.Select(e => e.GetSyntax(cancellationToken)).OfType(); - } - - /// - /// Returns a if the specified is a keyword type, otherwise. - /// - /// to get the for. - public static PredefinedTypeSyntax? GetPredefineTypeSyntax(this INamedTypeSymbol type) - { - if (type.SpecialType == SpecialType.None) - { - return default; - } - - SyntaxKind kind = type.SpecialType.GetSyntaxKind(); - - if (kind == default) - { - return default; - } - - return SyntaxFactory.PredefinedType(SyntaxFactory.Token(kind)); - } - - /// - /// Returns the primary constructor of the specified . - /// - /// to get the primary constructor of. - public static IMethodSymbol? GetPrimaryConstructor(this INamedTypeSymbol type) - { - return type.InstanceConstructors.FirstOrDefault(ctor => ctor.IsPrimaryConstructor()); - } - - /// - /// Returns a created from the specified . - /// - /// A collection of s to create the from. - /// A created by combining the . -or- if there were less then 2 provided. - public static QualifiedNameSyntax? GetQualifiedName(this IEnumerable namespaces) - { - return AnalysisUtilities.GetQualifiedName(namespaces.Select(n => n.GetVerbatimName())); - } - - /// - /// Returns all struct members with the modifier applied. - /// - /// to get all members with the modifier applied. - /// If the is not a , empty collection is returned. - public static IEnumerable GetReadOnlyMembers(this INamedTypeSymbol type) - { - if (type.TypeKind != TypeKind.Struct) - { - return Array.Empty(); - } - - return type - .GetMembers() - .Where(m => m.IsStructReadOnly()); - } - - /// - /// Returns root namespace of the (excluding the global namespace). - /// - /// to get the root namespaces of. - /// The root -or- if root was not found. - public static INamespaceSymbol? GetRootNamespace(this ISymbol symbol) - { - return GetContainingNamespaces(symbol).FirstOrDefault(); - } - - /// - /// Returns the defined on the specified that is of the given . - /// - /// to get the of. - /// to check for. - public static AttributeData? GetSpecialAttribute(this ISymbol symbol, SpecialAttribute attributeKind) - { - string? name = attributeKind.GetAttributeName(); - - if (name is null) - { - return default; - } - - string? @namespace = attributeKind.GetNamespaceName(); - - if (@namespace is null) - { - return default; - } - - return symbol.GetAttributes().FirstOrDefault(attr => - attr.AttributeClass is not null && - attr.AttributeClass.Name == name && - attr.AttributeClass.IsWithinNamespace(@namespace, @namespace != "System") - ); - } - - /// - /// Returns the kind of this represents. - /// - /// to get the kind of. - public static SpecialAttribute GetSpecialAttributeKind(this INamedTypeSymbol type) - { - if (!type.Name.EndsWith("Attribute")) - { - return default; - } - - return MapToSpecialAttribute(type.Name, (@namespace, toReturn) => type.IsWithinNamespace(@namespace, @namespace.Length > 6) ? toReturn : default); - } - - /// - /// Returns an representing the given kind of special constructor available from the specified . - /// - /// to get the special member from. - /// Kind of special constructor to return. - public static IMethodSymbol? GetSpecialConstructor(this INamedTypeSymbol type, SpecialConstructor kind) - { - return kind switch - { - SpecialConstructor.Static => type.StaticConstructors.FirstOrDefault(), - SpecialConstructor.None => default, - SpecialConstructor.Parameterless => type.InstanceConstructors.FirstOrDefault(ctor => ctor.GetConstructorKind() is SpecialConstructor.Parameterless or SpecialConstructor.Default), - _ => type.InstanceConstructors.FirstOrDefault(ctor => ctor.GetConstructorKind() == kind), - }; - } - - /// - /// Returns an representing the given kind of available from the specified . - /// - /// to get the special member from. - /// Kind of special member to return. - public static ISymbol? GetSpecialMember(this INamedTypeSymbol type, SpecialMember specialMember) - { - return type.GetAllMembers().FirstOrDefault(member => member.IsSpecialMember(specialMember)); - } - - /// - /// Returns all sub-namespaces of the specified . - /// - /// to get the sub-namespaces of. - /// Determines whether to include the global namespace in the returned collection. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetSubNamespaces(this IAssemblySymbol assembly, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - return assembly.GlobalNamespace.GetSubNamespaces(includeGlobal, order); - } - - /// - /// Returns all sub-namespaces of the specified . - /// - /// to get the sub-namespaces of. - /// Determines whether to also include the itself in the collection. - /// Specifies ordering of the returned members. - public static IReturnOrderEnumerable GetSubNamespaces(this INamespaceSymbol @namespace, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ParentToChild); - - IEnumerable Yield() - { - const int CAPACITY = 32; - - if (includeSelf) - { - yield return @namespace; - } - - ImmutableArray array = @namespace.GetNamespaceMembers().ToImmutableArray(); - - if (array.Length == 0) - { - yield break; - } - - Stack subs = new(array.Length > CAPACITY ? array.Length : CAPACITY); - - PushReverse(ref array, subs); - - while (subs.Count > 0) - { - INamespaceSymbol t = subs.Pop(); - yield return t; - - array = t.GetNamespaceMembers().ToImmutableArray(); - - if (array.Length == 0) - { - continue; - } - - PushReverse(ref array, subs); - } - } - } - - /// - /// Returns a of type associated with the specified . - /// - /// Type of to return. - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a syntax node of type . - public static T GetSyntax(this ISymbol symbol, CancellationToken cancellationToken = default) where T : SyntaxNode - { - if (!symbol.TryGetSyntax(out T? declaration, cancellationToken)) - { - throw Exc_SymbolNotAssociatedWithNode(symbol, typeof(T)); - } - - return declaration; - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static BaseMethodDeclarationSyntax GetSyntax(this IMethodSymbol method, CancellationToken cancellationToken = default) - { - return method.GetSyntax(cancellationToken); - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static BaseTypeDeclarationSyntax GetSyntax(this INamedTypeSymbol type, CancellationToken cancellationToken = default) - { - return type.GetSyntax(cancellationToken); - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static ParameterSyntax GetSyntax(this IParameterSymbol parameter, CancellationToken cancellationToken = default) - { - return parameter.GetSyntax(cancellationToken); - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static TypeParameterSyntax GetSyntax(this ITypeParameterSymbol parameter, CancellationToken cancellationToken = default) - { - return parameter.GetSyntax(cancellationToken); - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static EventFieldDeclarationSyntax GetSyntax(this IEventSymbol @event, CancellationToken cancellationToken = default) - { - if (!@event.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not EventFieldDeclarationSyntax decl) - { - throw Exc_SymbolNotAssociatedWithNode(@event, typeof(EventFieldDeclarationSyntax)); - } - - return decl; - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static FieldDeclarationSyntax GetSyntax(this IFieldSymbol field, CancellationToken cancellationToken = default) - { - if (!field.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not FieldDeclarationSyntax decl) - { - throw Exc_SymbolNotAssociatedWithNode(field, typeof(FieldDeclarationSyntax)); - } - - return decl; - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static LocalDeclarationStatementSyntax GetSyntax(this ILocalSymbol local, CancellationToken cancellationToken = default) - { - if (!local.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not LocalDeclarationStatementSyntax decl) - { - throw Exc_SymbolNotAssociatedWithNode(local, typeof(LocalDeclarationStatementSyntax)); - } - - return decl; - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static BasePropertyDeclarationSyntax GetSyntax(this IPropertySymbol property, CancellationToken cancellationToken = default) - { - return property.GetSyntax(cancellationToken); - } - - /// - /// Returns a associated with the specified . - /// - /// to get the associated with. - /// that specifies if the operation should be canceled. - /// is not associated with a . - public static LabeledStatementSyntax GetSyntax(this ILabelSymbol label, CancellationToken cancellationToken = default) - { - return label.GetSyntax(cancellationToken); - } - - /// - /// Returns a representation of a C# keyword associated with the specified . - /// - /// to get the keyword associated with. - public static string? GetTypeKeyword(this ITypeSymbol type) - { - if (type is IDynamicTypeSymbol) - { - return "dynamic"; - } - - return type.SpecialType.GetKeywordText(); - } - - /// - /// Returns a representing a C# keyword associated with the specified . - /// - /// to get the keyword associated with. - public static TypeKeyword GetTypeKeywordKind(this ITypeSymbol type) - { - if (type is IDynamicTypeSymbol) - { - return TypeKeyword.Dynamic; - } - - return type.SpecialType.GetKeyword(); - } - - /// - /// Returns a new build for the specified symbol. - /// - /// to built the from. - public static UsingDirectiveSyntax GetUsingDirective(this INamespaceSymbol @namespace) - { - NameSyntax name; - - if (@namespace.GetContainingNamespaces().GetQualifiedName() is QualifiedNameSyntax q) - { - name = q; - } - else - { - name = SyntaxFactory.IdentifierName(@namespace.GetVerbatimName()); - } - - return SyntaxFactory.UsingDirective(name); - } - - /// - /// Returns a new build for the specified symbol. - /// - /// A collection of s to build the from. - /// cannot be empty. - public static UsingDirectiveSyntax GetUsingDirective(this IEnumerable namespaces) - { - NameSyntax name; - - if (namespaces.GetQualifiedName() is QualifiedNameSyntax q) - { - name = q; - } - else if (namespaces.FirstOrDefault() is INamespaceSymbol first) - { - name = SyntaxFactory.IdentifierName(first.GetVerbatimName()); - } - else - { - throw new ArgumentException($"'{nameof(namespaces)}' cannot be empty"); - } - - return SyntaxFactory.UsingDirective(name); - } - - /// - /// Returns name of the with a verbatim identifier '@' token applied if necessary. - /// - /// to get the effective name of. - public static string GetVerbatimName(this ISymbol symbol) - { - string value = symbol.Name; - AnalysisUtilities.ApplyVerbatimIfNecessary(ref value); - return value; - } - - /// - /// Returns the of the specified . - /// - /// to get the virtuality of. - public static Virtuality GetVirtuality(this ISymbol symbol) - { - if (symbol.IsAbstract) - { - return Virtuality.Abstract; - } - - if (symbol.IsOverride) - { - if (symbol.IsSealed) - { - return Virtuality.Sealed; - } - - return Virtuality.Virtual; - } - - if (symbol.IsVirtual) - { - return Virtuality.Virtual; - } - - return default; - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// Invalid type kind. - /// is . -or- is . - public static IMemberData ToData(this ITypeSymbol type, ICompilationData compilation, MemberData.Properties? properties = default) - { - switch (type) - { - case INamedTypeSymbol named: - return named.ToData(compilation, properties); - - case ITypeParameterSymbol typeParameter: - return typeParameter.ToData(compilation, properties); - - default: - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - throw new ArgumentException($"Invalid type kind: '{type.TypeKind}'", nameof(type)); - } - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// Invalid type kind. - /// is . -or- is . - public static ITypeData ToData(this INamedTypeSymbol type, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - if (type.IsRecord) - { - return new RecordData(type, compilation, properties); - } - - return type.TypeKind switch - { - TypeKind.Class => new ClassData(type, compilation, properties), - TypeKind.Struct => new StructData(type, compilation, properties), - TypeKind.Interface => new InterfaceData(type, compilation, properties), - TypeKind.Delegate => new DelegateData(type, compilation, properties), - TypeKind.Enum => new EnumData(type, compilation, properties), - _ => throw new ArgumentException($"Unknown type kind: '{type.TypeKind}'", nameof(type)) - }; - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// Invalid method kind. - /// is . -or- is . - public static IMethodData ToData(this IMethodSymbol method, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (method is null) - { - throw new ArgumentNullException(nameof(method)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return method.MethodKind switch - { - MethodKind.Ordinary => new MethodData(method, compilation, properties), - MethodKind.UserDefinedOperator => new OperatorData(method, compilation, properties), - MethodKind.Constructor or MethodKind.StaticConstructor => new ConstructorData(method, compilation, properties), - MethodKind.Destructor => new DestructorData(method, compilation, properties), - MethodKind.LocalFunction => new LocalFunctionData(method, compilation, properties), - MethodKind.Conversion => new ConversionOperatorData(method, compilation, properties), - MethodKind.AnonymousFunction => new LambdaData(method, compilation, properties), - _ => method.IsAccessor() - ? new AccessorData(method, compilation, properties) - : throw new ArgumentException($"Unknown method kind: '{method.MethodKind}'", nameof(method)) - }; - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static IFieldData ToData(this IFieldSymbol field, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (field is null) - { - throw new ArgumentNullException(nameof(field)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new FieldData(field, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static IEventData ToData(this IEventSymbol @event, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (@event is null) - { - throw new ArgumentNullException(nameof(@event)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new EventData(@event, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static IPropertyData ToData(this IPropertySymbol property, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (property is null) - { - throw new ArgumentNullException(nameof(property)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - if (property.IsIndexer) - { - return new IndexerData(property, compilation); - } - - return new PropertyData(property, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static ILocalData ToData(this ILocalSymbol local, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (local is null) - { - throw new ArgumentNullException(nameof(local)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new LocalData(local, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static ITypeParameterData ToData(this ITypeParameterSymbol typeParameter, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (typeParameter is null) - { - throw new ArgumentNullException(nameof(typeParameter)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new TypeParameterData(typeParameter, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static IParameterData ToData(this IParameterSymbol parameter, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (parameter is null) - { - throw new ArgumentNullException(nameof(parameter)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new ParameterData(parameter, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// Invalid type kind. - /// is . -or- is . - public static INamespaceOrTypeData ToData(this INamespaceOrTypeSymbol symbol, ICompilationData compilation, MemberData.Properties? properties = default) - { - switch (symbol) - { - case INamespaceSymbol @namespace: - return @namespace.ToData(compilation, properties); - - case INamedTypeSymbol type: - return type.ToData(compilation, properties); - - default: - - if (symbol is null) - { - throw new ArgumentNullException(nameof(symbol)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - if (symbol is not ITypeParameterSymbol) - { - throw new ArgumentException("Invalid type kind", nameof(symbol)); - } - - return new NamespaceOrTypeData(symbol, compilation, properties); - } - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// Invalid type kind. - /// is . -or- is . - public static IMemberData ToData(this ISymbol symbol, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return symbol switch - { - ITypeParameterSymbol typeParameter => typeParameter.ToData(compilation, properties), - INamedTypeSymbol type => type.ToData(compilation, properties), - IMethodSymbol method => method.ToData(compilation, properties), - IPropertySymbol property => property.ToData(compilation, properties), - IFieldSymbol field => field.ToData(compilation, properties), - IEventSymbol @event => @event.ToData(compilation, properties), - IParameterSymbol parameter => parameter.ToData(compilation, properties), - INamespaceSymbol @namespace => @namespace.ToData(compilation, properties), - ILocalSymbol local => local.ToData(compilation, properties), - ITypeSymbol unknownType => throw new ArgumentException($"Invalid type kind: '{unknownType.TypeKind}'", nameof(symbol)), - INamespaceOrTypeSymbol namespaceOrType => namespaceOrType.ToData(compilation, properties), - null => throw new ArgumentNullException(nameof(symbol)), - _ => new MemberData(symbol, compilation, properties) - }; - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// to use for the current instance. - /// is . -or- is . - public static INamespaceData ToData(this INamespaceSymbol @namespace, ICompilationData compilation, MemberData.Properties? properties = default) - { - if (@namespace is null) - { - throw new ArgumentNullException(nameof(@namespace)); - } - - if (compilation is null) - { - throw new ArgumentNullException(nameof(compilation)); - } - - return new NamespaceData(@namespace, compilation, properties); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Invalid type kind. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ISymbol symbol, ICompilationData? compilation = default) - { - return symbol switch - { - ITypeParameterSymbol typeParameter => typeParameter.ToDataOrSymbol(compilation), - INamedTypeSymbol type => type.ToDataOrSymbol(compilation), - IMethodSymbol method => method.ToDataOrSymbol(compilation), - IPropertySymbol property => property.ToDataOrSymbol(compilation), - IFieldSymbol field => field.ToDataOrSymbol(compilation), - IEventSymbol @event => @event.ToDataOrSymbol(compilation), - IParameterSymbol parameter => parameter.ToDataOrSymbol(compilation), - INamespaceSymbol @namespace => @namespace.ToDataOrSymbol(compilation), - ILocalSymbol local => local.ToDataOrSymbol(compilation), - ITypeSymbol unknownType => throw new ArgumentException($"Invalid type kind: '{unknownType.TypeKind}'", nameof(symbol)), - INamespaceOrTypeSymbol namespaceOrType => namespaceOrType.ToDataOrSymbol(compilation), - null => throw new ArgumentNullException(nameof(symbol)), - _ => new SymbolOrMemberWrapper(symbol, compilation) - }; - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ITypeSymbol type, ICompilationData? compilation = default) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - return new SymbolOrMemberWrapper(type, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ITypeSymbol type, ICompilationData? compilation = default) where TData : class, IMemberData - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - return new SymbolOrMemberWrapper(type, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamespaceSymbol @namespace, ICompilationData? compilation = default) - { - if (@namespace is null) - { - throw new ArgumentNullException(nameof(@namespace)); - } - - return new SymbolOrMemberWrapper(@namespace, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamespaceSymbol @namespace, ICompilationData? compilation = default) where TData : class, INamespaceData - { - if (@namespace is null) - { - throw new ArgumentNullException(nameof(@namespace)); - } - - return new SymbolOrMemberWrapper(@namespace, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamedTypeSymbol type, ICompilationData? compilation = default) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - return new SymbolOrMemberWrapper(type, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamedTypeSymbol type, ICompilationData? compilation = default) where TData : class, ITypeData - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - return new SymbolOrMemberWrapper(type, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamespaceOrTypeSymbol symbol, ICompilationData? compilation = default) - { - if (symbol is null) - { - throw new ArgumentNullException(nameof(symbol)); - } - - return new SymbolOrMemberWrapper(symbol, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this INamespaceOrTypeSymbol symbol, ICompilationData? compilation = default) where TData : class, INamespaceOrTypeData - { - if (symbol is null) - { - throw new ArgumentNullException(nameof(symbol)); - } - - return new SymbolOrMemberWrapper(symbol, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IParameterSymbol parameter, ICompilationData? compilation = default) - { - if (parameter is null) - { - throw new ArgumentNullException(nameof(parameter)); - } - - return new SymbolOrMemberWrapper(parameter, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IParameterSymbol parameter, ICompilationData? compilation = default) where TData : class, IParameterData - { - if (parameter is null) - { - throw new ArgumentNullException(nameof(parameter)); - } - - return new SymbolOrMemberWrapper(parameter, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IMethodSymbol method, ICompilationData? compilation = default) - { - if (method is null) - { - throw new ArgumentNullException(nameof(method)); - } - - return new SymbolOrMemberWrapper(method, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IMethodSymbol method, ICompilationData? compilation = default) where TData : class, IMethodData - { - if (method is null) - { - throw new ArgumentNullException(nameof(method)); - } - - return new SymbolOrMemberWrapper(method, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ITypeParameterSymbol typeParameter, ICompilationData? compilation = default) - { - if (typeParameter is null) - { - throw new ArgumentNullException(nameof(typeParameter)); - } - - return new SymbolOrMemberWrapper(typeParameter, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ITypeParameterSymbol typeParameter, ICompilationData? compilation = default) where TData : class, ITypeParameterData - { - if (typeParameter is null) - { - throw new ArgumentNullException(nameof(typeParameter)); - } - - return new SymbolOrMemberWrapper(typeParameter, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IEventSymbol @event, ICompilationData? compilation = default) - { - if (@event is null) - { - throw new ArgumentNullException(nameof(@event)); - } - - return new SymbolOrMemberWrapper(@event, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IEventSymbol @event, ICompilationData? compilation = default) where TData : class, IEventData - { - if (@event is null) - { - throw new ArgumentNullException(nameof(@event)); - } - - return new SymbolOrMemberWrapper(@event, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IFieldSymbol field, ICompilationData? compilation = default) - { - if (field is null) - { - throw new ArgumentNullException(nameof(field)); - } - - return new SymbolOrMemberWrapper(field, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IFieldSymbol field, ICompilationData? compilation = default) where TData : class, IFieldData - { - if (field is null) - { - throw new ArgumentNullException(nameof(field)); - } - - return new SymbolOrMemberWrapper(field, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IPropertySymbol property, ICompilationData? compilation = default) - { - if (property is null) - { - throw new ArgumentNullException(nameof(property)); - } - - return new SymbolOrMemberWrapper(property, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this IPropertySymbol property, ICompilationData? compilation = default) where TData : class, IPropertyData - { - if (property is null) - { - throw new ArgumentNullException(nameof(property)); - } - - return new SymbolOrMemberWrapper(property, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ILocalSymbol local, ICompilationData? compilation = default) - { - if (local is null) - { - throw new ArgumentNullException(nameof(local)); - } - - return new SymbolOrMemberWrapper(local, compilation); - } - - /// - /// Returns new created for the specified . - /// - /// to create the for. - /// to create the from. - /// Type of returned data. - /// is . - public static ISymbolOrMember ToDataOrSymbol(this ILocalSymbol local, ICompilationData? compilation = default) where TData : class, ILocalData - { - if (local is null) - { - throw new ArgumentNullException(nameof(local)); - } - - return new SymbolOrMemberWrapper(local, compilation); - } - - /// - /// Attempts to return a of type associated with the specified . - /// - /// Type of to return. - /// to get the associated with. - /// associated with the specified . - /// that specifies if the operation should be canceled. - public static bool TryGetSyntax(this ISymbol symbol, [NotNullWhen(true)] out T? syntax, CancellationToken cancellationToken = default) where T : SyntaxNode - { - SyntaxNode? node = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(cancellationToken); - syntax = node as T; - return syntax is not null; - } - - [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.", Justification = "")] - internal static IEnumerable GetImplicitImplementations_Internal(T symbol, Func> memberFunction) where T : ISymbol - { - if (symbol.DeclaredAccessibility != Accessibility.Public) - { - return Array.Empty(); - } - - return symbol.ContainingType.AllInterfaces - .SelectMany(memberFunction) - .OfType() - .Where(m => - { - ISymbol? s = symbol.ContainingType.FindImplementationForInterfaceMember(m); - - if (s is not T t || t.IsImplementedExplicitly()) - { - return false; - } - - return SymbolEqualityComparer.Default.Equals(t, symbol); - }); - } - - [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.")] - internal static NullableAnnotationAttribute MapToNullableAnnotationAttribute(string name, Func function) - { - return name switch - { - "AllowNullAttribute" => function(NullableAnnotationAttribute.AllowNull), - "DisallowNullAttribute" => function(NullableAnnotationAttribute.DisallowNull), - "MaybeNullAttribute" => function(NullableAnnotationAttribute.MaybeNull), - "NotNullAttribute" => function(NullableAnnotationAttribute.NotNull), - "NotNullWhenAttribute" => function(NullableAnnotationAttribute.NotNullWhen), - "NotNullIfNotNullAttribute" => function(NullableAnnotationAttribute.NotNullIfNotNull), - "MemberNotNullAttribute" => function(NullableAnnotationAttribute.MemberNotNull), - "MemberNotNullWhenAttribute" => function(NullableAnnotationAttribute.MemberNotNullWhen), - _ => default - }; - } - - [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.")] - internal static SpecialAttribute MapToSpecialAttribute(string name, Func function) - { - return name switch - { - "ObsoleteAttribute" => function("System", SpecialAttribute.Obsolete), - "AttributeUsageAttribute" => function("System", SpecialAttribute.AttributeUsage), - "FlagsAttribute" => function("System", SpecialAttribute.Flags), - "CLSCompliantAttribute" => function("System", SpecialAttribute.CLSCompliant), - "ThreadStaticAttribute" => function("System", SpecialAttribute.ThreadStatic), - "ConditionalAttribute" => function("System.Diagnostics", SpecialAttribute.Conditional), - "StructLayoutAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.StructLayout), - "MarhsalAsAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.MarshalAs), - "DllImportAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.DllImport), - "FieldOffsetAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.FieldOffset), - "MethodImplAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.MethodImpl), - "SkipLocalsInitAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.SkipLocalsInit), - "CallerFilePathAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerFilePath), - "CallerLineNumberAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerLineNumber), - "CallerMemberNameAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerMemberName), - "CallerArgumentExpressionAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerArgumentExpression), - "ModuleInitializerAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.ModuleInitializer), - "DoesNotReturnAttribute" => function("System.Diagnostics.CodeAnalysis", SpecialAttribute.DoesNotReturn), - "DoesNotReturnIfAttribute" => function("System.Diagnostics.CodeAnalysis", SpecialAttribute.DoesNotReturnIf), - "GeneratedCodeAttribute" => function("System.CodeDom.Compiler", SpecialAttribute.GeneratedCode), - _ => default - }; - } - - internal static IReturnOrderEnumerable OrderBy(this IEnumerable collection, ReturnOrder order, ReturnOrder reverseIfThis) - { - if (order == reverseIfThis) - { - collection = collection.Reverse(); - } - - return new ReturnOrderEnumerable(collection, order); - } - - private static void AddAccessibilityModifiers(List modifiers, Accessibility accessibility) - { - switch (accessibility) - { - case Accessibility.Public: - modifiers.Add("public"); - break; - - case Accessibility.Private: - modifiers.Add("private"); - break; - - case Accessibility.Protected: - modifiers.Add("protected"); - break; - - case Accessibility.Internal: - modifiers.Add("internal"); - break; - - case Accessibility.ProtectedOrInternal: - modifiers.Add("protected"); - modifiers.Add("internal"); - break; - - case Accessibility.ProtectedAndInternal: - modifiers.Add("private"); - modifiers.Add("protected"); - break; - } - } - - private static void AddBasicMethodModifiers(List modifiers, ISymbol symbol) - { - if (symbol.IsStatic) - { - modifiers.Add("static"); - } - - if (symbol.IsExtern) - { - modifiers.Add("extern"); - } - - if (symbol.IsNew()) - { - modifiers.Add("new"); - } - - if (symbol.IsAbstract) - { - modifiers.Add("abstract"); - } - else if (symbol.IsSealed) - { - modifiers.Add("sealed"); - } - else if (symbol.IsVirtual) - { - modifiers.Add("virtual"); - } - - if (symbol.IsOverride) - { - modifiers.Add("override"); - } - } - - private static TypeSyntax ApplyAnnotation(TypeSyntax syntax, NullableAnnotation annotation) - { - if (annotation == NullableAnnotation.Annotated) - { - return SyntaxFactory.NullableType(syntax); - } - - return syntax; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static InvalidOperationException Exc_SymbolNotAssociatedWithNode(ISymbol symbol, Type type) - { - return new InvalidOperationException($"Method '{symbol}' is not associated with a syntax node of type '{type.Name}'"); - } - - private static IEnumerable GetBaseTypes_Internal(INamedTypeSymbol type, bool includeSelf) - { - if (includeSelf) - { - yield return type; - } - - if (type.TypeKind == TypeKind.Interface) - { - foreach (INamedTypeSymbol t in type.AllInterfaces) - { - yield return t; - } - - yield break; - } - - INamedTypeSymbol? currentType = type.BaseType; - - if (currentType is not null) - { - yield return currentType; - - while ((currentType = currentType!.BaseType) is not null) - { - yield return currentType; - } - } - } - - private static ISymbol? GetHiddenSymbol_Internal(ISymbol symbol) - { - return symbol.ContainingType - .GetAllMembers(symbol.Name) - .FirstOrDefault(member => member switch - { - INamedTypeSymbol type => type.Arity == 0, - IMethodSymbol method => method.Arity == 0, - IPropertySymbol property => !property.IsIndexer, - IFieldSymbol or IFieldSymbol => true, - _ => false - }); - } - - private static IEnumerable GetImplicitImplementations_Internal(T symbol) where T : ISymbol - { - return GetImplicitImplementations_Internal(symbol, intf => intf.GetMembers(symbol.Name)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReturnOrder GetNoReverseFlag(ReturnOrder currentOrder) - { - const ReturnOrder DEFAULT_FLAG = (ReturnOrder)(-1); - - return currentOrder == DEFAULT_FLAG ? (ReturnOrder)(-2) : DEFAULT_FLAG; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void PushReverse(ref ImmutableArray array, Stack stack) - { - for (int i = array.Length - 1; i > -1; i--) - { - stack.Push(array[i]); - } - } -} +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection.Metadata; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using Durian.Analysis.CodeGeneration; +using Durian.Analysis.Data; +using Durian.Analysis.Data.FromSource; +using Durian.Analysis.SymbolContainers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Durian.Analysis; + +/// +/// Contains various extension methods for the -derived interfaces. +/// +public static class SymbolExtensions +{ + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this INamedTypeSymbol type) + { + TypeSyntax syntax; + + if (type.IsGenericType) + { + List arguments = new(type.TypeArguments.Length); + + foreach (ITypeSymbol t in type.TypeArguments) + { + arguments.Add(t.CreateTypeSyntax()); + } + + syntax = SyntaxFactory.GenericName( + SyntaxFactory.Identifier(type.GetVerbatimName()), + SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(arguments))); + } + else if (type.GetPredefineTypeSyntax() is PredefinedTypeSyntax predefined) + { + syntax = predefined; + } + else + { + syntax = SyntaxFactory.IdentifierName(type.GetVerbatimName()); + } + + return ApplyAnnotation(syntax, NullableAnnotation.Annotated); + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this IArrayTypeSymbol type) + { + ITypeSymbol[] elementTypes = type.GetElementTypes().ToArray(); + TypeSyntax elementSyntax = elementTypes[0].CreateTypeSyntax(); + + List ranks = new(elementTypes.Length - 1); + + for (int i = 1; i < elementTypes.Length; i++) + { + IArrayTypeSymbol array = (IArrayTypeSymbol)elementTypes[i]; + ranks.Add(GetArrayRank(array)); + + if (array.NullableAnnotation == NullableAnnotation.Annotated) + { + elementSyntax = SyntaxFactory.NullableType(SyntaxFactory.ArrayType(elementSyntax, SyntaxFactory.List(ranks))); + ranks.Clear(); + } + } + + ranks.Add(GetArrayRank(type)); + + return ApplyAnnotation(SyntaxFactory.ArrayType(elementSyntax, SyntaxFactory.List(ranks)), type.NullableAnnotation); + + static ArrayRankSpecifierSyntax GetArrayRank(IArrayTypeSymbol array) + { + return SyntaxFactory.ArrayRankSpecifier(SyntaxFactory.SeparatedList( + array.Sizes.Select(s => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(s))))); + } + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this IFunctionPointerTypeSymbol functionPointer) + { + IMethodSymbol signature = functionPointer.Signature; + + FunctionPointerCallingConventionSyntax? callingConvention; + + if (signature.CallingConvention == SignatureCallingConvention.Unmanaged) + { + FunctionPointerUnmanagedCallingConventionListSyntax? list = signature.UnmanagedCallingConventionTypes.Length > 0 ? + SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(SyntaxFactory.SeparatedList(signature.UnmanagedCallingConventionTypes.Select(u => + SyntaxFactory.FunctionPointerUnmanagedCallingConvention(SyntaxFactory.Identifier(u.Name))))) + : default; + + callingConvention = SyntaxFactory.FunctionPointerCallingConvention(SyntaxFactory.Token(SyntaxKind.UnmanagedKeyword), list); + } + else + { + callingConvention = default; + } + + List parameters = new(signature.Parameters.Length + 1); + + foreach (IParameterSymbol parameter in signature.Parameters) + { + TypeSyntax parameterType = parameter.Type.CreateTypeSyntax(); + parameters.Add(GetParameterSyntax(parameterType, parameter.RefKind, false)); + } + + parameters.Add(GetParameterSyntax(signature.ReturnType.CreateTypeSyntax(), signature.RefKind, true)); + + return SyntaxFactory.FunctionPointerType(callingConvention, SyntaxFactory.FunctionPointerParameterList(SyntaxFactory.SeparatedList(parameters))); + + static FunctionPointerParameterSyntax GetParameterSyntax(TypeSyntax parameterType, RefKind refKind, bool allowRefReadonly) + { + switch (refKind) + { + case RefKind.None: + return SyntaxFactory.FunctionPointerParameter(parameterType); + + case RefKind.RefReadOnly: + + if (!allowRefReadonly) + { + goto default; + } + + return SyntaxFactory.FunctionPointerParameter(default, SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), parameterType); + + default: + SyntaxKind kind = refKind.GetSyntaxKind(); + return SyntaxFactory.FunctionPointerParameter(default, SyntaxFactory.TokenList(SyntaxFactory.Token(kind)), parameterType); + } + } + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this IDynamicTypeSymbol type) + { + return ApplyAnnotation(SyntaxFactory.IdentifierName("dynamic"), type.NullableAnnotation); + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this ITypeParameterSymbol typeParameter) + { + return ApplyAnnotation(SyntaxFactory.IdentifierName(typeParameter.GetVerbatimName()), typeParameter.NullableAnnotation); + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this IPointerTypeSymbol pointer) + { + return SyntaxFactory.PointerType(pointer.PointedAtType.CreateTypeSyntax()); + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this ITypeSymbol type) + { + return type switch + { + INamedTypeSymbol named => named.CreateTypeSyntax(), + IDynamicTypeSymbol dynamic => dynamic.CreateTypeSyntax(), + IArrayTypeSymbol array => array.CreateTypeSyntax(), + ITypeParameterSymbol typeParameter => typeParameter.CreateTypeSyntax(), + IPointerTypeSymbol pointer => pointer.CreateTypeSyntax(), + IFunctionPointerTypeSymbol functionPointer => functionPointer.CreateTypeSyntax(), + _ => ApplyAnnotation(SyntaxFactory.IdentifierName(type.GetVerbatimName()), type.NullableAnnotation), + }; + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this ISymbol symbol) + { + if (symbol is ITypeSymbol type) + { + return type.CreateTypeSyntax(); + } + + if (symbol is IMethodSymbol method) + { + return method.CreateTypeSyntax(); + } + + return SyntaxFactory.IdentifierName(symbol.GetVerbatimName()); + } + + /// + /// Creates a representing the specified . + /// + /// to get the for. + public static TypeSyntax CreateTypeSyntax(this IMethodSymbol method) + { + if (!method.IsGenericMethod) + { + return SyntaxFactory.IdentifierName(method.GetVerbatimName()); + } + + List arguments = new(method.TypeArguments.Length); + + foreach (ITypeSymbol type in method.TypeArguments) + { + arguments.Add(type.CreateTypeSyntax()); + } + + return SyntaxFactory.GenericName( + SyntaxFactory.Identifier(method.GetVerbatimName()), + SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(arguments))); + } + + /// + /// Returns the kind of accessor the specified represents. + /// + /// to get the accessor kind of. + public static AccessorKind GetAccessorKind(this IMethodSymbol method) + { + return method.MethodKind.GetAccessorKind(); + } + + /// + /// Returns a collection of all inner types of the specified . + /// + /// to get the inner types of. + /// Determines whether to include the in the returned collection if its a . + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetAllInnerTypes(this INamespaceOrTypeSymbol type, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ChildToParent); + + IEnumerable Yield() + { + const int CAPACITY = 32; + + if (includeSelf && type is INamedTypeSymbol named) + { + yield return named; + } + + ImmutableArray array = type.GetTypeMembers(); + + if (array.Length == 0) + { + yield break; + } + + Stack innerTypes = new(array.Length > CAPACITY ? array.Length : CAPACITY); + + PushReverse(ref array, innerTypes); + + while (innerTypes.Count > 0) + { + INamedTypeSymbol t = innerTypes.Pop(); + yield return t; + + array = t.GetTypeMembers(); + + if (array.Length == 0) + { + continue; + } + + PushReverse(ref array, innerTypes); + } + } + } + + /// + public static IReturnOrderEnumerable GetAllMembers(this INamedTypeSymbol type, ReturnOrder order = ReturnOrder.ParentToChild) + { + return GetBaseTypes_Internal(type, true).SelectMany(t => t.GetMembers()).OrderBy(order, ReturnOrder.ChildToParent); + } + + /// + /// Returns all members of the specified including the members that are declared in base types of this . + /// + /// to get the members of. + /// Name of the members to find. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetAllMembers(this INamedTypeSymbol type, string name, ReturnOrder order = ReturnOrder.ParentToChild) + { + return GetBaseTypes_Internal(type, true).SelectMany(t => t.GetMembers(name)).OrderBy(order, ReturnOrder.ChildToParent); + } + + /// + /// Returns an associated with the and defined on the specified . + /// + /// Target . + /// Type of attribute to look for. + /// The associated with the and defined on the specified . -or- if no such found. + public static AttributeData? GetAttribute(this ISymbol symbol, INamedTypeSymbol attrSymbol) + { + return symbol.GetAttributes() + .FirstOrDefault(attr => attrSymbol.IsEquivalentTo(attr.AttributeClass)); + } + + /// + /// Returns an associated with the defined on the specified . + /// + /// Target . + /// to get the data of. + /// The associated with the . -or- if no such found. + public static AttributeData? GetAttribute(this ISymbol symbol, AttributeSyntax syntax) + { + foreach (AttributeData attr in symbol.GetAttributes()) + { + SyntaxReference? reference = attr.ApplicationSyntaxReference; + + if (reference is null) + { + continue; + } + + if (reference.Span == syntax.Span) + { + return attr; + } + } + + return null; + } + + /// + /// Returns a collection of s associated with the and defined on the specified . + /// + /// Target . + /// Type of attributes to look for. + public static IEnumerable GetAttributes(this ISymbol symbol, INamedTypeSymbol attrSymbol) + { + foreach (AttributeData attr in symbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attrSymbol)) + { + yield return attr; + } + } + } + + /// + /// Returns the that is accessed by using the specified in the context of the given . + /// + /// to get the attribute target symbol of. + /// Kind of attribute target. + /// Note: In actual code the target applied to an event refers to both the and accessors. In such case, this method returns the event itself. + public static ISymbol? GetAttributeTarget(this ISymbol symbol, AttributeTarget target) + { + switch (target) + { + case AttributeTarget.Assembly: + return symbol as IAssemblySymbol; + + case AttributeTarget.Return: + { + if (symbol is IMethodSymbol method) + { + if (!method.IsConstructor() && method.MethodKind != MethodKind.Destructor) + { + return method.ReturnType; + } + } + else if (symbol is INamedTypeSymbol type) + { + if (type.DelegateInvokeMethod is not null) + { + return type.DelegateInvokeMethod.ReturnType; + } + } + + return default; + } + + case AttributeTarget.Field: + { + if (symbol is IPropertySymbol property) + { + if (property.GetBackingField() is IFieldSymbol backingField) + { + return backingField; + } + } + else if (symbol is IEventSymbol @event) + { + if (@event.GetBackingField() is IFieldSymbol backingField) + { + return backingField; + } + } + + return symbol as IFieldSymbol; + } + + case AttributeTarget.Method: + return symbol is IMethodSymbol or IEventSymbol ? symbol : default; + + case AttributeTarget.Property: + return symbol as IPropertySymbol; + + case AttributeTarget.Event: + return symbol as IEventSymbol; + + case AttributeTarget.Type: + return symbol as INamedTypeSymbol; + + case AttributeTarget.Param: + { + if (symbol is IMethodSymbol method && method.MethodKind is MethodKind.PropertySet or MethodKind.EventAdd or MethodKind.EventRemove) + { + return method.Parameters[0]; + } + + return symbol as IParameterSymbol; + } + + case AttributeTarget.Module: + return symbol as IModuleSymbol; + + case AttributeTarget.TypeVar: + return symbol as ITypeParameterSymbol; + + default: + return default; + } + } + + /// + /// Returns the that is accessed by using an attribute target if the specified in the context of the given . + /// + /// to get the attribute target symbol of. + /// Kind of attribute target. + /// Note: In actual code the target applied to an event refers to both the and accessors. In such case, this method returns the event itself. + public static ISymbol? GetAttributeTarget(this ISymbol symbol, AttributeTargetKind kind) + { + return symbol switch + { + IAssemblySymbol => ThisOrDefault(), + IFieldSymbol => ThisOrDefault(), + IMethodSymbol method => kind switch + { + AttributeTargetKind.This => method.SupportsAttributeTargets() ? method : default, + AttributeTargetKind.Value => method.SupportsAlternativeAttributeTargets() ? method.ReturnType : default, + AttributeTargetKind.Handler when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => method.Parameters[0], + _ => default + }, + IPropertySymbol property => kind switch + { + AttributeTargetKind.This => property, + AttributeTargetKind.Value => property.GetBackingField(), + _ => default + }, + IEventSymbol @event => kind switch + { + AttributeTargetKind.This => @event, + AttributeTargetKind.Value => @event.GetBackingField(), + AttributeTargetKind.Handler when @event.IsFieldEvent() => @event, + _ => default + }, + INamedTypeSymbol type => kind switch + { + AttributeTargetKind.This => type, + AttributeTargetKind.Value when type.DelegateInvokeMethod is IMethodSymbol method => method.ReturnType, + _ => default + }, + IParameterSymbol => ThisOrDefault(), + ITypeParameterSymbol => ThisOrDefault(), + IModuleSymbol => ThisOrDefault(), + _ => default + }; + + ISymbol? ThisOrDefault() + { + return kind == AttributeTargetKind.This ? symbol : default; + } + } + + /// + /// Determines the kind of the specified attribute used in context of the given . + /// + /// to get the kind of attribute target of. + /// Attribute target to get the kind of. + public static AttributeTargetKind GetAttributeTargetKind(this ISymbol symbol, AttributeTarget target) + { + return target switch + { + AttributeTarget.Assembly => symbol is IAssemblySymbol ? AttributeTargetKind.This : default, + AttributeTarget.Field => symbol switch + { + IFieldSymbol => AttributeTargetKind.This, + IPropertySymbol property => property.IsAutoProperty() ? AttributeTargetKind.Value : default, + IEventSymbol @event when @event.IsFieldEvent() => AttributeTargetKind.Value, + _ => default + }, + AttributeTarget.Return => symbol switch + { + IMethodSymbol method => method.SupportsAlternativeAttributeTargets() ? AttributeTargetKind.Value : default, + INamedTypeSymbol type when type.SupportsAlternativeAttributeTargets() => AttributeTargetKind.Value, + _ => default + }, + AttributeTarget.Method => symbol switch + { + IMethodSymbol => AttributeTargetKind.This, + IEventSymbol @event when @event.IsFieldEvent() => AttributeTargetKind.Handler, + _ => default + }, + AttributeTarget.Property => symbol is IPropertySymbol ? AttributeTargetKind.This : default, + AttributeTarget.Event => symbol is IEventSymbol ? AttributeTargetKind.This : default, + AttributeTarget.Type => symbol is INamedTypeSymbol ? AttributeTargetKind.This : default, + AttributeTarget.Param => symbol switch + { + IParameterSymbol => AttributeTargetKind.This, + IMethodSymbol method when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => AttributeTargetKind.Handler, + _ => default + }, + AttributeTarget.TypeVar => symbol is ITypeParameterSymbol ? AttributeTargetKind.This : default, + AttributeTarget.Module => symbol is IModuleSymbol ? AttributeTargetKind.This : default, + _ => default + }; + } + + /// + /// Returns an attribute target keyword used to refer to the specified inside an attribute list. + /// + /// to get the associated attribute target keyword of. + /// Determines which keyword to return when there is more than one option (e.g '' and '' for methods). + public static AttributeTarget GetAttributeTargetKind(this ISymbol symbol, AttributeTargetKind kind = AttributeTargetKind.This) + { + return symbol switch + { + IAssemblySymbol => ThisOrDefault(AttributeTarget.Assembly), + IFieldSymbol => ThisOrDefault(AttributeTarget.Field), + IMethodSymbol method => kind switch + { + AttributeTargetKind.This => method.SupportsAttributeTargets() ? AttributeTarget.Method : default, + AttributeTargetKind.Value => method.SupportsAlternativeAttributeTargets() && method.MethodKind != MethodKind.PropertySet ? AttributeTarget.Return : default, + AttributeTargetKind.Handler when method.MethodKind == MethodKind.PropertySet || method.IsEventAccessor() => AttributeTarget.Param, + _ => default + }, + IPropertySymbol property => kind switch + { + AttributeTargetKind.This => AttributeTarget.Property, + AttributeTargetKind.Value when property.IsAutoProperty() => AttributeTarget.Field, + _ => default + }, + IEventSymbol @event => kind switch + { + AttributeTargetKind.This => AttributeTarget.Event, + AttributeTargetKind.Value => @event.IsFieldEvent() ? AttributeTarget.Field : default, + AttributeTargetKind.Handler when @event.IsFieldEvent() => AttributeTarget.Method, + _ => default + }, + INamedTypeSymbol type => kind switch + { + AttributeTargetKind.This => AttributeTarget.Type, + AttributeTargetKind.Value when type.SupportsAlternativeAttributeTargets() => AttributeTarget.Return, + _ => default + }, + IParameterSymbol => ThisOrDefault(AttributeTarget.Param), + ITypeParameterSymbol => ThisOrDefault(AttributeTarget.TypeVar), + IModuleSymbol => ThisOrDefault(AttributeTarget.Module), + _ => default, + }; + + AttributeTarget ThisOrDefault(AttributeTarget @this) + { + return kind == AttributeTargetKind.This ? @this : default; + } + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + /// Determines whether to return even if the is or . + public static AutoPropertyKind GetAutoPropertyKind(this IPropertySymbol property, bool includeAbstract = false) + { + if (includeAbstract) + { + if (property.GetMethod is null) + { + if (property.SetMethod is not null) + { + if (property.SetMethod.IsInitOnly) + { + return AutoPropertyKind.InitOnly; + } + + return AutoPropertyKind.SetOnly; + } + + return default; + } + } + else if (property.IsAbstract || property.IsExtern || !property.IsAutoProperty() || property.GetMethod is null) + { + return default; + } + + if (property.SetMethod is null) + { + return AutoPropertyKind.GetOnly; + } + + if (property.SetMethod.IsInitOnly) + { + return AutoPropertyKind.GetInit; + } + + return AutoPropertyKind.GetSet; + } + + /// + /// Returns the type of result of awaiting on the specified . + /// + /// to get the type of result of awaiting on. + public static ITypeSymbol? GetAwaitResult(this INamedTypeSymbol type) + { + bool hasIsCompleted = false; + bool hasGetResult = false; + + ITypeSymbol? resultType = default; + + if (!type.IsINotifyCompletion()) + { + foreach (IMethodSymbol method in type.GetAllMembers().OfType()) + { + if (method.IsGetAwaiterRaw(out INamedTypeSymbol? returnType) && HandleAwaiterType(type)) + { + return resultType; + } + } + + return default; + } + + List awaiters = new(); + + foreach (ISymbol symbol in type.GetAllMembers()) + { + bool? handleResultType = HandleResultType(symbol); + + if (handleResultType.HasValue) + { + if (handleResultType.Value) + { + return resultType; + } + } + else if (symbol is IMethodSymbol method && method.IsGetAwaiterRaw(out INamedTypeSymbol? awaiter)) + { + awaiters.Add(awaiter); + } + } + + foreach (INamedTypeSymbol awaiter in awaiters) + { + if (HandleAwaiterType(awaiter)) + { + return resultType; + } + } + + return default; + + bool HandleAwaiterType(INamedTypeSymbol type) + { + if (!type.IsINotifyCompletion()) + { + return false; + } + + resultType = default; + + hasIsCompleted = false; + hasGetResult = false; + + foreach (ISymbol symbol in type.GetAllMembers()) + { + bool? handleResultType = HandleResultType(symbol); + + if (handleResultType == true) + { + return true; + } + } + + return false; + } + + bool? HandleResultType(ISymbol symbol) + { + if (!hasIsCompleted && symbol.IsSpecialMember(SpecialMember.IsCompleted)) + { + if (hasGetResult) + { + return true; + } + + hasIsCompleted = true; + + return false; + } + else if (!hasGetResult && symbol.IsSpecialMember(SpecialMember.GetResult)) + { + IMethodSymbol method = (symbol as IMethodSymbol)!; + resultType = method.ReturnsVoid ? default : method.ReturnType; + + if (hasIsCompleted) + { + return true; + } + + hasGetResult = true; + + return false; + } + + return default; + } + } + + /// + /// Returns the backing field of the specified or if the is not auto-implemented. + /// + /// to get the backing field of. + public static IFieldSymbol? GetBackingField(this IPropertySymbol property) + { + if (property.IsIndexer || property.IsAbstract || property.IsExtern) + { + return default; + } + + return property.ContainingType? + .GetMembers() + .OfType() + .FirstOrDefault(f => SymbolEqualityComparer.Default.Equals(f.AssociatedSymbol, property)); + } + + /// + /// Returns the backing field of the specified or if the is not a field-like event. + /// + /// to get the backing field of. + public static IFieldSymbol? GetBackingField(this IEventSymbol @event) + { + return @event.ContainingType? + .GetMembers() + .OfType() + .FirstOrDefault(f => SymbolEqualityComparer.Default.Equals(f.AssociatedSymbol, @event)); + } + + /// + /// Returns the kind of the of the specified . + /// + /// to get the of. + public static BackingFieldKind GetBackingFieldKind(this IFieldSymbol field) + { + return field.AssociatedSymbol switch + { + IPropertySymbol => BackingFieldKind.Property, + IEventSymbol => BackingFieldKind.Event, + _ => default + }; + } + + /// + /// Returns the kind of the backing field of the specified . + /// + /// to get the kind of the backing field of. + public static BackingFieldKind GetBackingFieldKind(this ISymbol symbol) + { + return symbol switch + { + IFieldSymbol field => field.GetBackingFieldKind(), + IPropertySymbol => BackingFieldKind.Property, + IEventSymbol => BackingFieldKind.Event, + _ => default + }; + } + + /// + /// Returns all types the specified inherits from. + /// + /// to get the base types of. + /// Determines whether to include the in the returned collection. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetBaseTypes(this INamedTypeSymbol type, bool includeSelf = false, ReturnOrder order = ReturnOrder.ChildToParent) + { + return GetBaseTypes_Internal(type, includeSelf).OrderBy(order, ReturnOrder.ParentToChild); + } + + /// + /// Returns the compiler condition applied to the through the . + /// + /// to get the compiler condition of. + public static string? GetCompilerCondition(this IMethodSymbol method) + { + AttributeData? attribute = method.GetSpecialAttribute(SpecialAttribute.Conditional); + return attribute?.GetConstructorArgumentValue(0); + } + + /// + /// Returns the compiler condition applied to the through the . + /// + /// to get the compiler condition of. + public static string? GetCompilerCondition(this INamedTypeSymbol type) + { + AttributeData? attribute = type.GetSpecialAttribute(SpecialAttribute.Conditional); + return attribute?.GetConstructorArgumentValue(0); + } + + /// + /// Returns generic constraints applied to type parameters of the specified . + /// + /// to get the generic constraints of. + /// + /// If a is constrained to another , + /// determines whether to also include constraints of that 's base parameter. + /// + public static GenericConstraint[] GetConstraints(this IMethodSymbol method, bool includeParentParameters = false) + { + if (!method.IsGenericMethod) + { + return Array.Empty(); + } + + return method.TypeParameters.Select(p => p.GetConstraints(includeParentParameters)).ToArray(); + } + + /// + /// Returns generic constraints applied to type parameters of the specified . + /// + /// to get the generic constraints of. + /// + /// If a is constrained to another , + /// determines whether to also include constraints of that 's base parameter. + /// + public static GenericConstraint[] GetConstraints(this INamedTypeSymbol type, bool includeParentParameters = false) + { + if (!type.IsGenericType) + { + return Array.Empty(); + } + + return type.TypeParameters.Select(p => p.GetConstraints(includeParentParameters)).ToArray(); + } + + /// + /// Returns generic constraints applied to the specified . + /// + /// to get the generic constraint of. + /// + /// If the is constrained to another , + /// determines whether to also include constraints of the 's base parameter. + /// + public static GenericConstraint GetConstraints(this ITypeParameterSymbol parameter, bool includeParentParameter = false) + { + GenericConstraint constraint = default; + + if (parameter.HasReferenceTypeConstraint) + { + constraint |= GenericConstraint.Class; + } + + if (parameter.HasValueTypeConstraint) + { + constraint |= GenericConstraint.Struct; + } + + if (parameter.HasUnmanagedTypeConstraint) + { + constraint |= GenericConstraint.Unmanaged; + } + + if (parameter.HasConstructorConstraint) + { + constraint |= GenericConstraint.New; + } + + if (parameter.HasNotNullConstraint) + { + constraint |= GenericConstraint.NotNull; + } + + if (parameter.ConstraintTypes.Length > 0) + { + constraint |= GenericConstraint.Type; + + if (includeParentParameter && parameter.ConstraintTypes.FirstOrDefault(p => p.TypeKind == TypeKind.TypeParameter) is ITypeParameterSymbol baseParameter) + { + constraint |= baseParameter.GetConstraints(true); + } + } + + return constraint; + } + + /// + /// Returns value representing special kind of the specified . + /// + /// to get the special constructor kind of. + public static SpecialConstructor GetConstructorKind(this IMethodSymbol method) + { + if (method.MethodKind == MethodKind.StaticConstructor) + { + return SpecialConstructor.Static; + } + + if (method.IsVararg) + { + return default; + } + + if (method.Parameters.Length == 0) + { + return method.IsImplicitlyDeclared ? SpecialConstructor.Default : SpecialConstructor.Parameterless; + } + + if (method.Parameters.Length == 1 && method.Parameters[0].RefKind == RefKind.None && SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, method.ContainingType)) + { + return SpecialConstructor.Copy; + } + + return default; + } + + /// + /// Returns all s that contain the target . + /// + /// to get the parent namespaces of. + /// Determines whether to return the global namespace as well. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetContainingNamespaces(this ISymbol symbol, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + IEnumerable namespaces = Yield(symbol); + + if (!includeGlobal) + { + namespaces = namespaces.Where(n => !n.IsGlobalNamespace); + } + + return namespaces.OrderBy(order, ReturnOrder.ParentToChild); + + static IEnumerable Yield(ISymbol symbol) + { + INamespaceSymbol parent = symbol.ContainingNamespace; + + if (parent is not null) + { + yield return parent; + + while ((parent = parent!.ContainingNamespace) is not null) + { + yield return parent; + } + } + } + } + + /// + /// Returns all s contain the target in namespace-first order. + /// + /// to get the parent types and namespaces of. + /// Determines whether to return the global namespace as well + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetContainingNamespacesAndTypes(this ISymbol symbol, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + IEnumerable first; + IEnumerable second; + + if (order == ReturnOrder.ParentToChild) + { + first = symbol.GetContainingNamespaces(includeGlobal, order); + second = symbol.GetContainingTypes(false, order); + } + else + { + first = symbol.GetContainingTypes(false, order); + second = symbol.GetContainingNamespaces(includeGlobal, order); + } + + return first.Concat(second).OrderBy(order, GetNoReverseFlag(order)); + } + + /// + /// Returns all s that contain the target . + /// + /// to get the parent types of. + /// Determines whether to include the in the returned collection if its a . + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetContainingTypes(this ISymbol symbol, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield(symbol, includeSelf).OrderBy(order, ReturnOrder.ParentToChild); + + static IEnumerable Yield(ISymbol symbol, bool includeSelf) + { + if (includeSelf && symbol is INamedTypeSymbol t) + { + yield return t; + } + + INamedTypeSymbol parent = symbol.ContainingType; + + if (parent is not null) + { + yield return parent; + + while ((parent = parent!.ContainingType) is not null) + { + yield return parent; + } + } + } + } + + /// + /// Returns the custom offset applied to the field through a or -1 if no custom offset applied. + /// + /// to get the custom offset of. + public static int GetCustomOffset(this IFieldSymbol field) + { + AttributeData? attribute = field.GetSpecialAttribute(SpecialAttribute.FieldOffset); + + if (attribute is null) + { + return -1; + } + + return attribute.TryGetConstructorArgumentValue(0, out int value) ? value : -1; + } + + /// + /// Returns a keyword used to declare the specified (e.g. , ). + /// + /// to get the keyword of. + public static string? GetDeclaredKeyword(this ISymbol symbol) + { + return symbol switch + { + INamedTypeSymbol type => type.GetDeclaredKeyword(), + IEventSymbol => "event", + IMethodSymbol method when method.IsOperator() => "operator", + _ => default + }; + } + + /// + /// Returns a keyword used to declare the specified (e.g. , ). + /// + /// to get the keyword of. + /// Determines whether to include the keyword for record classes. + public static string? GetDeclaredKeyword(this INamedTypeSymbol type, bool includeSecondary = false) + { + return type.TypeKind switch + { + TypeKind.Class => type.IsRecord ? (includeSecondary ? "record class" : "record") : "class", + TypeKind.Struct => type.IsRecord ? "record struct" : "struct", + TypeKind.Interface => "interface", + TypeKind.Enum => "enum", + TypeKind.Delegate => "delegate", + _ => default + }; + } + + /// + /// Returns the default in the context of the specified , that is: + /// + /// For top-level types: . + /// For interface members other than partial methods: . + /// For property/event accessors: accessibility of the parent property/event. + /// For all other members: . + /// + /// + /// to get the default accessibility of. + /// Determines whether accessibility of an associated member of the (e.g. parent property of an accessor) should be treated as default. + public static Accessibility GetDefaultAccessibility(this ISymbol symbol, bool includeAssociated = true) + { + if (symbol.IsTopLevel()) + { + return Accessibility.Internal; + } + + if (symbol.ContainingSymbol is INamedTypeSymbol type && type.TypeKind == TypeKind.Interface) + { + if (symbol is IMethodSymbol intfMethod && intfMethod.IsPartial(true)) + { + return Accessibility.Private; + } + + return Accessibility.Public; + } + + if (includeAssociated && symbol is IMethodSymbol method && method.IsAccessor()) + { + return method.AssociatedSymbol!.DeclaredAccessibility; + } + + return Accessibility.Private; + } + + /// + /// Returns all interface members that have default implementations. + /// + /// of an interface to get the default implementations of. + /// Determines whether to also include default implementations from the implemented interfaces. + public static IEnumerable GetDefaultImplementations(this INamedTypeSymbol type, bool baseInterfaces = false) + { + if (type.TypeKind != TypeKind.Interface) + { + return Array.Empty(); + } + + IEnumerable members = baseInterfaces + ? type.GetAllMembers() + : type.GetMembers(); + + return members.Where(m => m.IsDefaultImplementation()); + } + + /// + /// Returns the effective of the specified . + /// + /// to get the effective of. + public static Accessibility GetEffectiveAccessibility(this ISymbol symbol) + { + ISymbol? s = symbol; + Accessibility lowest = Accessibility.Public; + + while (s is not null) + { + Accessibility current = s.DeclaredAccessibility; + + if (current == Accessibility.Private) + { + return current; + } + + if (current != Accessibility.NotApplicable && current < lowest) + { + lowest = current; + } + + s = s.ContainingSymbol; + } + + return lowest; + } + + /// + /// Returns the effective underlaying element type of the specified . + /// + /// to get the effective underlaying type of. + public static ITypeSymbol? GetEffectiveElementType(this ITypeSymbol type) + { + return type switch + { + IArrayTypeSymbol array => array.GetEffectiveElementType(), + IPointerTypeSymbol pointer => pointer.GetEffectiveElementType(), + _ => type.GetNullableUnderlayingType() is ITypeSymbol nullable ? nullable : default, + }; + } + + /// + /// Returns the effective underlaying element type of the . + /// + /// to get the effective underlaying type of. + public static ITypeSymbol GetEffectiveElementType(this IArrayTypeSymbol array) + { + return array.GetEffectiveElementType(out _); + } + + /// + /// Returns the effective underlaying element type of the . + /// + /// to get the effective underlaying type of. + /// Number of inner s (including the itself). + public static ITypeSymbol GetEffectiveElementType(this IArrayTypeSymbol array, out int nestingLevel) + { + int count = 0; + ITypeSymbol? a = array; + + while (a is IArrayTypeSymbol t) + { + a = t.ElementType; + count++; + } + + nestingLevel = count; + return a; + } + + /// + /// Returns the effective underlaying type the . + /// + /// to get the effective underlaying type of. + public static ITypeSymbol GetEffectiveElementType(this IPointerTypeSymbol pointer) + { + return pointer.GetEffectiveElementType(out _); + } + + /// + /// Returns the effective underlaying type the . + /// + /// to get the effective underlaying type of. + /// Number of inner s (including the itself). + public static ITypeSymbol GetEffectiveElementType(this IPointerTypeSymbol pointer, out int nestingLevel) + { + ITypeSymbol? p = pointer; + int count = 0; + + while (p is IPointerTypeSymbol t) + { + p = t.PointedAtType; + count++; + } + + nestingLevel = count; + return p; + } + + /// + /// Returns all underlaying element types of the specified . + /// + /// to get the element types of. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetElementTypes(this IArrayTypeSymbol array, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ChildToParent); + + IEnumerable Yield() + { + ITypeSymbol element = array.ElementType; + + yield return element; + + while (element is IArrayTypeSymbol array) + { + yield return array.ElementType; + element = array.ElementType; + } + } + } + + /// + /// Returns all underlaying element types of the specified . + /// + /// to get the element types of. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetElementTypes(this IPointerTypeSymbol pointer, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ChildToParent); + + IEnumerable Yield() + { + ITypeSymbol element = pointer.PointedAtType; + + yield return element; + + while (element is IPointerTypeSymbol pointer) + { + yield return pointer.PointedAtType; + element = pointer.PointedAtType; + } + } + } + + /// + /// Returns a representing a C# keyword associated with the of the specified . + /// + /// to get the keyword associated with. + public static TypeKeyword GetEnumUnderlayingTypeKeyword(this INamedTypeSymbol type) + { + return type.EnumUnderlyingType?.GetTypeKeywordKind() ?? default; + } + + /// + /// Returns formatted name of the specified . + /// + /// to get the formatted name of. + /// format to apply. + public static string GetFormattedName(this ISymbol symbol, SymbolName format) + { + CodeBuilder builder = new(false); + builder.Name(symbol, format); + return builder.ToString(); + } + + /// + /// Returns fully qualified name of the specified . + /// + /// to get the fully qualified name of. + /// Determines format of the returned qualified name. + public static string GetFullyQualifiedName(this ISymbol symbol, QualifiedName format = default) + { + if (format == QualifiedName.Metadata) + { + return symbol.ToString(); + } + + CodeBuilder builder = new(false); + builder.QualifiedName(symbol); + string value = builder.ToString(); + + if (format == QualifiedName.Xml) + { + return AnalysisUtilities.ToXmlCompatible(value); + } + + return value; + } + + /// + /// Returns a containing generic identifier of the specified or name of the if it is not an or . + /// + /// to get the generic name of. + /// Determines whether to use type arguments instead of type parameters. + public static string GetGenericName(this ISymbol symbol, bool substituted = false) + { + CodeBuilder builder = new(false); + builder.Name(symbol, substituted ? SymbolName.Substituted : SymbolName.Generic); + return builder.ToString(); + } + + /// + /// Returns a containing generic identifier of the specified . + /// + /// to get the generic name of. + /// Determines whether to use type arguments instead of type parameters. + public static string GetGenericName(this IMethodSymbol method, bool substituted = false) + { + CodeBuilder builder = new(false); + builder.Name(method, substituted ? SymbolName.Substituted : SymbolName.Generic); + return builder.ToString(); + } + + /// + /// Returns a containing generic identifier of the specified . + /// + /// to get the generic name of. + /// Determines whether to use type arguments instead of type parameters. + public static string GetGenericName(this INamedTypeSymbol type, bool substituted = false) + { + CodeBuilder builder = new(false); + builder.Name(type, substituted ? SymbolName.Substituted : SymbolName.Generic); + return builder.ToString(); + } + + /// + /// Returns a containing the generic part of an identifier created from the collection of . + /// + /// Type parameters. + /// Determines whether to include variance of the . + /// Pointers can't be used as generic arguments. + public static string GetGenericName(this IEnumerable typeParameters, bool includeVariance = false) + { + return typeParameters.GetGenericName(null, includeVariance); + } + + /// + /// Returns a containing generic identifier combined of the specified and the collection of . + /// + /// Type parameters. + /// Actual member identifier. + /// Determines whether to include variance of the . + public static string GetGenericName(this IEnumerable typeParameters, string? name, bool includeVariance = false) + { + if (includeVariance) + { + return AnalysisUtilities.GetGenericName(typeParameters.Select(p => + { + if (p.Variance == VarianceKind.Out || p.Variance == VarianceKind.In) + { + return $"{p.Variance.ToString().ToLower()} {p.GetVerbatimName()}"; + } + + return p.GetVerbatimName(); + }), + name); + } + + return AnalysisUtilities.GetGenericName(typeParameters.Select(p => p.GetVerbatimName()), name); + } + + /// + /// Returns a containing the generic part of an identifier created from the collection of . + /// + /// Type arguments. + public static string GetGenericName(this IEnumerable typeArguments) + { + CodeBuilder builder = new(false); + builder.TypeArgumentList(typeArguments); + return builder.ToString(); + } + + /// + /// Returns a containing generic identifier combined of the specified and the collection of . + /// + /// Type arguments. + /// Actual member identifier. + public static string GetGenericName(this IEnumerable typeArguments, string? name) + { + CodeBuilder builder = new(false); + + if (!string.IsNullOrWhiteSpace(name)) + { + builder.Write(name!); + } + + builder.TypeArgumentList(typeArguments); + return builder.ToString(); + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this ISymbol symbol) + { + return symbol switch + { + INamedTypeSymbol type => type.GetHiddenSymbol(), + IMethodSymbol method => method.GetHiddenSymbol(), + IPropertySymbol property => property.GetHiddenSymbol(), + IFieldSymbol field => field.GetHiddenSymbol(), + IEventSymbol @event => @event.GetHiddenSymbol(), + _ => default + }; + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this IMethodSymbol method) + { + if (method.MethodKind != MethodKind.Ordinary || method.ContainingType is null) + { + return default; + } + + if (method.Arity == 0) + { + return method.ContainingType + .GetAllMembers(method.Name) + .FirstOrDefault(member => member switch + { + INamedTypeSymbol type => type.Arity == 0, + IMethodSymbol other => method.CanHideSymbol(other), + IPropertySymbol property => !property.IsIndexer, + IFieldSymbol or IFieldSymbol => true, + _ => false + }); + } + + return method.ContainingType + .GetAllMembers(method.Name) + .FirstOrDefault(member => member switch + { + INamedTypeSymbol type => type.Arity == method.Arity, + IMethodSymbol other => method.CanHideSymbol(other), + _ => false + }); + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this INamedTypeSymbol type) + { + if (type.ContainingType is null || !type.IsDeclarationKind()) + { + return default; + } + + if (type.Arity == 0) + { + return GetHiddenSymbol_Internal(type); + } + + return type.ContainingType + .GetAllMembers(type.GetVerbatimName()) + .FirstOrDefault(member => member switch + { + INamedTypeSymbol other => other.Arity == type.Arity, + IMethodSymbol method => method.Arity == type.Arity, + _ => false + }); + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this IPropertySymbol property) + { + if (property.ContainingType is null) + { + return default; + } + + if (property.IsIndexer) + { + return property.ContainingType + .GetAllMembers() + .OfType() + .FirstOrDefault(p => p.IsIndexer && SymbolFacts.ParametersAreEquivalent(property.Parameters, p.Parameters)); + } + + return GetHiddenSymbol_Internal(property); + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this IFieldSymbol field) + { + if (field.ContainingType is null) + { + return default; + } + + return GetHiddenSymbol_Internal(field); + } + + /// + /// Returns the hidden by the specified using the keyword. + /// + /// to get the symbol hidden by. + public static ISymbol? GetHiddenSymbol(this IEventSymbol @event) + { + if (@event.ContainingType is null) + { + return default; + } + + return @event.ContainingType + .GetAllMembers(@event.GetVerbatimName()) + .FirstOrDefault(member => member switch + { + INamedTypeSymbol type => type.Arity == 0, + IMethodSymbol method => method.Arity == 0, + IPropertySymbol property => !property.IsIndexer, + IFieldSymbol or IEventSymbol => true, + _ => false + }); + } + + /// + /// Returns a collection of all s implicitly implemented by the specified . + /// + /// to get the implicitly implemented s of. + public static IEnumerable GetImplicitImplementations(this ISymbol symbol) + { + return symbol switch + { + IMethodSymbol method => method.GetImplicitImplementations(), + IPropertySymbol property => property.GetImplicitImplementations(), + IEventSymbol @event => @event.GetImplicitImplementations(), + INamedTypeSymbol type => type.GetImplicitImplementations(), + _ => Array.Empty() + }; + } + + /// + /// Returns a collection of all s implicitly implemented by the specified . + /// + /// to get the implicitly implemented s by. + public static IEnumerable GetImplicitImplementations(this IPropertySymbol property) + { + if (property.IsImplementedExplicitly()) + { + return Array.Empty(); + } + + return GetImplicitImplementations_Internal(property); + } + + /// + /// Returns a collection of all s implicitly implemented by the specified . + /// + /// to get the implicitly implemented s by. + public static IEnumerable GetImplicitImplementations(this IMethodSymbol method) + { + if (method.IsImplementedExplicitly()) + { + return Array.Empty(); + } + + return GetImplicitImplementations_Internal(method); + } + + /// + /// Returns a collection of all s implicitly implemented by the specified . + /// + /// to get the implicitly implemented s by. + public static IEnumerable GetImplicitImplementations(this IEventSymbol @event) + { + if (@event.IsImplementedExplicitly()) + { + return Array.Empty(); + } + + return GetImplicitImplementations_Internal(@event); + } + + /// + /// Returns a collection of all s implicitly implemented by the specified . + /// + /// to get the implicitly implemented s by. + public static IEnumerable GetImplicitImplementations(this INamedTypeSymbol type) + { + return type.AllInterfaces + .SelectMany(m => m.GetMembers()) + .Where(m => type.FindImplementationForInterfaceMember(m) is not null); + } + + /// + /// Returns a collection of all s of the given implicitly implemented by the specified . + /// + /// to get the implicitly implemented s by. + /// to get the implicitly implemented s of. + public static IEnumerable GetImplicitImplementations(this INamedTypeSymbol type, INamedTypeSymbol @interface) + { + return @interface.GetMembers() + .Where(m => type.FindImplementationForInterfaceMember(m) is not null); + } + + /// + /// Creates an <inheritdoc/> tag from the specified . + /// + /// to get the <inheritdoc/> tag from. + /// Determines whether to return the <inheritdoc/> event if it cannot be referenced by other symbols. + /// A containing the created <inheritdoc/> tag -or- if has no documentation comment. + public static string? GetInheritdocIfHasDocumentation(this ISymbol symbol, bool forceUnsupported = false) + { + if (forceUnsupported) + { + if (!symbol.HasDocumentation()) + { + return default; + } + } + else if (!symbol.HasInheritableDocumentation()) + { + return default; + } + + CodeBuilder builder = new(false); + + foreach (INamedTypeSymbol type in symbol.GetContainingTypes()) + { + builder.XmlName(type); + builder.Write('.'); + } + + builder.XmlName(symbol); + + return AutoGenerated.GetInheritdoc(builder.ToString()); + } + + /// + /// Returns a collection of all local functions of the specified . + /// + /// to get the local functions of. + /// Determines whether to include the itself. + /// Determines whether to include nested local functions. + /// Specifies ordering of the returned members. + public static IEnumerable GetLocalFunctions(this IMethodSymbol method, bool includeSelf = false, bool includeNested = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + IEnumerable collection; + + if (includeNested) + { + collection = GetFuncs(method); + } + else + { + collection = GetNested(); + } + + if (includeSelf) + { + collection = new[] { method }.Concat(collection); + } + + return GetNested().OrderBy(order, ReturnOrder.ChildToParent); + + IEnumerable GetFuncs(IMethodSymbol method) + { + return method.ContainingType + .GetMembers() + .OfType() + .Where(m => m.MethodKind == MethodKind.LocalFunction && SymbolEqualityComparer.Default.Equals(method, m.ContainingSymbol)); + } + + IEnumerable GetNested() + { + const int CAPACITY = 8; + + ImmutableArray array = GetFuncs(method).ToImmutableArray(); + + if (array.Length == 0) + { + yield break; + } + + Stack subs = new(array.Length > CAPACITY ? array.Length : CAPACITY); + + PushReverse(ref array, subs); + + while (subs.Count > 0) + { + IMethodSymbol local = subs.Pop(); + yield return local; + + array = GetFuncs(local).ToImmutableArray(); + + if (array.Length == 0) + { + continue; + } + + PushReverse(ref array, subs); + } + } + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this ISymbol symbol) + { + return symbol switch + { + INamedTypeSymbol type => type.GetModifiers(), + IMethodSymbol method => method.GetModifiers(), + IPropertySymbol property => property.GetModifiers(), + IFieldSymbol field => field.GetModifiers(), + IEventSymbol @event => @event.GetModifiers(), + _ => Array.Empty() + }; + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this IFieldSymbol field) + { + List modifiers = new(4); + + AddAccessibilityModifiers(modifiers, field.DeclaredAccessibility); + + if (field.IsConst) + { + modifiers.Add("const"); + } + else if (field.IsStatic) + { + modifiers.Add("static"); + } + + if (field.IsReadOnly) + { + modifiers.Add("readonly"); + } + + if (field.IsUnsafe()) + { + modifiers.Add("unsafe"); + } + + if (field.IsVolatile) + { + modifiers.Add("volatile"); + } + + if (field.IsFixedSizeBuffer) + { + modifiers.Add("fixed"); + } + + return modifiers.ToArray(); + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this ILocalSymbol local) + { + List modifiers = new(2); + + if (local.IsConst) + { + modifiers.Add("const"); + } + + switch (local.RefKind) + { + case RefKind.Ref: + modifiers.Add("ref"); + break; + + case RefKind.RefReadOnly: + modifiers.Add("ref"); + modifiers.Add("readonly"); + break; + } + + return modifiers.ToArray(); + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this IParameterSymbol parameter) + { + List modifiers = new(2); + + if (parameter.IsThis) + { + modifiers.Add("this"); + } + + if (parameter.RefKind.GetText() is string refKind) + { + modifiers.Add(refKind); + } + + if (parameter.IsParams) + { + modifiers.Add("params"); + } + + return modifiers.ToArray(); + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this IPropertySymbol property) + { + List modifiers = new(8); + + AddAccessibilityModifiers(modifiers, property.DeclaredAccessibility); + AddBasicMethodModifiers(modifiers, property); + + if (property.IsReadOnly) + { + CheckAccessor(property.GetMethod); + } + else if (property.IsWriteOnly) + { + CheckAccessor(property.SetMethod); + } + else if (property.IsReadOnlyContext()) + { + modifiers.Add("readonly"); + } + + if (property.IsUnsafe()) + { + modifiers.Add("unsafe"); + } + + return modifiers.ToArray(); + + void CheckAccessor(IMethodSymbol? accessor) + { + if (accessor is not null && accessor.IsReadOnly) + { + modifiers.Add("readonly"); + } + } + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this IEventSymbol @event) + { + List modifiers = new(8); + + AddAccessibilityModifiers(modifiers, @event.DeclaredAccessibility); + AddBasicMethodModifiers(modifiers, @event); + + if (@event.IsReadOnlyContext()) + { + modifiers.Add("readonly"); + } + + if (@event.IsUnsafe()) + { + modifiers.Add("unsafe"); + } + + return modifiers.ToArray(); + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this IMethodSymbol method) + { + List modifiers = new(8); + + AddAccessibilityModifiers(modifiers, method.DeclaredAccessibility); + AddBasicMethodModifiers(modifiers, method); + + if (method.IsReadOnly) + { + modifiers.Add("readonly"); + } + + if (method.IsUnsafe()) + { + modifiers.Add("unsafe"); + } + + if (method.IsAsync) + { + modifiers.Add("async"); + } + + if (method.IsPartial(true)) + { + modifiers.Add("partial"); + } + + return modifiers.ToArray(); + } + + /// + /// Returns modifiers applied to the target . + /// + /// to get the modifiers of. + public static string[] GetModifiers(this INamedTypeSymbol type) + { + List modifiers = new(8); + + AddAccessibilityModifiers(modifiers, type.DeclaredAccessibility); + + if (type.IsStatic) + { + modifiers.Add("static"); + } + + if (type.IsNew()) + { + modifiers.Add("new"); + } + + if (type.IsAbstract) + { + modifiers.Add("abstract"); + } + else if (type.IsRefLikeType) + { + modifiers.Add("ref"); + } + else if (type.IsSealed) + { + modifiers.Add("sealed"); + } + + if (type.IsReadOnly) + { + modifiers.Add("readonly"); + } + + if (type.IsUnsafe()) + { + modifiers.Add("unsafe"); + } + + if (type.IsPartial()) + { + modifiers.Add("partial"); + } + + return modifiers.ToArray(); + } + + /// + /// Returns the defined on the specified that is of the given . + /// + /// to get the of. + /// to check for. + public static AttributeData? GetNullableAnnotationAttribute(this ISymbol symbol, NullableAnnotationAttribute attributeKind) + { + string? name = attributeKind.GetAttributeName(); + + if (name is null) + { + return default; + } + + string? @namespace = attributeKind.GetNamespaceName(); + + if (@namespace is null) + { + return default; + } + + return symbol.GetAttributes().FirstOrDefault(attr => + attr.AttributeClass is not null && + attr.AttributeClass.Name == name && + attr.AttributeClass.IsWithinNamespace(@namespace, @namespace != "System") + ); + } + + /// + /// Returns the kind of this represents. + /// + /// to get the kind of. + public static NullableAnnotationAttribute GetNullableAnnotationAttributeKind(this INamedTypeSymbol type) + { + return MapToNullableAnnotationAttribute(type.Name, toReturn => type.IsWithinNamespace("System.Diagnostics.CodeAnalysis", true) ? toReturn : default); + } + + /// + /// Returns the underlaying of a nullable . + /// + /// to get the underlaying of. + public static ITypeSymbol? GetNullableUnderlayingType(this ITypeSymbol type) + { + if (type.NullableAnnotation == NullableAnnotation.Annotated) + { + return type; + } + + if (type is not INamedTypeSymbol named || !named.IsValueType || named.ConstructedFrom is null || named.ConstructedFrom.SpecialType != SpecialType.System_Nullable_T) + { + return default; + } + + ImmutableArray arguments = named.TypeArguments; + + if (arguments.Length != 1) + { + return default; + } + + return arguments[0]; + } + + /// + /// Returns kind of operator this overloads. + /// + /// to get the kind of the overloaded operator. + public static OverloadableOperator GetOperatorKind(this IMethodSymbol method) + { + if (method.MethodKind != MethodKind.UserDefinedOperator && method.MethodKind != MethodKind.BuiltinOperator) + { + return default; + } + + return AnalysisUtilities.GetOperatorType(method.Name); + } + + /// + /// Returns text of operator this overloads. + /// + /// to get the kind of the overloaded operator. + public static string? GetOperatorToken(this IMethodSymbol method) + { + if (method.MethodKind != MethodKind.UserDefinedOperator && method.MethodKind != MethodKind.BuiltinOperator) + { + return default; + } + + return AnalysisUtilities.GetOperatorText(method.Name); + } + + /// + /// Returns collection of overloads of the specified . + /// + /// to get the overloads of. + /// Determines whether to also include inherited overloads. + /// Determines whether to also include methods with different arity than the . + public static IEnumerable GetOverloads(this IMethodSymbol method, bool includeInherited = true, bool ignoreArity = false) + { + if (method.MethodKind != MethodKind.Ordinary) + { + return Array.Empty(); + } + + IEnumerable overloads = method.ContainingType + .GetMembers(method.Name) + .OfType(); + + if (ignoreArity) + { + overloads = overloads.Where(m => method.Arity == m.Arity); + } + + if (!includeInherited || !method.ContainingType.HasExplicitBaseType()) + { + return overloads; + } + + IMethodSymbol[] array = overloads.ToArray(); + + List inheritedMethods = new(array.Length * 4); + List overrides = new(inheritedMethods.Count); + + inheritedMethods.Add(method); + + if (method.IsOverride) + { + overrides.Add(method); + } + + foreach (INamedTypeSymbol type in method.ContainingType.GetBaseTypes()) + { + // These two values allow to skip methods that were added to the lists during this loop pass. + + int currentOverrideLength = overrides.Count; + int currentRegistryLength = inheritedMethods.Count; + + foreach (IMethodSymbol inheritedMethod in type.GetMembers(method.Name).OfType()) + { + if (!CheckVirtuality(inheritedMethod, currentOverrideLength, out bool addOverride)) + { + continue; + } + + if (!CheckNewModifier(inheritedMethod, currentRegistryLength)) + { + continue; + } + + inheritedMethods.Add(inheritedMethod); + + if (addOverride) + { + overrides.Add(inheritedMethod); + } + } + } + + return overloads.Concat(inheritedMethods); + + bool CheckVirtuality(IMethodSymbol inheritedMethod, int length, out bool addOverride) + { + Virtuality virtuality = inheritedMethod.GetVirtuality(); + + switch (virtuality) + { + case Virtuality.Sealed: + addOverride = true; + break; + + case Virtuality.Abstract: + case Virtuality.Virtual: + + for (int i = 0; i < length; i++) + { + if (SymbolEqualityComparer.Default.Equals(overrides[i], inheritedMethod)) + { + addOverride = false; + return false; + } + } + + break; + } + + addOverride = false; + return true; + } + + bool CheckNewModifier(IMethodSymbol inheritedMethod, int length) + { + for (int i = 0; i < length; i++) + { + IMethodSymbol registered = inheritedMethods[i]; + + if (registered.CanHideSymbol_Internal(inheritedMethod, ignoreArity)) + { + return false; + } + } + + return true; + } + } + + /// + /// Returns the overridden by the specified . + /// + /// to get the symbol overridden by. + public static ISymbol? GetOverriddenSymbol(this ISymbol symbol) + { + return symbol switch + { + IMethodSymbol method => method.OverriddenMethod, + IPropertySymbol property => property.OverriddenProperty, + IEventSymbol @event => @event.OverriddenEvent, + _ => default + }; + } + + /// + /// Returns all s overridden by the specified . + /// + /// to get the methods overridden by. + public static IEnumerable GetOverriddenSymbols(this IMethodSymbol method) + { + IMethodSymbol? m = method; + + while ((m = m!.OverriddenMethod) is not null) + { + yield return m; + } + } + + /// + /// Returns all s overridden by the specified . + /// + /// to get the properties overridden by. + public static IEnumerable GetOverriddenSymbols(this IPropertySymbol property) + { + IPropertySymbol? p = property; + + while ((p = p!.OverriddenProperty) is not null) + { + yield return p; + } + } + + /// + /// Returns all s overridden by the specified . + /// + /// to get the events overridden by. + public static IEnumerable GetOverriddenSymbols(this IEventSymbol @event) + { + IEventSymbol? e = @event; + + while ((e = e!.OverriddenEvent) is not null) + { + yield return e; + } + } + + /// + /// Returns all s overridden by the specified . + /// + /// to get the symbols overridden by. + public static IEnumerable GetOverriddenSymbols(this ISymbol symbol) + { + return symbol switch + { + IMethodSymbol method => method.GetOverriddenSymbols(), + IPropertySymbol property => property.GetOverriddenSymbols(), + IEventSymbol @event => @event.GetOverriddenSymbols(), + _ => Array.Empty() + }; + } + + /// + /// Returns all es of the specified . + /// + /// to get the es of. + /// that specifies if the operation should be canceled. + public static IEnumerable GetPartialDeclarations(this INamedTypeSymbol type, CancellationToken cancellationToken = default) where T : TypeDeclarationSyntax + { + return type.DeclaringSyntaxReferences.Select(e => e.GetSyntax(cancellationToken)).OfType(); + } + + /// + /// Returns a if the specified is a keyword type, otherwise. + /// + /// to get the for. + public static PredefinedTypeSyntax? GetPredefineTypeSyntax(this INamedTypeSymbol type) + { + if (type.SpecialType == SpecialType.None) + { + return default; + } + + SyntaxKind kind = type.SpecialType.GetSyntaxKind(); + + if (kind == default) + { + return default; + } + + return SyntaxFactory.PredefinedType(SyntaxFactory.Token(kind)); + } + + /// + /// Returns the primary constructor of the specified . + /// + /// to get the primary constructor of. + public static IMethodSymbol? GetPrimaryConstructor(this INamedTypeSymbol type) + { + return type.InstanceConstructors.FirstOrDefault(ctor => ctor.IsPrimaryConstructor()); + } + + /// + /// Returns a created from the specified . + /// + /// A collection of s to create the from. + /// A created by combining the . -or- if there were less then 2 provided. + public static QualifiedNameSyntax? GetQualifiedName(this IEnumerable namespaces) + { + return AnalysisUtilities.GetQualifiedName(namespaces.Select(n => n.GetVerbatimName())); + } + + /// + /// Returns all struct members with the modifier applied. + /// + /// to get all members with the modifier applied. + /// If the is not a , empty collection is returned. + public static IEnumerable GetReadOnlyMembers(this INamedTypeSymbol type) + { + if (type.TypeKind != TypeKind.Struct) + { + return Array.Empty(); + } + + return type + .GetMembers() + .Where(m => m.IsReadOnly()); + } + + /// + /// Returns root namespace of the (excluding the global namespace). + /// + /// to get the root namespaces of. + /// The root -or- if root was not found. + public static INamespaceSymbol? GetRootNamespace(this ISymbol symbol) + { + return GetContainingNamespaces(symbol).FirstOrDefault(); + } + + /// + /// Returns the defined on the specified that is of the given . + /// + /// to get the of. + /// to check for. + public static AttributeData? GetSpecialAttribute(this ISymbol symbol, SpecialAttribute attributeKind) + { + string? name = attributeKind.GetAttributeName(); + + if (name is null) + { + return default; + } + + string? @namespace = attributeKind.GetNamespaceName(); + + if (@namespace is null) + { + return default; + } + + return symbol.GetAttributes().FirstOrDefault(attr => + attr.AttributeClass is not null && + attr.AttributeClass.Name == name && + attr.AttributeClass.IsWithinNamespace(@namespace, @namespace != "System") + ); + } + + /// + /// Returns the kind of this represents. + /// + /// to get the kind of. + public static SpecialAttribute GetSpecialAttributeKind(this INamedTypeSymbol type) + { + if (!type.Name.EndsWith("Attribute")) + { + return default; + } + + return MapToSpecialAttribute(type.Name, (@namespace, toReturn) => type.IsWithinNamespace(@namespace, @namespace.Length > 6) ? toReturn : default); + } + + /// + /// Returns an representing the given kind of special constructor available from the specified . + /// + /// to get the special member from. + /// Kind of special constructor to return. + public static IMethodSymbol? GetSpecialConstructor(this INamedTypeSymbol type, SpecialConstructor kind) + { + return kind switch + { + SpecialConstructor.Static => type.StaticConstructors.FirstOrDefault(), + SpecialConstructor.None => default, + SpecialConstructor.Parameterless => type.InstanceConstructors.FirstOrDefault(ctor => ctor.GetConstructorKind() is SpecialConstructor.Parameterless or SpecialConstructor.Default), + _ => type.InstanceConstructors.FirstOrDefault(ctor => ctor.GetConstructorKind() == kind), + }; + } + + /// + /// Returns an representing the given kind of available from the specified . + /// + /// to get the special member from. + /// Kind of special member to return. + public static ISymbol? GetSpecialMember(this INamedTypeSymbol type, SpecialMember specialMember) + { + return type.GetAllMembers().FirstOrDefault(member => member.IsSpecialMember(specialMember)); + } + + /// + /// Returns all sub-namespaces of the specified . + /// + /// to get the sub-namespaces of. + /// Determines whether to include the global namespace in the returned collection. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetSubNamespaces(this IAssemblySymbol assembly, bool includeGlobal = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + return assembly.GlobalNamespace.GetSubNamespaces(includeGlobal, order); + } + + /// + /// Returns all sub-namespaces of the specified . + /// + /// to get the sub-namespaces of. + /// Determines whether to also include the itself in the collection. + /// Specifies ordering of the returned members. + public static IReturnOrderEnumerable GetSubNamespaces(this INamespaceSymbol @namespace, bool includeSelf = false, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ParentToChild); + + IEnumerable Yield() + { + const int CAPACITY = 32; + + if (includeSelf) + { + yield return @namespace; + } + + ImmutableArray array = @namespace.GetNamespaceMembers().ToImmutableArray(); + + if (array.Length == 0) + { + yield break; + } + + Stack subs = new(array.Length > CAPACITY ? array.Length : CAPACITY); + + PushReverse(ref array, subs); + + while (subs.Count > 0) + { + INamespaceSymbol t = subs.Pop(); + yield return t; + + array = t.GetNamespaceMembers().ToImmutableArray(); + + if (array.Length == 0) + { + continue; + } + + PushReverse(ref array, subs); + } + } + } + + /// + /// Returns a of type associated with the specified . + /// + /// Type of to return. + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a syntax node of type . + public static T GetSyntax(this ISymbol symbol, CancellationToken cancellationToken = default) where T : SyntaxNode + { + if (!symbol.TryGetSyntax(out T? declaration, cancellationToken)) + { + throw Exc_SymbolNotAssociatedWithNode(symbol, typeof(T)); + } + + return declaration; + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static BaseMethodDeclarationSyntax GetSyntax(this IMethodSymbol method, CancellationToken cancellationToken = default) + { + return method.GetSyntax(cancellationToken); + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static BaseTypeDeclarationSyntax GetSyntax(this INamedTypeSymbol type, CancellationToken cancellationToken = default) + { + return type.GetSyntax(cancellationToken); + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static ParameterSyntax GetSyntax(this IParameterSymbol parameter, CancellationToken cancellationToken = default) + { + return parameter.GetSyntax(cancellationToken); + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static TypeParameterSyntax GetSyntax(this ITypeParameterSymbol parameter, CancellationToken cancellationToken = default) + { + return parameter.GetSyntax(cancellationToken); + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static EventFieldDeclarationSyntax GetSyntax(this IEventSymbol @event, CancellationToken cancellationToken = default) + { + if (!@event.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not EventFieldDeclarationSyntax decl) + { + throw Exc_SymbolNotAssociatedWithNode(@event, typeof(EventFieldDeclarationSyntax)); + } + + return decl; + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static FieldDeclarationSyntax GetSyntax(this IFieldSymbol field, CancellationToken cancellationToken = default) + { + if (!field.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not FieldDeclarationSyntax decl) + { + throw Exc_SymbolNotAssociatedWithNode(field, typeof(FieldDeclarationSyntax)); + } + + return decl; + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static LocalDeclarationStatementSyntax GetSyntax(this ILocalSymbol local, CancellationToken cancellationToken = default) + { + if (!local.TryGetSyntax(out VariableDeclaratorSyntax? syntax, cancellationToken) || syntax.Parent?.Parent is not LocalDeclarationStatementSyntax decl) + { + throw Exc_SymbolNotAssociatedWithNode(local, typeof(LocalDeclarationStatementSyntax)); + } + + return decl; + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static BasePropertyDeclarationSyntax GetSyntax(this IPropertySymbol property, CancellationToken cancellationToken = default) + { + return property.GetSyntax(cancellationToken); + } + + /// + /// Returns a associated with the specified . + /// + /// to get the associated with. + /// that specifies if the operation should be canceled. + /// is not associated with a . + public static LabeledStatementSyntax GetSyntax(this ILabelSymbol label, CancellationToken cancellationToken = default) + { + return label.GetSyntax(cancellationToken); + } + + /// + /// Returns a representation of a C# keyword associated with the specified . + /// + /// to get the keyword associated with. + public static string? GetTypeKeyword(this ITypeSymbol type) + { + if (type is IDynamicTypeSymbol) + { + return "dynamic"; + } + + return type.SpecialType.GetKeywordText(); + } + + /// + /// Returns a representing a C# keyword associated with the specified . + /// + /// to get the keyword associated with. + public static TypeKeyword GetTypeKeywordKind(this ITypeSymbol type) + { + if (type is IDynamicTypeSymbol) + { + return TypeKeyword.Dynamic; + } + + return type.SpecialType.GetKeyword(); + } + + /// + /// Returns a new build for the specified symbol. + /// + /// to built the from. + public static UsingDirectiveSyntax GetUsingDirective(this INamespaceSymbol @namespace) + { + NameSyntax name; + + if (@namespace.GetContainingNamespaces().GetQualifiedName() is QualifiedNameSyntax q) + { + name = q; + } + else + { + name = SyntaxFactory.IdentifierName(@namespace.GetVerbatimName()); + } + + return SyntaxFactory.UsingDirective(name); + } + + /// + /// Returns a new build for the specified symbol. + /// + /// A collection of s to build the from. + /// cannot be empty. + public static UsingDirectiveSyntax GetUsingDirective(this IEnumerable namespaces) + { + NameSyntax name; + + if (namespaces.GetQualifiedName() is QualifiedNameSyntax q) + { + name = q; + } + else if (namespaces.FirstOrDefault() is INamespaceSymbol first) + { + name = SyntaxFactory.IdentifierName(first.GetVerbatimName()); + } + else + { + throw new ArgumentException($"'{nameof(namespaces)}' cannot be empty"); + } + + return SyntaxFactory.UsingDirective(name); + } + + /// + /// Returns name of the with a verbatim identifier '@' token applied if necessary. + /// + /// to get the effective name of. + public static string GetVerbatimName(this ISymbol symbol) + { + string value = symbol.Name; + AnalysisUtilities.ApplyVerbatimIfNecessary(ref value); + return value; + } + + /// + /// Returns the of the specified . + /// + /// to get the virtuality of. + public static Virtuality GetVirtuality(this ISymbol symbol) + { + if (symbol.IsAbstract) + { + return Virtuality.Abstract; + } + + if (symbol.IsOverride) + { + if (symbol.IsSealed) + { + return Virtuality.Sealed; + } + + return Virtuality.Virtual; + } + + if (symbol.IsVirtual) + { + return Virtuality.Virtual; + } + + return default; + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// Invalid type kind. + /// is . -or- is . + public static IMemberData ToData(this ITypeSymbol type, ICompilationData compilation, MemberData.Properties? properties = default) + { + switch (type) + { + case INamedTypeSymbol named: + return named.ToData(compilation, properties); + + case ITypeParameterSymbol typeParameter: + return typeParameter.ToData(compilation, properties); + + default: + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + throw new ArgumentException($"Invalid type kind: '{type.TypeKind}'", nameof(type)); + } + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// Invalid type kind. + /// is . -or- is . + public static ITypeData ToData(this INamedTypeSymbol type, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + if (type.IsRecord) + { + return new RecordData(type, compilation, properties); + } + + return type.TypeKind switch + { + TypeKind.Class => new ClassData(type, compilation, properties), + TypeKind.Struct => new StructData(type, compilation, properties), + TypeKind.Interface => new InterfaceData(type, compilation, properties), + TypeKind.Delegate => new DelegateData(type, compilation, properties), + TypeKind.Enum => new EnumData(type, compilation, properties), + _ => throw new ArgumentException($"Unknown type kind: '{type.TypeKind}'", nameof(type)) + }; + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// Invalid method kind. + /// is . -or- is . + public static IMethodData ToData(this IMethodSymbol method, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (method is null) + { + throw new ArgumentNullException(nameof(method)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return method.MethodKind switch + { + MethodKind.Ordinary => new MethodData(method, compilation, properties), + MethodKind.UserDefinedOperator => new OperatorData(method, compilation, properties), + MethodKind.Constructor or MethodKind.StaticConstructor => new ConstructorData(method, compilation, properties), + MethodKind.Destructor => new DestructorData(method, compilation, properties), + MethodKind.LocalFunction => new LocalFunctionData(method, compilation, properties), + MethodKind.Conversion => new ConversionOperatorData(method, compilation, properties), + MethodKind.AnonymousFunction => new LambdaData(method, compilation, properties), + _ => method.IsAccessor() + ? new AccessorData(method, compilation, properties) + : throw new ArgumentException($"Unknown method kind: '{method.MethodKind}'", nameof(method)) + }; + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static IFieldData ToData(this IFieldSymbol field, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (field is null) + { + throw new ArgumentNullException(nameof(field)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new FieldData(field, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static IEventData ToData(this IEventSymbol @event, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (@event is null) + { + throw new ArgumentNullException(nameof(@event)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new EventData(@event, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static IPropertyData ToData(this IPropertySymbol property, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (property is null) + { + throw new ArgumentNullException(nameof(property)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + if (property.IsIndexer) + { + return new IndexerData(property, compilation); + } + + return new PropertyData(property, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static ILocalData ToData(this ILocalSymbol local, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (local is null) + { + throw new ArgumentNullException(nameof(local)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new LocalData(local, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static ITypeParameterData ToData(this ITypeParameterSymbol typeParameter, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (typeParameter is null) + { + throw new ArgumentNullException(nameof(typeParameter)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new TypeParameterData(typeParameter, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static IParameterData ToData(this IParameterSymbol parameter, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (parameter is null) + { + throw new ArgumentNullException(nameof(parameter)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new ParameterData(parameter, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// Invalid type kind. + /// is . -or- is . + public static INamespaceOrTypeData ToData(this INamespaceOrTypeSymbol symbol, ICompilationData compilation, MemberData.Properties? properties = default) + { + switch (symbol) + { + case INamespaceSymbol @namespace: + return @namespace.ToData(compilation, properties); + + case INamedTypeSymbol type: + return type.ToData(compilation, properties); + + default: + + if (symbol is null) + { + throw new ArgumentNullException(nameof(symbol)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + if (symbol is not ITypeParameterSymbol) + { + throw new ArgumentException("Invalid type kind", nameof(symbol)); + } + + return new NamespaceOrTypeData(symbol, compilation, properties); + } + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// Invalid type kind. + /// is . -or- is . + public static IMemberData ToData(this ISymbol symbol, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return symbol switch + { + ITypeParameterSymbol typeParameter => typeParameter.ToData(compilation, properties), + INamedTypeSymbol type => type.ToData(compilation, properties), + IMethodSymbol method => method.ToData(compilation, properties), + IPropertySymbol property => property.ToData(compilation, properties), + IFieldSymbol field => field.ToData(compilation, properties), + IEventSymbol @event => @event.ToData(compilation, properties), + IParameterSymbol parameter => parameter.ToData(compilation, properties), + INamespaceSymbol @namespace => @namespace.ToData(compilation, properties), + ILocalSymbol local => local.ToData(compilation, properties), + ITypeSymbol unknownType => throw new ArgumentException($"Invalid type kind: '{unknownType.TypeKind}'", nameof(symbol)), + INamespaceOrTypeSymbol namespaceOrType => namespaceOrType.ToData(compilation, properties), + null => throw new ArgumentNullException(nameof(symbol)), + _ => new MemberData(symbol, compilation, properties) + }; + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// to use for the current instance. + /// is . -or- is . + public static INamespaceData ToData(this INamespaceSymbol @namespace, ICompilationData compilation, MemberData.Properties? properties = default) + { + if (@namespace is null) + { + throw new ArgumentNullException(nameof(@namespace)); + } + + if (compilation is null) + { + throw new ArgumentNullException(nameof(compilation)); + } + + return new NamespaceData(@namespace, compilation, properties); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Invalid type kind. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ISymbol symbol, ICompilationData? compilation = default) + { + return symbol switch + { + ITypeParameterSymbol typeParameter => typeParameter.ToDataOrSymbol(compilation), + INamedTypeSymbol type => type.ToDataOrSymbol(compilation), + IMethodSymbol method => method.ToDataOrSymbol(compilation), + IPropertySymbol property => property.ToDataOrSymbol(compilation), + IFieldSymbol field => field.ToDataOrSymbol(compilation), + IEventSymbol @event => @event.ToDataOrSymbol(compilation), + IParameterSymbol parameter => parameter.ToDataOrSymbol(compilation), + INamespaceSymbol @namespace => @namespace.ToDataOrSymbol(compilation), + ILocalSymbol local => local.ToDataOrSymbol(compilation), + ITypeSymbol unknownType => throw new ArgumentException($"Invalid type kind: '{unknownType.TypeKind}'", nameof(symbol)), + INamespaceOrTypeSymbol namespaceOrType => namespaceOrType.ToDataOrSymbol(compilation), + null => throw new ArgumentNullException(nameof(symbol)), + _ => new SymbolOrMemberWrapper(symbol, compilation) + }; + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ITypeSymbol type, ICompilationData? compilation = default) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + return new SymbolOrMemberWrapper(type, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ITypeSymbol type, ICompilationData? compilation = default) where TData : class, IMemberData + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + return new SymbolOrMemberWrapper(type, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamespaceSymbol @namespace, ICompilationData? compilation = default) + { + if (@namespace is null) + { + throw new ArgumentNullException(nameof(@namespace)); + } + + return new SymbolOrMemberWrapper(@namespace, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamespaceSymbol @namespace, ICompilationData? compilation = default) where TData : class, INamespaceData + { + if (@namespace is null) + { + throw new ArgumentNullException(nameof(@namespace)); + } + + return new SymbolOrMemberWrapper(@namespace, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamedTypeSymbol type, ICompilationData? compilation = default) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + return new SymbolOrMemberWrapper(type, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamedTypeSymbol type, ICompilationData? compilation = default) where TData : class, ITypeData + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + return new SymbolOrMemberWrapper(type, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamespaceOrTypeSymbol symbol, ICompilationData? compilation = default) + { + if (symbol is null) + { + throw new ArgumentNullException(nameof(symbol)); + } + + return new SymbolOrMemberWrapper(symbol, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this INamespaceOrTypeSymbol symbol, ICompilationData? compilation = default) where TData : class, INamespaceOrTypeData + { + if (symbol is null) + { + throw new ArgumentNullException(nameof(symbol)); + } + + return new SymbolOrMemberWrapper(symbol, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IParameterSymbol parameter, ICompilationData? compilation = default) + { + if (parameter is null) + { + throw new ArgumentNullException(nameof(parameter)); + } + + return new SymbolOrMemberWrapper(parameter, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IParameterSymbol parameter, ICompilationData? compilation = default) where TData : class, IParameterData + { + if (parameter is null) + { + throw new ArgumentNullException(nameof(parameter)); + } + + return new SymbolOrMemberWrapper(parameter, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IMethodSymbol method, ICompilationData? compilation = default) + { + if (method is null) + { + throw new ArgumentNullException(nameof(method)); + } + + return new SymbolOrMemberWrapper(method, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IMethodSymbol method, ICompilationData? compilation = default) where TData : class, IMethodData + { + if (method is null) + { + throw new ArgumentNullException(nameof(method)); + } + + return new SymbolOrMemberWrapper(method, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ITypeParameterSymbol typeParameter, ICompilationData? compilation = default) + { + if (typeParameter is null) + { + throw new ArgumentNullException(nameof(typeParameter)); + } + + return new SymbolOrMemberWrapper(typeParameter, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ITypeParameterSymbol typeParameter, ICompilationData? compilation = default) where TData : class, ITypeParameterData + { + if (typeParameter is null) + { + throw new ArgumentNullException(nameof(typeParameter)); + } + + return new SymbolOrMemberWrapper(typeParameter, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IEventSymbol @event, ICompilationData? compilation = default) + { + if (@event is null) + { + throw new ArgumentNullException(nameof(@event)); + } + + return new SymbolOrMemberWrapper(@event, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IEventSymbol @event, ICompilationData? compilation = default) where TData : class, IEventData + { + if (@event is null) + { + throw new ArgumentNullException(nameof(@event)); + } + + return new SymbolOrMemberWrapper(@event, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IFieldSymbol field, ICompilationData? compilation = default) + { + if (field is null) + { + throw new ArgumentNullException(nameof(field)); + } + + return new SymbolOrMemberWrapper(field, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IFieldSymbol field, ICompilationData? compilation = default) where TData : class, IFieldData + { + if (field is null) + { + throw new ArgumentNullException(nameof(field)); + } + + return new SymbolOrMemberWrapper(field, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IPropertySymbol property, ICompilationData? compilation = default) + { + if (property is null) + { + throw new ArgumentNullException(nameof(property)); + } + + return new SymbolOrMemberWrapper(property, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this IPropertySymbol property, ICompilationData? compilation = default) where TData : class, IPropertyData + { + if (property is null) + { + throw new ArgumentNullException(nameof(property)); + } + + return new SymbolOrMemberWrapper(property, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ILocalSymbol local, ICompilationData? compilation = default) + { + if (local is null) + { + throw new ArgumentNullException(nameof(local)); + } + + return new SymbolOrMemberWrapper(local, compilation); + } + + /// + /// Returns new created for the specified . + /// + /// to create the for. + /// to create the from. + /// Type of returned data. + /// is . + public static ISymbolOrMember ToDataOrSymbol(this ILocalSymbol local, ICompilationData? compilation = default) where TData : class, ILocalData + { + if (local is null) + { + throw new ArgumentNullException(nameof(local)); + } + + return new SymbolOrMemberWrapper(local, compilation); + } + + /// + /// Attempts to return a of type associated with the specified . + /// + /// Type of to return. + /// to get the associated with. + /// associated with the specified . + /// that specifies if the operation should be canceled. + public static bool TryGetSyntax(this ISymbol symbol, [NotNullWhen(true)] out T? syntax, CancellationToken cancellationToken = default) where T : SyntaxNode + { + SyntaxNode? node = symbol.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(cancellationToken); + syntax = node as T; + return syntax is not null; + } + + [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.", Justification = "")] + internal static IEnumerable GetImplicitImplementations_Internal(T symbol, Func> memberFunction) where T : ISymbol + { + if (symbol.DeclaredAccessibility != Accessibility.Public) + { + return Array.Empty(); + } + + return symbol.ContainingType.AllInterfaces + .SelectMany(memberFunction) + .OfType() + .Where(m => + { + ISymbol? s = symbol.ContainingType.FindImplementationForInterfaceMember(m); + + if (s is not T t || t.IsImplementedExplicitly()) + { + return false; + } + + return SymbolEqualityComparer.Default.Equals(t, symbol); + }); + } + + [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.")] + internal static NullableAnnotationAttribute MapToNullableAnnotationAttribute(string name, Func function) + { + return name switch + { + "AllowNullAttribute" => function(NullableAnnotationAttribute.AllowNull), + "DisallowNullAttribute" => function(NullableAnnotationAttribute.DisallowNull), + "MaybeNullAttribute" => function(NullableAnnotationAttribute.MaybeNull), + "NotNullAttribute" => function(NullableAnnotationAttribute.NotNull), + "NotNullWhenAttribute" => function(NullableAnnotationAttribute.NotNullWhen), + "NotNullIfNotNullAttribute" => function(NullableAnnotationAttribute.NotNullIfNotNull), + "MemberNotNullAttribute" => function(NullableAnnotationAttribute.MemberNotNull), + "MemberNotNullWhenAttribute" => function(NullableAnnotationAttribute.MemberNotNullWhen), + _ => default + }; + } + + [SuppressMessage("Roslynator", "RCS1224:Make method an extension method.")] + internal static SpecialAttribute MapToSpecialAttribute(string name, Func function) + { + return name switch + { + "ObsoleteAttribute" => function("System", SpecialAttribute.Obsolete), + "AttributeUsageAttribute" => function("System", SpecialAttribute.AttributeUsage), + "FlagsAttribute" => function("System", SpecialAttribute.Flags), + "CLSCompliantAttribute" => function("System", SpecialAttribute.CLSCompliant), + "ThreadStaticAttribute" => function("System", SpecialAttribute.ThreadStatic), + "ConditionalAttribute" => function("System.Diagnostics", SpecialAttribute.Conditional), + "StructLayoutAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.StructLayout), + "MarhsalAsAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.MarshalAs), + "DllImportAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.DllImport), + "FieldOffsetAttribute" => function("System.Runtime.InteropServices", SpecialAttribute.FieldOffset), + "MethodImplAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.MethodImpl), + "SkipLocalsInitAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.SkipLocalsInit), + "CallerFilePathAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerFilePath), + "CallerLineNumberAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerLineNumber), + "CallerMemberNameAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerMemberName), + "CallerArgumentExpressionAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.CallerArgumentExpression), + "ModuleInitializerAttribute" => function("System.Runtime.CompilerServices", SpecialAttribute.ModuleInitializer), + "DoesNotReturnAttribute" => function("System.Diagnostics.CodeAnalysis", SpecialAttribute.DoesNotReturn), + "DoesNotReturnIfAttribute" => function("System.Diagnostics.CodeAnalysis", SpecialAttribute.DoesNotReturnIf), + "GeneratedCodeAttribute" => function("System.CodeDom.Compiler", SpecialAttribute.GeneratedCode), + _ => default + }; + } + + internal static IReturnOrderEnumerable OrderBy(this IEnumerable collection, ReturnOrder order, ReturnOrder reverseIfThis) + { + if (order == reverseIfThis) + { + collection = collection.Reverse(); + } + + return new ReturnOrderEnumerable(collection, order); + } + + private static void AddAccessibilityModifiers(List modifiers, Accessibility accessibility) + { + switch (accessibility) + { + case Accessibility.Public: + modifiers.Add("public"); + break; + + case Accessibility.Private: + modifiers.Add("private"); + break; + + case Accessibility.Protected: + modifiers.Add("protected"); + break; + + case Accessibility.Internal: + modifiers.Add("internal"); + break; + + case Accessibility.ProtectedOrInternal: + modifiers.Add("protected"); + modifiers.Add("internal"); + break; + + case Accessibility.ProtectedAndInternal: + modifiers.Add("private"); + modifiers.Add("protected"); + break; + } + } + + private static void AddBasicMethodModifiers(List modifiers, ISymbol symbol) + { + if (symbol.IsStatic) + { + modifiers.Add("static"); + } + + if (symbol.IsExtern) + { + modifiers.Add("extern"); + } + + if (symbol.IsNew()) + { + modifiers.Add("new"); + } + + if (symbol.IsAbstract) + { + modifiers.Add("abstract"); + } + else if (symbol.IsSealed) + { + modifiers.Add("sealed"); + } + else if (symbol.IsVirtual) + { + modifiers.Add("virtual"); + } + + if (symbol.IsOverride) + { + modifiers.Add("override"); + } + } + + private static TypeSyntax ApplyAnnotation(TypeSyntax syntax, NullableAnnotation annotation) + { + if (annotation == NullableAnnotation.Annotated) + { + return SyntaxFactory.NullableType(syntax); + } + + return syntax; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static InvalidOperationException Exc_SymbolNotAssociatedWithNode(ISymbol symbol, Type type) + { + return new InvalidOperationException($"Method '{symbol}' is not associated with a syntax node of type '{type.Name}'"); + } + + private static IEnumerable GetBaseTypes_Internal(INamedTypeSymbol type, bool includeSelf) + { + if (includeSelf) + { + yield return type; + } + + if (type.TypeKind == TypeKind.Interface) + { + foreach (INamedTypeSymbol t in type.AllInterfaces) + { + yield return t; + } + + yield break; + } + + INamedTypeSymbol? currentType = type.BaseType; + + if (currentType is not null) + { + yield return currentType; + + while ((currentType = currentType!.BaseType) is not null) + { + yield return currentType; + } + } + } + + private static ISymbol? GetHiddenSymbol_Internal(ISymbol symbol) + { + return symbol.ContainingType + .GetAllMembers(symbol.Name) + .FirstOrDefault(member => member switch + { + INamedTypeSymbol type => type.Arity == 0, + IMethodSymbol method => method.Arity == 0, + IPropertySymbol property => !property.IsIndexer, + IFieldSymbol or IFieldSymbol => true, + _ => false + }); + } + + private static IEnumerable GetImplicitImplementations_Internal(T symbol) where T : ISymbol + { + return GetImplicitImplementations_Internal(symbol, intf => intf.GetMembers(symbol.Name)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ReturnOrder GetNoReverseFlag(ReturnOrder currentOrder) + { + const ReturnOrder DEFAULT_FLAG = (ReturnOrder)(-1); + + return currentOrder == DEFAULT_FLAG ? (ReturnOrder)(-2) : DEFAULT_FLAG; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void PushReverse(ref ImmutableArray array, Stack stack) + { + for (int i = array.Length - 1; i > -1; i--) + { + stack.Push(array[i]); + } + } +} diff --git a/src/Durian.AnalysisServices/Extensions/SymbolFacts.cs b/src/Durian.AnalysisServices/SymbolFacts.cs similarity index 96% rename from src/Durian.AnalysisServices/Extensions/SymbolFacts.cs rename to src/Durian.AnalysisServices/SymbolFacts.cs index 0226428..c83483d 100644 --- a/src/Durian.AnalysisServices/Extensions/SymbolFacts.cs +++ b/src/Durian.AnalysisServices/SymbolFacts.cs @@ -17,7 +17,7 @@ #endif -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains methods that determine state and properties is a given . @@ -433,7 +433,7 @@ public static bool ContainsSymbol(this ISymbol parent, ISymbol child) while (current is not null) { - if (SymbolEqualityComparer.Default.Equals(current, parent)) + if (current.IsEquivalentTo(parent)) { return true; } @@ -451,7 +451,7 @@ public static bool ContainsSymbol(this ISymbol parent, ISymbol child) /// to check if is used by the target . public static bool HandlesTypeParameter(this ITypeSymbol type, ITypeParameterSymbol typeParameter) { - if (SymbolEqualityComparer.Default.Equals(type, typeParameter)) + if (type.IsEquivalentTo(typeParameter)) { return true; } @@ -471,7 +471,7 @@ public static bool HandlesTypeParameter(this ITypeSymbol type, ITypeParameterSym return false; } - if (SymbolEqualityComparer.Default.Equals(symbol, typeParameter)) + if (symbol.IsEquivalentTo(typeParameter)) { return true; } @@ -821,7 +821,7 @@ public static bool ImplementsExplicitly(this INamedTypeSymbol type, ISymbol symb /// to determine whether is explicitly implemented by the . public static bool ImplementsExplicitly(this IMethodSymbol method, IMethodSymbol other) { - return method.ExplicitInterfaceImplementations.Any(ex => SymbolEqualityComparer.Default.Equals(ex, other)); + return method.ExplicitInterfaceImplementations.Any(ex => ex.IsEquivalentTo(other)); } /// @@ -849,7 +849,7 @@ public static bool ImplementsExplicitly(this INamedTypeSymbol type, IMethodSymbo /// to determine whether is explicitly implemented by the . public static bool ImplementsExplicitly(this IPropertySymbol property, IPropertySymbol other) { - return property.ExplicitInterfaceImplementations.Any(ex => SymbolEqualityComparer.Default.Equals(ex, other)); + return property.ExplicitInterfaceImplementations.Any(ex => ex.IsEquivalentTo(other)); } /// @@ -877,7 +877,7 @@ public static bool ImplementsExplicitly(this INamedTypeSymbol type, IPropertySym /// to determine whether is explicitly implemented by the . public static bool ImplementsExplicitly(this IEventSymbol @event, IEventSymbol other) { - return @event.ExplicitInterfaceImplementations.Any(ex => SymbolEqualityComparer.Default.Equals(ex, other)); + return @event.ExplicitInterfaceImplementations.Any(ex => ex.IsEquivalentTo(other)); } /// @@ -950,7 +950,7 @@ public static bool ImplementsImplicitly(this IMethodSymbol method, IMethodSymbol return false; } - return SymbolEqualityComparer.Default.Equals(method, m); + return method.IsEquivalentTo(m); } /// @@ -987,7 +987,7 @@ public static bool ImplementsImplicitly(this IPropertySymbol property, IProperty return false; } - return SymbolEqualityComparer.Default.Equals(property, prop); + return property.IsEquivalentTo(prop); } /// @@ -1053,7 +1053,7 @@ public static bool Inherits(this ITypeSymbol type, ITypeSymbol baseType) while (current is not null) { - if (SymbolEqualityComparer.Default.Equals(current, baseType)) + if (current.IsEquivalentTo(baseType)) { return true; } @@ -1749,6 +1749,88 @@ public static bool IsGeneric(this ISymbol symbol) }; } + /// + /// Determines whether the specified is an . + /// + /// Symbol to check. + public static bool IsInterface(this ISymbol symbol) + { + return symbol is ITypeSymbol type && type.IsInterface(); + } + + /// + /// Determines whether the specified is an . + /// + /// Symbol to check. + public static bool IsInterface(this ITypeSymbol symbol) + { + return symbol.TypeKind == TypeKind.Interface; + } + + /// + /// Determines whether the specified is a . + /// + /// Symbol to check. + public static bool IsClass(this ISymbol symbol) + { + return symbol is ITypeSymbol type && type.IsClass(); + } + + /// + /// Determines whether the specified is a . + /// + /// Symbol to check. + public static bool IsClass(this ITypeSymbol symbol) + { + return symbol.TypeKind == TypeKind.Class; + } + + /// + /// Determines whether the specified is a . + /// + /// Symbol to check. + public static bool IsStaticClass(this ISymbol symbol) + { + return symbol is ITypeSymbol type && type.IsStaticClass(); + } + + /// + /// Determines whether the specified is a . + /// + /// Symbol to check. + public static bool IsStaticClass(this ITypeSymbol symbol) + { + return symbol.IsClass() && symbol.IsStatic; + } + + /// + /// Determines whether the specified is an . + /// + /// Symbol to check. + public static bool IsAbstractClass(this ISymbol symbol) + { + return symbol is ITypeSymbol type && type.IsAbstractClass(); + } + + /// + /// Determines whether the specified is an . + /// + /// Symbol to check. + public static bool IsAbstractClass(this ITypeSymbol symbol) + { + return symbol.IsClass() && symbol.IsAbstract; + } + + /// + /// Determines whether the specified s are equal according to . + /// + /// to compare. + /// to compare. + public static bool IsEquivalentTo(this ISymbol symbol, ISymbol? other) + { + return symbol.IsEquivalentTo(other); + } + /// /// Determines whether the specified is a variant of the symbol. /// @@ -1781,7 +1863,7 @@ bool IsSameOrConstructed(INamedTypeSymbol type) // type: IA // other: IA - if (SymbolEqualityComparer.Default.Equals(type, other)) + if (type.IsEquivalentTo(other)) { return true; } @@ -1823,7 +1905,7 @@ bool IsSameOrConstructed(INamedTypeSymbol type) default: - if (!SymbolEqualityComparer.Default.Equals(t, o)) + if (!t.IsEquivalentTo(o)) { return false; } @@ -2587,7 +2669,7 @@ symbol is IMethodSymbol method && /// Determines whether the specified has the modifier applied. /// /// to determine whether has the modifier applied. - public static bool IsStructReadOnly(this ISymbol symbol) + public static bool IsReadOnly(this ISymbol symbol) { return symbol switch { @@ -2595,6 +2677,7 @@ public static bool IsStructReadOnly(this ISymbol symbol) IPropertySymbol property => property.IsReadOnlyContext(), IEventSymbol @event => @event.IsReadOnlyContext(), IFieldSymbol field => field.IsReadOnly, + ITypeSymbol type => type.IsReadOnly, _ => false }; } @@ -2792,7 +2875,7 @@ public static bool IsWithinNamespace(this ISymbol symbol, string @namespace, boo /// to check if is overridden by the specified . public static bool Overrides(this IMethodSymbol method, IMethodSymbol other) { - if (SymbolEqualityComparer.Default.Equals(method, other)) + if (method.IsEquivalentTo(other)) { return false; } @@ -2801,7 +2884,7 @@ public static bool Overrides(this IMethodSymbol method, IMethodSymbol other) while (baseMethod is not null) { - if (SymbolEqualityComparer.Default.Equals(other, baseMethod)) + if (other.IsEquivalentTo(baseMethod)) { return true; } diff --git a/src/Durian.AnalysisServices/SymbolNameResolver.cs b/src/Durian.AnalysisServices/SymbolNameResolver.cs index aee0821..51fe91d 100644 --- a/src/Durian.AnalysisServices/SymbolNameResolver.cs +++ b/src/Durian.AnalysisServices/SymbolNameResolver.cs @@ -1,6 +1,5 @@ using System; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; namespace Durian.Analysis; diff --git a/src/Durian.AnalysisServices/Extensions/SyntaxNodeExtensions.cs b/src/Durian.AnalysisServices/SyntaxNodeExtensions.cs similarity index 97% rename from src/Durian.AnalysisServices/Extensions/SyntaxNodeExtensions.cs rename to src/Durian.AnalysisServices/SyntaxNodeExtensions.cs index 0907768..72dc1a1 100644 --- a/src/Durian.AnalysisServices/Extensions/SyntaxNodeExtensions.cs +++ b/src/Durian.AnalysisServices/SyntaxNodeExtensions.cs @@ -1,3447 +1,3447 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Durian.Analysis.CodeGeneration; -using Durian.Analysis.Data; -using Durian.Analysis.Data.FromSource; -using Durian.Analysis.SymbolContainers; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Durian.Analysis.Extensions; - -/// -/// Contains various extension methods for -derived classes. -/// -public static class SyntaxNodeExtensions -{ - /// - /// Builds a from the specified and adds it to the given . - /// - /// to add the using directive to. - /// to build the from. - public static CompilationUnitSyntax AddUsings(this CompilationUnitSyntax compilationUnit, INamespaceSymbol @namespace) - { - UsingDirectiveSyntax directive = @namespace.GetUsingDirective(); - string name = directive.NamespaceOrType.ToString(); - - if (compilationUnit.Usings.Any(u => u.NamespaceOrType.ToString() == name)) - { - return compilationUnit; - } - - return compilationUnit.AddUsings(directive); - } - - /// - /// Builds es from the specified and adds them to the given . - /// - /// to add the using directives to. - /// A collection of s to build the es from. - public static CompilationUnitSyntax AddUsings(this CompilationUnitSyntax compilationUnit, IEnumerable? namespaces) - { - HashSet usings = new(compilationUnit.Usings.Where(u => u.Alias is null).Select(u => u.NamespaceOrType.ToString())); - UsingDirectiveSyntax[] directives = namespaces - .Where(n => n.Name != string.Empty) - .Select(n => n.GetUsingDirective()) - .Where(n => usings.Add(n.NamespaceOrType.ToString())) - .ToArray(); - - if (directives.Length == 0) - { - return compilationUnit; - } - - return compilationUnit.AddUsings(directives); - } - - /// - /// Determines whether the specified can have accessibility modifiers applied. - /// - /// to determine can have accessibility modifiers applied. - public static bool CanApplyAccessibility(this SyntaxNode node) - { - return node switch - { - ConstructorDeclarationSyntax ctor => !ctor.IsStatic(), - - BaseMethodDeclarationSyntax or - BaseFieldDeclarationSyntax or - BasePropertyDeclarationSyntax or - DelegateDeclarationSyntax or - BaseTypeDeclarationSyntax - => true, - - AccessorDeclarationSyntax accessor => accessor.IsPropertyAccessor(), - - _ => default - }; - } - - /// - /// Gets the first node of type that matches the . - /// - /// Type of ancestor node to return. - /// to get the ancestor of. - /// Function that filters the ancestor nodes. - /// Determine whether to leave from structured trivia. - public static TNode? FirstAncestor(this SyntaxNode node, Func? predicate = default, bool ascendOutOfTrivia = true) where TNode : SyntaxNode - { - return node.Parent?.FirstAncestorOrSelf(predicate, ascendOutOfTrivia); - } - - /// - /// Gets the first node of type that matches the . - /// - /// Type of ancestor node to return. - /// Type of argument passed for each call to the . - /// to get the ancestor of. - /// Function that filters the ancestor nodes. - /// Argument to pass for each call. - /// Determine whether to leave from structured trivia. - public static TNode? FirstAncestor(this SyntaxNode node, Func predicate, TArg argument, bool ascendOutOfTrivia = true) where TNode : SyntaxNode - { - return node.Parent?.FirstAncestorOrSelf(predicate, argument, ascendOutOfTrivia); - } - - /// - /// Returns the of the specified . - /// - /// to get the accessibility of. - public static Accessibility GetAccessibility(this SyntaxNode node) - { - return node.GetModifiers().GetAccessibility(); - } - - /// - /// Returns the kind of the specified represents. - /// - /// to get the kind represented by. - public static AccessorKind GetAccessorKind(this AccessorDeclarationSyntax node) - { - return node.Keyword.GetAccessor(); - } - - /// - /// Returns attribute argument with the specified - /// or if no argument with the was found. - /// - /// to get the argument of. - /// Name of argument to get. - /// Determines whether to include arguments with colons in the search. - public static AttributeArgumentSyntax? GetArgument(this AttributeSyntax attribute, string argumentName, bool includeParameters = false) - { - if (attribute.ArgumentList is null) - { - return null; - } - - SeparatedSyntaxList arguments = attribute.ArgumentList.Arguments; - - if (!arguments.Any()) - { - return null; - } - - Func func; - - if (includeParameters) - { - func = arg => - { - if (arg.NameEquals is not null) - { - return arg.NameEquals.Name.Identifier.ValueText == argumentName; - } - - return arg.NameColon is not null && arg.NameColon.Name.Identifier.ValueText == argumentName; - }; - } - else - { - func = arg => arg.NameEquals is not null && arg.NameEquals.Name.Identifier.ValueText == argumentName; - } - - return arguments.FirstOrDefault(func); - } - - /// - /// Returns attribute argument at the specified and with the given . - /// If is , only is included in the search. - /// If no appropriate argument found, returns . - /// - /// to get the argument of. - /// Position of argument to get. - /// Name of the argument to get the location of. - public static AttributeArgumentSyntax? GetArgument(this AttributeSyntax attribute, int position, string? argumentName = null) - { - if (attribute.ArgumentList is null) - { - return null; - } - - SeparatedSyntaxList arguments = attribute.ArgumentList.Arguments; - - if (!arguments.Any()) - { - return null; - } - - if (string.IsNullOrWhiteSpace(argumentName)) - { - if (position >= arguments.Count) - { - return null; - } - - return arguments[position]; - } - - if (position < arguments.Count) - { - AttributeArgumentSyntax arg = arguments[position]; - - if (arg.GetName() == argumentName) - { - return arg; - } - } - - return arguments.FirstOrDefault(arg => arg.GetName() == argumentName); - } - - /// - /// Returns location of attribute argument with the specified - /// or location of the if no argument with the was found. - /// - /// to get the location of argument of. - /// Name of the argument to get the location of. - /// Determines whether to include arguments with colons in the search. - public static Location GetArgumentLocation(this AttributeSyntax attribute, string argumentName, bool includeParameters = false) - { - AttributeArgumentSyntax? arg = attribute.GetArgument(argumentName, includeParameters); - - if (arg is null) - { - return attribute.GetLocation(); - } - - return arg.GetLocation(); - } - - /// - /// Returns location of attribute argument at the specified and with the given - /// or location of the is no appropriate argument was found. - /// - /// to get the location of argument of. - /// Position of argument to get. - /// Name of the argument to get the location of. - public static Location GetArgumentLocation(this AttributeSyntax attribute, int position, string? argumentName = null) - { - AttributeArgumentSyntax? arg = attribute.GetArgument(position, argumentName); - - if (arg is null) - { - return attribute.GetLocation(); - } - - return arg.GetLocation(); - } - - /// - /// Returns attribute declaration list of the specified or an empty list if the has no attributes. - /// - /// to get attribute lists of. - public static SyntaxList GetAttributeLists(this SyntaxNode node) - { - return node switch - { - MemberDeclarationSyntax member => member.AttributeLists, - StatementSyntax statement => statement.AttributeLists, - LambdaExpressionSyntax lambda => lambda.AttributeLists, - AccessorDeclarationSyntax accessor => accessor.AttributeLists, - CompilationUnitSyntax unit => unit.AttributeLists, - TypeParameterSyntax typeParameter => typeParameter.AttributeLists, - BaseParameterSyntax parameter => parameter.AttributeLists, - _ => SyntaxFactory.List() - }; - } - - /// - /// Returns the that is accessed by using the specified in the context of the given . - /// - /// to get the attribute target node of. - /// Kind of attribute target. - /// - /// Note: In some cases, the refers to symbols that are compiler-generated, thus have no associated s. In such situations, is returned. This includes: - /// - /// . - /// . - /// for , , and accessors. - /// for , , and accessors. - /// for properties and events. - /// for events. - /// - /// - public static SyntaxNode? GetAttributeTarget(this SyntaxNode node, AttributeTarget target) - { - switch (target) - { - case AttributeTarget.Return: - return node.GetReturnType(); - - case AttributeTarget.Field: - return node as FieldDeclarationSyntax; - - case AttributeTarget.Method: - return node is - BaseMethodDeclarationSyntax or - LocalFunctionStatementSyntax or - ParenthesizedLambdaExpressionSyntax or - AccessorDeclarationSyntax - ? node : default; - - case AttributeTarget.Type: - return node is - BaseTypeDeclarationSyntax or - DelegateDeclarationSyntax - ? node : default; - - case AttributeTarget.TypeVar: - return node as TypeParameterSyntax; - - case AttributeTarget.Event: - - if (node is EventDeclarationSyntax or EventFieldDeclarationSyntax) - { - return node; - } - - return default; - - case AttributeTarget.Param: - return node as ParameterSyntax; - - case AttributeTarget.Property: - return node as BasePropertyDeclarationSyntax; - - default: - return default; - } - } - - /// - /// Returns the that is accessed by using the specified in the context of the given . - /// - /// to get the attribute target node of. - /// Kind of attribute target. - public static SyntaxNode? GetAttributeTarget(this SyntaxNode node, AttributeTargetKind target) - { - return target switch - { - AttributeTargetKind.This => node is - ParameterSyntax or - TypeParameterSyntax or - BaseFieldDeclarationSyntax or - BasePropertyDeclarationSyntax or - BaseTypeDeclarationSyntax or - BaseMethodDeclarationSyntax or - LocalFunctionStatementSyntax or - ParenthesizedLambdaExpressionSyntax or - AccessorDeclarationSyntax - ? node : default, - - AttributeTargetKind.Value => node is not BasePropertyDeclarationSyntax ? node.GetReturnType() : default, - - // All members resolved using AttributeTargetKind.Handler are compiler-generated. - // AttributeTargetKind.Handler => - - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTarget GetAttributeTarget(this AttributeTargetSpecifierSyntax node) - { - return node.Identifier.GetAttributeTarget(); - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTarget GetAttributeTarget(this AttributeListSyntax node) - { - return node.Target is AttributeTargetSpecifierSyntax target ? target.GetAttributeTarget() : default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTarget GetAttributeTarget(this AttributeSyntax node) - { - return node.Parent is AttributeListSyntax attrList ? attrList.GetAttributeTarget() : default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTargetKind GetAttributeTargetKind(this AttributeTargetSpecifierSyntax node) - { - if (node.Parent?.Parent is not SyntaxNode decl) - { - return default; - } - - AttributeTarget target = node.GetAttributeTarget(); - - if (decl.GetAttributeTarget(target) is SyntaxNode targetNode) - { - return targetNode == decl ? AttributeTargetKind.This : AttributeTargetKind.Value; - } - - return default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTargetKind GetAttributeTargetKind(this AttributeListSyntax node) - { - return node.Target?.GetAttributeTargetKind() ?? default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static AttributeTargetKind GetAttributeTargetKind(this AttributeSyntax node) - { - return (node.Parent as AttributeListSyntax)?.GetAttributeTargetKind() ?? default; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static AutoPropertyKind GetAutoPropertyKind(this BasePropertyDeclarationSyntax node) - { - return (node as PropertyDeclarationSyntax)?.GetAutoPropertyKind() ?? default; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static AutoPropertyKind GetAutoPropertyKind(this PropertyDeclarationSyntax node) - { - return node.AccessorList?.GetAutoPropertyKind() ?? default; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static AutoPropertyKind GetAutoPropertyKind(this AccessorListSyntax node) - { - if (!node.Accessors.Any() || node.Accessors.Count > 2) - { - return default; - } - - PropertyAccessorKind first = node.Accessors[0].GetPropertyAccessorKind(); - - if (node.Accessors.Count == 1) - { - return first.GetAutoPropertyKind(); - } - - PropertyAccessorKind second = node.Accessors[1].GetPropertyAccessorKind(); - - return second switch - { - PropertyAccessorKind.Set => AutoPropertyKind.GetSet, - PropertyAccessorKind.Init => AutoPropertyKind.GetInit, - _ => default - }; - } - - /// - /// Returns the block body of the specified . - /// - /// to get the block body of. - public static BlockSyntax? GetBlock(this SyntaxNode node) - { - return node switch - { - BaseMethodDeclarationSyntax method => method.Body, - AccessorDeclarationSyntax accessor => accessor.Body, - AnonymousFunctionExpressionSyntax lambda => lambda.Block, - StatementSyntax statement => statement.GetBlock(), - CatchClauseSyntax @catch => @catch.Block, - FinallyClauseSyntax @finally => @finally.Block, - _ => default - }; - } - - /// - /// Returns the block body of the specified . - /// - /// to get the block body of. - public static BlockSyntax? GetBlock(this StatementSyntax node) - { - return node switch - { - LocalFunctionStatementSyntax local => local.Body, - CheckedStatementSyntax @checked => @checked.Block, - UnsafeStatementSyntax @unsafe => @unsafe.Block, - TryStatementSyntax @try => @try.Block, - BlockSyntax block => block, - _ => default - }; - } - - /// - /// Returns the body of the specified . - /// - /// to get the body of. - public static SyntaxNode? GetBody(this BaseMethodDeclarationSyntax node) - { - return node.Body ?? (SyntaxNode?)node.ExpressionBody; - } - - /// - /// Returns the body of the specified . - /// - /// to get the body of. - public static SyntaxNode? GetBody(this LocalFunctionStatementSyntax node) - { - return node.Body ?? (SyntaxNode?)node.ExpressionBody; - } - - /// - /// Returns the body of the specified . - /// - /// to get the body of. - public static SyntaxNode? GetBody(this AccessorDeclarationSyntax node) - { - return node.Body ?? (SyntaxNode?)node.ExpressionBody; - } - - /// - /// Returns the body of the specified . - /// - /// to get the body of. - public static SyntaxNode? GetBody(this AnonymousFunctionExpressionSyntax node) - { - return node.Body ?? (SyntaxNode?)node.ExpressionBody; - } - - /// - /// Returns type of the body of the specified . - /// - /// to get the type of body of. - public static MethodStyle GetBodyType(this BaseMethodDeclarationSyntax node) - { - if (node.Body is not null) - { - return MethodStyle.Block; - } - - if (node.ExpressionBody is not null) - { - return MethodStyle.Expression; - } - - return default; - } - - /// - /// Returns type of the body of the specified . - /// - /// to get the type of body of. - public static MethodStyle GetBodyType(this AccessorDeclarationSyntax node) - { - if (node.Body is not null) - { - return MethodStyle.Block; - } - - if (node.ExpressionBody is not null) - { - return MethodStyle.Expression; - } - - return default; - } - - /// - /// Returns type of the body of the specified . - /// - /// to get the type of body of. - public static MethodStyle GetBodyType(this LocalFunctionStatementSyntax node) - { - if (node.Body is not null) - { - return MethodStyle.Block; - } - - if (node.ExpressionBody is not null) - { - return MethodStyle.Expression; - } - - return default; - } - - /// - /// Returns type of the body of the specified . - /// - /// to get the type of body of. - public static LambdaStyle GetBodyType(this AnonymousFunctionExpressionSyntax node) - { - if (node is AnonymousMethodExpressionSyntax) - { - return LambdaStyle.Method; - } - - if (node.Body is not null) - { - return LambdaStyle.Block; - } - - if (node.ExpressionBody is not null) - { - return LambdaStyle.Expression; - } - - return default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeParameterConstraintClauseSyntax? GetConstraintClause(this TypeParameterSyntax node) - { - return node.Parent?.Parent switch - { - TypeDeclarationSyntax type => GetNode(type.ConstraintClauses), - MethodDeclarationSyntax method => GetNode(method.ConstraintClauses), - DelegateDeclarationSyntax @delegate => GetNode(@delegate.ConstraintClauses), - LocalFunctionStatementSyntax local => GetNode(local.ConstraintClauses), - _ => default - }; - - TypeParameterConstraintClauseSyntax? GetNode(SyntaxList clauses) - { - return clauses.FirstOrDefault(c => c.Name.Identifier.Value == node.Identifier.Value); - } - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint GetConstraints(this TypeParameterConstraintSyntax node, bool includeImplicit = false) - { - switch (node) - { - case ClassOrStructConstraintSyntax classOrStruct: - - if (classOrStruct.IsClass()) - { - return GenericConstraint.Class; - } - - if (classOrStruct.IsStruct()) - { - if (includeImplicit) - { - return GenericConstraint.Struct | GenericConstraint.New; - } - - return GenericConstraint.Struct; - } - - return default; - - case TypeConstraintSyntax type: - - if (type.Type.IsNotNull) - { - return GenericConstraint.NotNull; - } - - if (type.Type.IsUnmanaged) - { - if (includeImplicit) - { - return GenericConstraint.Unmanaged | GenericConstraint.Struct | GenericConstraint.New; - } - - return GenericConstraint.Unmanaged; - } - - if (includeImplicit) - { - return GenericConstraint.Type | GenericConstraint.Class; - } - - return GenericConstraint.Type; - - case ConstructorConstraintSyntax: - return GenericConstraint.New; - - case DefaultConstraintSyntax: - return GenericConstraint.Default; - - default: - return default; - } - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint GetConstraints(this TypeParameterConstraintClauseSyntax node, bool includeImplicit = false) - { - GenericConstraint constraint = default; - - foreach (TypeParameterConstraintSyntax syntax in node.Constraints) - { - constraint |= syntax.GetConstraints(includeImplicit); - } - - return constraint; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint GetConstraints(this TypeParameterSyntax node, bool includeImplicit = false) - { - return node.GetConstraintClause()?.GetConstraints(includeImplicit) ?? default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint[] GetConstraints(this TypeDeclarationSyntax node, bool includeImplicit = false) - { - return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint[] GetConstraints(this DelegateDeclarationSyntax node, bool includeImplicit = false) - { - return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - /// Determines whether to include constraints that are implicitly applied to the . - public static GenericConstraint[] GetConstraints(this MethodDeclarationSyntax node, bool includeImplicit = false) - { - return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); - } - - /// - /// Returns the kind of the specified represents. - /// - /// to get the kind represented by. - public static ConstructorInitializer GetConstructorInitializer(this ConstructorInitializerSyntax node) - { - return ((SyntaxKind)node.RawKind).GetConstructorInitializer(); - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static ConstructorInitializer GetConstructorInitializer(this ConstructorDeclarationSyntax node) - { - return node.Initializer?.GetConstructorInitializer() ?? default; - } - - /// - /// Returns the kind of the specified . - /// - /// to get the kind of. - public static SpecialConstructor GetConstructorKind(this ConstructorDeclarationSyntax node) - { - if (node.ParameterList.IsParameterless()) - { - if (node.IsStatic()) - { - return SpecialConstructor.Static; - } - - return SpecialConstructor.Parameterless; - } - - if (node.ParameterList.Parameters.Count != 1) - { - return default; - } - - ParameterSyntax parameter = node.ParameterList.Parameters[0]; - - if (parameter.Type is IdentifierNameSyntax name && name.Identifier.IsEquivalentTo(node.Identifier)) - { - return SpecialConstructor.Copy; - } - - return default; - } - - /// - /// Returns the that contains the specified . - /// - /// to get the containing of. - public static BaseNamespaceDeclarationSyntax? GetContainingNamespace(this SyntaxNode node) - { - return node.Ancestors().OfType().FirstOrDefault(); - } - - /// - /// Returns names of namespaces that contain the specified . - /// - /// to get the containing namespaces of. - /// Specifies ordering of the returned values. - public static IReturnOrderEnumerable GetContainingNamespaces(this SyntaxNode node, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ParentToChild); - - IEnumerable Yield() - { - SyntaxNode? current = node; - - while ((current = current!.Parent) is not null) - { - if (current is BaseNamespaceDeclarationSyntax decl) - { - string[] split = decl.Name.ToString().Split('.'); - int length = split.Length; - - for (int i = length - 1; i > -1; i--) - { - yield return split[i]; - } - } - } - } - } - - /// - /// Returns the that contains the specified . - /// - /// to get the containing of. - public static BaseTypeDeclarationSyntax? GetContainingType(this SyntaxNode node) - { - return node.Ancestors().OfType().FirstOrDefault(); - } - - /// - /// Returns es that contain the specified . - /// - /// to get the containing es of. - /// Specifies ordering of the returned values. - public static IReturnOrderEnumerable GetContainingTypes(this SyntaxNode node, ReturnOrder order = ReturnOrder.ParentToChild) - { - return Yield().OrderBy(order, ReturnOrder.ParentToChild); - - IEnumerable Yield() - { - SyntaxNode? current = node; - - while ((current = current!.Parent) is not null) - { - if (current is BaseTypeDeclarationSyntax type) - { - yield return type; - } - } - } - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static DecimalLiteralSuffix GetDecimalSuffix(this LiteralExpressionSyntax node) - { - return node.Token.GetDecimalSuffix(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static DecimalValueType GetDecimalType(this LiteralExpressionSyntax node) - { - return node.Token.GetDecimalType(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static DecimalValueType GetDecimalType(this PredefinedTypeSyntax node) - { - return node.Keyword.GetDecimalType(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static DecimalValueType GetDecimalType(this TypeSyntax node) - { - return (node as PredefinedTypeSyntax)?.GetDecimalType() ?? default; - } - - /// - /// Returns a keyword used to declare the specified (e.g. , ). - /// - /// to get the keyword of. - public static string? GetDeclaredKeyword(this MemberDeclarationSyntax node) - { - return node switch - { - BaseTypeDeclarationSyntax type => type.GetDeclaredKeyword(), - EventDeclarationSyntax or EventFieldDeclarationSyntax => "event", - OperatorDeclarationSyntax or ConversionOperatorDeclarationSyntax => "operator", - DelegateDeclarationSyntax => "delegate", - _ => default - }; - } - - /// - /// Returns a keyword used to declare the specified (e.g. , ). - /// - /// to get the keyword of. - public static string? GetDeclaredKeyword(this BaseTypeDeclarationSyntax node) - { - return node switch - { - ClassDeclarationSyntax => "class", - StructDeclarationSyntax => "struct", - EnumDeclarationSyntax => "enum", - InterfaceDeclarationSyntax => "interface", - RecordDeclarationSyntax record => (SyntaxKind)record.ClassOrStructKeyword.RawKind switch - { - SyntaxKind.ClassKeyword => "record class", - SyntaxKind.StructKeyword => "record struct", - _ => "record" - }, - _ => default - }; - } - - /// - /// Returns the default that is applied to the during semantic analysis, that is: - /// - /// For top-level types: . - /// For interface members other than partial methods: . - /// For property/event accessors: accessibility of the parent property/event. - /// For all other members: . - /// - /// - /// to get the default accessibility of. - /// Determines whether accessibility of an associated member of the (e.g. parent property of an accessor) should be treated as default. - public static Accessibility GetDefaultAccessibility(this SyntaxNode node, bool includeAssociated = true) - { - if (node.IsTopLevelOrInNamespace()) - { - return node.IsTypeDeclaration() ? Accessibility.Internal : default; - } - - if (node.GetContainingType() is InterfaceDeclarationSyntax) - { - if (node is MethodDeclarationSyntax method && method.IsPartial()) - { - return Accessibility.Private; - } - - return Accessibility.Public; - } - - if (includeAssociated && node is AccessorDeclarationSyntax accessor) - { - return accessor.GetProperty()?.GetAccessibility() ?? default; - } - - if (node.CanApplyAccessibility()) - { - return Accessibility.Private; - } - - return default; - } - - /// - /// Returns the effective of the specified . - /// - /// to get the effective of. - public static Accessibility GetEffectiveAccessibility(this SyntaxNode node) - { - SyntaxNode? n = node; - Accessibility lowest = Accessibility.Public; - - while (n is not null) - { - Accessibility current = n.GetAccessibility(); - - if (current == Accessibility.Private) - { - return current; - } - - if (current != Accessibility.NotApplicable && current < lowest) - { - lowest = current; - } - - n = n.Parent; - } - - return lowest; - } - - /// - /// Returns element of the specified . Node kinds with element types are: - /// - /// - /// - /// - /// - /// - /// to get the element type of. - public static TypeSyntax? GetElementType(this TypeSyntax node) - { - return node switch - { - ArrayTypeSyntax array => array.ElementType, - PointerTypeSyntax pointer => pointer.ElementType, - NullableTypeSyntax nullable => nullable.ElementType, - _ => default - }; - } - - /// - /// Returns the kind of the specified represents. - /// - /// to get the kind represented by. - public static EventAccessorKind GetEventAccessorKind(this AccessorDeclarationSyntax node) - { - return node.GetAccessorKind().GetEventAccessorKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static ExponentialStyle GetExponentialStyle(this LiteralExpressionSyntax node) - { - return node.Token.GetExponentialStyle(); - } - - /// - /// Returns the expression body of the specified . - /// - /// to get the expression body of. - public static ArrowExpressionClauseSyntax? GetExpressionBody(this SyntaxNode node) - { - return node switch - { - BaseMethodDeclarationSyntax method => method.ExpressionBody, - PropertyDeclarationSyntax property => property.ExpressionBody, - AccessorDeclarationSyntax accessor => accessor.ExpressionBody, - IndexerDeclarationSyntax indexer => indexer.ExpressionBody, - LocalFunctionStatementSyntax local => local.ExpressionBody, - ArrowExpressionClauseSyntax arrow => arrow, - _ => default - }; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static GoToKind GetGoToKind(this GotoStatementSyntax node) - { - return ((SyntaxKind)node.RawKind).GetGoToKind(); - } - - /// - /// Returns a collection of all inner types of the specified . - /// - /// to get the inner types of. - /// Determines whether to include the in the returned collection. - public static IEnumerable GetInnerTypes(this BaseTypeDeclarationSyntax node, bool includeSelf = false) - { - return (node as TypeDeclarationSyntax)?.GetInnerTypes(includeSelf) ?? Array.Empty(); - } - - /// - /// Returns a collection of all inner types of the specified . - /// - /// to get the inner types of. - /// Determines whether to include the in the returned collection. - public static IEnumerable GetInnerTypes(this TypeDeclarationSyntax node, bool includeSelf = false) - { - const int CAPACITY = 32; - - if (includeSelf) - { - yield return node; - } - - BaseTypeDeclarationSyntax[] members = node.Members.OfType().ToArray(); - - if (members.Length == 0) - { - yield break; - } - - Stack stack = new(members.Length > CAPACITY ? members.Length : CAPACITY); - - foreach (BaseTypeDeclarationSyntax t in members) - { - stack.Push(t); - } - - while (stack.Count > 0) - { - BaseTypeDeclarationSyntax t = stack.Pop(); - yield return t; - - if (t is not TypeDeclarationSyntax decl) - { - continue; - } - - foreach (BaseTypeDeclarationSyntax child in decl.Members.OfType().Reverse()) - { - stack.Push(child); - } - } - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static IntegerValueType GetIntegerType(this LiteralExpressionSyntax node) - { - return node.Token.GetIntegerType(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static IntegerValueType GetIntegerType(this PredefinedTypeSyntax node) - { - return node.Keyword.GetIntegerType(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static IntegerValueType GetIntegerType(this TypeSyntax node) - { - return (node as PredefinedTypeSyntax)?.GetIntegerType() ?? default; - } - - /// - /// Returns the keyword that is used to declare the given . - /// - /// to get the keyword of. - public static string? GetKeyword(this BaseTypeDeclarationSyntax type) - { - return type switch - { - EnumDeclarationSyntax => "enum", - RecordDeclarationSyntax record => record.ClassOrStructKeyword == default ? "record" : $"record {record.ClassOrStructKeyword}", - TypeDeclarationSyntax t => t.Keyword.ValueText, - _ => default - }; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static LiteralKind GetLiteralKind(this ExpressionSyntax node) - { - return (node as LiteralExpressionSyntax)?.GetLiteralKind() ?? default; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static LiteralKind GetLiteralKind(this TypeSyntax node) - { - return (node as PredefinedTypeSyntax)?.GetLiteralKind() ?? default; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static LiteralKind GetLiteralKind(this PredefinedTypeSyntax node) - { - return (SyntaxKind)node.RawKind switch - { - SyntaxKind.BoolKeyword => LiteralKind.False, - SyntaxKind.StringKeyword => LiteralKind.String, - SyntaxKind.CharKeyword => LiteralKind.Character, - SyntaxKind.ObjectKeyword => LiteralKind.Null, - - SyntaxKind.IntKeyword or - SyntaxKind.UIntKeyword or - SyntaxKind.LongKeyword or - SyntaxKind.ULongKeyword or - SyntaxKind.ShortKeyword or - SyntaxKind.UShortKeyword or - SyntaxKind.ByteKeyword or - SyntaxKind.SByteKeyword or - SyntaxKind.FloatKeyword or - SyntaxKind.DoubleKeyword or - SyntaxKind.DecimalKeyword - => LiteralKind.Number, - - _ => default - }; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static LiteralKind GetLiteralKind(this LiteralExpressionSyntax node) - { - return (SyntaxKind)node.RawKind switch - { - SyntaxKind.NumericLiteralToken => LiteralKind.Number, - SyntaxKind.CharacterLiteralToken => LiteralKind.Character, - SyntaxKind.StringLiteralToken => LiteralKind.String, - SyntaxKind.DefaultKeyword => LiteralKind.Default, - SyntaxKind.NullKeyword => LiteralKind.Null, - SyntaxKind.FalseKeyword => LiteralKind.False, - SyntaxKind.TrueKeyword => LiteralKind.True, - SyntaxKind.ArgListKeyword => LiteralKind.ArgList, - _ => default - }; - } - - /// - /// Returns the literal value of type the represents. - /// - /// Type of literal value this represents. - /// to get the literal value of. - public static T GetLiteralValue(this LiteralExpressionSyntax node) where T : unmanaged - { - return node.Token.GetLiteralValue(); - } - - /// - /// Returns the literal value of type the represents. - /// - /// Type of literal value this represents. - /// to get the literal value of. - public static T GetLiteralValue(this ExpressionSyntax node) where T : unmanaged - { - return (node as LiteralExpressionSyntax)?.Token.GetLiteralValue() ?? default; - } - - /// - /// Returns new instance of associated with the specified . - /// - /// to get the data of. - /// Current . - public static IMemberData GetMemberData(this SyntaxNode member, ICompilationData compilation) - { - return member switch - { - ClassDeclarationSyntax => new ClassData((ClassDeclarationSyntax)member, compilation), - StructDeclarationSyntax => new StructData((StructDeclarationSyntax)member, compilation), - InterfaceDeclarationSyntax => new InterfaceData((InterfaceDeclarationSyntax)member, compilation), - RecordDeclarationSyntax => new RecordData((RecordDeclarationSyntax)member, compilation), - EnumDeclarationSyntax => new EnumData((EnumDeclarationSyntax)member, compilation), - MethodDeclarationSyntax => new MethodData((MethodDeclarationSyntax)member, compilation), - FieldDeclarationSyntax => new FieldData((FieldDeclarationSyntax)member, compilation, 0), - PropertyDeclarationSyntax => new PropertyData((PropertyDeclarationSyntax)member, compilation), - BaseNamespaceDeclarationSyntax => new NamespaceData((BaseNamespaceDeclarationSyntax)member, compilation), - VariableDeclaratorSyntax variable => variable.Parent?.Parent switch - { - FieldDeclarationSyntax field => new FieldData(field, compilation, new FieldData.Properties() { Variable = variable }), - EventFieldDeclarationSyntax @event => new EventData(@event, compilation, new EventData.Properties() { Variable = variable }), - LocalDeclarationStatementSyntax local => new LocalData(local, compilation, new LocalData.Properties() { Variable = variable }), - _ => new MemberData(variable, compilation) - }, - EventDeclarationSyntax => new EventData((EventDeclarationSyntax)member, compilation), - EventFieldDeclarationSyntax => new EventData((EventFieldDeclarationSyntax)member, compilation, 0), - DelegateDeclarationSyntax => new DelegateData((DelegateDeclarationSyntax)member, compilation), - ParameterSyntax => new ParameterData((ParameterSyntax)member, compilation), - TypeParameterSyntax => new TypeParameterData((TypeParameterSyntax)member, compilation), - IndexerDeclarationSyntax => new IndexerData((IndexerDeclarationSyntax)member, compilation), - ConstructorDeclarationSyntax => new ConstructorData((ConstructorDeclarationSyntax)member, compilation), - DestructorDeclarationSyntax => new DestructorData((DestructorDeclarationSyntax)member, compilation), - OperatorDeclarationSyntax => new OperatorData((OperatorDeclarationSyntax)member, compilation), - ConversionOperatorDeclarationSyntax => new ConversionOperatorData((ConversionOperatorDeclarationSyntax)member, compilation), - LocalFunctionStatementSyntax => new LocalFunctionData((LocalFunctionStatementSyntax)member, compilation), - LocalDeclarationStatementSyntax => new LocalData((LocalDeclarationStatementSyntax)member, compilation, 0), - - _ => new MemberData(member, compilation), - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static MethodKind GetMethodKind(this SyntaxNode node) - { - return node switch - { - BaseMethodDeclarationSyntax method => method.GetMethodKind(), - AnonymousFunctionExpressionSyntax => MethodKind.AnonymousFunction, - LocalFunctionStatementSyntax => MethodKind.LocalFunction, - FunctionPointerTypeSyntax or FunctionPointerParameterListSyntax or FunctionPointerCallingConventionSyntax => MethodKind.FunctionPointerSignature, - DelegateDeclarationSyntax => MethodKind.DelegateInvoke, - AccessorDeclarationSyntax accessor => accessor.GetAccessorKind() switch - { - AccessorKind.Get => MethodKind.PropertyGet, - AccessorKind.Set or AccessorKind.Init => MethodKind.PropertySet, - AccessorKind.Add => MethodKind.EventAdd, - AccessorKind.Remove => MethodKind.EventRemove, - _ => default - }, - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static MethodKind GetMethodKind(this BaseMethodDeclarationSyntax node) - { - return node switch - { - MethodDeclarationSyntax method => method.ExplicitInterfaceSpecifier is null ? MethodKind.Ordinary : MethodKind.ExplicitInterfaceImplementation, - OperatorDeclarationSyntax => MethodKind.UserDefinedOperator, - ConversionOperatorDeclarationSyntax => MethodKind.Conversion, - ConstructorDeclarationSyntax ctor => ctor.IsStatic() ? MethodKind.StaticConstructor : MethodKind.Constructor, - DestructorDeclarationSyntax => MethodKind.Destructor, - _ => default - }; - } - - /// - /// Return list of modifiers of the specified . - /// - /// to get the modifiers of. - public static SyntaxTokenList GetModifiers(this SyntaxNode node) - { - return node switch - { - MemberDeclarationSyntax member => member.Modifiers, - BaseParameterSyntax parameter => parameter.Modifiers, - LocalFunctionStatementSyntax localFunction => localFunction.Modifiers, - LocalDeclarationStatementSyntax local => local.Modifiers, - AccessorDeclarationSyntax accessor => accessor.Modifiers, - AnonymousFunctionExpressionSyntax lambda => lambda.Modifiers, - _ => SyntaxFactory.TokenList() - }; - } - - /// - /// Returns modifiers contained withing the given collection of es. - /// - /// Collection of es to get the modifiers from. - public static IEnumerable GetModifiers(this IEnumerable decl) - { - List tokens = new(); - - foreach (MemberDeclarationSyntax d in decl) - { - if (d is null) - { - continue; - } - - foreach (SyntaxToken modifier in d.Modifiers) - { - if (!tokens.Exists(m => m.IsKind(modifier.Kind()))) - { - tokens.Add(modifier); - yield return modifier; - } - } - } - } - - /// - /// Returns the name of attribute argument represented by the specified - /// or if the argument has neither or . - /// - /// to get the name of. - public static string? GetName(this AttributeArgumentSyntax syntax) - { - if (syntax.NameEquals is not null) - { - return syntax.NameEquals.GetName(); - } - - if (syntax.NameColon is not null) - { - return syntax.NameColon.GetName(); - } - - return default; - } - - /// - /// Returns the name of member represented by the specified . - /// - /// that contains the member name. - public static string GetName(this NameEqualsSyntax syntax) - { - return syntax.Name.Identifier.ValueText; - } - - /// - /// Returns the name of member represented by the specified . - /// - /// that contains the member name. - public static string GetName(this NameColonSyntax syntax) - { - return syntax.Name.Identifier.ValueText; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static NamespaceStyle GetNamespaceStyle(this BaseNamespaceDeclarationSyntax node) - { - if (node is FileScopedNamespaceDeclarationSyntax) - { - return NamespaceStyle.File; - } - - if (node.Parent is NamespaceDeclarationSyntax) - { - return NamespaceStyle.Nested; - } - - return NamespaceStyle.Default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static NumericLiteralPrefix GetNumericPrefix(this LiteralExpressionSyntax node) - { - return node.Token.GetNumericPrefix(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static NumericLiteralSuffix GetNumericSuffix(this LiteralExpressionSyntax node) - { - return node.Token.GetNumericSuffix(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static OverloadableOperator GetOperatorType(this ExpressionSyntax node) - { - return node switch - { - BinaryExpressionSyntax binary => binary.GetOperatorType(), - PostfixUnaryExpressionSyntax postfix => postfix.GetOperatorType(), - PrefixUnaryExpressionSyntax prefix => prefix.GetOperatorType(), - _ => default - }; - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static OverloadableOperator GetOperatorType(this OperatorDeclarationSyntax node) - { - return (SyntaxKind)node.OperatorToken.RawKind switch - { - SyntaxKind.PlusToken => node.ParameterList.Parameters.Count > 1 ? OverloadableOperator.Addition : OverloadableOperator.UnaryPlus, - SyntaxKind.MinusToken => node.ParameterList.Parameters.Count > 1 ? OverloadableOperator.Subtraction : OverloadableOperator.UnaryMinus, - _ => node.OperatorToken.GetOperator() - }; - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static OverloadableOperator GetOperatorType(this BinaryExpressionSyntax node) - { - return (SyntaxKind)node.RawKind switch - { - SyntaxKind.AddExpression or - SyntaxKind.AddAssignmentExpression - => OverloadableOperator.Addition, - - SyntaxKind.SubtractExpression or - SyntaxKind.SubtractAssignmentExpression - => OverloadableOperator.Subtraction, - - SyntaxKind.MultiplyExpression or - SyntaxKind.MultiplyAssignmentExpression - => OverloadableOperator.Multiplication, - - SyntaxKind.DivideExpression or - SyntaxKind.DivideAssignmentExpression - => OverloadableOperator.Division, - - SyntaxKind.ModuloExpression or - SyntaxKind.ModuloAssignmentExpression - => OverloadableOperator.Remainder, - - SyntaxKind.EqualsExpression - => OverloadableOperator.Equality, - - SyntaxKind.NotEqualsExpression - => OverloadableOperator.Inequality, - - SyntaxKind.ExclusiveOrExpression or - SyntaxKind.ExclusiveOrAssignmentExpression - => OverloadableOperator.LogicalXor, - - SyntaxKind.LogicalAndExpression or - SyntaxKind.BitwiseAndExpression or - SyntaxKind.AndAssignmentExpression - => OverloadableOperator.LogicalAnd, - - SyntaxKind.LogicalOrExpression or - SyntaxKind.BitwiseOrExpression or - SyntaxKind.OrAssignmentExpression - => OverloadableOperator.LogicalOr, - - SyntaxKind.GreaterThanExpression - => OverloadableOperator.GreaterThan, - - SyntaxKind.GreaterThanOrEqualExpression - => OverloadableOperator.GreaterThanOrEqual, - - SyntaxKind.LessThanExpression - => OverloadableOperator.LessThan, - - SyntaxKind.LessThanOrEqualExpression - => OverloadableOperator.LessThanOrEqual, - - SyntaxKind.RightShiftExpression or - SyntaxKind.RightShiftAssignmentExpression - => OverloadableOperator.RightShift, - - SyntaxKind.LeftShiftExpression or - SyntaxKind.LeftShiftAssignmentExpression - => OverloadableOperator.LeftShift, - - _ => default - }; - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static OverloadableOperator GetOperatorType(this PostfixUnaryExpressionSyntax node) - { - return (SyntaxKind)node.RawKind switch - { - SyntaxKind.PostIncrementExpression => OverloadableOperator.Increment, - SyntaxKind.PostDecrementExpression => OverloadableOperator.Decrement, - _ => default - }; - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static OverloadableOperator GetOperatorType(this PrefixUnaryExpressionSyntax node) - { - return (SyntaxKind)node.RawKind switch - { - SyntaxKind.PreIncrementExpression => OverloadableOperator.Increment, - SyntaxKind.PreDecrementExpression => OverloadableOperator.Decrement, - SyntaxKind.UnaryPlusExpression => OverloadableOperator.UnaryPlus, - SyntaxKind.UnaryMinusExpression => OverloadableOperator.UnaryMinus, - SyntaxKind.LogicalNotExpression => OverloadableOperator.Negation, - SyntaxKind.BitwiseNotExpression => OverloadableOperator.Complement, - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated of. - public static BasePropertyDeclarationSyntax? GetProperty(this AccessorDeclarationSyntax node) - { - return node?.Parent?.Parent as BasePropertyDeclarationSyntax; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated of. - public static BasePropertyDeclarationSyntax? GetProperty(this AccessorListSyntax node) - { - return node.Parent as BasePropertyDeclarationSyntax; - } - - /// - /// Returns the kind of the specified represents. - /// - /// to get the kind represented by. - public static PropertyAccessorKind GetPropertyAccessorKind(this AccessorDeclarationSyntax node) - { - return node.GetAccessorKind().GetPropertyAccessorKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this PropertyDeclarationSyntax node) - { - return node.Type.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this IndexerDeclarationSyntax node) - { - return node.Type.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this LocalDeclarationStatementSyntax node) - { - return node.Declaration.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this VariableDeclarationSyntax node) - { - return node.Type.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this MethodDeclarationSyntax node) - { - return node.ReturnType.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this DelegateDeclarationSyntax node) - { - return node.ReturnType.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this ParenthesizedLambdaExpressionSyntax node) - { - return node.ReturnType?.GetRefKind() ?? default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this AnonymousFunctionExpressionSyntax node) - { - return (node as ParenthesizedLambdaExpressionSyntax)?.GetRefKind() ?? default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this ParameterSyntax node) - { - SyntaxTokenList list = node.Modifiers; - - for (int i = 0; i < list.Count; i++) - { - SyntaxToken token = list[i]; - - switch ((SyntaxKind)token.RawKind) - { - case SyntaxKind.InKeyword: - return RefKind.In; - - case SyntaxKind.RefKeyword: - return RefKind.Ref; - - case SyntaxKind.OutKeyword: - return RefKind.Out; - } - } - - return default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this FunctionPointerParameterSyntax node) - { - SyntaxTokenList list = node.Modifiers; - - for (int i = 0; i < list.Count; i++) - { - SyntaxToken token = list[i]; - - switch ((SyntaxKind)token.RawKind) - { - case SyntaxKind.RefKeyword: - - if (i < list.Count - 1 && (SyntaxKind)list[i + 1].RawKind == SyntaxKind.ReadOnlyKeyword) - { - return RefKind.RefReadOnly; - } - - return RefKind.Ref; - - case SyntaxKind.OutKeyword: - return RefKind.Out; - } - } - - return default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this BaseParameterSyntax node) - { - return node switch - { - ParameterSyntax parameter => parameter.GetRefKind(), - FunctionPointerParameterSyntax pointer => pointer.GetRefKind(), - _ => default - }; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this LocalFunctionStatementSyntax node) - { - return node.ReturnType.GetRefKind(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this TypeSyntax node) - { - return (node as RefTypeSyntax)?.GetRefKind() ?? default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static RefKind GetRefKind(this RefTypeSyntax node) - { - if (node.ReadOnlyKeyword != default) - { - return RefKind.RefReadOnly; - } - - return RefKind.Ref; - } - - /// - /// Returns the return type of the specified . - /// - /// to get the return type of. - public static TypeSyntax? GetReturnType(this SyntaxNode node) - { - return node switch - { - BaseMethodDeclarationSyntax method => method.GetReturnType(), - DelegateDeclarationSyntax @delegate => @delegate.ReturnType, - AccessorDeclarationSyntax accessor => accessor.GetReturnType(), - LocalFunctionStatementSyntax local => local.ReturnType, - ParenthesizedLambdaExpressionSyntax lambda => lambda.ReturnType, - BasePropertyDeclarationSyntax property => property.Type, - _ => default - }; - } - - /// - /// Returns the return type of the specified . - /// - /// to get the return type of. - public static TypeSyntax? GetReturnType(this BaseMethodDeclarationSyntax node) - { - return node switch - { - MethodDeclarationSyntax method => method.ReturnType, - OperatorDeclarationSyntax @operator => @operator.ReturnType, - ConversionOperatorDeclarationSyntax conversion => conversion.Type, - _ => default - }; - } - - /// - /// Returns the return type of the specified . - /// - /// to get the return type of. - public static TypeSyntax? GetReturnType(this AccessorDeclarationSyntax node) - { - if (node.GetAccessorKind().HasReturnType()) - { - return (node.Parent?.Parent as PropertyDeclarationSyntax)?.Type; - } - - return default; - } - - /// - /// Returns name of the root namespace of the specified . - /// - /// to get the root namespace of. - public static string? GetRootNamespace(this SyntaxNode node) - { - return node.GetContainingNamespaces(ReturnOrder.ParentToChild).FirstOrDefault(); - } - - /// - /// Returns a of the given declared in the specified . - /// - /// to get the of. - /// Kind of special constructor to return. - public static ConstructorDeclarationSyntax? GetSpecialConstructor(this TypeDeclarationSyntax node, SpecialConstructor kind) - { - if (kind == SpecialConstructor.None || kind == SpecialConstructor.Default) - { - return default; - } - - return node.Members - .OfType() - .FirstOrDefault(ctor => ctor.GetConstructorKind() == kind); - } - - /// - /// Returns a of the given declared in the specified . - /// - /// to get the of. - /// Kind of special constructor to return. - public static ConstructorDeclarationSyntax? GetSpecialConstructor(this BaseTypeDeclarationSyntax node, SpecialConstructor kind) - { - return (node as TypeDeclarationSyntax)?.GetSpecialConstructor(kind) ?? default; - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static StringModifiers GetStringModifiers(this LiteralExpressionSyntax node) - { - return node.Token.GetStringModifiers(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static StringModifiers GetStringModifiers(this InterpolatedStringExpressionSyntax node) - { - return node.StringStartToken.GetStringModifiers(); - } - - /// - /// Returns the applied to the specified . - /// - /// to get the applied to. - public static StringModifiers GetStringModifiers(this ExpressionSyntax node) - { - return node switch - { - LiteralExpressionSyntax literal => literal.GetStringModifiers(), - InterpolatedStringExpressionSyntax interpolated => interpolated.GetStringModifiers(), - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static SymbolKind GetSymbolKind(this SyntaxNode node) - { - return node switch - { - BaseNamespaceDeclarationSyntax - => SymbolKind.Namespace, - - BaseTypeDeclarationSyntax or - DelegateDeclarationSyntax or - AnonymousObjectCreationExpressionSyntax or - TupleExpressionSyntax - => SymbolKind.NamedType, - - BaseMethodDeclarationSyntax or - AnonymousFunctionExpressionSyntax or - LocalFunctionStatementSyntax or - AccessorDeclarationSyntax - => SymbolKind.Method, - - PropertyDeclarationSyntax or - IndexerDeclarationSyntax or - AnonymousObjectMemberDeclaratorSyntax - => SymbolKind.Property, - - EventDeclarationSyntax or - EventFieldDeclarationSyntax - => SymbolKind.Event, - - BaseParameterSyntax - => SymbolKind.Parameter, - - TypeParameterSyntax - => SymbolKind.TypeParameter, - - ExternAliasDirectiveSyntax - => SymbolKind.Alias, - - EnumMemberDeclarationSyntax or - FieldDeclarationSyntax - => SymbolKind.Field, - - LocalDeclarationStatementSyntax - => SymbolKind.Local, - - LabeledStatementSyntax or - SwitchLabelSyntax - => SymbolKind.Label, - - ArrayTypeSyntax - => SymbolKind.ArrayType, - - PointerTypeSyntax - => SymbolKind.PointerType, - - FunctionPointerTypeSyntax - => SymbolKind.FunctionPointerType, - - QueryClauseSyntax or - QueryContinuationSyntax or - JoinIntoClauseSyntax - => SymbolKind.RangeVariable, - - DiscardPatternSyntax - => SymbolKind.Discard, - - DirectiveTriviaSyntax - => SymbolKind.Preprocessing, - - UsingDirectiveSyntax @using when @using.GetUsingKind() == UsingKind.Alias - => SymbolKind.Alias, - - _ => default - }; - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this ArrayTypeSyntax node) - { - return node.ElementType.GetTypeKeyword(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this PointerTypeSyntax node) - { - return node.ElementType.GetTypeKeyword(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this NullableTypeSyntax node) - { - return node.ElementType.GetTypeKeyword(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this RefTypeSyntax node) - { - return node.Type.GetTypeKeyword(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this PredefinedTypeSyntax node) - { - return node.Keyword.GetTypeKeyword(); - } - - /// - /// Returns the represented by the specified . - /// - /// to get the represented by. - public static TypeKeyword GetTypeKeyword(this TypeSyntax node) - { - switch (node) - { - case PredefinedTypeSyntax predefined: - return predefined.GetTypeKeyword(); - - case RefTypeSyntax refType: - return refType.GetTypeKeyword(); - - case NullableTypeSyntax nullable: - return nullable.GetTypeKeyword(); - - case PointerTypeSyntax pointer: - return pointer.GetTypeKeyword(); - - case ArrayTypeSyntax array: - return array.GetTypeKeyword(); - } - - if (node.IsNint) - { - return TypeKeyword.NInt; - } - - if (node.IsNuint) - { - return TypeKeyword.NUInt; - } - - if (node.IsDynamic()) - { - return TypeKeyword.Dynamic; - } - - return default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeKind GetTypeKind(this SyntaxNode node) - { - return node switch - { - BaseTypeDeclarationSyntax decl => decl.GetTypeKind(), - DelegateDeclarationSyntax => TypeKind.Delegate, - TypeParameterSyntax => TypeKind.TypeParameter, - TypeSyntax type => type.GetTypeKind(), - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeKind GetTypeKind(this TypeSyntax node) - { - if (node is NullableTypeSyntax nullable) - { - node = nullable.ElementType; - } - - return node switch - { - ArrayTypeSyntax => TypeKind.Array, - PointerTypeSyntax => TypeKind.Pointer, - FunctionPointerTypeSyntax => TypeKind.FunctionPointer, - _ => node.IsDynamic() ? TypeKind.Dynamic : default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeKind GetTypeKind(this BaseTypeDeclarationSyntax node) - { - return node switch - { - ClassDeclarationSyntax => TypeKind.Class, - StructDeclarationSyntax => TypeKind.Struct, - EnumDeclarationSyntax => TypeKind.Enum, - InterfaceDeclarationSyntax => TypeKind.Interface, - RecordDeclarationSyntax record => record.IsStruct() ? TypeKind.Struct : TypeKind.Class, - _ => default - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeParameterKind GetTypeParameterKind(this TypeSyntax node) - { - return node.Ancestors().OfType().Any() ? TypeParameterKind.Cref : default; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static TypeParameterKind GetTypeParameterKind(this TypeParameterSyntax node) - { - return node?.Parent?.Parent switch - { - TypeDeclarationSyntax or DelegateDeclarationSyntax => TypeParameterKind.Type, - MethodDeclarationSyntax or LocalFunctionStatementSyntax => TypeParameterKind.Method, - _ => default - }; - } - - /// - /// Returns a of the or if the has no type parameters. - /// - /// to get the of. - public static TypeParameterListSyntax? GetTypeParameterList(this MemberDeclarationSyntax member) - { - return member switch - { - TypeDeclarationSyntax t => t.TypeParameterList, - MethodDeclarationSyntax m => m.TypeParameterList, - DelegateDeclarationSyntax d => d.TypeParameterList, - _ => null - }; - } - - /// - /// Returns the associated with the specified . - /// - /// to get the associated with. - public static UsingKind GetUsingKind(this UsingDirectiveSyntax node) - { - if (node.Alias is not null) - { - return UsingKind.Alias; - } - - if (node.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) - { - return UsingKind.Static; - } - - return UsingKind.Ordinary; - } - - /// - /// Returns a at the specified in the . - /// - /// to get the variable of. - /// Index to get the at. - public static VariableDeclaratorSyntax GetVariable(this LocalDeclarationStatementSyntax node, int index) - { - return node.Declaration.GetVariable(index); - } - - /// - /// Returns a at the specified in the . - /// - /// to get the variable of. - /// Index to get the at. - public static VariableDeclaratorSyntax GetVariable(this BaseFieldDeclarationSyntax node, int index) - { - return node.Declaration.GetVariable(index); - } - - /// - /// Returns a at the specified in the . - /// - /// to get the variable of. - /// Index to get the at. - public static VariableDeclaratorSyntax GetVariable(this VariableDeclarationSyntax node, int index) - { - return node.Variables[index]; - } - - /// - /// Returns the of the specified . - /// - /// to get the of. - public static VarianceKind GetVariance(this TypeParameterSyntax node) - { - return node.VarianceKeyword.GetVariance(); - } - - /// - /// Determines whether the specified defines an of a given kind. - /// - /// to determines whether has an of a given kind. - /// Kind of accessor to check for. - public static bool HasAccessor(this PropertyDeclarationSyntax node, PropertyAccessorKind accessor) - { - if (node.ExpressionBody is not null) - { - return accessor == PropertyAccessorKind.Get; - } - - return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; - } - - /// - /// Determines whether the specified defines an of a given kind. - /// - /// to determines whether has an of a given kind. - /// Kind of accessor to check for. - public static bool HasAccessor(this IndexerDeclarationSyntax node, PropertyAccessorKind accessor) - { - if (node.ExpressionBody is not null) - { - return accessor == PropertyAccessorKind.Get; - } - - return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; - } - - /// - /// Determines whether the specified defines an of a given kind. - /// - /// to determines whether has an of a given kind. - /// Kind of accessor to check for. - public static bool HasAccessor(this EventDeclarationSyntax node, EventAccessorKind accessor) - { - return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; - } - - /// - /// Determines whether the specified defines an of a given kind. - /// - /// to determines whether has an of a given kind. - /// Kind of accessor to check for. - public static bool HasAccessor(this BasePropertyDeclarationSyntax node, AccessorKind accessor) - { - return node.AccessorList?.HasAccessor(accessor) ?? false; - } - - /// - /// Determines whether the specified defines an of a given kind. - /// - /// to determines whether has an of a given kind. - /// Kind of accessor to check for. - public static bool HasAccessor(this AccessorListSyntax node, AccessorKind accessor) - { - return node.Accessors.Any(acc => acc.GetAccessorKind() == accessor); - } - - /// - /// Checks if the target has a body, either block or expression. - /// - /// to check if has a body. - public static bool HasBody(this BaseMethodDeclarationSyntax method) - { - return method.GetBody() is not null; - } - - /// - /// Determines whether the specified has any generic constraints applied. - /// - /// to determine whether has any generic constraints applied. - public static bool HasConstraints(this TypeParameterSyntax node) - { - return node.GetConstraintClause() is not null; - } - - /// - /// Determines whether the specified has a of the given kind applied. - /// - /// to determine whether has a of the given kind applied. - /// to check for. - /// Determines whether to include constraints that are implicitly applied to the . - public static bool HasConstraints(this TypeParameterSyntax node, GenericConstraint constraint, bool includeImplicit = false) - { - return node.GetConstraintClause()?.HasConstraints(constraint, includeImplicit) ?? false; - } - - /// - /// Determines whether the specified contains a of the given kind. - /// - /// to determine whether contains a of the given kind. - /// to check for. - /// Determines whether to include constraints that are implicitly applied to the . - public static bool HasConstraints(this TypeParameterConstraintSyntax node, GenericConstraint constraint, bool includeImplicit = false) - { - if (!includeImplicit) - { - return HasConstraintExplicit(node, constraint); - } - - return HasConstraintImplicit(node, constraint); - } - - /// - /// Determines whether the specified contains a of the given kind. - /// - /// to determine whether contains a of the given kind. - /// to check for. - /// Determines whether to include constraints that are implicitly applied to the . - public static unsafe bool HasConstraints(this TypeParameterConstraintClauseSyntax node, GenericConstraint constraint, bool includeImplicit = false) - { - GenericConstraint[] values = constraint.GetFlags(); - - if (values.Length == 0) - { - return false; - } - - Queue queue = new(values); - - // Why function pointer instead of a Func? Because it's more fun this way! - - delegate* func = includeImplicit - ? &HasConstraintImplicit - : &HasConstraintExplicit; - - foreach (TypeParameterConstraintSyntax cons in node.Constraints) - { - int count = queue.Count; - - for (int i = 0; i < count; i++) - { - GenericConstraint value = queue.Dequeue(); - - if (!func(cons, value)) - { - queue.Enqueue(value); - } - } - - if (queue.Count == 0) - { - return true; - } - } - - return false; - } - - /// - /// Returns the applied to the specified . - /// - /// get the applied to. - public static DocumentationCommentTriviaSyntax? GetXmlDocumentation(this SyntaxNode node) - { - if (!node.HasLeadingTrivia) - { - return default; - } - - SyntaxTriviaList leadingTrivia = node.GetLeadingTrivia(); - SyntaxTrivia token = leadingTrivia.FirstOrDefault(token => token.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || token.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)); - - if (token.IsKind(SyntaxKind.None)) - { - return default; - } - - SyntaxNode? structure = token.GetStructure(); - - return structure as DocumentationCommentTriviaSyntax; - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsAbstract(this SyntaxNode node) - { - return node.GetModifiers().IsAbstract(); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this BaseMethodDeclarationSyntax node) - { - return node.ParameterList.IsArgList(); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this DelegateDeclarationSyntax node) - { - return node.ParameterList.IsArgList(); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this BaseParameterListSyntax node) - { - return node.Parameters.Any(IsArgList); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this LocalFunctionStatementSyntax node) - { - return node.ParameterList.IsArgList(); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this RecordDeclarationSyntax node) - { - return node.ParameterList?.IsArgList() ?? false; - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this AnonymousMethodExpressionSyntax node) - { - return node.ParameterList?.IsArgList() ?? false; - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this AnonymousFunctionExpressionSyntax node) - { - return node switch - { - LambdaExpressionSyntax lambda => lambda.IsArgList(), - AnonymousMethodExpressionSyntax method => method.IsArgList(), - _ => false - }; - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this LambdaExpressionSyntax node) - { - return (node as ParenthesizedLambdaExpressionSyntax)?.IsArgList() ?? false; - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this ParenthesizedLambdaExpressionSyntax node) - { - return node.ParameterList.IsArgList(); - } - - /// - /// Determines whether any parameter of the specified represents the keyword. - /// - /// to determine whether contains any parameter representing the keyword. - public static bool IsArgList(this IndexerDeclarationSyntax node) - { - return node.ParameterList.IsArgList(); - } - - /// - /// Determines whether the specified represents the keyword. - /// - /// to determine whether represents the keyword. - public static bool IsArgList(this BaseParameterSyntax node) - { - return (node as ParameterSyntax)?.IsArgList() ?? false; - } - - /// - /// Determines whether the specified represents the keyword. - /// - /// to determine whether represents the keyword. - public static bool IsArgList(this ParameterSyntax node) - { - return node.Type is null && node.Identifier.IsKind(SyntaxKind.ArgListKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. -#pragma warning disable RCS1047 // Non-asynchronous method name should not end with 'Async'. - public static bool IsAsync(this SyntaxNode node) -#pragma warning restore RCS1047 // Non-asynchronous method name should not end with 'Async'. - { - return node.GetModifiers().IsAsync(); - } - - /// - /// Determines whether the specified represents an auto-property. - /// - /// to determine whether represents an auto-property. - public static bool IsAutoProperty(this PropertyDeclarationSyntax node) - { - if (node.AccessorList is null) - { - return false; - } - - return node.AccessorList.IsAutoProperty(); - } - - /// - /// Determines whether the specified represents an auto-property. - /// - /// to determine whether represents an auto-property. - public static bool IsAutoProperty(this BasePropertyDeclarationSyntax node) - { - return (node as PropertyDeclarationSyntax)?.IsAutoProperty() ?? false; - } - - /// - /// Determines whether the specified represents an auto-property accessor list. - /// - /// to determine whether represents an auto-property accessor list. - public static bool IsAutoProperty(this AccessorListSyntax node) - { - foreach (AccessorDeclarationSyntax accessor in node.Accessors) - { - if (accessor.GetBody() is not null) - { - return false; - } - } - - return true; - } - - /// - /// Determines whether the specified is an auto-property accessor. - /// - /// to determine whether is an auto-property accessor. - public static bool IsAutoPropertyAccessor(this AccessorDeclarationSyntax node) - { - return (node.Parent?.Parent as PropertyDeclarationSyntax)?.IsAutoProperty() ?? false; - } - - /// - /// Determines whether the specified is a class constraint. - /// - /// to determine whether is a class constraint. - public static bool IsClass(this ClassOrStructConstraintSyntax node) - { - return node.ClassOrStructKeyword.IsKind(SyntaxKind.ClassKeyword); - } - - /// - /// Determines whether the specified is a class type. - /// - /// to determine whether is a class type. - public static bool IsClass(this BaseTypeDeclarationSyntax node) - { - return node is ClassDeclarationSyntax || (node is RecordDeclarationSyntax record && record.IsClass()); - } - - /// - /// Determines whether the specified is a class type. - /// - /// to determine whether is a class type. - public static bool IsClass(this RecordDeclarationSyntax node) - { - return node.ClassOrStructKeyword.IsKind(SyntaxKind.ClassKeyword); - } - - /// - /// Determines whether the specified is considered a declaration node and can be used as argument for the GetDeclaredSymbol method of a . - /// - /// to determine whether is considered a declaration node. - public static bool IsDeclaration(this SyntaxNode node) - { - return node is - MemberDeclarationSyntax or - AccessorDeclarationSyntax or - TypeParameterSyntax or - ParameterSyntax or - VariableDesignationSyntax or - AnonymousObjectCreationExpressionSyntax or - AnonymousObjectMemberDeclaratorSyntax or - ArgumentSyntax or - CatchDeclarationSyntax or - ExternAliasDirectiveSyntax or - CompilationUnitSyntax or - ForEachStatementSyntax or - LabeledStatementSyntax or - JoinIntoClauseSyntax or - QueryClauseSyntax or - QueryContinuationSyntax or - SingleVariableDesignationSyntax or - SwitchLabelSyntax or - UsingDirectiveSyntax or - TupleElementSyntax or - TupleExpressionSyntax; - } - - /// - /// Determines whether the specified represents a #pragma warning disable directive. - /// - /// to determine whether represents a #pragma warning disable directive. - public static bool IsDisable(this PragmaWarningDirectiveTriviaSyntax node) - { - return node.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword); - } - - /// - /// Determines whether the specified represents the keyword. - /// - /// to determine whether represents the keyword. - public static bool IsDynamic(this TypeSyntax node) - { - return node is IdentifierNameSyntax { Identifier.ValueText: "dynamic" }; - } - - /// - /// Determines whether the specified is an event accessor. - /// - /// to determine whether is an event accessor. - public static bool IsEventAccessor(this AccessorDeclarationSyntax node) - { - return node.Parent?.Parent is EventDeclarationSyntax; - } - - /// - /// Determines whether the specified represents a declaration of an . This applies to: - /// - /// . - /// - /// - /// - /// to determine whether represents a declaration of an . - public static bool IsEventDeclaration(this SyntaxNode node) - { - return node is - EventFieldDeclarationSyntax or - EventDeclarationSyntax; - } - - /// - /// Determines whether the specified represents an explicit operator. - /// - /// to determine whether represents an explicit operator. - public static bool IsExplicit(this ConversionOperatorDeclarationSyntax node) - { - return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ExplicitKeyword); - } - - /// - /// Determines whether the specified represents an explicit operator. - /// - /// to determine whether represents an explicit operator. - public static bool IsExplicit(this ConversionOperatorMemberCrefSyntax node) - { - return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ExplicitKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsExtern(this SyntaxNode node) - { - return node.GetModifiers().IsExtern(); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsFixed(this SyntaxNode node) - { - return node.GetModifiers().IsFixed(); - } - - /// - /// Determines whether the specified represents a directive. - /// - /// to determine whether represents a directive. - public static bool IsGlobal(this UsingDirectiveSyntax node) - { - return node.GlobalKeyword.IsKind(SyntaxKind.GlobalKeyword); - } - - /// - /// Determines whether the specified represents an implicit operator. - /// - /// to determine whether represents an implicit operator. - public static bool IsImplicit(this ConversionOperatorDeclarationSyntax node) - { - return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword); - } - - /// - /// Determines whether the specified represents an implicit operator. - /// - /// to determine whether represents an implicit operator. - public static bool IsImplicit(this ConversionOperatorMemberCrefSyntax node) - { - return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsIn(this SyntaxNode node) - { - return node.GetModifiers().IsIn(); - } - - /// - /// Determines whether the specified is contained within another . - /// - /// to determine whether is contained within another . - public static bool IsInnerType(this BaseTypeDeclarationSyntax node) - { - return node.Ancestors().OfType().Any(); - } - - /// - /// Determines whether the specified is an iterator (contains any es). - /// - /// to determine whether is an iterator. - public static bool IsIterator(this BaseMethodDeclarationSyntax node) - { - return (node as MethodDeclarationSyntax)?.IsIterator() ?? false; - } - - /// - /// Determines whether the specified is an iterator (contains any es). - /// - /// to determine whether is an iterator. - public static bool IsIterator(this MethodDeclarationSyntax node) - { - return node - .DescendantNodes(node => node.Kind() is - not SyntaxKind.LocalFunctionStatement and - not SyntaxKind.AnonymousMethodExpression and - not SyntaxKind.SimpleLambdaExpression and - not SyntaxKind.ParenthesizedLambdaExpression && - node is not ExpressionSyntax - ) - .Any(n => n is YieldStatementSyntax); - } - - /// - /// Determines whether the specified is an iterator (contains any es). - /// - /// to determine whether is an iterator. - public static bool IsIterator(this LocalFunctionStatementSyntax node) - { - return node - .DescendantNodes(node => node.Kind() is - not SyntaxKind.LocalFunctionStatement and - not SyntaxKind.AnonymousMethodExpression and - not SyntaxKind.SimpleLambdaExpression and - not SyntaxKind.ParenthesizedLambdaExpression && - node is not ExpressionSyntax - ) - .Any(n => n is YieldStatementSyntax); - } - - /// - /// Determines whether the specified uses the calling convention. - /// - /// to determine whether uses the calling convention. - public static bool IsManaged(this FunctionPointerTypeSyntax node) - { - return node.CallingConvention?.IsManaged() ?? true; - } - - /// - /// Determines whether the specified uses the calling convention. - /// - /// to determine whether uses the calling convention. - public static bool IsManaged(this FunctionPointerCallingConventionSyntax node) - { - return node.ManagedOrUnmanagedKeyword == default || node.ManagedOrUnmanagedKeyword.IsKind(SyntaxKind.ManagedKeyword); - } - - /// - /// Determines whether the specified represents a declaration of an . This applies to: - /// - /// (and its derived types) - /// (and its derived types) - /// - /// - /// - /// - /// to determine whether represents a declaration of an . - public static bool IsMethodDeclaration(this SyntaxNode node) - { - return node is - BaseMethodDeclarationSyntax or - AnonymousFunctionExpressionSyntax or - LocalFunctionStatementSyntax or - AccessorDeclarationSyntax; - } - - /// - /// Determines whether the specified contains the token. - /// - /// to determine whether contains the modifier. - public static bool IsNew(this SyntaxNode node) - { - return node.GetModifiers().IsNew(); - } - - /// - /// Determines whether the specified represents the constraint. - /// - /// to determine whether represents the constraint. - public static bool IsNotNullConstraint(this TypeConstraintSyntax node) - { - return node.Type.IsNotNull; - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsOverride(this SyntaxNode node) - { - return node.GetModifiers().IsOverride(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this BaseMethodDeclarationSyntax node) - { - return node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this DelegateDeclarationSyntax node) - { - return node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this RecordDeclarationSyntax node) - { - return node.ParameterList is null || node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this LocalFunctionStatementSyntax node) - { - return node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this AnonymousMethodExpressionSyntax node) - { - return node.ParameterList is null || node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this AnonymousFunctionExpressionSyntax node) - { - return node switch - { - LambdaExpressionSyntax lambda => lambda.IsParameterless(), - AnonymousMethodExpressionSyntax method => method.IsParameterless(), - _ => default - }; - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this ParenthesizedLambdaExpressionSyntax node) - { - return node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this LambdaExpressionSyntax node) - { - if (node is SimpleLambdaExpressionSyntax) - { - return true; - } - - return (node as ParenthesizedLambdaExpressionSyntax)?.IsParameterless() ?? false; - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this BaseParameterListSyntax node) - { - return !node.Parameters.Any(); - } - - /// - /// Determines whether the specified is parameterless. - /// - /// to determine whether is parameterless - public static bool IsParameterless(this IndexerDeclarationSyntax node) - { - return node.ParameterList.IsParameterless(); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsParams(this SyntaxNode node) - { - return node.GetModifiers().IsParams(); - } - - /// - /// Determines whether the specified contains the token. - /// - /// to determine whether contains the modifier. - public static bool IsPartial(this SyntaxNode node) - { - return node.GetModifiers().IsPartial(); - } - - /// - /// Determines whether the specified is a property accessor. - /// - /// to determine whether is a property accessor. - public static bool IsPropertyAccessor(this AccessorDeclarationSyntax node) - { - return node.Parent?.Parent is PropertyDeclarationSyntax or IndexerDeclarationSyntax; - } - - /// - /// Determines whether the specified contains the modifier ( does not count). - /// - /// to determine whether contains the modifier. - public static bool IsReadOnly(this SyntaxNode node) - { - return node.GetModifiers().IsReadOnly(); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsRef(this SyntaxNode node) - { - return node.GetModifiers().IsRef(); - } - - /// - /// Determines whether the specified contains the and modifier. - /// - /// to determine whether contains the and modifiers. - public static bool IsRefReadOnly(this SyntaxNode node) - { - return node.GetModifiers().IsRefReadOnly(); - } - - /// - /// Determines whether the specified represents a #pragma warning restore directive. - /// - /// to determine whether represents a #pragma warning restore directive. - public static bool IsRestore(this PragmaWarningDirectiveTriviaSyntax node) - { - return node.DisableOrRestoreKeyword.IsKind(SyntaxKind.RestoreKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsSealed(this SyntaxNode node) - { - return node.GetModifiers().IsSealed(); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsStatic(this SyntaxNode node) - { - return node.GetModifiers().IsStatic(); - } - - /// - /// Determines whether the specified is a struct constraint. - /// - /// to determine whether is a struct constraint. - public static bool IsStruct(this ClassOrStructConstraintSyntax node) - { - return node.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); - } - - /// - /// Determines whether the specified is a struct type. - /// - /// to determine whether is a struct type. - public static bool IsStruct(this BaseTypeDeclarationSyntax node) - { - return node is StructDeclarationSyntax || (node is RecordDeclarationSyntax record && record.IsStruct()); - } - - /// - /// Determines whether the specified is a struct type. - /// - /// to determine whether is a struct type. - public static bool IsStruct(this RecordDeclarationSyntax node) - { - return node.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsThis(this SyntaxNode node) - { - return node.GetModifiers().IsThis(); - } - - /// - /// Determines whether the specified as declared at the top level, meaning the is either: - /// - /// - /// - /// - /// - /// - /// to determine whether is at the top level. - public static bool IsTopLevel(this SyntaxNode node) - { - return node.Parent is - null or - CompilationUnitSyntax or - GlobalStatementSyntax; - } - - /// - /// Determines whether the specified as declared in a namespace or at the top level (see for more details). - /// - /// to determine whether is at the top level. - public static bool IsTopLevelOrInNamespace(this SyntaxNode node) - { - return node.Parent is - null or - CompilationUnitSyntax or - BaseNamespaceDeclarationSyntax; - } - - /// - /// Determines whether the specified represents a named type constraint. - /// - /// to determine whether represents a named type constraint. - public static bool IsTypeConstraint(this TypeConstraintSyntax node) - { - return !node.IsUnmanagedConstraint() && !node.IsNotNullConstraint(); - } - - /// - /// Determines whether the specified represents a declaration of an . This applies to: - /// - /// (and its derived types) - /// - /// - /// - /// to determine whether represents a declaration of an . - public static bool IsTypeDeclaration(this SyntaxNode node) - { - return node is - BaseTypeDeclarationSyntax or - DelegateDeclarationSyntax; - } - - /// - /// Determines whether the specified uses the calling convention. - /// - /// to determine whether uses the calling convention. - public static bool IsUnmanaged(this FunctionPointerTypeSyntax node) - { - return node.CallingConvention?.IsUnmanaged() ?? false; - } - - /// - /// Determines whether the specified uses the calling convention. - /// - /// to determine whether uses the calling convention. - public static bool IsUnmanaged(this FunctionPointerCallingConventionSyntax node) - { - return node.ManagedOrUnmanagedKeyword.IsKind(SyntaxKind.UnmanagedKeyword); - } - - /// - /// Determines whether the specified represents the constraint. - /// - /// to determine whether contains the modifier. - public static bool IsUnmanagedConstraint(this TypeConstraintSyntax node) - { - return node.Type.IsUnmanaged; - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsUnsafe(this SyntaxNode node) - { - return node.GetModifiers().IsUnsafe(); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsVirtual(this SyntaxNode node) - { - return node.GetModifiers().IsVirtual(); - } - - /// - /// Determines whether the specified returns . - /// - /// to determine whether returns . - public static bool IsVoid(this BaseMethodDeclarationSyntax node) - { - return (node as MethodDeclarationSyntax)?.IsVoid() ?? false; - } - - /// - /// Determines whether the specified returns . - /// - /// to determine whether returns . - public static bool IsVoid(this MethodDeclarationSyntax node) - { - return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); - } - - /// - /// Determines whether the specified returns . - /// - /// to determine whether returns . - public static bool IsVoid(this LocalFunctionStatementSyntax node) - { - return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); - } - - /// - /// Determines whether the specified returns . - /// - /// to determine whether returns . - public static bool IsVoid(this DelegateDeclarationSyntax node) - { - return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); - } - - /// - /// Determines whether the specified contains the modifier. - /// - /// to determine whether contains the modifier. - public static bool IsVolatile(this SyntaxNode node) - { - return node.GetModifiers().IsVolatile(); - } - - /// - /// Determines whether the specified represents a break statement. - /// - /// to determine whether represents a break statement. - public static bool IsYieldBreak(this YieldStatementSyntax node) - { - return node.ReturnOrBreakKeyword.IsKind(SyntaxKind.BreakKeyword); - } - - /// - /// Determines whether the specified represents a return statement. - /// - /// to determine whether represents a return statement. - public static bool IsYieldReturn(this YieldStatementSyntax node) - { - return node.ReturnOrBreakKeyword.IsKind(SyntaxKind.ReturnKeyword); - } - - /// - /// Determines whether the specified supports more than one attribute target kind. - /// - /// to determine whether supports more than one attribute target kind. - public static bool SupportsAlternativeAttributeTargets(this SyntaxNode node) - { - return node switch - { - MemberDeclarationSyntax member - => member.SupportsAlternativeAttributeTargets(), - - CompilationUnitSyntax or - AccessorDeclarationSyntax or - LambdaExpressionSyntax or - LocalFunctionStatementSyntax - => true, - - _ => false - }; - } - - /// - /// Determines whether the specified supports more than one attribute target kind. - /// - /// to determine whether supports more than one attribute target kind. - public static bool SupportsAlternativeAttributeTargets(this MemberDeclarationSyntax node) - { - return node switch - { - MethodDeclarationSyntax or - DelegateDeclarationSyntax or - EventFieldDeclarationSyntax or - ConversionOperatorDeclarationSyntax or - OperatorDeclarationSyntax or - BaseNamespaceDeclarationSyntax - => true, - - PropertyDeclarationSyntax property - => property.IsAutoProperty(), - - _ => false - }; - } - - /// - /// Determines whether the specified can have an explicit base type. - /// - /// to check whether can have an explicit base type. - public static bool SupportsExplicitBaseType(this BaseTypeDeclarationSyntax node) - { - return node switch - { - ClassDeclarationSyntax => !node.IsStatic(), - RecordDeclarationSyntax record => record.IsClass(), - EnumDeclarationSyntax or InterfaceDeclarationSyntax => true, - _ => false - }; - } - - private static bool HasConstraintExplicit(TypeParameterConstraintSyntax node, GenericConstraint constraint) - { - return constraint switch - { - GenericConstraint.Class => node is ClassOrStructConstraintSyntax @class && @class.IsClass(), - GenericConstraint.Struct => node is ClassOrStructConstraintSyntax @struct && @struct.IsStruct(), - GenericConstraint.New => node is ConstructorConstraintSyntax, - GenericConstraint.Unmanaged => node is TypeConstraintSyntax unmanaged && unmanaged.IsUnmanagedConstraint(), - GenericConstraint.NotNull => node is TypeConstraintSyntax notnull && notnull.IsNotNullConstraint(), - GenericConstraint.Type => node is TypeConstraintSyntax type && type.IsTypeConstraint(), - GenericConstraint.Default => node is DefaultConstraintSyntax, - _ => false - }; - } - - private static bool HasConstraintImplicit(TypeParameterConstraintSyntax node, GenericConstraint constraint) - { - bool isValid = false; - - if (constraint.HasFlag(GenericConstraint.Class)) - { - if (node is ClassOrStructConstraintSyntax @class) - { - if (!@class.IsClass()) - { - return false; - } - } - else if (!IsType()) - { - return false; - } - - isValid = true; - } - else if (constraint.HasFlag(GenericConstraint.Struct)) - { - if (node is ClassOrStructConstraintSyntax @struct) - { - if (!@struct.IsStruct()) - { - return false; - } - } - else if (!IsUnmanaged()) - { - return false; - } - - isValid = true; - } - else if (constraint.HasFlag(GenericConstraint.Unmanaged)) - { - if (!IsUnmanaged()) - { - return false; - } - - isValid = true; - } - else if (constraint.HasFlag(GenericConstraint.NotNull)) - { - if (node is not TypeConstraintSyntax notnull || !notnull.IsNotNullConstraint()) - { - return false; - } - - isValid = true; - } - else if (constraint.HasFlag(GenericConstraint.Default)) - { - if (node is not DefaultConstraintSyntax) - { - return false; - } - - isValid = true; - } - - if (constraint.HasFlag(GenericConstraint.Type)) - { - if (!IsType()) - { - return false; - } - - isValid = true; - } - - if (constraint.HasFlag(GenericConstraint.New)) - { - if (node is not ConstructorConstraintSyntax) - { - if (node is not ClassOrStructConstraintSyntax @struct || !@struct.IsStruct()) - { - return false; - } - } - - isValid = true; - } - - return isValid; - - bool IsType() - { - return node is TypeConstraintSyntax type && type.IsTypeConstraint(); - } - - bool IsUnmanaged() - { - return node is TypeConstraintSyntax unmanaged && unmanaged.IsUnmanagedConstraint(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Durian.Analysis.CodeGeneration; +using Durian.Analysis.Data; +using Durian.Analysis.Data.FromSource; +using Durian.Analysis.SymbolContainers; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Durian.Analysis; + +/// +/// Contains various extension methods for -derived classes. +/// +public static class SyntaxNodeExtensions +{ + /// + /// Builds a from the specified and adds it to the given . + /// + /// to add the using directive to. + /// to build the from. + public static CompilationUnitSyntax AddUsings(this CompilationUnitSyntax compilationUnit, INamespaceSymbol @namespace) + { + UsingDirectiveSyntax directive = @namespace.GetUsingDirective(); + string name = directive.NamespaceOrType.ToString(); + + if (compilationUnit.Usings.Any(u => u.NamespaceOrType.ToString() == name)) + { + return compilationUnit; + } + + return compilationUnit.AddUsings(directive); + } + + /// + /// Builds es from the specified and adds them to the given . + /// + /// to add the using directives to. + /// A collection of s to build the es from. + public static CompilationUnitSyntax AddUsings(this CompilationUnitSyntax compilationUnit, IEnumerable? namespaces) + { + HashSet usings = new(compilationUnit.Usings.Where(u => u.Alias is null).Select(u => u.NamespaceOrType.ToString())); + UsingDirectiveSyntax[] directives = namespaces + .Where(n => n.Name != string.Empty) + .Select(n => n.GetUsingDirective()) + .Where(n => usings.Add(n.NamespaceOrType.ToString())) + .ToArray(); + + if (directives.Length == 0) + { + return compilationUnit; + } + + return compilationUnit.AddUsings(directives); + } + + /// + /// Determines whether the specified can have accessibility modifiers applied. + /// + /// to determine can have accessibility modifiers applied. + public static bool CanApplyAccessibility(this SyntaxNode node) + { + return node switch + { + ConstructorDeclarationSyntax ctor => !ctor.IsStatic(), + + BaseMethodDeclarationSyntax or + BaseFieldDeclarationSyntax or + BasePropertyDeclarationSyntax or + DelegateDeclarationSyntax or + BaseTypeDeclarationSyntax + => true, + + AccessorDeclarationSyntax accessor => accessor.IsPropertyAccessor(), + + _ => default + }; + } + + /// + /// Gets the first node of type that matches the . + /// + /// Type of ancestor node to return. + /// to get the ancestor of. + /// Function that filters the ancestor nodes. + /// Determine whether to leave from structured trivia. + public static TNode? FirstAncestor(this SyntaxNode node, Func? predicate = default, bool ascendOutOfTrivia = true) where TNode : SyntaxNode + { + return node.Parent?.FirstAncestorOrSelf(predicate, ascendOutOfTrivia); + } + + /// + /// Gets the first node of type that matches the . + /// + /// Type of ancestor node to return. + /// Type of argument passed for each call to the . + /// to get the ancestor of. + /// Function that filters the ancestor nodes. + /// Argument to pass for each call. + /// Determine whether to leave from structured trivia. + public static TNode? FirstAncestor(this SyntaxNode node, Func predicate, TArg argument, bool ascendOutOfTrivia = true) where TNode : SyntaxNode + { + return node.Parent?.FirstAncestorOrSelf(predicate, argument, ascendOutOfTrivia); + } + + /// + /// Returns the of the specified . + /// + /// to get the accessibility of. + public static Accessibility GetAccessibility(this SyntaxNode node) + { + return node.GetModifiers().GetAccessibility(); + } + + /// + /// Returns the kind of the specified represents. + /// + /// to get the kind represented by. + public static AccessorKind GetAccessorKind(this AccessorDeclarationSyntax node) + { + return node.Keyword.GetAccessor(); + } + + /// + /// Returns attribute argument with the specified + /// or if no argument with the was found. + /// + /// to get the argument of. + /// Name of argument to get. + /// Determines whether to include arguments with colons in the search. + public static AttributeArgumentSyntax? GetArgument(this AttributeSyntax attribute, string argumentName, bool includeParameters = false) + { + if (attribute.ArgumentList is null) + { + return null; + } + + SeparatedSyntaxList arguments = attribute.ArgumentList.Arguments; + + if (!arguments.Any()) + { + return null; + } + + Func func; + + if (includeParameters) + { + func = arg => + { + if (arg.NameEquals is not null) + { + return arg.NameEquals.Name.Identifier.ValueText == argumentName; + } + + return arg.NameColon is not null && arg.NameColon.Name.Identifier.ValueText == argumentName; + }; + } + else + { + func = arg => arg.NameEquals is not null && arg.NameEquals.Name.Identifier.ValueText == argumentName; + } + + return arguments.FirstOrDefault(func); + } + + /// + /// Returns attribute argument at the specified and with the given . + /// If is , only is included in the search. + /// If no appropriate argument found, returns . + /// + /// to get the argument of. + /// Position of argument to get. + /// Name of the argument to get the location of. + public static AttributeArgumentSyntax? GetArgument(this AttributeSyntax attribute, int position, string? argumentName = null) + { + if (attribute.ArgumentList is null) + { + return null; + } + + SeparatedSyntaxList arguments = attribute.ArgumentList.Arguments; + + if (!arguments.Any()) + { + return null; + } + + if (string.IsNullOrWhiteSpace(argumentName)) + { + if (position >= arguments.Count) + { + return null; + } + + return arguments[position]; + } + + if (position < arguments.Count) + { + AttributeArgumentSyntax arg = arguments[position]; + + if (arg.GetName() == argumentName) + { + return arg; + } + } + + return arguments.FirstOrDefault(arg => arg.GetName() == argumentName); + } + + /// + /// Returns location of attribute argument with the specified + /// or location of the if no argument with the was found. + /// + /// to get the location of argument of. + /// Name of the argument to get the location of. + /// Determines whether to include arguments with colons in the search. + public static Location GetArgumentLocation(this AttributeSyntax attribute, string argumentName, bool includeParameters = false) + { + AttributeArgumentSyntax? arg = attribute.GetArgument(argumentName, includeParameters); + + if (arg is null) + { + return attribute.GetLocation(); + } + + return arg.GetLocation(); + } + + /// + /// Returns location of attribute argument at the specified and with the given + /// or location of the is no appropriate argument was found. + /// + /// to get the location of argument of. + /// Position of argument to get. + /// Name of the argument to get the location of. + public static Location GetArgumentLocation(this AttributeSyntax attribute, int position, string? argumentName = null) + { + AttributeArgumentSyntax? arg = attribute.GetArgument(position, argumentName); + + if (arg is null) + { + return attribute.GetLocation(); + } + + return arg.GetLocation(); + } + + /// + /// Returns attribute declaration list of the specified or an empty list if the has no attributes. + /// + /// to get attribute lists of. + public static SyntaxList GetAttributeLists(this SyntaxNode node) + { + return node switch + { + MemberDeclarationSyntax member => member.AttributeLists, + StatementSyntax statement => statement.AttributeLists, + LambdaExpressionSyntax lambda => lambda.AttributeLists, + AccessorDeclarationSyntax accessor => accessor.AttributeLists, + CompilationUnitSyntax unit => unit.AttributeLists, + TypeParameterSyntax typeParameter => typeParameter.AttributeLists, + BaseParameterSyntax parameter => parameter.AttributeLists, + _ => SyntaxFactory.List() + }; + } + + /// + /// Returns the that is accessed by using the specified in the context of the given . + /// + /// to get the attribute target node of. + /// Kind of attribute target. + /// + /// Note: In some cases, the refers to symbols that are compiler-generated, thus have no associated s. In such situations, is returned. This includes: + /// + /// . + /// . + /// for , , and accessors. + /// for , , and accessors. + /// for properties and events. + /// for events. + /// + /// + public static SyntaxNode? GetAttributeTarget(this SyntaxNode node, AttributeTarget target) + { + switch (target) + { + case AttributeTarget.Return: + return node.GetReturnType(); + + case AttributeTarget.Field: + return node as FieldDeclarationSyntax; + + case AttributeTarget.Method: + return node is + BaseMethodDeclarationSyntax or + LocalFunctionStatementSyntax or + ParenthesizedLambdaExpressionSyntax or + AccessorDeclarationSyntax + ? node : default; + + case AttributeTarget.Type: + return node is + BaseTypeDeclarationSyntax or + DelegateDeclarationSyntax + ? node : default; + + case AttributeTarget.TypeVar: + return node as TypeParameterSyntax; + + case AttributeTarget.Event: + + if (node is EventDeclarationSyntax or EventFieldDeclarationSyntax) + { + return node; + } + + return default; + + case AttributeTarget.Param: + return node as ParameterSyntax; + + case AttributeTarget.Property: + return node as BasePropertyDeclarationSyntax; + + default: + return default; + } + } + + /// + /// Returns the that is accessed by using the specified in the context of the given . + /// + /// to get the attribute target node of. + /// Kind of attribute target. + public static SyntaxNode? GetAttributeTarget(this SyntaxNode node, AttributeTargetKind target) + { + return target switch + { + AttributeTargetKind.This => node is + ParameterSyntax or + TypeParameterSyntax or + BaseFieldDeclarationSyntax or + BasePropertyDeclarationSyntax or + BaseTypeDeclarationSyntax or + BaseMethodDeclarationSyntax or + LocalFunctionStatementSyntax or + ParenthesizedLambdaExpressionSyntax or + AccessorDeclarationSyntax + ? node : default, + + AttributeTargetKind.Value => node is not BasePropertyDeclarationSyntax ? node.GetReturnType() : default, + + // All members resolved using AttributeTargetKind.Handler are compiler-generated. + // AttributeTargetKind.Handler => + + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTarget GetAttributeTarget(this AttributeTargetSpecifierSyntax node) + { + return node.Identifier.GetAttributeTarget(); + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTarget GetAttributeTarget(this AttributeListSyntax node) + { + return node.Target is AttributeTargetSpecifierSyntax target ? target.GetAttributeTarget() : default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTarget GetAttributeTarget(this AttributeSyntax node) + { + return node.Parent is AttributeListSyntax attrList ? attrList.GetAttributeTarget() : default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTargetKind GetAttributeTargetKind(this AttributeTargetSpecifierSyntax node) + { + if (node.Parent?.Parent is not SyntaxNode decl) + { + return default; + } + + AttributeTarget target = node.GetAttributeTarget(); + + if (decl.GetAttributeTarget(target) is SyntaxNode targetNode) + { + return targetNode == decl ? AttributeTargetKind.This : AttributeTargetKind.Value; + } + + return default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTargetKind GetAttributeTargetKind(this AttributeListSyntax node) + { + return node.Target?.GetAttributeTargetKind() ?? default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static AttributeTargetKind GetAttributeTargetKind(this AttributeSyntax node) + { + return (node.Parent as AttributeListSyntax)?.GetAttributeTargetKind() ?? default; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static AutoPropertyKind GetAutoPropertyKind(this BasePropertyDeclarationSyntax node) + { + return (node as PropertyDeclarationSyntax)?.GetAutoPropertyKind() ?? default; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static AutoPropertyKind GetAutoPropertyKind(this PropertyDeclarationSyntax node) + { + return node.AccessorList?.GetAutoPropertyKind() ?? default; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static AutoPropertyKind GetAutoPropertyKind(this AccessorListSyntax node) + { + if (!node.Accessors.Any() || node.Accessors.Count > 2) + { + return default; + } + + PropertyAccessorKind first = node.Accessors[0].GetPropertyAccessorKind(); + + if (node.Accessors.Count == 1) + { + return first.GetAutoPropertyKind(); + } + + PropertyAccessorKind second = node.Accessors[1].GetPropertyAccessorKind(); + + return second switch + { + PropertyAccessorKind.Set => AutoPropertyKind.GetSet, + PropertyAccessorKind.Init => AutoPropertyKind.GetInit, + _ => default + }; + } + + /// + /// Returns the block body of the specified . + /// + /// to get the block body of. + public static BlockSyntax? GetBlock(this SyntaxNode node) + { + return node switch + { + BaseMethodDeclarationSyntax method => method.Body, + AccessorDeclarationSyntax accessor => accessor.Body, + AnonymousFunctionExpressionSyntax lambda => lambda.Block, + StatementSyntax statement => statement.GetBlock(), + CatchClauseSyntax @catch => @catch.Block, + FinallyClauseSyntax @finally => @finally.Block, + _ => default + }; + } + + /// + /// Returns the block body of the specified . + /// + /// to get the block body of. + public static BlockSyntax? GetBlock(this StatementSyntax node) + { + return node switch + { + LocalFunctionStatementSyntax local => local.Body, + CheckedStatementSyntax @checked => @checked.Block, + UnsafeStatementSyntax @unsafe => @unsafe.Block, + TryStatementSyntax @try => @try.Block, + BlockSyntax block => block, + _ => default + }; + } + + /// + /// Returns the body of the specified . + /// + /// to get the body of. + public static SyntaxNode? GetBody(this BaseMethodDeclarationSyntax node) + { + return node.Body ?? (SyntaxNode?)node.ExpressionBody; + } + + /// + /// Returns the body of the specified . + /// + /// to get the body of. + public static SyntaxNode? GetBody(this LocalFunctionStatementSyntax node) + { + return node.Body ?? (SyntaxNode?)node.ExpressionBody; + } + + /// + /// Returns the body of the specified . + /// + /// to get the body of. + public static SyntaxNode? GetBody(this AccessorDeclarationSyntax node) + { + return node.Body ?? (SyntaxNode?)node.ExpressionBody; + } + + /// + /// Returns the body of the specified . + /// + /// to get the body of. + public static SyntaxNode? GetBody(this AnonymousFunctionExpressionSyntax node) + { + return node.Body ?? (SyntaxNode?)node.ExpressionBody; + } + + /// + /// Returns type of the body of the specified . + /// + /// to get the type of body of. + public static MethodStyle GetBodyType(this BaseMethodDeclarationSyntax node) + { + if (node.Body is not null) + { + return MethodStyle.Block; + } + + if (node.ExpressionBody is not null) + { + return MethodStyle.Expression; + } + + return default; + } + + /// + /// Returns type of the body of the specified . + /// + /// to get the type of body of. + public static MethodStyle GetBodyType(this AccessorDeclarationSyntax node) + { + if (node.Body is not null) + { + return MethodStyle.Block; + } + + if (node.ExpressionBody is not null) + { + return MethodStyle.Expression; + } + + return default; + } + + /// + /// Returns type of the body of the specified . + /// + /// to get the type of body of. + public static MethodStyle GetBodyType(this LocalFunctionStatementSyntax node) + { + if (node.Body is not null) + { + return MethodStyle.Block; + } + + if (node.ExpressionBody is not null) + { + return MethodStyle.Expression; + } + + return default; + } + + /// + /// Returns type of the body of the specified . + /// + /// to get the type of body of. + public static LambdaStyle GetBodyType(this AnonymousFunctionExpressionSyntax node) + { + if (node is AnonymousMethodExpressionSyntax) + { + return LambdaStyle.Method; + } + + if (node.Body is not null) + { + return LambdaStyle.Block; + } + + if (node.ExpressionBody is not null) + { + return LambdaStyle.Expression; + } + + return default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeParameterConstraintClauseSyntax? GetConstraintClause(this TypeParameterSyntax node) + { + return node.Parent?.Parent switch + { + TypeDeclarationSyntax type => GetNode(type.ConstraintClauses), + MethodDeclarationSyntax method => GetNode(method.ConstraintClauses), + DelegateDeclarationSyntax @delegate => GetNode(@delegate.ConstraintClauses), + LocalFunctionStatementSyntax local => GetNode(local.ConstraintClauses), + _ => default + }; + + TypeParameterConstraintClauseSyntax? GetNode(SyntaxList clauses) + { + return clauses.FirstOrDefault(c => c.Name.Identifier.Value == node.Identifier.Value); + } + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint GetConstraints(this TypeParameterConstraintSyntax node, bool includeImplicit = false) + { + switch (node) + { + case ClassOrStructConstraintSyntax classOrStruct: + + if (classOrStruct.IsClass()) + { + return GenericConstraint.Class; + } + + if (classOrStruct.IsStruct()) + { + if (includeImplicit) + { + return GenericConstraint.Struct | GenericConstraint.New; + } + + return GenericConstraint.Struct; + } + + return default; + + case TypeConstraintSyntax type: + + if (type.Type.IsNotNull) + { + return GenericConstraint.NotNull; + } + + if (type.Type.IsUnmanaged) + { + if (includeImplicit) + { + return GenericConstraint.Unmanaged | GenericConstraint.Struct | GenericConstraint.New; + } + + return GenericConstraint.Unmanaged; + } + + if (includeImplicit) + { + return GenericConstraint.Type | GenericConstraint.Class; + } + + return GenericConstraint.Type; + + case ConstructorConstraintSyntax: + return GenericConstraint.New; + + case DefaultConstraintSyntax: + return GenericConstraint.Default; + + default: + return default; + } + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint GetConstraints(this TypeParameterConstraintClauseSyntax node, bool includeImplicit = false) + { + GenericConstraint constraint = default; + + foreach (TypeParameterConstraintSyntax syntax in node.Constraints) + { + constraint |= syntax.GetConstraints(includeImplicit); + } + + return constraint; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint GetConstraints(this TypeParameterSyntax node, bool includeImplicit = false) + { + return node.GetConstraintClause()?.GetConstraints(includeImplicit) ?? default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint[] GetConstraints(this TypeDeclarationSyntax node, bool includeImplicit = false) + { + return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint[] GetConstraints(this DelegateDeclarationSyntax node, bool includeImplicit = false) + { + return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + /// Determines whether to include constraints that are implicitly applied to the . + public static GenericConstraint[] GetConstraints(this MethodDeclarationSyntax node, bool includeImplicit = false) + { + return node.ConstraintClauses.Select(c => c.GetConstraints(includeImplicit)).ToArray(); + } + + /// + /// Returns the kind of the specified represents. + /// + /// to get the kind represented by. + public static ConstructorInitializer GetConstructorInitializer(this ConstructorInitializerSyntax node) + { + return ((SyntaxKind)node.RawKind).GetConstructorInitializer(); + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static ConstructorInitializer GetConstructorInitializer(this ConstructorDeclarationSyntax node) + { + return node.Initializer?.GetConstructorInitializer() ?? default; + } + + /// + /// Returns the kind of the specified . + /// + /// to get the kind of. + public static SpecialConstructor GetConstructorKind(this ConstructorDeclarationSyntax node) + { + if (node.ParameterList.IsParameterless()) + { + if (node.IsStatic()) + { + return SpecialConstructor.Static; + } + + return SpecialConstructor.Parameterless; + } + + if (node.ParameterList.Parameters.Count != 1) + { + return default; + } + + ParameterSyntax parameter = node.ParameterList.Parameters[0]; + + if (parameter.Type is IdentifierNameSyntax name && name.Identifier.IsEquivalentTo(node.Identifier)) + { + return SpecialConstructor.Copy; + } + + return default; + } + + /// + /// Returns the that contains the specified . + /// + /// to get the containing of. + public static BaseNamespaceDeclarationSyntax? GetContainingNamespace(this SyntaxNode node) + { + return node.Ancestors().OfType().FirstOrDefault(); + } + + /// + /// Returns names of namespaces that contain the specified . + /// + /// to get the containing namespaces of. + /// Specifies ordering of the returned values. + public static IReturnOrderEnumerable GetContainingNamespaces(this SyntaxNode node, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ParentToChild); + + IEnumerable Yield() + { + SyntaxNode? current = node; + + while ((current = current!.Parent) is not null) + { + if (current is BaseNamespaceDeclarationSyntax decl) + { + string[] split = decl.Name.ToString().Split('.'); + int length = split.Length; + + for (int i = length - 1; i > -1; i--) + { + yield return split[i]; + } + } + } + } + } + + /// + /// Returns the that contains the specified . + /// + /// to get the containing of. + public static BaseTypeDeclarationSyntax? GetContainingType(this SyntaxNode node) + { + return node.Ancestors().OfType().FirstOrDefault(); + } + + /// + /// Returns es that contain the specified . + /// + /// to get the containing es of. + /// Specifies ordering of the returned values. + public static IReturnOrderEnumerable GetContainingTypes(this SyntaxNode node, ReturnOrder order = ReturnOrder.ParentToChild) + { + return Yield().OrderBy(order, ReturnOrder.ParentToChild); + + IEnumerable Yield() + { + SyntaxNode? current = node; + + while ((current = current!.Parent) is not null) + { + if (current is BaseTypeDeclarationSyntax type) + { + yield return type; + } + } + } + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static DecimalLiteralSuffix GetDecimalSuffix(this LiteralExpressionSyntax node) + { + return node.Token.GetDecimalSuffix(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static DecimalValueType GetDecimalType(this LiteralExpressionSyntax node) + { + return node.Token.GetDecimalType(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static DecimalValueType GetDecimalType(this PredefinedTypeSyntax node) + { + return node.Keyword.GetDecimalType(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static DecimalValueType GetDecimalType(this TypeSyntax node) + { + return (node as PredefinedTypeSyntax)?.GetDecimalType() ?? default; + } + + /// + /// Returns a keyword used to declare the specified (e.g. , ). + /// + /// to get the keyword of. + public static string? GetDeclaredKeyword(this MemberDeclarationSyntax node) + { + return node switch + { + BaseTypeDeclarationSyntax type => type.GetDeclaredKeyword(), + EventDeclarationSyntax or EventFieldDeclarationSyntax => "event", + OperatorDeclarationSyntax or ConversionOperatorDeclarationSyntax => "operator", + DelegateDeclarationSyntax => "delegate", + _ => default + }; + } + + /// + /// Returns a keyword used to declare the specified (e.g. , ). + /// + /// to get the keyword of. + public static string? GetDeclaredKeyword(this BaseTypeDeclarationSyntax node) + { + return node switch + { + ClassDeclarationSyntax => "class", + StructDeclarationSyntax => "struct", + EnumDeclarationSyntax => "enum", + InterfaceDeclarationSyntax => "interface", + RecordDeclarationSyntax record => (SyntaxKind)record.ClassOrStructKeyword.RawKind switch + { + SyntaxKind.ClassKeyword => "record class", + SyntaxKind.StructKeyword => "record struct", + _ => "record" + }, + _ => default + }; + } + + /// + /// Returns the default that is applied to the during semantic analysis, that is: + /// + /// For top-level types: . + /// For interface members other than partial methods: . + /// For property/event accessors: accessibility of the parent property/event. + /// For all other members: . + /// + /// + /// to get the default accessibility of. + /// Determines whether accessibility of an associated member of the (e.g. parent property of an accessor) should be treated as default. + public static Accessibility GetDefaultAccessibility(this SyntaxNode node, bool includeAssociated = true) + { + if (node.IsTopLevelOrInNamespace()) + { + return node.IsTypeDeclaration() ? Accessibility.Internal : default; + } + + if (node.GetContainingType() is InterfaceDeclarationSyntax) + { + if (node is MethodDeclarationSyntax method && method.IsPartial()) + { + return Accessibility.Private; + } + + return Accessibility.Public; + } + + if (includeAssociated && node is AccessorDeclarationSyntax accessor) + { + return accessor.GetProperty()?.GetAccessibility() ?? default; + } + + if (node.CanApplyAccessibility()) + { + return Accessibility.Private; + } + + return default; + } + + /// + /// Returns the effective of the specified . + /// + /// to get the effective of. + public static Accessibility GetEffectiveAccessibility(this SyntaxNode node) + { + SyntaxNode? n = node; + Accessibility lowest = Accessibility.Public; + + while (n is not null) + { + Accessibility current = n.GetAccessibility(); + + if (current == Accessibility.Private) + { + return current; + } + + if (current != Accessibility.NotApplicable && current < lowest) + { + lowest = current; + } + + n = n.Parent; + } + + return lowest; + } + + /// + /// Returns element of the specified . Node kinds with element types are: + /// + /// + /// + /// + /// + /// + /// to get the element type of. + public static TypeSyntax? GetElementType(this TypeSyntax node) + { + return node switch + { + ArrayTypeSyntax array => array.ElementType, + PointerTypeSyntax pointer => pointer.ElementType, + NullableTypeSyntax nullable => nullable.ElementType, + _ => default + }; + } + + /// + /// Returns the kind of the specified represents. + /// + /// to get the kind represented by. + public static EventAccessorKind GetEventAccessorKind(this AccessorDeclarationSyntax node) + { + return node.GetAccessorKind().GetEventAccessorKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static ExponentialStyle GetExponentialStyle(this LiteralExpressionSyntax node) + { + return node.Token.GetExponentialStyle(); + } + + /// + /// Returns the expression body of the specified . + /// + /// to get the expression body of. + public static ArrowExpressionClauseSyntax? GetExpressionBody(this SyntaxNode node) + { + return node switch + { + BaseMethodDeclarationSyntax method => method.ExpressionBody, + PropertyDeclarationSyntax property => property.ExpressionBody, + AccessorDeclarationSyntax accessor => accessor.ExpressionBody, + IndexerDeclarationSyntax indexer => indexer.ExpressionBody, + LocalFunctionStatementSyntax local => local.ExpressionBody, + ArrowExpressionClauseSyntax arrow => arrow, + _ => default + }; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static GoToKind GetGoToKind(this GotoStatementSyntax node) + { + return ((SyntaxKind)node.RawKind).GetGoToKind(); + } + + /// + /// Returns a collection of all inner types of the specified . + /// + /// to get the inner types of. + /// Determines whether to include the in the returned collection. + public static IEnumerable GetInnerTypes(this BaseTypeDeclarationSyntax node, bool includeSelf = false) + { + return (node as TypeDeclarationSyntax)?.GetInnerTypes(includeSelf) ?? Array.Empty(); + } + + /// + /// Returns a collection of all inner types of the specified . + /// + /// to get the inner types of. + /// Determines whether to include the in the returned collection. + public static IEnumerable GetInnerTypes(this TypeDeclarationSyntax node, bool includeSelf = false) + { + const int CAPACITY = 32; + + if (includeSelf) + { + yield return node; + } + + BaseTypeDeclarationSyntax[] members = node.Members.OfType().ToArray(); + + if (members.Length == 0) + { + yield break; + } + + Stack stack = new(members.Length > CAPACITY ? members.Length : CAPACITY); + + foreach (BaseTypeDeclarationSyntax t in members) + { + stack.Push(t); + } + + while (stack.Count > 0) + { + BaseTypeDeclarationSyntax t = stack.Pop(); + yield return t; + + if (t is not TypeDeclarationSyntax decl) + { + continue; + } + + foreach (BaseTypeDeclarationSyntax child in decl.Members.OfType().Reverse()) + { + stack.Push(child); + } + } + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static IntegerValueType GetIntegerType(this LiteralExpressionSyntax node) + { + return node.Token.GetIntegerType(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static IntegerValueType GetIntegerType(this PredefinedTypeSyntax node) + { + return node.Keyword.GetIntegerType(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static IntegerValueType GetIntegerType(this TypeSyntax node) + { + return (node as PredefinedTypeSyntax)?.GetIntegerType() ?? default; + } + + /// + /// Returns the keyword that is used to declare the given . + /// + /// to get the keyword of. + public static string? GetKeyword(this BaseTypeDeclarationSyntax type) + { + return type switch + { + EnumDeclarationSyntax => "enum", + RecordDeclarationSyntax record => record.ClassOrStructKeyword == default ? "record" : $"record {record.ClassOrStructKeyword}", + TypeDeclarationSyntax t => t.Keyword.ValueText, + _ => default + }; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static LiteralKind GetLiteralKind(this ExpressionSyntax node) + { + return (node as LiteralExpressionSyntax)?.GetLiteralKind() ?? default; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static LiteralKind GetLiteralKind(this TypeSyntax node) + { + return (node as PredefinedTypeSyntax)?.GetLiteralKind() ?? default; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static LiteralKind GetLiteralKind(this PredefinedTypeSyntax node) + { + return (SyntaxKind)node.RawKind switch + { + SyntaxKind.BoolKeyword => LiteralKind.False, + SyntaxKind.StringKeyword => LiteralKind.String, + SyntaxKind.CharKeyword => LiteralKind.Character, + SyntaxKind.ObjectKeyword => LiteralKind.Null, + + SyntaxKind.IntKeyword or + SyntaxKind.UIntKeyword or + SyntaxKind.LongKeyword or + SyntaxKind.ULongKeyword or + SyntaxKind.ShortKeyword or + SyntaxKind.UShortKeyword or + SyntaxKind.ByteKeyword or + SyntaxKind.SByteKeyword or + SyntaxKind.FloatKeyword or + SyntaxKind.DoubleKeyword or + SyntaxKind.DecimalKeyword + => LiteralKind.Number, + + _ => default + }; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static LiteralKind GetLiteralKind(this LiteralExpressionSyntax node) + { + return (SyntaxKind)node.RawKind switch + { + SyntaxKind.NumericLiteralToken => LiteralKind.Number, + SyntaxKind.CharacterLiteralToken => LiteralKind.Character, + SyntaxKind.StringLiteralToken => LiteralKind.String, + SyntaxKind.DefaultKeyword => LiteralKind.Default, + SyntaxKind.NullKeyword => LiteralKind.Null, + SyntaxKind.FalseKeyword => LiteralKind.False, + SyntaxKind.TrueKeyword => LiteralKind.True, + SyntaxKind.ArgListKeyword => LiteralKind.ArgList, + _ => default + }; + } + + /// + /// Returns the literal value of type the represents. + /// + /// Type of literal value this represents. + /// to get the literal value of. + public static T GetLiteralValue(this LiteralExpressionSyntax node) where T : unmanaged + { + return node.Token.GetLiteralValue(); + } + + /// + /// Returns the literal value of type the represents. + /// + /// Type of literal value this represents. + /// to get the literal value of. + public static T GetLiteralValue(this ExpressionSyntax node) where T : unmanaged + { + return (node as LiteralExpressionSyntax)?.Token.GetLiteralValue() ?? default; + } + + /// + /// Returns new instance of associated with the specified . + /// + /// to get the data of. + /// Current . + public static IMemberData GetMemberData(this SyntaxNode member, ICompilationData compilation) + { + return member switch + { + ClassDeclarationSyntax => new ClassData((ClassDeclarationSyntax)member, compilation), + StructDeclarationSyntax => new StructData((StructDeclarationSyntax)member, compilation), + InterfaceDeclarationSyntax => new InterfaceData((InterfaceDeclarationSyntax)member, compilation), + RecordDeclarationSyntax => new RecordData((RecordDeclarationSyntax)member, compilation), + EnumDeclarationSyntax => new EnumData((EnumDeclarationSyntax)member, compilation), + MethodDeclarationSyntax => new MethodData((MethodDeclarationSyntax)member, compilation), + FieldDeclarationSyntax => new FieldData((FieldDeclarationSyntax)member, compilation, 0), + PropertyDeclarationSyntax => new PropertyData((PropertyDeclarationSyntax)member, compilation), + BaseNamespaceDeclarationSyntax => new NamespaceData((BaseNamespaceDeclarationSyntax)member, compilation), + VariableDeclaratorSyntax variable => variable.Parent?.Parent switch + { + FieldDeclarationSyntax field => new FieldData(field, compilation, new FieldData.Properties() { Variable = variable }), + EventFieldDeclarationSyntax @event => new EventData(@event, compilation, new EventData.Properties() { Variable = variable }), + LocalDeclarationStatementSyntax local => new LocalData(local, compilation, new LocalData.Properties() { Variable = variable }), + _ => new MemberData(variable, compilation) + }, + EventDeclarationSyntax => new EventData((EventDeclarationSyntax)member, compilation), + EventFieldDeclarationSyntax => new EventData((EventFieldDeclarationSyntax)member, compilation, 0), + DelegateDeclarationSyntax => new DelegateData((DelegateDeclarationSyntax)member, compilation), + ParameterSyntax => new ParameterData((ParameterSyntax)member, compilation), + TypeParameterSyntax => new TypeParameterData((TypeParameterSyntax)member, compilation), + IndexerDeclarationSyntax => new IndexerData((IndexerDeclarationSyntax)member, compilation), + ConstructorDeclarationSyntax => new ConstructorData((ConstructorDeclarationSyntax)member, compilation), + DestructorDeclarationSyntax => new DestructorData((DestructorDeclarationSyntax)member, compilation), + OperatorDeclarationSyntax => new OperatorData((OperatorDeclarationSyntax)member, compilation), + ConversionOperatorDeclarationSyntax => new ConversionOperatorData((ConversionOperatorDeclarationSyntax)member, compilation), + LocalFunctionStatementSyntax => new LocalFunctionData((LocalFunctionStatementSyntax)member, compilation), + LocalDeclarationStatementSyntax => new LocalData((LocalDeclarationStatementSyntax)member, compilation, 0), + + _ => new MemberData(member, compilation), + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static MethodKind GetMethodKind(this SyntaxNode node) + { + return node switch + { + BaseMethodDeclarationSyntax method => method.GetMethodKind(), + AnonymousFunctionExpressionSyntax => MethodKind.AnonymousFunction, + LocalFunctionStatementSyntax => MethodKind.LocalFunction, + FunctionPointerTypeSyntax or FunctionPointerParameterListSyntax or FunctionPointerCallingConventionSyntax => MethodKind.FunctionPointerSignature, + DelegateDeclarationSyntax => MethodKind.DelegateInvoke, + AccessorDeclarationSyntax accessor => accessor.GetAccessorKind() switch + { + AccessorKind.Get => MethodKind.PropertyGet, + AccessorKind.Set or AccessorKind.Init => MethodKind.PropertySet, + AccessorKind.Add => MethodKind.EventAdd, + AccessorKind.Remove => MethodKind.EventRemove, + _ => default + }, + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static MethodKind GetMethodKind(this BaseMethodDeclarationSyntax node) + { + return node switch + { + MethodDeclarationSyntax method => method.ExplicitInterfaceSpecifier is null ? MethodKind.Ordinary : MethodKind.ExplicitInterfaceImplementation, + OperatorDeclarationSyntax => MethodKind.UserDefinedOperator, + ConversionOperatorDeclarationSyntax => MethodKind.Conversion, + ConstructorDeclarationSyntax ctor => ctor.IsStatic() ? MethodKind.StaticConstructor : MethodKind.Constructor, + DestructorDeclarationSyntax => MethodKind.Destructor, + _ => default + }; + } + + /// + /// Return list of modifiers of the specified . + /// + /// to get the modifiers of. + public static SyntaxTokenList GetModifiers(this SyntaxNode node) + { + return node switch + { + MemberDeclarationSyntax member => member.Modifiers, + BaseParameterSyntax parameter => parameter.Modifiers, + LocalFunctionStatementSyntax localFunction => localFunction.Modifiers, + LocalDeclarationStatementSyntax local => local.Modifiers, + AccessorDeclarationSyntax accessor => accessor.Modifiers, + AnonymousFunctionExpressionSyntax lambda => lambda.Modifiers, + _ => SyntaxFactory.TokenList() + }; + } + + /// + /// Returns modifiers contained withing the given collection of es. + /// + /// Collection of es to get the modifiers from. + public static IEnumerable GetModifiers(this IEnumerable decl) + { + List tokens = new(); + + foreach (MemberDeclarationSyntax d in decl) + { + if (d is null) + { + continue; + } + + foreach (SyntaxToken modifier in d.Modifiers) + { + if (!tokens.Exists(m => m.IsKind(modifier.Kind()))) + { + tokens.Add(modifier); + yield return modifier; + } + } + } + } + + /// + /// Returns the name of attribute argument represented by the specified + /// or if the argument has neither or . + /// + /// to get the name of. + public static string? GetName(this AttributeArgumentSyntax syntax) + { + if (syntax.NameEquals is not null) + { + return syntax.NameEquals.GetName(); + } + + if (syntax.NameColon is not null) + { + return syntax.NameColon.GetName(); + } + + return default; + } + + /// + /// Returns the name of member represented by the specified . + /// + /// that contains the member name. + public static string GetName(this NameEqualsSyntax syntax) + { + return syntax.Name.Identifier.ValueText; + } + + /// + /// Returns the name of member represented by the specified . + /// + /// that contains the member name. + public static string GetName(this NameColonSyntax syntax) + { + return syntax.Name.Identifier.ValueText; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static NamespaceStyle GetNamespaceStyle(this BaseNamespaceDeclarationSyntax node) + { + if (node is FileScopedNamespaceDeclarationSyntax) + { + return NamespaceStyle.File; + } + + if (node.Parent is NamespaceDeclarationSyntax) + { + return NamespaceStyle.Nested; + } + + return NamespaceStyle.Default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static NumericLiteralPrefix GetNumericPrefix(this LiteralExpressionSyntax node) + { + return node.Token.GetNumericPrefix(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static NumericLiteralSuffix GetNumericSuffix(this LiteralExpressionSyntax node) + { + return node.Token.GetNumericSuffix(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static OverloadableOperator GetOperatorType(this ExpressionSyntax node) + { + return node switch + { + BinaryExpressionSyntax binary => binary.GetOperatorType(), + PostfixUnaryExpressionSyntax postfix => postfix.GetOperatorType(), + PrefixUnaryExpressionSyntax prefix => prefix.GetOperatorType(), + _ => default + }; + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static OverloadableOperator GetOperatorType(this OperatorDeclarationSyntax node) + { + return (SyntaxKind)node.OperatorToken.RawKind switch + { + SyntaxKind.PlusToken => node.ParameterList.Parameters.Count > 1 ? OverloadableOperator.Addition : OverloadableOperator.UnaryPlus, + SyntaxKind.MinusToken => node.ParameterList.Parameters.Count > 1 ? OverloadableOperator.Subtraction : OverloadableOperator.UnaryMinus, + _ => node.OperatorToken.GetOperator() + }; + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static OverloadableOperator GetOperatorType(this BinaryExpressionSyntax node) + { + return (SyntaxKind)node.RawKind switch + { + SyntaxKind.AddExpression or + SyntaxKind.AddAssignmentExpression + => OverloadableOperator.Addition, + + SyntaxKind.SubtractExpression or + SyntaxKind.SubtractAssignmentExpression + => OverloadableOperator.Subtraction, + + SyntaxKind.MultiplyExpression or + SyntaxKind.MultiplyAssignmentExpression + => OverloadableOperator.Multiplication, + + SyntaxKind.DivideExpression or + SyntaxKind.DivideAssignmentExpression + => OverloadableOperator.Division, + + SyntaxKind.ModuloExpression or + SyntaxKind.ModuloAssignmentExpression + => OverloadableOperator.Remainder, + + SyntaxKind.EqualsExpression + => OverloadableOperator.Equality, + + SyntaxKind.NotEqualsExpression + => OverloadableOperator.Inequality, + + SyntaxKind.ExclusiveOrExpression or + SyntaxKind.ExclusiveOrAssignmentExpression + => OverloadableOperator.LogicalXor, + + SyntaxKind.LogicalAndExpression or + SyntaxKind.BitwiseAndExpression or + SyntaxKind.AndAssignmentExpression + => OverloadableOperator.LogicalAnd, + + SyntaxKind.LogicalOrExpression or + SyntaxKind.BitwiseOrExpression or + SyntaxKind.OrAssignmentExpression + => OverloadableOperator.LogicalOr, + + SyntaxKind.GreaterThanExpression + => OverloadableOperator.GreaterThan, + + SyntaxKind.GreaterThanOrEqualExpression + => OverloadableOperator.GreaterThanOrEqual, + + SyntaxKind.LessThanExpression + => OverloadableOperator.LessThan, + + SyntaxKind.LessThanOrEqualExpression + => OverloadableOperator.LessThanOrEqual, + + SyntaxKind.RightShiftExpression or + SyntaxKind.RightShiftAssignmentExpression + => OverloadableOperator.RightShift, + + SyntaxKind.LeftShiftExpression or + SyntaxKind.LeftShiftAssignmentExpression + => OverloadableOperator.LeftShift, + + _ => default + }; + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static OverloadableOperator GetOperatorType(this PostfixUnaryExpressionSyntax node) + { + return (SyntaxKind)node.RawKind switch + { + SyntaxKind.PostIncrementExpression => OverloadableOperator.Increment, + SyntaxKind.PostDecrementExpression => OverloadableOperator.Decrement, + _ => default + }; + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static OverloadableOperator GetOperatorType(this PrefixUnaryExpressionSyntax node) + { + return (SyntaxKind)node.RawKind switch + { + SyntaxKind.PreIncrementExpression => OverloadableOperator.Increment, + SyntaxKind.PreDecrementExpression => OverloadableOperator.Decrement, + SyntaxKind.UnaryPlusExpression => OverloadableOperator.UnaryPlus, + SyntaxKind.UnaryMinusExpression => OverloadableOperator.UnaryMinus, + SyntaxKind.LogicalNotExpression => OverloadableOperator.Negation, + SyntaxKind.BitwiseNotExpression => OverloadableOperator.Complement, + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated of. + public static BasePropertyDeclarationSyntax? GetProperty(this AccessorDeclarationSyntax node) + { + return node?.Parent?.Parent as BasePropertyDeclarationSyntax; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated of. + public static BasePropertyDeclarationSyntax? GetProperty(this AccessorListSyntax node) + { + return node.Parent as BasePropertyDeclarationSyntax; + } + + /// + /// Returns the kind of the specified represents. + /// + /// to get the kind represented by. + public static PropertyAccessorKind GetPropertyAccessorKind(this AccessorDeclarationSyntax node) + { + return node.GetAccessorKind().GetPropertyAccessorKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this PropertyDeclarationSyntax node) + { + return node.Type.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this IndexerDeclarationSyntax node) + { + return node.Type.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this LocalDeclarationStatementSyntax node) + { + return node.Declaration.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this VariableDeclarationSyntax node) + { + return node.Type.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this MethodDeclarationSyntax node) + { + return node.ReturnType.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this DelegateDeclarationSyntax node) + { + return node.ReturnType.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this ParenthesizedLambdaExpressionSyntax node) + { + return node.ReturnType?.GetRefKind() ?? default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this AnonymousFunctionExpressionSyntax node) + { + return (node as ParenthesizedLambdaExpressionSyntax)?.GetRefKind() ?? default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this ParameterSyntax node) + { + SyntaxTokenList list = node.Modifiers; + + for (int i = 0; i < list.Count; i++) + { + SyntaxToken token = list[i]; + + switch ((SyntaxKind)token.RawKind) + { + case SyntaxKind.InKeyword: + return RefKind.In; + + case SyntaxKind.RefKeyword: + return RefKind.Ref; + + case SyntaxKind.OutKeyword: + return RefKind.Out; + } + } + + return default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this FunctionPointerParameterSyntax node) + { + SyntaxTokenList list = node.Modifiers; + + for (int i = 0; i < list.Count; i++) + { + SyntaxToken token = list[i]; + + switch ((SyntaxKind)token.RawKind) + { + case SyntaxKind.RefKeyword: + + if (i < list.Count - 1 && (SyntaxKind)list[i + 1].RawKind == SyntaxKind.ReadOnlyKeyword) + { + return RefKind.RefReadOnly; + } + + return RefKind.Ref; + + case SyntaxKind.OutKeyword: + return RefKind.Out; + } + } + + return default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this BaseParameterSyntax node) + { + return node switch + { + ParameterSyntax parameter => parameter.GetRefKind(), + FunctionPointerParameterSyntax pointer => pointer.GetRefKind(), + _ => default + }; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this LocalFunctionStatementSyntax node) + { + return node.ReturnType.GetRefKind(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this TypeSyntax node) + { + return (node as RefTypeSyntax)?.GetRefKind() ?? default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static RefKind GetRefKind(this RefTypeSyntax node) + { + if (node.ReadOnlyKeyword != default) + { + return RefKind.RefReadOnly; + } + + return RefKind.Ref; + } + + /// + /// Returns the return type of the specified . + /// + /// to get the return type of. + public static TypeSyntax? GetReturnType(this SyntaxNode node) + { + return node switch + { + BaseMethodDeclarationSyntax method => method.GetReturnType(), + DelegateDeclarationSyntax @delegate => @delegate.ReturnType, + AccessorDeclarationSyntax accessor => accessor.GetReturnType(), + LocalFunctionStatementSyntax local => local.ReturnType, + ParenthesizedLambdaExpressionSyntax lambda => lambda.ReturnType, + BasePropertyDeclarationSyntax property => property.Type, + _ => default + }; + } + + /// + /// Returns the return type of the specified . + /// + /// to get the return type of. + public static TypeSyntax? GetReturnType(this BaseMethodDeclarationSyntax node) + { + return node switch + { + MethodDeclarationSyntax method => method.ReturnType, + OperatorDeclarationSyntax @operator => @operator.ReturnType, + ConversionOperatorDeclarationSyntax conversion => conversion.Type, + _ => default + }; + } + + /// + /// Returns the return type of the specified . + /// + /// to get the return type of. + public static TypeSyntax? GetReturnType(this AccessorDeclarationSyntax node) + { + if (node.GetAccessorKind().HasReturnType()) + { + return (node.Parent?.Parent as PropertyDeclarationSyntax)?.Type; + } + + return default; + } + + /// + /// Returns name of the root namespace of the specified . + /// + /// to get the root namespace of. + public static string? GetRootNamespace(this SyntaxNode node) + { + return node.GetContainingNamespaces(ReturnOrder.ParentToChild).FirstOrDefault(); + } + + /// + /// Returns a of the given declared in the specified . + /// + /// to get the of. + /// Kind of special constructor to return. + public static ConstructorDeclarationSyntax? GetSpecialConstructor(this TypeDeclarationSyntax node, SpecialConstructor kind) + { + if (kind == SpecialConstructor.None || kind == SpecialConstructor.Default) + { + return default; + } + + return node.Members + .OfType() + .FirstOrDefault(ctor => ctor.GetConstructorKind() == kind); + } + + /// + /// Returns a of the given declared in the specified . + /// + /// to get the of. + /// Kind of special constructor to return. + public static ConstructorDeclarationSyntax? GetSpecialConstructor(this BaseTypeDeclarationSyntax node, SpecialConstructor kind) + { + return (node as TypeDeclarationSyntax)?.GetSpecialConstructor(kind) ?? default; + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static StringModifiers GetStringModifiers(this LiteralExpressionSyntax node) + { + return node.Token.GetStringModifiers(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static StringModifiers GetStringModifiers(this InterpolatedStringExpressionSyntax node) + { + return node.StringStartToken.GetStringModifiers(); + } + + /// + /// Returns the applied to the specified . + /// + /// to get the applied to. + public static StringModifiers GetStringModifiers(this ExpressionSyntax node) + { + return node switch + { + LiteralExpressionSyntax literal => literal.GetStringModifiers(), + InterpolatedStringExpressionSyntax interpolated => interpolated.GetStringModifiers(), + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static SymbolKind GetSymbolKind(this SyntaxNode node) + { + return node switch + { + BaseNamespaceDeclarationSyntax + => SymbolKind.Namespace, + + BaseTypeDeclarationSyntax or + DelegateDeclarationSyntax or + AnonymousObjectCreationExpressionSyntax or + TupleExpressionSyntax + => SymbolKind.NamedType, + + BaseMethodDeclarationSyntax or + AnonymousFunctionExpressionSyntax or + LocalFunctionStatementSyntax or + AccessorDeclarationSyntax + => SymbolKind.Method, + + PropertyDeclarationSyntax or + IndexerDeclarationSyntax or + AnonymousObjectMemberDeclaratorSyntax + => SymbolKind.Property, + + EventDeclarationSyntax or + EventFieldDeclarationSyntax + => SymbolKind.Event, + + BaseParameterSyntax + => SymbolKind.Parameter, + + TypeParameterSyntax + => SymbolKind.TypeParameter, + + ExternAliasDirectiveSyntax + => SymbolKind.Alias, + + EnumMemberDeclarationSyntax or + FieldDeclarationSyntax + => SymbolKind.Field, + + LocalDeclarationStatementSyntax + => SymbolKind.Local, + + LabeledStatementSyntax or + SwitchLabelSyntax + => SymbolKind.Label, + + ArrayTypeSyntax + => SymbolKind.ArrayType, + + PointerTypeSyntax + => SymbolKind.PointerType, + + FunctionPointerTypeSyntax + => SymbolKind.FunctionPointerType, + + QueryClauseSyntax or + QueryContinuationSyntax or + JoinIntoClauseSyntax + => SymbolKind.RangeVariable, + + DiscardPatternSyntax + => SymbolKind.Discard, + + DirectiveTriviaSyntax + => SymbolKind.Preprocessing, + + UsingDirectiveSyntax @using when @using.GetUsingKind() == UsingKind.Alias + => SymbolKind.Alias, + + _ => default + }; + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this ArrayTypeSyntax node) + { + return node.ElementType.GetTypeKeyword(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this PointerTypeSyntax node) + { + return node.ElementType.GetTypeKeyword(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this NullableTypeSyntax node) + { + return node.ElementType.GetTypeKeyword(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this RefTypeSyntax node) + { + return node.Type.GetTypeKeyword(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this PredefinedTypeSyntax node) + { + return node.Keyword.GetTypeKeyword(); + } + + /// + /// Returns the represented by the specified . + /// + /// to get the represented by. + public static TypeKeyword GetTypeKeyword(this TypeSyntax node) + { + switch (node) + { + case PredefinedTypeSyntax predefined: + return predefined.GetTypeKeyword(); + + case RefTypeSyntax refType: + return refType.GetTypeKeyword(); + + case NullableTypeSyntax nullable: + return nullable.GetTypeKeyword(); + + case PointerTypeSyntax pointer: + return pointer.GetTypeKeyword(); + + case ArrayTypeSyntax array: + return array.GetTypeKeyword(); + } + + if (node.IsNint) + { + return TypeKeyword.NInt; + } + + if (node.IsNuint) + { + return TypeKeyword.NUInt; + } + + if (node.IsDynamic()) + { + return TypeKeyword.Dynamic; + } + + return default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeKind GetTypeKind(this SyntaxNode node) + { + return node switch + { + BaseTypeDeclarationSyntax decl => decl.GetTypeKind(), + DelegateDeclarationSyntax => TypeKind.Delegate, + TypeParameterSyntax => TypeKind.TypeParameter, + TypeSyntax type => type.GetTypeKind(), + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeKind GetTypeKind(this TypeSyntax node) + { + if (node is NullableTypeSyntax nullable) + { + node = nullable.ElementType; + } + + return node switch + { + ArrayTypeSyntax => TypeKind.Array, + PointerTypeSyntax => TypeKind.Pointer, + FunctionPointerTypeSyntax => TypeKind.FunctionPointer, + _ => node.IsDynamic() ? TypeKind.Dynamic : default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeKind GetTypeKind(this BaseTypeDeclarationSyntax node) + { + return node switch + { + ClassDeclarationSyntax => TypeKind.Class, + StructDeclarationSyntax => TypeKind.Struct, + EnumDeclarationSyntax => TypeKind.Enum, + InterfaceDeclarationSyntax => TypeKind.Interface, + RecordDeclarationSyntax record => record.IsStruct() ? TypeKind.Struct : TypeKind.Class, + _ => default + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeParameterKind GetTypeParameterKind(this TypeSyntax node) + { + return node.Ancestors().OfType().Any() ? TypeParameterKind.Cref : default; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static TypeParameterKind GetTypeParameterKind(this TypeParameterSyntax node) + { + return node?.Parent?.Parent switch + { + TypeDeclarationSyntax or DelegateDeclarationSyntax => TypeParameterKind.Type, + MethodDeclarationSyntax or LocalFunctionStatementSyntax => TypeParameterKind.Method, + _ => default + }; + } + + /// + /// Returns a of the or if the has no type parameters. + /// + /// to get the of. + public static TypeParameterListSyntax? GetTypeParameterList(this MemberDeclarationSyntax member) + { + return member switch + { + TypeDeclarationSyntax t => t.TypeParameterList, + MethodDeclarationSyntax m => m.TypeParameterList, + DelegateDeclarationSyntax d => d.TypeParameterList, + _ => null + }; + } + + /// + /// Returns the associated with the specified . + /// + /// to get the associated with. + public static UsingKind GetUsingKind(this UsingDirectiveSyntax node) + { + if (node.Alias is not null) + { + return UsingKind.Alias; + } + + if (node.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) + { + return UsingKind.Static; + } + + return UsingKind.Ordinary; + } + + /// + /// Returns a at the specified in the . + /// + /// to get the variable of. + /// Index to get the at. + public static VariableDeclaratorSyntax GetVariable(this LocalDeclarationStatementSyntax node, int index) + { + return node.Declaration.GetVariable(index); + } + + /// + /// Returns a at the specified in the . + /// + /// to get the variable of. + /// Index to get the at. + public static VariableDeclaratorSyntax GetVariable(this BaseFieldDeclarationSyntax node, int index) + { + return node.Declaration.GetVariable(index); + } + + /// + /// Returns a at the specified in the . + /// + /// to get the variable of. + /// Index to get the at. + public static VariableDeclaratorSyntax GetVariable(this VariableDeclarationSyntax node, int index) + { + return node.Variables[index]; + } + + /// + /// Returns the of the specified . + /// + /// to get the of. + public static VarianceKind GetVariance(this TypeParameterSyntax node) + { + return node.VarianceKeyword.GetVariance(); + } + + /// + /// Determines whether the specified defines an of a given kind. + /// + /// to determines whether has an of a given kind. + /// Kind of accessor to check for. + public static bool HasAccessor(this PropertyDeclarationSyntax node, PropertyAccessorKind accessor) + { + if (node.ExpressionBody is not null) + { + return accessor == PropertyAccessorKind.Get; + } + + return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; + } + + /// + /// Determines whether the specified defines an of a given kind. + /// + /// to determines whether has an of a given kind. + /// Kind of accessor to check for. + public static bool HasAccessor(this IndexerDeclarationSyntax node, PropertyAccessorKind accessor) + { + if (node.ExpressionBody is not null) + { + return accessor == PropertyAccessorKind.Get; + } + + return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; + } + + /// + /// Determines whether the specified defines an of a given kind. + /// + /// to determines whether has an of a given kind. + /// Kind of accessor to check for. + public static bool HasAccessor(this EventDeclarationSyntax node, EventAccessorKind accessor) + { + return node.AccessorList?.HasAccessor(accessor.GetAccessorKind()) ?? false; + } + + /// + /// Determines whether the specified defines an of a given kind. + /// + /// to determines whether has an of a given kind. + /// Kind of accessor to check for. + public static bool HasAccessor(this BasePropertyDeclarationSyntax node, AccessorKind accessor) + { + return node.AccessorList?.HasAccessor(accessor) ?? false; + } + + /// + /// Determines whether the specified defines an of a given kind. + /// + /// to determines whether has an of a given kind. + /// Kind of accessor to check for. + public static bool HasAccessor(this AccessorListSyntax node, AccessorKind accessor) + { + return node.Accessors.Any(acc => acc.GetAccessorKind() == accessor); + } + + /// + /// Checks if the target has a body, either block or expression. + /// + /// to check if has a body. + public static bool HasBody(this BaseMethodDeclarationSyntax method) + { + return method.GetBody() is not null; + } + + /// + /// Determines whether the specified has any generic constraints applied. + /// + /// to determine whether has any generic constraints applied. + public static bool HasConstraints(this TypeParameterSyntax node) + { + return node.GetConstraintClause() is not null; + } + + /// + /// Determines whether the specified has a of the given kind applied. + /// + /// to determine whether has a of the given kind applied. + /// to check for. + /// Determines whether to include constraints that are implicitly applied to the . + public static bool HasConstraints(this TypeParameterSyntax node, GenericConstraint constraint, bool includeImplicit = false) + { + return node.GetConstraintClause()?.HasConstraints(constraint, includeImplicit) ?? false; + } + + /// + /// Determines whether the specified contains a of the given kind. + /// + /// to determine whether contains a of the given kind. + /// to check for. + /// Determines whether to include constraints that are implicitly applied to the . + public static bool HasConstraints(this TypeParameterConstraintSyntax node, GenericConstraint constraint, bool includeImplicit = false) + { + if (!includeImplicit) + { + return HasConstraintExplicit(node, constraint); + } + + return HasConstraintImplicit(node, constraint); + } + + /// + /// Determines whether the specified contains a of the given kind. + /// + /// to determine whether contains a of the given kind. + /// to check for. + /// Determines whether to include constraints that are implicitly applied to the . + public static unsafe bool HasConstraints(this TypeParameterConstraintClauseSyntax node, GenericConstraint constraint, bool includeImplicit = false) + { + GenericConstraint[] values = constraint.GetFlags(); + + if (values.Length == 0) + { + return false; + } + + Queue queue = new(values); + + // Why function pointer instead of a Func? Because it's more fun this way! + + delegate* func = includeImplicit + ? &HasConstraintImplicit + : &HasConstraintExplicit; + + foreach (TypeParameterConstraintSyntax cons in node.Constraints) + { + int count = queue.Count; + + for (int i = 0; i < count; i++) + { + GenericConstraint value = queue.Dequeue(); + + if (!func(cons, value)) + { + queue.Enqueue(value); + } + } + + if (queue.Count == 0) + { + return true; + } + } + + return false; + } + + /// + /// Returns the applied to the specified . + /// + /// get the applied to. + public static DocumentationCommentTriviaSyntax? GetXmlDocumentation(this SyntaxNode node) + { + if (!node.HasLeadingTrivia) + { + return default; + } + + SyntaxTriviaList leadingTrivia = node.GetLeadingTrivia(); + SyntaxTrivia token = leadingTrivia.FirstOrDefault(token => token.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || token.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)); + + if (token.IsKind(SyntaxKind.None)) + { + return default; + } + + SyntaxNode? structure = token.GetStructure(); + + return structure as DocumentationCommentTriviaSyntax; + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsAbstract(this SyntaxNode node) + { + return node.GetModifiers().IsAbstract(); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this BaseMethodDeclarationSyntax node) + { + return node.ParameterList.IsArgList(); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this DelegateDeclarationSyntax node) + { + return node.ParameterList.IsArgList(); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this BaseParameterListSyntax node) + { + return node.Parameters.Any(IsArgList); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this LocalFunctionStatementSyntax node) + { + return node.ParameterList.IsArgList(); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this RecordDeclarationSyntax node) + { + return node.ParameterList?.IsArgList() ?? false; + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this AnonymousMethodExpressionSyntax node) + { + return node.ParameterList?.IsArgList() ?? false; + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this AnonymousFunctionExpressionSyntax node) + { + return node switch + { + LambdaExpressionSyntax lambda => lambda.IsArgList(), + AnonymousMethodExpressionSyntax method => method.IsArgList(), + _ => false + }; + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this LambdaExpressionSyntax node) + { + return (node as ParenthesizedLambdaExpressionSyntax)?.IsArgList() ?? false; + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this ParenthesizedLambdaExpressionSyntax node) + { + return node.ParameterList.IsArgList(); + } + + /// + /// Determines whether any parameter of the specified represents the keyword. + /// + /// to determine whether contains any parameter representing the keyword. + public static bool IsArgList(this IndexerDeclarationSyntax node) + { + return node.ParameterList.IsArgList(); + } + + /// + /// Determines whether the specified represents the keyword. + /// + /// to determine whether represents the keyword. + public static bool IsArgList(this BaseParameterSyntax node) + { + return (node as ParameterSyntax)?.IsArgList() ?? false; + } + + /// + /// Determines whether the specified represents the keyword. + /// + /// to determine whether represents the keyword. + public static bool IsArgList(this ParameterSyntax node) + { + return node.Type is null && node.Identifier.IsKind(SyntaxKind.ArgListKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. +#pragma warning disable RCS1047 // Non-asynchronous method name should not end with 'Async'. + public static bool IsAsync(this SyntaxNode node) +#pragma warning restore RCS1047 // Non-asynchronous method name should not end with 'Async'. + { + return node.GetModifiers().IsAsync(); + } + + /// + /// Determines whether the specified represents an auto-property. + /// + /// to determine whether represents an auto-property. + public static bool IsAutoProperty(this PropertyDeclarationSyntax node) + { + if (node.AccessorList is null) + { + return false; + } + + return node.AccessorList.IsAutoProperty(); + } + + /// + /// Determines whether the specified represents an auto-property. + /// + /// to determine whether represents an auto-property. + public static bool IsAutoProperty(this BasePropertyDeclarationSyntax node) + { + return (node as PropertyDeclarationSyntax)?.IsAutoProperty() ?? false; + } + + /// + /// Determines whether the specified represents an auto-property accessor list. + /// + /// to determine whether represents an auto-property accessor list. + public static bool IsAutoProperty(this AccessorListSyntax node) + { + foreach (AccessorDeclarationSyntax accessor in node.Accessors) + { + if (accessor.GetBody() is not null) + { + return false; + } + } + + return true; + } + + /// + /// Determines whether the specified is an auto-property accessor. + /// + /// to determine whether is an auto-property accessor. + public static bool IsAutoPropertyAccessor(this AccessorDeclarationSyntax node) + { + return (node.Parent?.Parent as PropertyDeclarationSyntax)?.IsAutoProperty() ?? false; + } + + /// + /// Determines whether the specified is a class constraint. + /// + /// to determine whether is a class constraint. + public static bool IsClass(this ClassOrStructConstraintSyntax node) + { + return node.ClassOrStructKeyword.IsKind(SyntaxKind.ClassKeyword); + } + + /// + /// Determines whether the specified is a class type. + /// + /// to determine whether is a class type. + public static bool IsClass(this BaseTypeDeclarationSyntax node) + { + return node is ClassDeclarationSyntax || (node is RecordDeclarationSyntax record && record.IsClass()); + } + + /// + /// Determines whether the specified is a class type. + /// + /// to determine whether is a class type. + public static bool IsClass(this RecordDeclarationSyntax node) + { + return node.ClassOrStructKeyword.IsKind(SyntaxKind.ClassKeyword); + } + + /// + /// Determines whether the specified is considered a declaration node and can be used as argument for the GetDeclaredSymbol method of a . + /// + /// to determine whether is considered a declaration node. + public static bool IsDeclaration(this SyntaxNode node) + { + return node is + MemberDeclarationSyntax or + AccessorDeclarationSyntax or + TypeParameterSyntax or + ParameterSyntax or + VariableDesignationSyntax or + AnonymousObjectCreationExpressionSyntax or + AnonymousObjectMemberDeclaratorSyntax or + ArgumentSyntax or + CatchDeclarationSyntax or + ExternAliasDirectiveSyntax or + CompilationUnitSyntax or + ForEachStatementSyntax or + LabeledStatementSyntax or + JoinIntoClauseSyntax or + QueryClauseSyntax or + QueryContinuationSyntax or + SingleVariableDesignationSyntax or + SwitchLabelSyntax or + UsingDirectiveSyntax or + TupleElementSyntax or + TupleExpressionSyntax; + } + + /// + /// Determines whether the specified represents a #pragma warning disable directive. + /// + /// to determine whether represents a #pragma warning disable directive. + public static bool IsDisable(this PragmaWarningDirectiveTriviaSyntax node) + { + return node.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword); + } + + /// + /// Determines whether the specified represents the keyword. + /// + /// to determine whether represents the keyword. + public static bool IsDynamic(this TypeSyntax node) + { + return node is IdentifierNameSyntax { Identifier.ValueText: "dynamic" }; + } + + /// + /// Determines whether the specified is an event accessor. + /// + /// to determine whether is an event accessor. + public static bool IsEventAccessor(this AccessorDeclarationSyntax node) + { + return node.Parent?.Parent is EventDeclarationSyntax; + } + + /// + /// Determines whether the specified represents a declaration of an . This applies to: + /// + /// . + /// + /// + /// + /// to determine whether represents a declaration of an . + public static bool IsEventDeclaration(this SyntaxNode node) + { + return node is + EventFieldDeclarationSyntax or + EventDeclarationSyntax; + } + + /// + /// Determines whether the specified represents an explicit operator. + /// + /// to determine whether represents an explicit operator. + public static bool IsExplicit(this ConversionOperatorDeclarationSyntax node) + { + return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ExplicitKeyword); + } + + /// + /// Determines whether the specified represents an explicit operator. + /// + /// to determine whether represents an explicit operator. + public static bool IsExplicit(this ConversionOperatorMemberCrefSyntax node) + { + return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ExplicitKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsExtern(this SyntaxNode node) + { + return node.GetModifiers().IsExtern(); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsFixed(this SyntaxNode node) + { + return node.GetModifiers().IsFixed(); + } + + /// + /// Determines whether the specified represents a directive. + /// + /// to determine whether represents a directive. + public static bool IsGlobal(this UsingDirectiveSyntax node) + { + return node.GlobalKeyword.IsKind(SyntaxKind.GlobalKeyword); + } + + /// + /// Determines whether the specified represents an implicit operator. + /// + /// to determine whether represents an implicit operator. + public static bool IsImplicit(this ConversionOperatorDeclarationSyntax node) + { + return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword); + } + + /// + /// Determines whether the specified represents an implicit operator. + /// + /// to determine whether represents an implicit operator. + public static bool IsImplicit(this ConversionOperatorMemberCrefSyntax node) + { + return node.ImplicitOrExplicitKeyword.IsKind(SyntaxKind.ImplicitKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsIn(this SyntaxNode node) + { + return node.GetModifiers().IsIn(); + } + + /// + /// Determines whether the specified is contained within another . + /// + /// to determine whether is contained within another . + public static bool IsInnerType(this BaseTypeDeclarationSyntax node) + { + return node.Ancestors().OfType().Any(); + } + + /// + /// Determines whether the specified is an iterator (contains any es). + /// + /// to determine whether is an iterator. + public static bool IsIterator(this BaseMethodDeclarationSyntax node) + { + return (node as MethodDeclarationSyntax)?.IsIterator() ?? false; + } + + /// + /// Determines whether the specified is an iterator (contains any es). + /// + /// to determine whether is an iterator. + public static bool IsIterator(this MethodDeclarationSyntax node) + { + return node + .DescendantNodes(node => node.Kind() is + not SyntaxKind.LocalFunctionStatement and + not SyntaxKind.AnonymousMethodExpression and + not SyntaxKind.SimpleLambdaExpression and + not SyntaxKind.ParenthesizedLambdaExpression && + node is not ExpressionSyntax + ) + .Any(n => n is YieldStatementSyntax); + } + + /// + /// Determines whether the specified is an iterator (contains any es). + /// + /// to determine whether is an iterator. + public static bool IsIterator(this LocalFunctionStatementSyntax node) + { + return node + .DescendantNodes(node => node.Kind() is + not SyntaxKind.LocalFunctionStatement and + not SyntaxKind.AnonymousMethodExpression and + not SyntaxKind.SimpleLambdaExpression and + not SyntaxKind.ParenthesizedLambdaExpression && + node is not ExpressionSyntax + ) + .Any(n => n is YieldStatementSyntax); + } + + /// + /// Determines whether the specified uses the calling convention. + /// + /// to determine whether uses the calling convention. + public static bool IsManaged(this FunctionPointerTypeSyntax node) + { + return node.CallingConvention?.IsManaged() ?? true; + } + + /// + /// Determines whether the specified uses the calling convention. + /// + /// to determine whether uses the calling convention. + public static bool IsManaged(this FunctionPointerCallingConventionSyntax node) + { + return node.ManagedOrUnmanagedKeyword == default || node.ManagedOrUnmanagedKeyword.IsKind(SyntaxKind.ManagedKeyword); + } + + /// + /// Determines whether the specified represents a declaration of an . This applies to: + /// + /// (and its derived types) + /// (and its derived types) + /// + /// + /// + /// + /// to determine whether represents a declaration of an . + public static bool IsMethodDeclaration(this SyntaxNode node) + { + return node is + BaseMethodDeclarationSyntax or + AnonymousFunctionExpressionSyntax or + LocalFunctionStatementSyntax or + AccessorDeclarationSyntax; + } + + /// + /// Determines whether the specified contains the token. + /// + /// to determine whether contains the modifier. + public static bool IsNew(this SyntaxNode node) + { + return node.GetModifiers().IsNew(); + } + + /// + /// Determines whether the specified represents the constraint. + /// + /// to determine whether represents the constraint. + public static bool IsNotNullConstraint(this TypeConstraintSyntax node) + { + return node.Type.IsNotNull; + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsOverride(this SyntaxNode node) + { + return node.GetModifiers().IsOverride(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this BaseMethodDeclarationSyntax node) + { + return node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this DelegateDeclarationSyntax node) + { + return node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this RecordDeclarationSyntax node) + { + return node.ParameterList is null || node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this LocalFunctionStatementSyntax node) + { + return node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this AnonymousMethodExpressionSyntax node) + { + return node.ParameterList is null || node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this AnonymousFunctionExpressionSyntax node) + { + return node switch + { + LambdaExpressionSyntax lambda => lambda.IsParameterless(), + AnonymousMethodExpressionSyntax method => method.IsParameterless(), + _ => default + }; + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this ParenthesizedLambdaExpressionSyntax node) + { + return node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this LambdaExpressionSyntax node) + { + if (node is SimpleLambdaExpressionSyntax) + { + return true; + } + + return (node as ParenthesizedLambdaExpressionSyntax)?.IsParameterless() ?? false; + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this BaseParameterListSyntax node) + { + return !node.Parameters.Any(); + } + + /// + /// Determines whether the specified is parameterless. + /// + /// to determine whether is parameterless + public static bool IsParameterless(this IndexerDeclarationSyntax node) + { + return node.ParameterList.IsParameterless(); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsParams(this SyntaxNode node) + { + return node.GetModifiers().IsParams(); + } + + /// + /// Determines whether the specified contains the token. + /// + /// to determine whether contains the modifier. + public static bool IsPartial(this SyntaxNode node) + { + return node.GetModifiers().IsPartial(); + } + + /// + /// Determines whether the specified is a property accessor. + /// + /// to determine whether is a property accessor. + public static bool IsPropertyAccessor(this AccessorDeclarationSyntax node) + { + return node.Parent?.Parent is PropertyDeclarationSyntax or IndexerDeclarationSyntax; + } + + /// + /// Determines whether the specified contains the modifier ( does not count). + /// + /// to determine whether contains the modifier. + public static bool IsReadOnly(this SyntaxNode node) + { + return node.GetModifiers().IsReadOnly(); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsRef(this SyntaxNode node) + { + return node.GetModifiers().IsRef(); + } + + /// + /// Determines whether the specified contains the and modifier. + /// + /// to determine whether contains the and modifiers. + public static bool IsRefReadOnly(this SyntaxNode node) + { + return node.GetModifiers().IsRefReadOnly(); + } + + /// + /// Determines whether the specified represents a #pragma warning restore directive. + /// + /// to determine whether represents a #pragma warning restore directive. + public static bool IsRestore(this PragmaWarningDirectiveTriviaSyntax node) + { + return node.DisableOrRestoreKeyword.IsKind(SyntaxKind.RestoreKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsSealed(this SyntaxNode node) + { + return node.GetModifiers().IsSealed(); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsStatic(this SyntaxNode node) + { + return node.GetModifiers().IsStatic(); + } + + /// + /// Determines whether the specified is a struct constraint. + /// + /// to determine whether is a struct constraint. + public static bool IsStruct(this ClassOrStructConstraintSyntax node) + { + return node.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); + } + + /// + /// Determines whether the specified is a struct type. + /// + /// to determine whether is a struct type. + public static bool IsStruct(this BaseTypeDeclarationSyntax node) + { + return node is StructDeclarationSyntax || (node is RecordDeclarationSyntax record && record.IsStruct()); + } + + /// + /// Determines whether the specified is a struct type. + /// + /// to determine whether is a struct type. + public static bool IsStruct(this RecordDeclarationSyntax node) + { + return node.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsThis(this SyntaxNode node) + { + return node.GetModifiers().IsThis(); + } + + /// + /// Determines whether the specified as declared at the top level, meaning the is either: + /// + /// + /// + /// + /// + /// + /// to determine whether is at the top level. + public static bool IsTopLevel(this SyntaxNode node) + { + return node.Parent is + null or + CompilationUnitSyntax or + GlobalStatementSyntax; + } + + /// + /// Determines whether the specified as declared in a namespace or at the top level (see for more details). + /// + /// to determine whether is at the top level. + public static bool IsTopLevelOrInNamespace(this SyntaxNode node) + { + return node.Parent is + null or + CompilationUnitSyntax or + BaseNamespaceDeclarationSyntax; + } + + /// + /// Determines whether the specified represents a named type constraint. + /// + /// to determine whether represents a named type constraint. + public static bool IsTypeConstraint(this TypeConstraintSyntax node) + { + return !node.IsUnmanagedConstraint() && !node.IsNotNullConstraint(); + } + + /// + /// Determines whether the specified represents a declaration of an . This applies to: + /// + /// (and its derived types) + /// + /// + /// + /// to determine whether represents a declaration of an . + public static bool IsTypeDeclaration(this SyntaxNode node) + { + return node is + BaseTypeDeclarationSyntax or + DelegateDeclarationSyntax; + } + + /// + /// Determines whether the specified uses the calling convention. + /// + /// to determine whether uses the calling convention. + public static bool IsUnmanaged(this FunctionPointerTypeSyntax node) + { + return node.CallingConvention?.IsUnmanaged() ?? false; + } + + /// + /// Determines whether the specified uses the calling convention. + /// + /// to determine whether uses the calling convention. + public static bool IsUnmanaged(this FunctionPointerCallingConventionSyntax node) + { + return node.ManagedOrUnmanagedKeyword.IsKind(SyntaxKind.UnmanagedKeyword); + } + + /// + /// Determines whether the specified represents the constraint. + /// + /// to determine whether contains the modifier. + public static bool IsUnmanagedConstraint(this TypeConstraintSyntax node) + { + return node.Type.IsUnmanaged; + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsUnsafe(this SyntaxNode node) + { + return node.GetModifiers().IsUnsafe(); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsVirtual(this SyntaxNode node) + { + return node.GetModifiers().IsVirtual(); + } + + /// + /// Determines whether the specified returns . + /// + /// to determine whether returns . + public static bool IsVoid(this BaseMethodDeclarationSyntax node) + { + return (node as MethodDeclarationSyntax)?.IsVoid() ?? false; + } + + /// + /// Determines whether the specified returns . + /// + /// to determine whether returns . + public static bool IsVoid(this MethodDeclarationSyntax node) + { + return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); + } + + /// + /// Determines whether the specified returns . + /// + /// to determine whether returns . + public static bool IsVoid(this LocalFunctionStatementSyntax node) + { + return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); + } + + /// + /// Determines whether the specified returns . + /// + /// to determine whether returns . + public static bool IsVoid(this DelegateDeclarationSyntax node) + { + return node.ReturnType is PredefinedTypeSyntax type && type.Keyword.IsKind(SyntaxKind.VoidKeyword); + } + + /// + /// Determines whether the specified contains the modifier. + /// + /// to determine whether contains the modifier. + public static bool IsVolatile(this SyntaxNode node) + { + return node.GetModifiers().IsVolatile(); + } + + /// + /// Determines whether the specified represents a break statement. + /// + /// to determine whether represents a break statement. + public static bool IsYieldBreak(this YieldStatementSyntax node) + { + return node.ReturnOrBreakKeyword.IsKind(SyntaxKind.BreakKeyword); + } + + /// + /// Determines whether the specified represents a return statement. + /// + /// to determine whether represents a return statement. + public static bool IsYieldReturn(this YieldStatementSyntax node) + { + return node.ReturnOrBreakKeyword.IsKind(SyntaxKind.ReturnKeyword); + } + + /// + /// Determines whether the specified supports more than one attribute target kind. + /// + /// to determine whether supports more than one attribute target kind. + public static bool SupportsAlternativeAttributeTargets(this SyntaxNode node) + { + return node switch + { + MemberDeclarationSyntax member + => member.SupportsAlternativeAttributeTargets(), + + CompilationUnitSyntax or + AccessorDeclarationSyntax or + LambdaExpressionSyntax or + LocalFunctionStatementSyntax + => true, + + _ => false + }; + } + + /// + /// Determines whether the specified supports more than one attribute target kind. + /// + /// to determine whether supports more than one attribute target kind. + public static bool SupportsAlternativeAttributeTargets(this MemberDeclarationSyntax node) + { + return node switch + { + MethodDeclarationSyntax or + DelegateDeclarationSyntax or + EventFieldDeclarationSyntax or + ConversionOperatorDeclarationSyntax or + OperatorDeclarationSyntax or + BaseNamespaceDeclarationSyntax + => true, + + PropertyDeclarationSyntax property + => property.IsAutoProperty(), + + _ => false + }; + } + + /// + /// Determines whether the specified can have an explicit base type. + /// + /// to check whether can have an explicit base type. + public static bool SupportsExplicitBaseType(this BaseTypeDeclarationSyntax node) + { + return node switch + { + ClassDeclarationSyntax => !node.IsStatic(), + RecordDeclarationSyntax record => record.IsClass(), + EnumDeclarationSyntax or InterfaceDeclarationSyntax => true, + _ => false + }; + } + + private static bool HasConstraintExplicit(TypeParameterConstraintSyntax node, GenericConstraint constraint) + { + return constraint switch + { + GenericConstraint.Class => node is ClassOrStructConstraintSyntax @class && @class.IsClass(), + GenericConstraint.Struct => node is ClassOrStructConstraintSyntax @struct && @struct.IsStruct(), + GenericConstraint.New => node is ConstructorConstraintSyntax, + GenericConstraint.Unmanaged => node is TypeConstraintSyntax unmanaged && unmanaged.IsUnmanagedConstraint(), + GenericConstraint.NotNull => node is TypeConstraintSyntax notnull && notnull.IsNotNullConstraint(), + GenericConstraint.Type => node is TypeConstraintSyntax type && type.IsTypeConstraint(), + GenericConstraint.Default => node is DefaultConstraintSyntax, + _ => false + }; + } + + private static bool HasConstraintImplicit(TypeParameterConstraintSyntax node, GenericConstraint constraint) + { + bool isValid = false; + + if (constraint.HasFlag(GenericConstraint.Class)) + { + if (node is ClassOrStructConstraintSyntax @class) + { + if (!@class.IsClass()) + { + return false; + } + } + else if (!IsType()) + { + return false; + } + + isValid = true; + } + else if (constraint.HasFlag(GenericConstraint.Struct)) + { + if (node is ClassOrStructConstraintSyntax @struct) + { + if (!@struct.IsStruct()) + { + return false; + } + } + else if (!IsUnmanaged()) + { + return false; + } + + isValid = true; + } + else if (constraint.HasFlag(GenericConstraint.Unmanaged)) + { + if (!IsUnmanaged()) + { + return false; + } + + isValid = true; + } + else if (constraint.HasFlag(GenericConstraint.NotNull)) + { + if (node is not TypeConstraintSyntax notnull || !notnull.IsNotNullConstraint()) + { + return false; + } + + isValid = true; + } + else if (constraint.HasFlag(GenericConstraint.Default)) + { + if (node is not DefaultConstraintSyntax) + { + return false; + } + + isValid = true; + } + + if (constraint.HasFlag(GenericConstraint.Type)) + { + if (!IsType()) + { + return false; + } + + isValid = true; + } + + if (constraint.HasFlag(GenericConstraint.New)) + { + if (node is not ConstructorConstraintSyntax) + { + if (node is not ClassOrStructConstraintSyntax @struct || !@struct.IsStruct()) + { + return false; + } + } + + isValid = true; + } + + return isValid; + + bool IsType() + { + return node is TypeConstraintSyntax type && type.IsTypeConstraint(); + } + + bool IsUnmanaged() + { + return node is TypeConstraintSyntax unmanaged && unmanaged.IsUnmanagedConstraint(); + } + } +} diff --git a/src/Durian.AnalysisServices/Extensions/SyntaxReferenceExtensions.cs b/src/Durian.AnalysisServices/SyntaxReferenceExtensions.cs similarity index 97% rename from src/Durian.AnalysisServices/Extensions/SyntaxReferenceExtensions.cs rename to src/Durian.AnalysisServices/SyntaxReferenceExtensions.cs index f095cc4..203cec3 100644 --- a/src/Durian.AnalysisServices/Extensions/SyntaxReferenceExtensions.cs +++ b/src/Durian.AnalysisServices/SyntaxReferenceExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for classes. diff --git a/src/Durian.AnalysisServices/Extensions/SyntaxTokenExtensions.cs b/src/Durian.AnalysisServices/SyntaxTokenExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/SyntaxTokenExtensions.cs rename to src/Durian.AnalysisServices/SyntaxTokenExtensions.cs index 2bb47ff..7c9bac0 100644 --- a/src/Durian.AnalysisServices/Extensions/SyntaxTokenExtensions.cs +++ b/src/Durian.AnalysisServices/SyntaxTokenExtensions.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains extension methods for the and structs. diff --git a/src/Durian.AnalysisServices/Extensions/SyntaxTreeExtensions.cs b/src/Durian.AnalysisServices/SyntaxTreeExtensions.cs similarity index 99% rename from src/Durian.AnalysisServices/Extensions/SyntaxTreeExtensions.cs rename to src/Durian.AnalysisServices/SyntaxTreeExtensions.cs index 7a40f9c..47a73a9 100644 --- a/src/Durian.AnalysisServices/Extensions/SyntaxTreeExtensions.cs +++ b/src/Durian.AnalysisServices/SyntaxTreeExtensions.cs @@ -4,7 +4,7 @@ using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; -namespace Durian.Analysis.Extensions; +namespace Durian.Analysis; /// /// Contains various extension methods for the class. diff --git a/src/Durian.AnalysisServices/SyntaxVisitors/IdentifierToQualifiedName.cs b/src/Durian.AnalysisServices/SyntaxVisitors/IdentifierToQualifiedName.cs index 8c91807..d7a68f5 100644 --- a/src/Durian.AnalysisServices/SyntaxVisitors/IdentifierToQualifiedName.cs +++ b/src/Durian.AnalysisServices/SyntaxVisitors/IdentifierToQualifiedName.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.AnalysisServices/_init.cs b/src/Durian.AnalysisServices/_init.cs index e5247ad..c62e8e1 100644 --- a/src/Durian.AnalysisServices/_init.cs +++ b/src/Durian.AnalysisServices/_init.cs @@ -7,6 +7,7 @@ [assembly: InternalsVisibleTo("Durian.FriendClass")] [assembly: InternalsVisibleTo("Durian.Core.Analyzer")] [assembly: InternalsVisibleTo("Durian.TestServices")] +[assembly: InternalsVisibleTo("Durian.GlobalScope")] [assembly: SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1025:Configure generated code analysis", Justification = "Abstract class Durian.Analyzers.DurianAnayzer configured generated code analysis in its Initialize(context) method.")] [assembly: SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1026:Enable concurrent execution", Justification = "Abstract class Durian.Analyzers.DurianAnalyzer enables concurrent execution in its Initialize(context) method.")] diff --git a/src/Durian.CopyFrom/AnalyzerReleases.Shipped.md b/src/Durian.CopyFrom/AnalyzerReleases.Shipped.md index e760802..8a2ad9a 100644 --- a/src/Durian.CopyFrom/AnalyzerReleases.Shipped.md +++ b/src/Durian.CopyFrom/AnalyzerReleases.Shipped.md @@ -5,7 +5,7 @@ Rule ID | Category | Severity | Notes --------|----------|----------|----------------------------------------- DUR0201 | Durian.CopyFrom | Error | Containing type of a member with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0201.md)] DUR0202 | Durian.CopyFrom | Error | Member marked with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0202.md)] -DUR0203 | Durian.CopyFrom | Error | Target member cannot be resolved. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0204.md)] +DUR0203 | Durian.CopyFrom | Error | Target member cannot be resolved. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0203.md)] DUR0204 | Durian.CopyFrom | Error | Target member is not compatible. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0204.md)] DUR0205 | Durian.CopyFrom | Error | Implementation of the target member is not accessible. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0205.md)] DUR0206 | Durian.CopyFrom | Warning | Equivalent CopyFromTypeAttribute already specified. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0206.md)] diff --git a/src/Durian.CopyFrom/CopyFromAnalyzer.cs b/src/Durian.CopyFrom/CopyFromAnalyzer.cs index 8346bb6..d972acc 100644 --- a/src/Durian.CopyFrom/CopyFromAnalyzer.cs +++ b/src/Durian.CopyFrom/CopyFromAnalyzer.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -56,11 +54,17 @@ public CopyFromAnalyzer() } /// - public override void Register(IDurianAnalysisContext context, CopyFromCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, CopyFromCompilationData compilation) { context.RegisterSyntaxNodeAction(c => AnalyzeAttributeSyntax(c, compilation), SyntaxKind.Attribute); } + /// + protected override CopyFromCompilationData CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver) + { + return new CopyFromCompilationData(compilation); + } + internal static bool HasCopyFromsOnCurrentDeclaration(MemberDeclarationSyntax currentDeclaration, AttributeData[] attributes) { Location? currentLocation = currentDeclaration.GetLocation(); @@ -92,12 +96,6 @@ internal static bool IsCopyFromAttribute(AttributeData attribute, CopyFromCompil SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, compilation.CopyFromTypeAttribute); } - /// - protected override CopyFromCompilationData CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver) - { - return new CopyFromCompilationData(compilation); - } - private static void AnalyzeAttributeSyntax(SyntaxNodeAnalysisContext context, CopyFromCompilationData compilation) { if (context.Node is not AttributeSyntax attr || attr.ArgumentList is null || attr.Parent?.Parent is not CSharpSyntaxNode member) @@ -120,15 +118,15 @@ not LambdaExpressionSyntax return; } - if (SymbolEqualityComparer.Default.Equals(attributeSymbol.ContainingType, compilation.CopyFromTypeAttribute)) + if (attributeSymbol.ContainingType.IsEquivalentTo(compilation.CopyFromTypeAttribute)) { AnalyzeTypeAttribute(context, compilation, attr, member); } - else if (SymbolEqualityComparer.Default.Equals(attributeSymbol.ContainingType, compilation.CopyFromMethodAttribute)) + else if (attributeSymbol.ContainingType.IsEquivalentTo(compilation.CopyFromMethodAttribute)) { AnalyzeMethodAttribute(context, compilation, member); } - else if (SymbolEqualityComparer.Default.Equals(attributeSymbol.ContainingType, compilation.PatternAttribute)) + else if (attributeSymbol.ContainingType.IsEquivalentTo(compilation.PatternAttribute)) { AnalyzePatternAttribute(context, compilation, attr, member); } diff --git a/src/Durian.CopyFrom/CopyFromAnalyzer.pattern.cs b/src/Durian.CopyFrom/CopyFromAnalyzer.pattern.cs index afb92df..d92a679 100644 --- a/src/Durian.CopyFrom/CopyFromAnalyzer.pattern.cs +++ b/src/Durian.CopyFrom/CopyFromAnalyzer.pattern.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.CopyFrom/CopyFromDiagnostics.cs b/src/Durian.CopyFrom/CopyFromDiagnostics.cs index 2936776..334dae5 100644 --- a/src/Durian.CopyFrom/CopyFromDiagnostics.cs +++ b/src/Durian.CopyFrom/CopyFromDiagnostics.cs @@ -8,6 +8,7 @@ namespace Durian.Analysis.CopyFrom; /// public static class CopyFromDiagnostics { +#pragma warning disable IDE1006 // Naming Styles /// /// Provides a diagnostic message indicating that a containing type of a member marked with the Durian.CopyFromTypeAttribute or Durian.CopyFromMethodAttribute must be . /// @@ -17,8 +18,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Containing type of a member with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0201.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0201.md" ); /// @@ -30,8 +31,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member marked with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0202.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0202.md" ); /// @@ -43,8 +44,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member '{1}' cannot be resolved", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0203.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0203.md" ); /// @@ -56,8 +57,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member '{1}' is not compatible with the current member", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0204.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0204.md" ); /// @@ -69,8 +70,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Implementation of member '{1}' is not accessible", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0205.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0205.md" ); /// @@ -82,8 +83,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Equivalent CopyFromTypeAttribute already specified", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0206.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0206.md" ); /// @@ -95,8 +96,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member cannot copy from itself or its parent, child or outer type", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0207.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0207.md" ); /// @@ -108,8 +109,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Two or more members with name '{1}' were resolved", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0208.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0208.md" ); /// @@ -121,8 +122,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Cannot copy from a method without implementation", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0209.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0209.md" ); /// @@ -134,8 +135,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': CopyFromMethodAttribute is not valid on this kind of method", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0210.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0210.md" ); /// @@ -147,8 +148,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Method marked with the CopyFromMethodAttribute already has a declaration", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0211.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0211.md" ); /// @@ -160,8 +161,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Target member '{1}' does not have a return type", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0212.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0212.md" ); /// @@ -173,8 +174,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Target member cannot have a return type", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0213.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0213.md" ); /// @@ -186,8 +187,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Invalid PatternAttribute specified", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0214.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0214.md" ); /// @@ -199,8 +200,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': PatternAttribute is redundant", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0215.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0215.md" ); /// @@ -212,8 +213,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': PatternAttribute with equivalent pattern already specified", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0216.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0216.md" ); /// @@ -225,8 +226,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Type '{1}' is not a valid type argument", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0217.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0217.md" ); /// @@ -238,8 +239,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Unknown partial part '{1}' of type '{2}'", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0218.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0218.md" ); /// @@ -251,8 +252,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': PatternAttribute should be applied on the same partial declaration as a CopyFromTypeAttribute", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0219.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0219.md" ); /// @@ -264,8 +265,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Namespace '{1}' already specified for the AddUsings property", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0220.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0220.md" ); /// @@ -277,8 +278,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Circular dependency between target members", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0221.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0221.md" ); /// @@ -290,8 +291,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member already has documentation", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0222.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0222.md" ); /// @@ -303,8 +304,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Member already has generic constraints", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0223.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0223.md" ); /// @@ -316,8 +317,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Cannot copy constraints for a method or a non-generic member", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0224.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0224.md" ); /// @@ -329,8 +330,8 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Type already has a base type", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0225.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0225.md" ); /// @@ -342,9 +343,10 @@ public static class CopyFromDiagnostics messageFormat: "'{0}': Base type cannot be applied to this kind of member", category: "Durian.CopyFrom", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0226.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0226.md" ); +#pragma warning restore IDE1006 // Naming Styles /// /// Documentation directory of the DefaultParam module. diff --git a/src/Durian.CopyFrom/CopyFromGenerator.cs b/src/Durian.CopyFrom/CopyFromGenerator.cs index 0aabd6c..46afca7 100644 --- a/src/Durian.CopyFrom/CopyFromGenerator.cs +++ b/src/Durian.CopyFrom/CopyFromGenerator.cs @@ -7,7 +7,6 @@ using Durian.Analysis.Cache; using Durian.Analysis.CodeGeneration; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Filtering; using Durian.Analysis.Logging; using Durian.Analysis.SymbolContainers; diff --git a/src/Durian.CopyFrom/Methods/CopyFromAnalyzer.method.cs b/src/Durian.CopyFrom/Methods/CopyFromAnalyzer.method.cs index 3032a7d..2b979b8 100644 --- a/src/Durian.CopyFrom/Methods/CopyFromAnalyzer.method.cs +++ b/src/Durian.CopyFrom/Methods/CopyFromAnalyzer.method.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using Durian.Analysis.CopyFrom.Methods; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.CopyFrom/Methods/CopyFromGenerator.method.cs b/src/Durian.CopyFrom/Methods/CopyFromGenerator.method.cs index af4907e..0df7ce1 100644 --- a/src/Durian.CopyFrom/Methods/CopyFromGenerator.method.cs +++ b/src/Durian.CopyFrom/Methods/CopyFromGenerator.method.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using Durian.Analysis.CopyFrom.Methods; -using Durian.Analysis.Extensions; using Durian.Analysis.SyntaxVisitors; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.CopyFrom/Methods/CopyFromMethodContext.cs b/src/Durian.CopyFrom/Methods/CopyFromMethodContext.cs index daabfec..bd0a6d3 100644 --- a/src/Durian.CopyFrom/Methods/CopyFromMethodContext.cs +++ b/src/Durian.CopyFrom/Methods/CopyFromMethodContext.cs @@ -1,6 +1,5 @@ using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Filtering; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.CopyFrom/README.md b/src/Durian.CopyFrom/README.md index 5011335..516c9b0 100644 --- a/src/Durian.CopyFrom/README.md +++ b/src/Durian.CopyFrom/README.md @@ -13,7 +13,7 @@ ## -**CopyFrom allows to copy implementations of members to other members, without the need for inheritance. A regex pattern can be provided to customize the copied implementation.** +**CopyFrom allows to copy implementations of members to other members, without the need for inheritance. A REGEX pattern can be provided to customize the copied implementation.** ## Table of Contents diff --git a/src/Durian.CopyFrom/Types/CopyFromAnalyzer.type.cs b/src/Durian.CopyFrom/Types/CopyFromAnalyzer.type.cs index d1662d7..d1162dc 100644 --- a/src/Durian.CopyFrom/Types/CopyFromAnalyzer.type.cs +++ b/src/Durian.CopyFrom/Types/CopyFromAnalyzer.type.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Durian.Analysis.CopyFrom.Types; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.CopyFrom/Types/CopyFromGenerator.type.cs b/src/Durian.CopyFrom/Types/CopyFromGenerator.type.cs index eb5ee67..07cbfd8 100644 --- a/src/Durian.CopyFrom/Types/CopyFromGenerator.type.cs +++ b/src/Durian.CopyFrom/Types/CopyFromGenerator.type.cs @@ -5,7 +5,6 @@ using System.Linq; using Durian.Analysis.CodeGeneration; using Durian.Analysis.CopyFrom.Types; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Analysis.SyntaxVisitors; using Microsoft.CodeAnalysis; diff --git a/src/Durian.CopyFrom/Types/CopyFromTypeContext.cs b/src/Durian.CopyFrom/Types/CopyFromTypeContext.cs index 5fef33e..9f355f0 100644 --- a/src/Durian.CopyFrom/Types/CopyFromTypeContext.cs +++ b/src/Durian.CopyFrom/Types/CopyFromTypeContext.cs @@ -1,6 +1,5 @@ using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Filtering; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.Core.Analyzer/CustomTypesInGeneratorNamespaceAnalyzer.cs b/src/Durian.Core.Analyzer/CustomTypesInGeneratorNamespaceAnalyzer.cs index 300dc98..2b41605 100644 --- a/src/Durian.Core.Analyzer/CustomTypesInGeneratorNamespaceAnalyzer.cs +++ b/src/Durian.Core.Analyzer/CustomTypesInGeneratorNamespaceAnalyzer.cs @@ -26,7 +26,7 @@ public CustomTypesInGeneratorNamespaceAnalyzer() } /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.NamespaceDeclaration); } diff --git a/src/Durian.Core.Analyzer/DependencyAnalyzer.cs b/src/Durian.Core.Analyzer/DependencyAnalyzer.cs index e47343e..a88b222 100644 --- a/src/Durian.Core.Analyzer/DependencyAnalyzer.cs +++ b/src/Durian.Core.Analyzer/DependencyAnalyzer.cs @@ -91,7 +91,7 @@ public static bool Analyze(Compilation compilation) } /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterCompilationAction(Analyze); } diff --git a/src/Durian.Core.Analyzer/EnableLoggingAttributeAnalyzer.cs b/src/Durian.Core.Analyzer/EnableLoggingAttributeAnalyzer.cs index cc7a43e..430ef00 100644 --- a/src/Durian.Core.Analyzer/EnableLoggingAttributeAnalyzer.cs +++ b/src/Durian.Core.Analyzer/EnableLoggingAttributeAnalyzer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Durian.Analysis.Extensions; using Durian.Analysis.Logging; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -28,7 +27,7 @@ public EnableLoggingAttributeAnalyzer() } /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterCompilationStartAction(context => { diff --git a/src/Durian.Core.Analyzer/IsCSharpCompilationAnalyzer.cs b/src/Durian.Core.Analyzer/IsCSharpCompilationAnalyzer.cs index 31f01ff..c144c07 100644 --- a/src/Durian.Core.Analyzer/IsCSharpCompilationAnalyzer.cs +++ b/src/Durian.Core.Analyzer/IsCSharpCompilationAnalyzer.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; @@ -60,7 +59,7 @@ public static Diagnostic GetNotCSharpCompilationDiagnostic() } /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterCompilationAction(Analyze); } diff --git a/src/Durian.Core.Analyzer/PartialNameAnalyzer.cs b/src/Durian.Core.Analyzer/PartialNameAnalyzer.cs index f42bef6..065bbde 100644 --- a/src/Durian.Core.Analyzer/PartialNameAnalyzer.cs +++ b/src/Durian.Core.Analyzer/PartialNameAnalyzer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; using static Durian.Analysis.DurianDiagnostics; @@ -28,7 +27,7 @@ public PartialNameAnalyzer() } /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterCompilationStartAction(context => { diff --git a/src/Durian.Core.Analyzer/TypeImportAnalyzer.cs b/src/Durian.Core.Analyzer/TypeImportAnalyzer.cs index 613ff58..f5d1c55 100644 --- a/src/Durian.Core.Analyzer/TypeImportAnalyzer.cs +++ b/src/Durian.Core.Analyzer/TypeImportAnalyzer.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Info; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -34,7 +33,7 @@ public TypeImportAnalyzer() } /// - public override void Register(IDurianAnalysisContext context, CompilationWithImportedTypes compilation) + protected override void Register(IDurianAnalysisContext context, CompilationWithImportedTypes compilation) { context.RegisterSyntaxNodeAction(c => Analyze(c, compilation), SyntaxKind.IdentifierName, SyntaxKind.GenericName); } diff --git a/src/Durian.Core/.generated/ModuleRepository.cs b/src/Durian.Core/.generated/ModuleRepository.cs index c0bfe38..b69a574 100644 --- a/src/Durian.Core/.generated/ModuleRepository.cs +++ b/src/Durian.Core/.generated/ModuleRepository.cs @@ -7,882 +7,938 @@ // //------------------------------------------------------------------------------ -namespace Durian.Info; - -/// -/// Factory class of s for all available Durian modules. -/// -public static class ModuleRepository +namespace Durian.Info { /// - /// Returns a for the module. + /// Factory class of s for all available Durian modules. /// - public static ModuleIdentity Core + public static class ModuleRepository { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity Core { - if(!IdentityPool.Modules.TryGetValue("Core", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.Core, - id: 00, - packages: new DurianPackage[] - { - DurianPackage.Main, - DurianPackage.Core, - DurianPackage.CoreAnalyzer, - }, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core", - diagnostics: new DiagnosticData[] - { - new DiagnosticData( - title: "Projects with any Durian analyzer must reference the Durian.Core package", - id: 01, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0001.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Type cannot be accessed, because its module is not imported", - id: 02, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0002.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not use types from the Durian.Generator namespace", - id: 03, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0003.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Durian modules can be used only in C#", - id: 04, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0004.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not add custom types to the Durian.Generator namespace", - id: 05, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0005.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "PartialNameAttribute should be applied to a partial type", - id: 06, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0006.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not reference Durian analyzer package if the main Durian package is already included", - id: 07, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0007.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Separate analyzer packages detected, reference the main Durian package instead for better performance", - id: 08, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0008.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Type already has a PartialNameAttribute with same value", - id: 09, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0009.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Equivalent EnableLoggingAttribute already specified", - id: 10, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0010.md", - fatal: false, - hasLocation: true - ), - }, - types: new TypeIdentity[] - { - TypeRepository.EnableModuleAttribute, - TypeRepository.DurianGeneratedAttribute, - TypeRepository.PartialNameAttribute, - TypeRepository.UsingsAttribute, - } - ); + if(!IdentityPool.Modules.TryGetValue("Core", out ModuleIdentity module)) + { + module = new( + module: DurianModule.Core, + id: 00, + packages: new DurianPackage[] + { + DurianPackage.Main, + DurianPackage.Core, + DurianPackage.CoreAnalyzer, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Projects with any Durian analyzer must reference the Durian.Core package", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0001.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type cannot be accessed, because its module is not imported", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0002.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not use types from the Durian.Generator namespace", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0003.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Durian modules can be used only in C#", + id: 04, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0004.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not add custom types to the Durian.Generator namespace", + id: 05, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0005.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "PartialNameAttribute should be applied to a partial type", + id: 06, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0006.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not reference Durian analyzer package if the main Durian package is already included", + id: 07, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0007.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Separate analyzer packages detected, reference the main Durian package instead for better performance", + id: 08, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0008.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Type already has a PartialNameAttribute with same value", + id: 09, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0009.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Equivalent EnableLoggingAttribute already specified", + id: 10, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/Core/DUR0010.md", + fatal: false, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.EnableModuleAttribute, + TypeRepository.DurianGeneratedAttribute, + TypeRepository.PartialNameAttribute, + TypeRepository.UsingsAttribute, + } + ); + } + + return module; } - - return module; } - } - /// - /// Returns a for the module. - /// - public static ModuleIdentity Development - { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity Development { - if(!IdentityPool.Modules.TryGetValue("Development", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.Development, - id: default, - packages: new DurianPackage[] - { - DurianPackage.AnalysisServices, - DurianPackage.TestServices, - }, - docsPath: null, - diagnostics: null, - types: null - ); + if(!IdentityPool.Modules.TryGetValue("Development", out ModuleIdentity module)) + { + module = new( + module: DurianModule.Development, + id: default, + packages: new DurianPackage[] + { + DurianPackage.AnalysisServices, + DurianPackage.TestServices, + }, + docsPath: null, + diagnostics: null, + types: null + ); + } + + return module; } - - return module; } - } - /// - /// Returns a for the module. - /// - public static ModuleIdentity DefaultParam - { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity DefaultParam { - if(!IdentityPool.Modules.TryGetValue("DefaultParam", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.DefaultParam, - id: 01, - packages: new DurianPackage[] - { - DurianPackage.DefaultParam, - }, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam", - diagnostics: new DiagnosticData[] - { - new DiagnosticData( - title: "Containing type of a member with the DefaultParamAttribute must be partial", - id: 01, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0101.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Method with the DefaultParamAttribute cannot be partial or extern", - id: 02, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0102.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamAttribute is not valid on this type of method", - id: 03, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0103.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamAttribute cannot be applied to members with the GeneratedCodeAttribute or DurianGeneratedAttribute", - id: 04, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0104.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamAttribute must be placed on the right-most type parameter or right to the left-most DefaultParam type parameter", - id: 05, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0105.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Value of DefaultParamAttribute does not satisfy the type constraint", - id: 06, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0106.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not override methods generated using the DefaultParamAttribute", - id: 07, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0107.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Value of DefaultParamAttribute of overriding method must match the base method", - id: 08, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0108.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not add the DefaultParamAttribute on overridden type parameters that are not DefaultParam", - id: 09, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0109.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamAttribute of overridden type parameter should be added for clarity", - id: 10, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0110.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamConfigurationAttribute is not valid on members without the DefaultParamAttribute", - id: 11, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0111.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "TypeConvention property should not be used on members other than types", - id: 12, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0112.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "MethodConvention property should not be used on members other than methods", - id: 13, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0113.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Method with generated signature already exists", - id: 14, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0114.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamConfigurationAttribute is not valid on this type of method", - id: 15, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0115.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member with generated name already exists", - id: 16, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0116.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DPTypeConvention.Inherit cannot be used on a struct or a sealed type", - id: 17, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0117.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DPTypeConvention.Copy or DPTypeConvention.Default should be applied for clarity", - id: 18, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0118.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParam value cannot be less accessible than the target member", - id: 19, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0119.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Type is invalid DefaultParam value when there is a type parameter constrained to this type parameter", - id: 20, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0120.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Type is invalid DefaultParam value", - id: 21, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0121.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamAttribute cannot be used on a partial type", - id: 22, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0122.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "TypeConvention.Inherit cannot be used on a type without accessible constructor", - id: 23, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0123.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "ApplyNewModifierWhenPossible should not be used when target is not a child type", - id: 24, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0124.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "DefaultParamScopedConfigurationAttribute should not be used on types with no DefaultParam members", - id: 25, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0125.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Members with the DefaultParamAttribute cannot be nested within other DefaultParam members", - id: 26, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0126.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Target namespace is not a valid identifier", - id: 27, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0127.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not specify target namespace for a nested member", - id: 28, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0128.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Target namespace already contains member with the generated name", - id: 29, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0129.md", - fatal: true, - hasLocation: true - ), - }, - types: new TypeIdentity[] - { - TypeRepository.DefaultParamAttribute, - TypeRepository.DefaultParamConfigurationAttribute, - TypeRepository.DefaultParamScopedConfigurationAttribute, - TypeRepository.DPMethodConvention, - TypeRepository.DPTypeConvention, - } - ); + if(!IdentityPool.Modules.TryGetValue("DefaultParam", out ModuleIdentity module)) + { + module = new( + module: DurianModule.DefaultParam, + id: 01, + packages: new DurianPackage[] + { + DurianPackage.DefaultParam, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Containing type of a member with the DefaultParamAttribute must be partial", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0101.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Method with the DefaultParamAttribute cannot be partial or extern", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0102.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamAttribute is not valid on this type of method", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0103.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamAttribute cannot be applied to members with the GeneratedCodeAttribute or DurianGeneratedAttribute", + id: 04, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0104.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamAttribute must be placed on the right-most type parameter or right to the left-most DefaultParam type parameter", + id: 05, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0105.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Value of DefaultParamAttribute does not satisfy the type constraint", + id: 06, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0106.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not override methods generated using the DefaultParamAttribute", + id: 07, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0107.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Value of DefaultParamAttribute of overriding method must match the base method", + id: 08, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0108.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not add the DefaultParamAttribute on overridden type parameters that are not DefaultParam", + id: 09, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0109.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamAttribute of overridden type parameter should be added for clarity", + id: 10, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0110.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamConfigurationAttribute is not valid on members without the DefaultParamAttribute", + id: 11, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0111.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "TypeConvention property should not be used on members other than types", + id: 12, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0112.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "MethodConvention property should not be used on members other than methods", + id: 13, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0113.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Method with generated signature already exists", + id: 14, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0114.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamConfigurationAttribute is not valid on this type of method", + id: 15, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0115.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member with generated name already exists", + id: 16, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0116.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DPTypeConvention.Inherit cannot be used on a struct or a sealed type", + id: 17, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0117.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DPTypeConvention.Copy or DPTypeConvention.Default should be applied for clarity", + id: 18, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0118.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParam value cannot be less accessible than the target member", + id: 19, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0119.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type is invalid DefaultParam value when there is a type parameter constrained to this type parameter", + id: 20, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0120.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type is invalid DefaultParam value", + id: 21, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0121.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamAttribute cannot be used on a partial type", + id: 22, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0122.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "TypeConvention.Inherit cannot be used on a type without accessible constructor", + id: 23, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0123.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "ApplyNewModifierWhenPossible should not be used when target is not a child type", + id: 24, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0124.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "DefaultParamScopedConfigurationAttribute should not be used on types with no DefaultParam members", + id: 25, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0125.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Members with the DefaultParamAttribute cannot be nested within other DefaultParam members", + id: 26, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0126.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Target namespace is not a valid identifier", + id: 27, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0127.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not specify target namespace for a nested member", + id: 28, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0128.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Target namespace already contains member with the generated name", + id: 29, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/DefaultParam/DUR0129.md", + fatal: true, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.DefaultParamAttribute, + TypeRepository.DefaultParamConfigurationAttribute, + TypeRepository.DefaultParamScopedConfigurationAttribute, + TypeRepository.DPMethodConvention, + TypeRepository.DPTypeConvention, + } + ); + } + + return module; } - - return module; } - } - /// - /// Returns a for the module. - /// - public static ModuleIdentity FriendClass - { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity FriendClass { - if(!IdentityPool.Modules.TryGetValue("FriendClass", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.FriendClass, - id: 03, - packages: new DurianPackage[] - { - DurianPackage.FriendClass, - }, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass", - diagnostics: new DiagnosticData[] - { - new DiagnosticData( - title: "Target type is outside of the current assembly", - id: 01, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0301.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member cannot be accessed outside of friend types", - id: 02, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0302.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not use FriendClassConfigurationAttribute on types with no friend specified", - id: 03, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0303.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Type specified by a FriendClassAttribute cannot access the target type", - id: 04, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0304.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Target type does not declare any 'internal' members", - id: 05, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0305.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Friend type is specified multiple times by two different FriendClassAttributes", - id: 06, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0306.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member cannot be accessed by a child type", - id: 07, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0307.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Type is not a valid friend type", - id: 08, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0308.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Type cannot be a friend of itself", - id: 09, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0309.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member cannot be accessed by friend type's child type", - id: 10, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0310.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not use FriendClassConfigurationAttribute.AllowChildren on a sealed type", - id: 11, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0311.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Inner types don't need to be specified as friends explicitly", - id: 12, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0312.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "FriendClassConfigurationAttribute is redundant", - id: 13, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0313.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Inherited static members are not protected against access from non-friend types", - id: 14, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0314.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Do not use FriendClassConfigurationAttribute.IncludeInherited on a type without parent type", - id: 15, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0315.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Base type does not provide internal instance members", - id: 16, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0316.md", - fatal: false, - hasLocation: true - ), - }, - types: new TypeIdentity[] - { - TypeRepository.FriendClassAttribute, - TypeRepository.FriendClassConfigurationAttribute, - } - ); + if(!IdentityPool.Modules.TryGetValue("FriendClass", out ModuleIdentity module)) + { + module = new( + module: DurianModule.FriendClass, + id: 03, + packages: new DurianPackage[] + { + DurianPackage.FriendClass, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Target type is outside of the current assembly", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0301.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member cannot be accessed outside of friend types", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0302.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not use FriendClassConfigurationAttribute on types with no friend specified", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0303.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Type specified by a FriendClassAttribute cannot access the target type", + id: 04, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0304.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Target type does not declare any 'internal' members", + id: 05, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0305.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Friend type is specified multiple times by two different FriendClassAttributes", + id: 06, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0306.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member cannot be accessed by a child type", + id: 07, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0307.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type is not a valid friend type", + id: 08, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0308.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type cannot be a friend of itself", + id: 09, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0309.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member cannot be accessed by friend type's child type", + id: 10, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0310.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not use FriendClassConfigurationAttribute.AllowChildren on a sealed type", + id: 11, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0311.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Inner types don't need to be specified as friends explicitly", + id: 12, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0312.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "FriendClassConfigurationAttribute is redundant", + id: 13, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0313.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Inherited static members are not protected against access from non-friend types", + id: 14, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0314.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Do not use FriendClassConfigurationAttribute.IncludeInherited on a type without parent type", + id: 15, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0315.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Base type does not provide internal instance members", + id: 16, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0316.md", + fatal: false, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.FriendClassAttribute, + TypeRepository.FriendClassConfigurationAttribute, + } + ); + } + + return module; } - - return module; } - } - /// - /// Returns a for the module. - /// - public static ModuleIdentity InterfaceTargets - { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity InterfaceTargets { - if(!IdentityPool.Modules.TryGetValue("InterfaceTargets", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.InterfaceTargets, - id: 04, - packages: new DurianPackage[] - { - DurianPackage.InterfaceTargets, - }, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets", - diagnostics: new DiagnosticData[] - { - new DiagnosticData( - title: "Interface is not valid on members of this kind", - id: 01, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0401.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Interface cannot be a base of another interface", - id: 02, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0402.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Interface is accessible only through reflection", - id: 03, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0403.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Interface will never match target constraint", - id: 04, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0404.md", - fatal: false, - hasLocation: true - ), - }, - types: new TypeIdentity[] - { - TypeRepository.InterfaceTargets, - TypeRepository.InterfaceTargetsAttribute, - } - ); + if(!IdentityPool.Modules.TryGetValue("InterfaceTargets", out ModuleIdentity module)) + { + module = new( + module: DurianModule.InterfaceTargets, + id: 04, + packages: new DurianPackage[] + { + DurianPackage.InterfaceTargets, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Interface is not valid on members of this kind", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0401.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Interface cannot be a base of another interface", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0402.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Interface is accessible only through reflection", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0403.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Interface will never match target constraint", + id: 04, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/InterfaceTargets/DUR0404.md", + fatal: false, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.InterfaceTargets, + TypeRepository.InterfaceTargetsAttribute, + } + ); + } + + return module; } - - return module; } - } - /// - /// Returns a for the module. - /// - public static ModuleIdentity CopyFrom - { - get + /// + /// Returns a for the module. + /// + public static ModuleIdentity CopyFrom { - if(!IdentityPool.Modules.TryGetValue("CopyFrom", out ModuleIdentity module)) + get { - module = new( - module: DurianModule.CopyFrom, - id: 02, - packages: new DurianPackage[] - { - DurianPackage.CopyFrom, - }, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom", - diagnostics: new DiagnosticData[] - { - new DiagnosticData( - title: "Containing type of a member with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", - id: 01, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0201.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member marked with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", - id: 02, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0202.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Target member cannot be resolved", - id: 03, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0203.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Target member is not compatible", - id: 04, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0204.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Implementation of the target member is not accessible", - id: 05, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0205.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Equivalent CopyFromTypeAttribute already specified", - id: 06, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0206.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Member cannot copy from itself, parent, child or outer type", - id: 07, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0207.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Two or more members were resolved", - id: 08, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0208.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Cannot copy from a method without implementation", - id: 09, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0209.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "CopyFromMethodAttribute is not valid on this kind of method", - id: 10, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0210.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Method marked with the CopyFromMethodAttribute already has a declaration", - id: 11, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0211.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Target member does not have a return type", - id: 12, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0212.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Target member cannot have a return type", - id: 13, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0213.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Invalid PatternAttribute specified", - id: 14, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0214.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "PatternAttribute is redundant", - id: 15, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0215.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "PatternAttribute with equivalent pattern already specified", - id: 16, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0216.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Type is not a valid type argument", - id: 17, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0217.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Unknown partial part", - id: 18, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0218.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "PatternAttribute should be applied on the same partial declaration as a CopyFromTypeAttribute", - id: 19, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0219.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Namespace already specified for the AddUsings property", - id: 20, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0220.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Circular dependency between target members", - id: 21, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0221.md", - fatal: true, - hasLocation: true - ), - - new DiagnosticData( - title: "Member already has documentation", - id: 22, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0222.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Member already has generic constraints", - id: 23, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0223.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Cannot copy constraints for a method or a non-generic member", - id: 24, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0224.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Type already has a base type", - id: 25, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0225.md", - fatal: false, - hasLocation: true - ), - - new DiagnosticData( - title: "Base type cannot be applied to this kind of member", - id: 26, - docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0226.md", - fatal: false, - hasLocation: true - ), - }, - types: new TypeIdentity[] - { - TypeRepository.CopyFromTypeAttribute, - TypeRepository.CopyFromMethodAttribute, - TypeRepository.CopyFromAdditionalNodes, - TypeRepository.PatternAttribute, - TypeRepository.PartialNameAttribute, - } - ); + if(!IdentityPool.Modules.TryGetValue("CopyFrom", out ModuleIdentity module)) + { + module = new( + module: DurianModule.CopyFrom, + id: 02, + packages: new DurianPackage[] + { + DurianPackage.CopyFrom, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Containing type of a member with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0201.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member marked with the CopyFromTypeAttribute or CopyFromMethodAttribute must be partial", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0202.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Target member cannot be resolved", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0203.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Target member is not compatible", + id: 04, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0204.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Implementation of the target member is not accessible", + id: 05, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0205.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Equivalent CopyFromTypeAttribute already specified", + id: 06, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0206.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Member cannot copy from itself, parent, child or outer type", + id: 07, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0207.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Two or more members were resolved", + id: 08, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0208.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Cannot copy from a method without implementation", + id: 09, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0209.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "CopyFromMethodAttribute is not valid on this kind of method", + id: 10, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0210.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Method marked with the CopyFromMethodAttribute already has a declaration", + id: 11, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0211.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Target member does not have a return type", + id: 12, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0212.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Target member cannot have a return type", + id: 13, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0213.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Invalid PatternAttribute specified", + id: 14, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0214.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "PatternAttribute is redundant", + id: 15, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0215.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "PatternAttribute with equivalent pattern already specified", + id: 16, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0216.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Type is not a valid type argument", + id: 17, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0217.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Unknown partial part", + id: 18, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0218.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "PatternAttribute should be applied on the same partial declaration as a CopyFromTypeAttribute", + id: 19, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0219.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Namespace already specified for the AddUsings property", + id: 20, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0220.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Circular dependency between target members", + id: 21, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0221.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Member already has documentation", + id: 22, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0222.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Member already has generic constraints", + id: 23, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0223.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Cannot copy constraints for a method or a non-generic member", + id: 24, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0224.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Type already has a base type", + id: 25, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0225.md", + fatal: false, + hasLocation: true + ), + + new DiagnosticData( + title: "Base type cannot be applied to this kind of member", + id: 26, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/CopyFrom/DUR0226.md", + fatal: false, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.CopyFromTypeAttribute, + TypeRepository.CopyFromMethodAttribute, + TypeRepository.CopyFromAdditionalNodes, + TypeRepository.PatternAttribute, + TypeRepository.PartialNameAttribute, + } + ); + } + + return module; } + } - return module; + /// + /// Returns a for the module. + /// + public static ModuleIdentity GlobalScope + { + get + { + if(!IdentityPool.Modules.TryGetValue("GlobalScope", out ModuleIdentity module)) + { + module = new( + module: DurianModule.GlobalScope, + id: 05, + packages: new DurianPackage[] + { + DurianPackage.GlobalScope, + }, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope", + diagnostics: new DiagnosticData[] + { + new DiagnosticData( + title: "Type marked with the GlobalScopeAttribute must be static", + id: 01, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope/DUR0501.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Type marked with the GlobalScopeAttribute cannot be a nested type", + id: 02, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope/DUR0502.md", + fatal: true, + hasLocation: true + ), + + new DiagnosticData( + title: "Top level member cannot be accessed without importing the parent namespace", + id: 03, + docsPath: "https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope/DUR0503.md", + fatal: true, + hasLocation: true + ), + }, + types: new TypeIdentity[] + { + TypeRepository.GlobalScopeAttribute, + } + ); + } + + return module; + } } } } + diff --git a/src/Durian.Core/.generated/PackageRepository.cs b/src/Durian.Core/.generated/PackageRepository.cs index 451fd0f..9629688 100644 --- a/src/Durian.Core/.generated/PackageRepository.cs +++ b/src/Durian.Core/.generated/PackageRepository.cs @@ -7,226 +7,251 @@ // //------------------------------------------------------------------------------ -namespace Durian.Info; - -/// -/// Factory class of s for all available Durian packages. -/// -public static class PackageRepository +namespace Durian.Info { /// - /// Returns a for the package. + /// Factory class of s for all available Durian packages. /// - public static PackageIdentity Main + public static class PackageRepository { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity Main { - if(!IdentityPool.Packages.TryGetValue("Main", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.Main, - version: "3.0.0", - type: PackageType.Unspecified, - modules: new DurianModule[] - { - DurianModule.Core - } - ); - } + if(!IdentityPool.Packages.TryGetValue("Main", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.Main, + version: "3.0.0", + type: PackageType.Unspecified, + modules: new DurianModule[] + { + DurianModule.Core + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity Core - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity Core { - if(!IdentityPool.Packages.TryGetValue("Core", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.Core, - version: "3.0.0", - type: PackageType.Library, - modules: new DurianModule[] - { - DurianModule.Core - } - ); - } + if(!IdentityPool.Packages.TryGetValue("Core", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.Core, + version: "3.0.0", + type: PackageType.Library, + modules: new DurianModule[] + { + DurianModule.Core + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity CoreAnalyzer - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity CoreAnalyzer { - if(!IdentityPool.Packages.TryGetValue("CoreAnalyzer", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.CoreAnalyzer, - version: "3.0.0", - type: PackageType.Analyzer, - modules: new DurianModule[] - { - DurianModule.Core - } - ); - } + if(!IdentityPool.Packages.TryGetValue("CoreAnalyzer", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.CoreAnalyzer, + version: "3.0.0", + type: PackageType.Analyzer, + modules: new DurianModule[] + { + DurianModule.Core + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity AnalysisServices - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity AnalysisServices { - if(!IdentityPool.Packages.TryGetValue("AnalysisServices", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.AnalysisServices, - version: "3.0.0", - type: PackageType.Library, - modules: new DurianModule[] - { - DurianModule.Development - } - ); - } + if(!IdentityPool.Packages.TryGetValue("AnalysisServices", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.AnalysisServices, + version: "3.0.0", + type: PackageType.Library, + modules: new DurianModule[] + { + DurianModule.Development + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity TestServices - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity TestServices { - if(!IdentityPool.Packages.TryGetValue("TestServices", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.TestServices, - version: "3.0.0", - type: PackageType.Library, - modules: new DurianModule[] - { - DurianModule.Development - } - ); - } + if(!IdentityPool.Packages.TryGetValue("TestServices", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.TestServices, + version: "3.0.0", + type: PackageType.Library, + modules: new DurianModule[] + { + DurianModule.Development + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity DefaultParam - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity DefaultParam { - if(!IdentityPool.Packages.TryGetValue("DefaultParam", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.DefaultParam, - version: "3.0.0", - type: PackageType.Analyzer | PackageType.CodeFixLibrary | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator, - modules: new DurianModule[] - { - DurianModule.DefaultParam - } - ); - } + if(!IdentityPool.Packages.TryGetValue("DefaultParam", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.DefaultParam, + version: "3.0.0", + type: PackageType.Analyzer | PackageType.CodeFixLibrary | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator, + modules: new DurianModule[] + { + DurianModule.DefaultParam + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity FriendClass - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity FriendClass { - if(!IdentityPool.Packages.TryGetValue("FriendClass", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.FriendClass, - version: "2.0.0", - type: PackageType.Analyzer | PackageType.CodeFixLibrary | PackageType.StaticGenerator, - modules: new DurianModule[] - { - DurianModule.FriendClass - } - ); - } + if(!IdentityPool.Packages.TryGetValue("FriendClass", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.FriendClass, + version: "2.0.0", + type: PackageType.Analyzer | PackageType.CodeFixLibrary | PackageType.StaticGenerator, + modules: new DurianModule[] + { + DurianModule.FriendClass + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity InterfaceTargets - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity InterfaceTargets { - if(!IdentityPool.Packages.TryGetValue("InterfaceTargets", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.InterfaceTargets, - version: "2.0.0", - type: PackageType.Analyzer | PackageType.StaticGenerator, - modules: new DurianModule[] - { - DurianModule.InterfaceTargets - } - ); - } + if(!IdentityPool.Packages.TryGetValue("InterfaceTargets", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.InterfaceTargets, + version: "2.0.0", + type: PackageType.Analyzer | PackageType.StaticGenerator, + modules: new DurianModule[] + { + DurianModule.InterfaceTargets + } + ); + } - return package; + return package; + } } - } - /// - /// Returns a for the package. - /// - public static PackageIdentity CopyFrom - { - get + /// + /// Returns a for the package. + /// + public static PackageIdentity CopyFrom { - if(!IdentityPool.Packages.TryGetValue("CopyFrom", out PackageIdentity package)) + get { - package = new( - enumValue: DurianPackage.CopyFrom, - version: "1.0.0", - type: PackageType.Analyzer | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator | PackageType.CodeFixLibrary, - modules: new DurianModule[] - { - DurianModule.CopyFrom - } - ); + if(!IdentityPool.Packages.TryGetValue("CopyFrom", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.CopyFrom, + version: "1.0.0", + type: PackageType.Analyzer | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator | PackageType.CodeFixLibrary, + modules: new DurianModule[] + { + DurianModule.CopyFrom + } + ); + } + + return package; } + } + + /// + /// Returns a for the package. + /// + public static PackageIdentity GlobalScope + { + get + { + if(!IdentityPool.Packages.TryGetValue("GlobalScope", out PackageIdentity package)) + { + package = new( + enumValue: DurianPackage.GlobalScope, + version: "1.0.0", + type: PackageType.Analyzer | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator, + modules: new DurianModule[] + { + DurianModule.GlobalScope + } + ); + } - return package; + return package; + } } } -} \ No newline at end of file +} diff --git a/src/Durian.Core/.generated/TypeRepository.cs b/src/Durian.Core/.generated/TypeRepository.cs index b973dba..654735e 100644 --- a/src/Durian.Core/.generated/TypeRepository.cs +++ b/src/Durian.Core/.generated/TypeRepository.cs @@ -9,402 +9,426 @@ using System; -namespace Durian.Info; - -/// -/// Factory class of s for all available Durian s. -/// -public static class TypeRepository +namespace Durian.Info { /// - /// Returns a for the Durian.Generator.EnableModuleAttribute type. + /// Factory class of s for all available Durian s. /// - public static TypeIdentity EnableModuleAttribute + public static class TypeRepository { - get + /// + /// Returns a for the Durian.Generator.EnableModuleAttribute type. + /// + public static TypeIdentity EnableModuleAttribute { - if(!IdentityPool.Types.TryGetValue("EnableModuleAttribute", out TypeIdentity type)) + get { - type = new( - name: "EnableModuleAttribute", - @namespace: "Durian.Generator", - modules: new DurianModule[] - { - DurianModule.Core, - } - ); + if(!IdentityPool.Types.TryGetValue("EnableModuleAttribute", out TypeIdentity type)) + { + type = new( + name: "EnableModuleAttribute", + @namespace: "Durian.Generator", + modules: new DurianModule[] + { + DurianModule.Core, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Generator.DurianGeneratedAttribute type. - /// - public static TypeIdentity DurianGeneratedAttribute - { - get + /// + /// Returns a for the Durian.Generator.DurianGeneratedAttribute type. + /// + public static TypeIdentity DurianGeneratedAttribute { - if(!IdentityPool.Types.TryGetValue("DurianGeneratedAttribute", out TypeIdentity type)) + get { - type = new( - name: "DurianGeneratedAttribute", - @namespace: "Durian.Generator", - modules: new DurianModule[] - { - DurianModule.Core, - } - ); + if(!IdentityPool.Types.TryGetValue("DurianGeneratedAttribute", out TypeIdentity type)) + { + type = new( + name: "DurianGeneratedAttribute", + @namespace: "Durian.Generator", + modules: new DurianModule[] + { + DurianModule.Core, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.PartialNameAttribute type. - /// - public static TypeIdentity PartialNameAttribute - { - get + /// + /// Returns a for the Durian.PartialNameAttribute type. + /// + public static TypeIdentity PartialNameAttribute { - if(!IdentityPool.Types.TryGetValue("PartialNameAttribute", out TypeIdentity type)) + get { - type = new( - name: "PartialNameAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.Core, - DurianModule.CopyFrom, - } - ); + if(!IdentityPool.Types.TryGetValue("PartialNameAttribute", out TypeIdentity type)) + { + type = new( + name: "PartialNameAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.Core, + DurianModule.CopyFrom, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.UsingsAttribute type. - /// - public static TypeIdentity UsingsAttribute - { - get + /// + /// Returns a for the Durian.UsingsAttribute type. + /// + public static TypeIdentity UsingsAttribute { - if(!IdentityPool.Types.TryGetValue("UsingsAttribute", out TypeIdentity type)) + get { - type = new( - name: "UsingsAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.Core, - } - ); + if(!IdentityPool.Types.TryGetValue("UsingsAttribute", out TypeIdentity type)) + { + type = new( + name: "UsingsAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.Core, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.DefaultParamAttribute type. - /// - public static TypeIdentity DefaultParamAttribute - { - get + /// + /// Returns a for the Durian.DefaultParamAttribute type. + /// + public static TypeIdentity DefaultParamAttribute { - if(!IdentityPool.Types.TryGetValue("DefaultParamAttribute", out TypeIdentity type)) + get { - type = new( - name: "DefaultParamAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.DefaultParam, - } - ); + if(!IdentityPool.Types.TryGetValue("DefaultParamAttribute", out TypeIdentity type)) + { + type = new( + name: "DefaultParamAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.DefaultParam, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.DefaultParamConfigurationAttribute type. - /// - public static TypeIdentity DefaultParamConfigurationAttribute - { - get + /// + /// Returns a for the Durian.Configuration.DefaultParamConfigurationAttribute type. + /// + public static TypeIdentity DefaultParamConfigurationAttribute { - if(!IdentityPool.Types.TryGetValue("DefaultParamConfigurationAttribute", out TypeIdentity type)) + get { - type = new( - name: "DefaultParamConfigurationAttribute", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.DefaultParam, - } - ); + if(!IdentityPool.Types.TryGetValue("DefaultParamConfigurationAttribute", out TypeIdentity type)) + { + type = new( + name: "DefaultParamConfigurationAttribute", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.DefaultParam, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.DefaultParamScopedConfigurationAttribute type. - /// - public static TypeIdentity DefaultParamScopedConfigurationAttribute - { - get + /// + /// Returns a for the Durian.Configuration.DefaultParamScopedConfigurationAttribute type. + /// + public static TypeIdentity DefaultParamScopedConfigurationAttribute { - if(!IdentityPool.Types.TryGetValue("DefaultParamScopedConfigurationAttribute", out TypeIdentity type)) + get { - type = new( - name: "DefaultParamScopedConfigurationAttribute", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.DefaultParam, - } - ); + if(!IdentityPool.Types.TryGetValue("DefaultParamScopedConfigurationAttribute", out TypeIdentity type)) + { + type = new( + name: "DefaultParamScopedConfigurationAttribute", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.DefaultParam, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.DPMethodConvention type. - /// - public static TypeIdentity DPMethodConvention - { - get + /// + /// Returns a for the Durian.Configuration.DPMethodConvention type. + /// + public static TypeIdentity DPMethodConvention { - if(!IdentityPool.Types.TryGetValue("DPMethodConvention", out TypeIdentity type)) + get { - type = new( - name: "DPMethodConvention", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.DefaultParam, - } - ); + if(!IdentityPool.Types.TryGetValue("DPMethodConvention", out TypeIdentity type)) + { + type = new( + name: "DPMethodConvention", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.DefaultParam, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.DPTypeConvention type. - /// - public static TypeIdentity DPTypeConvention - { - get + /// + /// Returns a for the Durian.Configuration.DPTypeConvention type. + /// + public static TypeIdentity DPTypeConvention { - if(!IdentityPool.Types.TryGetValue("DPTypeConvention", out TypeIdentity type)) + get { - type = new( - name: "DPTypeConvention", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.DefaultParam, - } - ); + if(!IdentityPool.Types.TryGetValue("DPTypeConvention", out TypeIdentity type)) + { + type = new( + name: "DPTypeConvention", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.DefaultParam, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.FriendClassAttribute type. - /// - public static TypeIdentity FriendClassAttribute - { - get + /// + /// Returns a for the Durian.FriendClassAttribute type. + /// + public static TypeIdentity FriendClassAttribute { - if(!IdentityPool.Types.TryGetValue("FriendClassAttribute", out TypeIdentity type)) + get { - type = new( - name: "FriendClassAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.FriendClass, - } - ); + if(!IdentityPool.Types.TryGetValue("FriendClassAttribute", out TypeIdentity type)) + { + type = new( + name: "FriendClassAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.FriendClass, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.FriendClassConfigurationAttribute type. - /// - public static TypeIdentity FriendClassConfigurationAttribute - { - get + /// + /// Returns a for the Durian.Configuration.FriendClassConfigurationAttribute type. + /// + public static TypeIdentity FriendClassConfigurationAttribute { - if(!IdentityPool.Types.TryGetValue("FriendClassConfigurationAttribute", out TypeIdentity type)) + get { - type = new( - name: "FriendClassConfigurationAttribute", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.FriendClass, - } - ); + if(!IdentityPool.Types.TryGetValue("FriendClassConfigurationAttribute", out TypeIdentity type)) + { + type = new( + name: "FriendClassConfigurationAttribute", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.FriendClass, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.InterfaceTargets type. - /// - public static TypeIdentity InterfaceTargets - { - get + /// + /// Returns a for the Durian.InterfaceTargets type. + /// + public static TypeIdentity InterfaceTargets { - if(!IdentityPool.Types.TryGetValue("InterfaceTargets", out TypeIdentity type)) + get { - type = new( - name: "InterfaceTargets", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.InterfaceTargets, - } - ); + if(!IdentityPool.Types.TryGetValue("InterfaceTargets", out TypeIdentity type)) + { + type = new( + name: "InterfaceTargets", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.InterfaceTargets, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.InterfaceTargetsAttribute type. - /// - public static TypeIdentity InterfaceTargetsAttribute - { - get + /// + /// Returns a for the Durian.InterfaceTargetsAttribute type. + /// + public static TypeIdentity InterfaceTargetsAttribute { - if(!IdentityPool.Types.TryGetValue("InterfaceTargetsAttribute", out TypeIdentity type)) + get { - type = new( - name: "InterfaceTargetsAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.InterfaceTargets, - } - ); + if(!IdentityPool.Types.TryGetValue("InterfaceTargetsAttribute", out TypeIdentity type)) + { + type = new( + name: "InterfaceTargetsAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.InterfaceTargets, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.CopyFromTypeAttribute type. - /// - public static TypeIdentity CopyFromTypeAttribute - { - get + /// + /// Returns a for the Durian.CopyFromTypeAttribute type. + /// + public static TypeIdentity CopyFromTypeAttribute { - if(!IdentityPool.Types.TryGetValue("CopyFromTypeAttribute", out TypeIdentity type)) + get { - type = new( - name: "CopyFromTypeAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.CopyFrom, - } - ); + if(!IdentityPool.Types.TryGetValue("CopyFromTypeAttribute", out TypeIdentity type)) + { + type = new( + name: "CopyFromTypeAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.CopyFrom, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.CopyFromMethodAttribute type. - /// - public static TypeIdentity CopyFromMethodAttribute - { - get + /// + /// Returns a for the Durian.CopyFromMethodAttribute type. + /// + public static TypeIdentity CopyFromMethodAttribute { - if(!IdentityPool.Types.TryGetValue("CopyFromMethodAttribute", out TypeIdentity type)) + get { - type = new( - name: "CopyFromMethodAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.CopyFrom, - } - ); + if(!IdentityPool.Types.TryGetValue("CopyFromMethodAttribute", out TypeIdentity type)) + { + type = new( + name: "CopyFromMethodAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.CopyFrom, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.Configuration.CopyFromAdditionalNodes type. - /// - public static TypeIdentity CopyFromAdditionalNodes - { - get + /// + /// Returns a for the Durian.Configuration.CopyFromAdditionalNodes type. + /// + public static TypeIdentity CopyFromAdditionalNodes { - if(!IdentityPool.Types.TryGetValue("CopyFromAdditionalNodes", out TypeIdentity type)) + get { - type = new( - name: "CopyFromAdditionalNodes", - @namespace: "Durian.Configuration", - modules: new DurianModule[] - { - DurianModule.CopyFrom, - } - ); + if(!IdentityPool.Types.TryGetValue("CopyFromAdditionalNodes", out TypeIdentity type)) + { + type = new( + name: "CopyFromAdditionalNodes", + @namespace: "Durian.Configuration", + modules: new DurianModule[] + { + DurianModule.CopyFrom, + } + ); + } + + return type; } - - return type; } - } - /// - /// Returns a for the Durian.PatternAttribute type. - /// - public static TypeIdentity PatternAttribute - { - get + /// + /// Returns a for the Durian.PatternAttribute type. + /// + public static TypeIdentity PatternAttribute { - if(!IdentityPool.Types.TryGetValue("PatternAttribute", out TypeIdentity type)) + get { - type = new( - name: "PatternAttribute", - @namespace: "Durian", - modules: new DurianModule[] - { - DurianModule.CopyFrom, - } - ); + if(!IdentityPool.Types.TryGetValue("PatternAttribute", out TypeIdentity type)) + { + type = new( + name: "PatternAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.CopyFrom, + } + ); + } + + return type; } + } - return type; + /// + /// Returns a for the Durian.GlobalScopeAttribute type. + /// + public static TypeIdentity GlobalScopeAttribute + { + get + { + if(!IdentityPool.Types.TryGetValue("GlobalScopeAttribute", out TypeIdentity type)) + { + type = new( + name: "GlobalScopeAttribute", + @namespace: "Durian", + modules: new DurianModule[] + { + DurianModule.GlobalScope, + } + ); + } + + return type; + } } } -} \ No newline at end of file +} diff --git a/src/Durian.Core/GlobalInfo.cs b/src/Durian.Core/GlobalInfo.cs index 3fd4f31..1b5bb6e 100644 --- a/src/Durian.Core/GlobalInfo.cs +++ b/src/Durian.Core/GlobalInfo.cs @@ -13,7 +13,7 @@ public static class GlobalInfo /// /// Specifies the maximal valid value of the enum. /// - public static DurianModule ModuleMax => DurianModule.CopyFrom; + public static DurianModule ModuleMax => DurianModule.GlobalScope; /// /// Specifies the minimal valid value of the enum. @@ -38,7 +38,7 @@ public static class GlobalInfo /// /// Specifies the maximal valid value of the enum. /// - public static DurianPackage PackageMax => DurianPackage.CopyFrom; + public static DurianPackage PackageMax => DurianPackage.GlobalScope; /// /// Specifies the minimal valid value of the enum. diff --git a/src/Durian.Core/ModuleIdentity.manual.cs b/src/Durian.Core/ModuleIdentity.manual.cs index dd0b9fb..5c7866f 100644 --- a/src/Durian.Core/ModuleIdentity.manual.cs +++ b/src/Durian.Core/ModuleIdentity.manual.cs @@ -20,6 +20,7 @@ public static ModuleIdentity GetModule(DurianModule module) DurianModule.InterfaceTargets => ModuleRepository.InterfaceTargets, DurianModule.Development => ModuleRepository.Development, DurianModule.CopyFrom => ModuleRepository.CopyFrom, + DurianModule.GlobalScope => ModuleRepository.GlobalScope, DurianModule.None => throw new ArgumentException($"{nameof(DurianModule)}.{nameof(DurianModule.None)} is not a valid Durian module!"), _ => throw new ArgumentException($"Unknown {nameof(DurianModule)} value: {module}!") }; @@ -40,6 +41,7 @@ public static bool TryGetName(DurianModule module, [NotNullWhen(true)] out strin DurianModule.FriendClass => ModuleNames.FriendClass, DurianModule.InterfaceTargets => ModuleNames.InterfaceTargets, DurianModule.CopyFrom => ModuleNames.CopyFrom, + DurianModule.GlobalScope => ModuleNames.GlobalScope, _ => null }; @@ -99,6 +101,12 @@ public static bool TryParse([NotNullWhen(true)] string? moduleName, out DurianMo return true; } + if (name.Equals(ModuleNames.GlobalScope, StringComparison.OrdinalIgnoreCase)) + { + module = DurianModule.CopyFrom; + return true; + } + module = default; return false; } diff --git a/src/Durian.Core/ModuleNames.cs b/src/Durian.Core/ModuleNames.cs index 9b12c6f..6874608 100644 --- a/src/Durian.Core/ModuleNames.cs +++ b/src/Durian.Core/ModuleNames.cs @@ -34,4 +34,9 @@ public static class ModuleNames /// Name of the module. /// public const string CopyFrom = nameof(DurianModule.CopyFrom); + + /// + /// Name of the module. + /// + public const string GlobalScope = nameof(DurianModule.GlobalScope); } diff --git a/src/Durian.Core/PackageIdentity.manual.cs b/src/Durian.Core/PackageIdentity.manual.cs index 0b3604b..57abcac 100644 --- a/src/Durian.Core/PackageIdentity.manual.cs +++ b/src/Durian.Core/PackageIdentity.manual.cs @@ -27,6 +27,7 @@ public static PackageIdentity GetPackage(DurianPackage package) DurianPackage.FriendClass => PackageRepository.FriendClass, DurianPackage.InterfaceTargets => PackageRepository.InterfaceTargets, DurianPackage.CopyFrom => PackageRepository.CopyFrom, + DurianPackage.GlobalScope => PackageRepository.GlobalScope, _ => throw new InvalidOperationException($"Unknown {nameof(DurianPackage)} value: {package}!") }; } @@ -51,6 +52,7 @@ public static PackageType GetPackageType(DurianPackage package) DurianPackage.FriendClass => PackageType.Analyzer | PackageType.StaticGenerator | PackageType.CodeFixLibrary, DurianPackage.InterfaceTargets => PackageType.Analyzer | PackageType.StaticGenerator, DurianPackage.CopyFrom => PackageType.Analyzer | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator | PackageType.CodeFixLibrary, + DurianPackage.GlobalScope => PackageType.Analyzer | PackageType.StaticGenerator | PackageType.SyntaxBasedGenerator, _ => PackageType.Unspecified, }; } @@ -108,17 +110,20 @@ DurianPackage.CoreAnalyzer or DurianPackage.DefaultParam or DurianPackage.InterfaceTargets or DurianPackage.FriendClass or - DurianPackage.CopyFrom, + DurianPackage.CopyFrom or + DurianPackage.GlobalScope, PackageType.StaticGenerator => package is DurianPackage.DefaultParam or DurianPackage.InterfaceTargets or DurianPackage.FriendClass or - DurianPackage.CopyFrom, + DurianPackage.CopyFrom or + DurianPackage.GlobalScope, PackageType.SyntaxBasedGenerator => package is DurianPackage.DefaultParam or - DurianPackage.CopyFrom, + DurianPackage.CopyFrom or + DurianPackage.GlobalScope, //PackageType.FileBasedGenerator => package is @@ -150,6 +155,7 @@ public static bool TryGetName(DurianPackage package, [NotNullWhen(true)] out str DurianPackage.FriendClass => PackageNames.FriendClass, DurianPackage.InterfaceTargets => PackageNames.InterfaceTargets, DurianPackage.CopyFrom => PackageNames.CopyFrom, + DurianPackage.GlobalScope => PackageNames.GlobalScope, _ => null }; @@ -227,6 +233,12 @@ public static bool TryParse([NotNullWhen(true)] string? packageName, out DurianP return true; } + if (name.Equals(PackageNames.GlobalScope, StringComparison.OrdinalIgnoreCase)) + { + package = DurianPackage.GlobalScope; + return true; + } + package = default; return false; } diff --git a/src/Durian.Core/PackageNames.cs b/src/Durian.Core/PackageNames.cs index 721c81d..889275b 100644 --- a/src/Durian.Core/PackageNames.cs +++ b/src/Durian.Core/PackageNames.cs @@ -49,4 +49,9 @@ public static class PackageNames /// Name of the package. /// public const string CopyFrom = nameof(DurianPackage.CopyFrom); + + /// + /// Name of the package. + /// + public const string GlobalScope = nameof(DurianPackage.GlobalScope); } diff --git a/src/Durian.Core/_enum/DurianPackage.cs b/src/Durian.Core/_enum/DurianPackage.cs index 7ec1d70..6bc31b2 100644 --- a/src/Durian.Core/_enum/DurianPackage.cs +++ b/src/Durian.Core/_enum/DurianPackage.cs @@ -54,4 +54,9 @@ public enum DurianPackage /// Represents the Durian.CopyFrom package. /// CopyFrom, + + /// + /// Represents the Durian.GlobalScope package. + /// + GlobalScope, } diff --git a/src/Durian.Core/_init.cs b/src/Durian.Core/_init.cs index e0f0275..7c318e8 100644 --- a/src/Durian.Core/_init.cs +++ b/src/Durian.Core/_init.cs @@ -8,6 +8,7 @@ [assembly: InternalsVisibleTo("Durian.FriendClass")] [assembly: InternalsVisibleTo("Durian.Core.Analyzer")] [assembly: InternalsVisibleTo("Durian.TestServices")] +[assembly: InternalsVisibleTo("Durian.GlobalScope")] // // Original source: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs diff --git a/src/Durian.DefaultParam/CodeFixes/MakeValueOfOverriddenAttributeEquivalentCodeFix.cs b/src/Durian.DefaultParam/CodeFixes/MakeValueOfOverriddenAttributeEquivalentCodeFix.cs index f64517d..b055f36 100644 --- a/src/Durian.DefaultParam/CodeFixes/MakeValueOfOverriddenAttributeEquivalentCodeFix.cs +++ b/src/Durian.DefaultParam/CodeFixes/MakeValueOfOverriddenAttributeEquivalentCodeFix.cs @@ -1,7 +1,6 @@ using System.Threading; using System.Threading.Tasks; using Durian.Analysis.CodeFixes; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; diff --git a/src/Durian.DefaultParam/DPMethodConventionProvider.cs b/src/Durian.DefaultParam/DPMethodConventionProvider.cs index 6f88f82..493bba0 100644 --- a/src/Durian.DefaultParam/DPMethodConventionProvider.cs +++ b/src/Durian.DefaultParam/DPMethodConventionProvider.cs @@ -51,30 +51,32 @@ public override string GetNamespace() public override string GetText() { return -$@"namespace {Namespace} -{{ +$$""" +namespace {{Namespace}} +{ /// /// Determines how a DefaultParam method is generated. /// - public enum {TypeName} - {{ + public enum {{TypeName}} + { /// - /// Uses default convention, which is . + /// Uses default convention, which is . /// - {Default} = {Call}, + {{Default}} = {{Call}}, /// /// Calls the method. /// - {Call} = 0, + {{Call}} = 0, /// /// Copies contents of the method. /// - {Copy} = 1 - }} -}} -"; + {{Copy}} = 1 + } +} + +"""; } /// diff --git a/src/Durian.DefaultParam/DPTypeConventionProvider.cs b/src/Durian.DefaultParam/DPTypeConventionProvider.cs index db985ad..e85c262 100644 --- a/src/Durian.DefaultParam/DPTypeConventionProvider.cs +++ b/src/Durian.DefaultParam/DPTypeConventionProvider.cs @@ -51,30 +51,32 @@ public override string GetNamespace() public override string GetText() { return -$@"namespace {Namespace} -{{ +$$""" +namespace {{Namespace}} +{ /// /// Determines how a DefaultParam type is generated. /// - public enum {TypeName} - {{ + public enum {{TypeName}} + { /// - /// Uses default convention, which is . + /// Uses default convention, which is . /// - {Default} = {Inherit}, + {{Default}} = {{Inherit}}, /// /// Inherits from the type. /// - {Inherit} = 0, + {{Inherit}} = 0, /// /// Copies contents of the type. /// - {Copy} = 1 - }} -}} -"; + {{Copy}} = 1 + } +} + +"""; } /// diff --git a/src/Durian.DefaultParam/DefaultParamAnalyzer.cs b/src/Durian.DefaultParam/DefaultParamAnalyzer.cs index 192e5ca..b09045f 100644 --- a/src/Durian.DefaultParam/DefaultParamAnalyzer.cs +++ b/src/Durian.DefaultParam/DefaultParamAnalyzer.cs @@ -7,7 +7,6 @@ using System.Runtime.CompilerServices; using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Durian.Generator; using Microsoft.CodeAnalysis; @@ -54,10 +53,10 @@ public static bool AllowsNewModifier( InitializeAttributes(ref attributes, symbol); InitializeContainingTypes(ref containingTypes, symbol); - const string configPropertyName = DefaultParamConfigurationAttributeProvider.ApplyNewModifierWhenPossible; - const string scopedPropertyName = DefaultParamScopedConfigurationAttributeProvider.ApplyNewModifierWhenPossible; + const string CONFIG_PROPERTY_NAME = DefaultParamConfigurationAttributeProvider.ApplyNewModifierWhenPossible; + const string SCOPED_PROPERTY_NAME = DefaultParamScopedConfigurationAttributeProvider.ApplyNewModifierWhenPossible; - if (DefaultParamUtilities.TryGetConfigurationPropertyValue(attributes, compilation.DefaultParamConfigurationAttribute!, configPropertyName, out bool value)) + if (DefaultParamUtilities.TryGetConfigurationPropertyValue(attributes, compilation.DefaultParamConfigurationAttribute!, CONFIG_PROPERTY_NAME, out bool value)) { return value; } @@ -71,7 +70,7 @@ public static bool AllowsNewModifier( foreach (INamedTypeSymbol type in containingTypes.Reverse()) { - if (DefaultParamUtilities.TryGetConfigurationPropertyValue(type.GetAttributes(), scopedAttribute, scopedPropertyName, out value)) + if (DefaultParamUtilities.TryGetConfigurationPropertyValue(type.GetAttributes(), scopedAttribute, SCOPED_PROPERTY_NAME, out value)) { return value; } @@ -620,12 +619,12 @@ public static string GetTargetNamespace( ImmutableArray containingTypes = default ) { - const string propertyName = DefaultParamConfigurationAttributeProvider.TargetNamespace; + const string PROPERTY_NAME = DefaultParamConfigurationAttributeProvider.TargetNamespace; InitializeAttributes(ref attributes, symbol); InitializeContainingTypes(ref containingTypes, symbol); - if (DefaultParamUtilities.TryGetConfigurationPropertyValue(attributes, compilation.DefaultParamConfigurationAttribute!, propertyName, out string? value)) + if (DefaultParamUtilities.TryGetConfigurationPropertyValue(attributes, compilation.DefaultParamConfigurationAttribute!, PROPERTY_NAME, out string? value)) { return GetValueOrParentNamespace(value); } @@ -634,7 +633,7 @@ public static string GetTargetNamespace( foreach (INamedTypeSymbol type in containingTypes.Reverse()) { - if (DefaultParamUtilities.TryGetConfigurationPropertyValue(type.GetAttributes(), scopedConfigurationAttribute, propertyName, out value)) + if (DefaultParamUtilities.TryGetConfigurationPropertyValue(type.GetAttributes(), scopedConfigurationAttribute, PROPERTY_NAME, out value)) { return GetValueOrParentNamespace(value); } @@ -716,7 +715,7 @@ public static bool IsDefaultParamGenerated(ISymbol symbol, DefaultParamCompilati } /// - public override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) { context.RegisterSymbolAction(c => AnalyzeSymbol(c, compilation), SupportedSymbolKind); } diff --git a/src/Durian.DefaultParam/DefaultParamAttributeProvider.cs b/src/Durian.DefaultParam/DefaultParamAttributeProvider.cs index 5d9b65f..3d6ae9f 100644 --- a/src/Durian.DefaultParam/DefaultParamAttributeProvider.cs +++ b/src/Durian.DefaultParam/DefaultParamAttributeProvider.cs @@ -41,32 +41,34 @@ public override string GetNamespace() public override string GetText() { return -$@"using System; +$$""" +using System; -namespace {Namespace} -{{ +namespace {{Namespace}} +{ /// /// Applies a default type for the generic parameter. /// [AttributeUsage(AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = true)] - public sealed class {TypeName} : Attribute - {{ + public sealed class {{TypeName}} : Attribute + { /// /// Type that is used as the default type for this generic parameter. /// - public Type {Type} {{ get; }} + public Type {{Type}} { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Type that is used as the default type for this generic parameter. - public {TypeName}(Type type) - {{ - {Type} = type; - }} - }} -}} -"; + /// Type that is used as the default type for this generic parameter. + public {{TypeName}}(Type type) + { + {{Type}} = type; + } + } +} + +"""; } /// diff --git a/src/Durian.DefaultParam/DefaultParamCompilationData.cs b/src/Durian.DefaultParam/DefaultParamCompilationData.cs index a995ad2..cc03fd3 100644 --- a/src/Durian.DefaultParam/DefaultParamCompilationData.cs +++ b/src/Durian.DefaultParam/DefaultParamCompilationData.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/Durian.DefaultParam/DefaultParamConfigurationAnalyzer.cs b/src/Durian.DefaultParam/DefaultParamConfigurationAnalyzer.cs index bd8285e..ec99833 100644 --- a/src/Durian.DefaultParam/DefaultParamConfigurationAnalyzer.cs +++ b/src/Durian.DefaultParam/DefaultParamConfigurationAnalyzer.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -37,7 +36,7 @@ public DefaultParamConfigurationAnalyzer() } /// - public override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) { context.RegisterSyntaxNodeAction(c => Analyze(c, compilation), SyntaxKind.Attribute); } diff --git a/src/Durian.DefaultParam/DefaultParamConfigurationAttributeProvider.cs b/src/Durian.DefaultParam/DefaultParamConfigurationAttributeProvider.cs index cee5c9c..fddffb1 100644 --- a/src/Durian.DefaultParam/DefaultParamConfigurationAttributeProvider.cs +++ b/src/Durian.DefaultParam/DefaultParamConfigurationAttributeProvider.cs @@ -56,48 +56,50 @@ public override string GetNamespace() public override string GetText() { return -$@"using System; +$$""" +using System; #nullable enable -namespace {Namespace} -{{ +namespace {{Namespace}} +{ /// - /// Configures how members with the are handled by the generator. Applies only to this member. + /// Configures how members with the are handled by the generator. Applies only to this member. /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] - public sealed class {TypeName} : Attribute - {{ + public sealed class {{TypeName}} : Attribute + { /// - /// Determines whether to apply the modifier to the generated member when possible instead of reporting an error. Defaults to . + /// Determines whether to apply the modifier to the generated member when possible instead of reporting an error. Defaults to . /// - public bool {ApplyNewModifierWhenPossible} {{ get; set; }} = true; + public bool {{ApplyNewModifierWhenPossible}} { get; set; } = true; /// - /// Determines, how the DefaultParam generator generates a method. The default value is . + /// Determines, how the DefaultParam generator generates a method. The default value is . /// - public {DPMethodConventionProvider.TypeName} {MethodConvention} {{ get; set; }} + public {{DPMethodConventionProvider.TypeName}} {{MethodConvention}} { get; set; } /// /// Specifies the namespace where the target member should be generated in. /// - /// Set this property to global to use the global namespace or to to use namespace of the original member. - public string? {TargetNamespace} {{ get; set; }} + /// Set this property to global to use the global namespace or to to use namespace of the original member. + public string? {{TargetNamespace}} { get; set; } /// - /// Determines, how the DefaultParam generator generates a type. The default value is . + /// Determines, how the DefaultParam generator generates a type. The default value is . /// - public {DPTypeConventionProvider.TypeName} {TypeConvention} {{ get; set; }} + public {{DPTypeConventionProvider.TypeName}} {{TypeConvention}} { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public {TypeName}() - {{ - }} - }} -}} -"; + public {{TypeName}}() + { + } + } +} + +"""; } /// diff --git a/src/Durian.DefaultParam/DefaultParamDiagnostics.cs b/src/Durian.DefaultParam/DefaultParamDiagnostics.cs index 1fc9bb6..b869748 100644 --- a/src/Durian.DefaultParam/DefaultParamDiagnostics.cs +++ b/src/Durian.DefaultParam/DefaultParamDiagnostics.cs @@ -12,14 +12,15 @@ public static class DefaultParamDiagnostics /// /// Provides a diagnostic message indicating that a containing type of a member marked with the Durian.DefaultParamAttribute must be . /// +#pragma warning disable IDE1006 // Naming Styles public static readonly DiagnosticDescriptor DUR0101_ContainingTypeMustBePartial = new( id: "DUR0101", title: "Containing type of a member with the DefaultParamAttribute must be partial", messageFormat: "'{0}': Containing type of a member with the DefaultParamAttribute must be partial", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0101.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0101.md" ); /// @@ -31,8 +32,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Method with the DefaultParamAttribute cannot be partial or extern", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0102.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0102.md" ); /// @@ -44,8 +45,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamAttribute is not valid on this type of method", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0103.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0103.md" ); /// @@ -57,8 +58,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamAttribute cannot be applied to members with the GeneratedCodeAttribute or DurianGeneratedAttribute", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0104.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0104.md" ); /// @@ -70,8 +71,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamAttribute must be placed on the right-most type parameter or right to the left-most DefaultParam type parameter", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0105.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0105.md" ); /// @@ -83,8 +84,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Type '{1}' does not satisfy the type constraint", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0106.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0106.md" ); /// @@ -96,8 +97,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Do not override methods generated using the DefaultParamAttribute", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0107.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0107.md" ); /// @@ -109,8 +110,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Value of DefaultParamAttribute of overriding method must match the base method", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0108.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0108.md" ); /// @@ -122,8 +123,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Do not add the DefaultParamAttribute on overridden type parameters that are not DefaultParam", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0109.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0109.md" ); /// @@ -135,8 +136,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamAttribute of overridden type parameter should be added for clarity", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0110.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0110.md" ); /// @@ -148,8 +149,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamConfigurationAttribute is not valid on members without the DefaultParamAttribute", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0111.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0111.md" ); /// @@ -161,8 +162,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': TypeConvention property should not be used on members other than types", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0112.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0112.md" ); /// @@ -174,8 +175,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': MethodConvention property should not be used on members other than methods", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0113.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0113.md" ); /// @@ -187,8 +188,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Method with generated signature '{1}' already exists", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0114.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0114.md" ); /// @@ -200,8 +201,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamConfigurationAttribute is not valid on this type of method", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0115.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0115.md" ); /// @@ -213,8 +214,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Member with generated name '{1}' already exists", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0116.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0116.md" ); /// @@ -226,8 +227,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DPTypeConvention.Inherit cannot be used on a struct or sealed type", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0117.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0117.md" ); /// @@ -237,11 +238,11 @@ public static class DefaultParamDiagnostics id: "DUR0118", title: "DPTypeConvention.Copy or DPTypeConvention.Default should be applied for clarity", messageFormat: "'{0}': Apply DPTypeConvention.Copy or DPTypeConvention.Default for clarity", - description: "DPTypeConvention.Inherit is applied to the enclosing scope, but it is ignored for structs and classes marked as static or sealed with no accessible constructors. Explicitly apply DPTypeConvention.Copy or DPTypeConvention.Default to avoid confusion.", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0118.md", - isEnabledByDefault: true + isEnabledByDefault: true, + description: "DPTypeConvention.Inherit is applied to the enclosing scope, but it is ignored for structs and classes marked as static or sealed with no accessible constructors. Explicitly apply DPTypeConvention.Copy or DPTypeConvention.Default to avoid confusion.", + helpLinkUri: DocsPath + "/DUR0118.md" ); /// @@ -253,8 +254,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParam value '{1}' cannot be less accessible than the target member", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0119.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0119.md" ); /// @@ -266,8 +267,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Type '{1}' is not valid DefaultParam value when there is a type parameter constrained to this type parameter", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0120.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0120.md" ); /// @@ -279,8 +280,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Type '{1}' is not valid DefaultParam value", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0121.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0121.md" ); /// @@ -292,8 +293,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamAttribute cannot be used on a partial type", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0122.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0122.md" ); /// @@ -305,8 +306,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': TypeConvention.Inherit cannot be used on a type without accessible constructor", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0123.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0123.md" ); /// @@ -318,8 +319,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': ApplyNewModifierWhenPossible should not be used when target is not a child type", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0124.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0124.md" ); /// @@ -331,8 +332,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': DefaultParamScopedConfigurationAttribute should not be used on types with no DefaultParam members", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0125.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0125.md" ); /// @@ -344,8 +345,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Members with the DefaultParamAttribute cannot be nested within other DefaultParam members", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0126.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0126.md" ); /// @@ -357,8 +358,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Target namespace '{1}' is not a valid identifier; parent namespace will be used instead", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0127.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0127.md" ); /// @@ -370,8 +371,8 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Do not specify target namespace for a nested member", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Warning, - helpLinkUri: DocsPath + "/DUR0128.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0128.md" ); /// @@ -383,9 +384,10 @@ public static class DefaultParamDiagnostics messageFormat: "'{0}': Namespace '{1}' already contains member with name '{2}'", category: "Durian.DefaultParam", defaultSeverity: DiagnosticSeverity.Error, - helpLinkUri: DocsPath + "/DUR0129.md", - isEnabledByDefault: true + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0129.md" ); +#pragma warning restore IDE1006 // Naming Styles /// /// Documentation directory of the DefaultParam module. diff --git a/src/Durian.DefaultParam/DefaultParamGenerator.cs b/src/Durian.DefaultParam/DefaultParamGenerator.cs index 8563a1b..b34f707 100644 --- a/src/Durian.DefaultParam/DefaultParamGenerator.cs +++ b/src/Durian.DefaultParam/DefaultParamGenerator.cs @@ -2,7 +2,6 @@ using Durian.Analysis.Cache; using Durian.Analysis.CodeGeneration; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.Filtering; using Durian.Analysis.Logging; using Durian.Info; diff --git a/src/Durian.DefaultParam/DefaultParamScopedConfigurationAnalyzer.cs b/src/Durian.DefaultParam/DefaultParamScopedConfigurationAnalyzer.cs index 189c177..bf63d41 100644 --- a/src/Durian.DefaultParam/DefaultParamScopedConfigurationAnalyzer.cs +++ b/src/Durian.DefaultParam/DefaultParamScopedConfigurationAnalyzer.cs @@ -1,6 +1,5 @@ using System.Collections.Immutable; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -37,7 +36,7 @@ public static bool AnalyzeConfiguration(DefaultParamConfiguration configuration) } /// - public override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) { context.RegisterSyntaxNodeAction(c => Analyze(c, compilation), SyntaxKind.Attribute); } @@ -99,16 +98,16 @@ private static void Analyze(SyntaxNodeAnalysisContext context, DefaultParamCompi private static Diagnostic? GetDiagnosticIfInvalidTargetNamespace(ISymbol symbol, AttributeSyntax node) { - const string propertyName = DefaultParamConfigurationAttributeProvider.TargetNamespace; + const string PROPERTY_NAME = DefaultParamConfigurationAttributeProvider.TargetNamespace; if (node.ArgumentList is null || !node.ArgumentList.Arguments.Any()) { return null; } - if (node.GetArgument(propertyName) is AttributeArgumentSyntax argument && + if (node.GetArgument(PROPERTY_NAME) is AttributeArgumentSyntax argument && symbol.GetAttribute(node) is AttributeData data && - data.TryGetNamedArgumentValue(propertyName, out string? value) && + data.TryGetNamedArgumentValue(PROPERTY_NAME, out string? value) && !IsValidTargetNamespace(value)) { Location? location = argument.GetLocation(); diff --git a/src/Durian.DefaultParam/DefaultParamScopedConfigurationAttributeProvider.cs b/src/Durian.DefaultParam/DefaultParamScopedConfigurationAttributeProvider.cs index 4f84434..65703e7 100644 --- a/src/Durian.DefaultParam/DefaultParamScopedConfigurationAttributeProvider.cs +++ b/src/Durian.DefaultParam/DefaultParamScopedConfigurationAttributeProvider.cs @@ -56,48 +56,50 @@ public override string GetNamespace() public override string GetText() { return -$@"using System; +$$""" +using System; #nullable enable -namespace {Namespace} -{{ +namespace {{Namespace}} +{ /// - /// Configures how members with the are handled by the generator. Applies to all members in the current scope. + /// Configures how members with the are handled by the generator. Applies to all members in the current scope. /// [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] - public sealed class {TypeName} : Attribute - {{ + public sealed class {{TypeName}} : Attribute + { /// - /// Determines whether to apply the modifier to the generated member when possible instead of reporting an error. Defaults to . + /// Determines whether to apply the modifier to the generated member when possible instead of reporting an error. Defaults to . /// - public bool {ApplyNewModifierWhenPossible} {{ get; set; }} = true; + public bool {{ApplyNewModifierWhenPossible}} { get; set; } = true; /// - /// Determines, how the DefaultParam generator generates a method. The default value is . + /// Determines, how the DefaultParam generator generates a method. The default value is . /// - public {DPMethodConventionProvider.TypeName} {MethodConvention} {{ get; set; }} + public {{DPMethodConventionProvider.TypeName}} {{MethodConvention}} { get; set; } /// /// Specifies the namespace where the target member should be generated in. /// - /// Set this property to global to use the global namespace or to to use namespace of the original member. - public string? {TargetNamespace} {{ get; set; }} + /// Set this property to global to use the global namespace or to to use namespace of the original member. + public string? {{TargetNamespace}} { get; set; } /// - /// Determines, how the DefaultParam generator generates a type. The default value is . + /// Determines, how the DefaultParam generator generates a type. The default value is . /// - public {DPTypeConventionProvider.TypeName} {TypeConvention} {{ get; set; }} + public {{DPTypeConventionProvider.TypeName}} {{TypeConvention}} { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public {TypeName}() - {{ - }} - }} -}} -"; + public {{TypeName}}() + { + } + } +} + +"""; } /// diff --git a/src/Durian.DefaultParam/DefaultParamUtilities.cs b/src/Durian.DefaultParam/DefaultParamUtilities.cs index 3d2d8fd..354b81c 100644 --- a/src/Durian.DefaultParam/DefaultParamUtilities.cs +++ b/src/Durian.DefaultParam/DefaultParamUtilities.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Durian.Analysis.SymbolContainers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/Durian.DefaultParam/Delegates/DefaultParamDelegateAnalyzer.cs b/src/Durian.DefaultParam/Delegates/DefaultParamDelegateAnalyzer.cs index f6af20d..0cf9040 100644 --- a/src/Durian.DefaultParam/Delegates/DefaultParamDelegateAnalyzer.cs +++ b/src/Durian.DefaultParam/Delegates/DefaultParamDelegateAnalyzer.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Durian.DefaultParam/Methods/DefaultParamLocalFunctionAnalyzer.cs b/src/Durian.DefaultParam/Methods/DefaultParamLocalFunctionAnalyzer.cs index 7658b35..e1c20da 100644 --- a/src/Durian.DefaultParam/Methods/DefaultParamLocalFunctionAnalyzer.cs +++ b/src/Durian.DefaultParam/Methods/DefaultParamLocalFunctionAnalyzer.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -36,7 +35,7 @@ public static IEnumerable GetSupportedDiagnostics() } /// - public override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, DefaultParamCompilationData compilation) { context.RegisterSyntaxNodeAction(c => FindAndAnalyzeLocalFunction(c, compilation), SyntaxKind.LocalFunctionStatement); } diff --git a/src/Durian.DefaultParam/Methods/DefaultParamMethodAnalyzer.cs b/src/Durian.DefaultParam/Methods/DefaultParamMethodAnalyzer.cs index 324a697..2e61b8a 100644 --- a/src/Durian.DefaultParam/Methods/DefaultParamMethodAnalyzer.cs +++ b/src/Durian.DefaultParam/Methods/DefaultParamMethodAnalyzer.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Text; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/src/Durian.DefaultParam/TypeParameterContainer.cs b/src/Durian.DefaultParam/TypeParameterContainer.cs index 97f9259..e45d765 100644 --- a/src/Durian.DefaultParam/TypeParameterContainer.cs +++ b/src/Durian.DefaultParam/TypeParameterContainer.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.DefaultParam/TypeParameterData.cs b/src/Durian.DefaultParam/TypeParameterData.cs index d0fba96..903a0f6 100644 --- a/src/Durian.DefaultParam/TypeParameterData.cs +++ b/src/Durian.DefaultParam/TypeParameterData.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.DefaultParam/Types/DefaultParamTypeAnalyzer.cs b/src/Durian.DefaultParam/Types/DefaultParamTypeAnalyzer.cs index 6908db7..1f55c1f 100644 --- a/src/Durian.DefaultParam/Types/DefaultParamTypeAnalyzer.cs +++ b/src/Durian.DefaultParam/Types/DefaultParamTypeAnalyzer.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.DefaultParam/Types/TypeDeclarationBuilder.cs b/src/Durian.DefaultParam/Types/TypeDeclarationBuilder.cs index aa6e086..3228764 100644 --- a/src/Durian.DefaultParam/Types/TypeDeclarationBuilder.cs +++ b/src/Durian.DefaultParam/Types/TypeDeclarationBuilder.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.DefaultParam/_Supressions.cs b/src/Durian.DefaultParam/_init.cs similarity index 100% rename from src/Durian.DefaultParam/_Supressions.cs rename to src/Durian.DefaultParam/_init.cs diff --git a/src/Durian.FriendClass/CodeFixes/ReplaceStaticMemberAccessCodeFix.cs b/src/Durian.FriendClass/CodeFixes/ReplaceStaticMemberAccessCodeFix.cs index aff27d6..d1ee612 100644 --- a/src/Durian.FriendClass/CodeFixes/ReplaceStaticMemberAccessCodeFix.cs +++ b/src/Durian.FriendClass/CodeFixes/ReplaceStaticMemberAccessCodeFix.cs @@ -1,6 +1,5 @@ using System.Linq; using Durian.Analysis.CodeFixes; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/Durian.FriendClass/FriendClassAccessAnalyzer.cs b/src/Durian.FriendClass/FriendClassAccessAnalyzer.cs index 1718100..75153a5 100644 --- a/src/Durian.FriendClass/FriendClassAccessAnalyzer.cs +++ b/src/Durian.FriendClass/FriendClassAccessAnalyzer.cs @@ -3,7 +3,6 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -34,7 +33,7 @@ public FriendClassAccessAnalyzer() } /// - public override void Register(IDurianAnalysisContext context, FriendClassCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, FriendClassCompilationData compilation) { context.RegisterSyntaxNodeAction(context => AnalyzeIndentifierName(context, compilation), SyntaxKind.IdentifierName, @@ -170,9 +169,7 @@ private static void AnalyzeTypeOrConstructorDeclaration(SyntaxNodeAnalysisContex { if (record.BaseList is not null && record.BaseList.Types.Any()) { - BaseTypeSyntax baseType = record.BaseList.Types[0]; - - switch (baseType) + switch (record.BaseList.Types[0]) { case PrimaryConstructorBaseTypeSyntax primary: SymbolInfo info = semanticModel.GetSymbolInfo(primary); diff --git a/src/Durian.FriendClass/FriendClassDeclarationAnalyzer.cs b/src/Durian.FriendClass/FriendClassDeclarationAnalyzer.cs index a3f4f5e..2281b6e 100644 --- a/src/Durian.FriendClass/FriendClassDeclarationAnalyzer.cs +++ b/src/Durian.FriendClass/FriendClassDeclarationAnalyzer.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -41,22 +40,22 @@ public FriendClassDeclarationAnalyzer() } /// - public override void Register(IDurianAnalysisContext context, FriendClassCompilationData compilation) + protected override void Register(IDurianAnalysisContext context, FriendClassCompilationData compilation) { context.RegisterSymbolAction(context => Analyze(context, compilation), SymbolKind.NamedType); } - internal static bool IsInternal(ISymbol symbol) - { - return symbol.DeclaredAccessibility is Accessibility.Internal or Accessibility.ProtectedOrInternal; - } - /// protected override FriendClassCompilationData CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver) { return new FriendClassCompilationData(compilation); } + internal static bool IsInternal(ISymbol symbol) + { + return symbol.DeclaredAccessibility is Accessibility.Internal or Accessibility.ProtectedOrInternal; + } + private static void Analyze(SymbolAnalysisContext context, FriendClassCompilationData compilation) { if (context.Symbol is not INamedTypeSymbol symbol || !(symbol.TypeKind is TypeKind.Class or TypeKind.Struct)) diff --git a/src/Durian.GlobalScope/AnalyzerReleases.Shipped.md b/src/Durian.GlobalScope/AnalyzerReleases.Shipped.md index e45bf5b..9796bb1 100644 --- a/src/Durian.GlobalScope/AnalyzerReleases.Shipped.md +++ b/src/Durian.GlobalScope/AnalyzerReleases.Shipped.md @@ -3,26 +3,5 @@ ### New Rules Rule ID | Category | Severity | Notes --------|----------|----------|----------------------------------------- -DUR0301 | Durian.FriendClass | Error | Target type is outside of the current assembly. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0301.md)] -DUR0302 | Durian.FriendClass | Error | Member cannot be accessed outside of friend types. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0302.md)] -DUR0303 | Durian.FriendClass | Warning | Do not use FriendClassConfigurationAttribute on types with no friend specified. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0303.md)] -DUR0304 | Durian.FriendClass | Warning | Type specified by a FriendClassAttribute cannot access the target type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0304.md)] -DUR0305 | Durian.FriendClass | Warning | Target type does not declare any 'internal' members. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0305.md)] -DUR0306 | Durian.FriendClass | Error | Friend type is specified multiple times by two different FriendClassAttributes. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0306.md)] -DUR0307 | Durian.FriendClass | Error | Member cannot be accessed by a child type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0307.md)] -DUR0308 | Durian.FriendClass | Error | Type is not a valid friend type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0308.md)] -DUR0309 | Durian.FriendClass | Error | Type cannot be a friend of itself. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0309.md)] -DUR0310 | Durian.FriendClass | Error | Member cannot be accessed by friend type's child type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0310.md)] -DUR0311 | Durian.FriendClass | Warning | Do not use FriendClassConfigurationAttribute.AllowChildren on a sealed type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0311.md)] -DUR0312 | Durian.FriendClass | Warning | Inner types don't need to be specified as friends explicitly. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0312.md)] -DUR0313 | Durian.FriendClass | Warning | FriendClassConfigurationAttribute is redundant. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0313.md)] - -## Release 2.0.0 - -### New Rules - -Rule ID | Category | Severity | Notes ---------|----------|----------|----------------------------------------- -DUR0314 | Durian.FriendClass | Warning | Inherited static members are not protected against access from non-friend types. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0314.md)] -DUR0315| Durian.FriendClass | Error | Do not use FriendClassConfigurationAttribute.IncludeInherited on a type without parent type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0315.md)] -DUR0316| Durian.FriendClass | Warning | FriendClassConfigurationAttribute.IncludeInherited is redundant, because base type does not provide internal instance members. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/FriendClass/DUR0315.md)] \ No newline at end of file +DUR0501 | Durian.GlobalScope | Error | Type marked with the GlobalScopeAttribute must be static. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope/DUR0501.md)] +DUR0502 | Durian.GlobalScope | Error | Type marked with the GlobalScopeAttribute cannot be a nested type. [[DOC](https://github.com/piotrstenke/Durian/tree/master/docs/GlobalScope/DUR0502.md)] \ No newline at end of file diff --git a/src/Durian.GlobalScope/Durian.GlobalScope.csproj b/src/Durian.GlobalScope/Durian.GlobalScope.csproj index 3e1bc90..c64fc0c 100644 --- a/src/Durian.GlobalScope/Durian.GlobalScope.csproj +++ b/src/Durian.GlobalScope/Durian.GlobalScope.csproj @@ -3,8 +3,8 @@ netstandard2.0 - GlobalFunction provides support for top-level (global) functions and fields - outside of types. - Durian;Analyzer;Source;Generator;Generation;Roslyn;Code;Fix;Extension;Feature;CSharp;C#;Analysis;Syntax;Tree;Node;Friend;Type;Class + GlobalScope provides support for top-level (global) access of type members, outside of the type hierarchy. + Durian;Analyzer;Source;Generator;Generation;Roslyn;Code;Fix;Extension;Feature;CSharp;C#;Analysis;Syntax;Tree;Node;Type;Class;Global;Scope 1.0.0 1.0.0 1.0.0 diff --git a/src/Durian.GlobalScope/GlobalScopeAttributeProvider.cs b/src/Durian.GlobalScope/GlobalScopeAttributeProvider.cs index 4c15e30..9751696 100644 --- a/src/Durian.GlobalScope/GlobalScopeAttributeProvider.cs +++ b/src/Durian.GlobalScope/GlobalScopeAttributeProvider.cs @@ -1,4 +1,4 @@ -namespace Durian.Analysis.GlobalFunction; +namespace Durian.Analysis.GlobalScope; /// /// that creates syntax tree of the Durian.GlobalScopeAttribute class. diff --git a/src/Durian.GlobalScope/GlobalScopeCompilationData.cs b/src/Durian.GlobalScope/GlobalScopeCompilationData.cs new file mode 100644 index 0000000..13075c8 --- /dev/null +++ b/src/Durian.GlobalScope/GlobalScopeCompilationData.cs @@ -0,0 +1,41 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Durian.Analysis.Data; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Durian.Analysis.GlobalScope; + +/// +/// that contains all s needed to properly analyze types marked with the Durian.FriendClassAttribute. +/// +public class GlobalScopeCompilationData : CompilationData +{ + /// + /// representing the Durian.GlobalScopeAttribute class. + /// + public INamedTypeSymbol GlobalScopeAttribute { get; private set; } = default!; + + /// + [MemberNotNullWhen(false, nameof(GlobalScopeAttribute))] + public override bool HasErrors + { + get => base.HasErrors; + protected set => base.HasErrors = value; + } + + /// + /// Initializes a new instance of the class. + /// + /// Current . + /// is . + public GlobalScopeCompilationData(CSharpCompilation compilation) : base(compilation) + { + } + + /// + public override void Reset() + { + GlobalScopeAttribute = IncludeType(GlobalScopeAttributeProvider.FullName)!; + } +} diff --git a/src/Durian.GlobalScope/GlobalScopeDeclarationAnalyzer.cs b/src/Durian.GlobalScope/GlobalScopeDeclarationAnalyzer.cs new file mode 100644 index 0000000..8069830 --- /dev/null +++ b/src/Durian.GlobalScope/GlobalScopeDeclarationAnalyzer.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using static Durian.Analysis.GlobalScope.GlobalScopeDiagnostics; + +namespace Durian.Analysis.GlobalScope; + +/// +/// Analyzes types marked with the Durian.GlobalScopeAttribute. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class GlobalScopeDeclarationAnalyzer : DurianAnalyzer +{ + /// + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create( + DUR0501_TypeIsNotStaticClass, + DUR0502_TypeIsNotTopLevel + ); + + /// + /// Initializes a new instance of the class. + /// + public GlobalScopeDeclarationAnalyzer() + { + } + + /// + protected override void Register(IDurianAnalysisContext context, GlobalScopeCompilationData compilation) + { + context.RegisterSymbolAction(context => Analyze(context, compilation), SymbolKind.NamedType); + } + + /// + protected override GlobalScopeCompilationData CreateCompilation(CSharpCompilation compilation, IDiagnosticReceiver diagnosticReceiver) + { + return new(compilation); + } + + internal static bool Analyze(ISymbol symbol) + { + return symbol is INamedTypeSymbol type && Analyze(type, null); + } + + private static void Analyze(SymbolAnalysisContext context, GlobalScopeCompilationData compilation) + { + if(context.Symbol is not INamedTypeSymbol type || !type.IsClass()) + { + // Handled by the AttributeUsage attribute. + return; + } + + if(!type.HasAttribute(compilation.GlobalScopeAttribute)) + { + // Nothing to analyze. + return; + } + + Analyze(type, context.ReportDiagnostic); + } + + private static bool Analyze(INamedTypeSymbol type, Action? reportDiagnostic) + { + Location? location = null; + string? name = null; + + if (!type.IsStatic && !ReportDiagnostic(DUR0501_TypeIsNotStaticClass)) + { + return false; + } + + if (!type.IsTopLevel() && !ReportDiagnostic(DUR0502_TypeIsNotTopLevel)) + { + return false; + } + + return true; + + bool ReportDiagnostic(DiagnosticDescriptor descriptor) + { + if (reportDiagnostic is not null) + { + location ??= type.Locations.FirstOrDefault(); + name ??= type.GetFullyQualifiedName(); + + reportDiagnostic.Invoke(Diagnostic.Create(descriptor, location, name)); + + return true; + } + + return false; + } + } +} diff --git a/src/Durian.GlobalScope/GlobalScopeDiagnostics.cs b/src/Durian.GlobalScope/GlobalScopeDiagnostics.cs new file mode 100644 index 0000000..c2afdc6 --- /dev/null +++ b/src/Durian.GlobalScope/GlobalScopeDiagnostics.cs @@ -0,0 +1,58 @@ +using System; +using Durian.Info; +using Microsoft.CodeAnalysis; + +namespace Durian.Analysis.GlobalScope; + +/// +/// Contains s of all the s that can be reported by either . +/// +public static class GlobalScopeDiagnostics +{ +#pragma warning disable IDE1006 // Naming Styles + /// + /// Provides a diagnostic message indicating that marked with the Durian.GlobalScopeAttribute is not a static class. + /// + public static readonly DiagnosticDescriptor DUR0501_TypeIsNotStaticClass = new( + id: "DUR0501", + title: "Type marked with the GlobalScopeAttribute must be static", + messageFormat: "'{0}': Type marked with the GlobalScopeAttribute must be static", + category: "Durian.GlobalScope", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0501.md" + ); + + /// + /// Provides a diagnostic message indicating that marked with the Durian.GlobalScopeAttribute cannot be nested within other type. + /// + public static readonly DiagnosticDescriptor DUR0502_TypeIsNotTopLevel = new( + id: "DUR0502", + title: "Type marked with the GlobalScopeAttribute cannot be a nested type", + messageFormat: "'{0}': Type marked with the GlobalScopeAttribute cannot be a nested type", + category: "Durian.GlobalScope", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + helpLinkUri: DocsPath + "/DUR0502.md" + ); + + ///// + ///// Provides a diagnostic message indicating that marked with the Durian.GlobalScopeAttribute cannot be accessed. + ///// + //public static readonly DiagnosticDescriptor DUR0503_MemberNotAccessible = new( + // id: "DUR0503", + // title: "Top level member cannot be accessed without importing the parent namespace", + // messageFormat: "'{0}': Top level member cannot be accessed without importing the parent namespace", + // category: "Durian.GlobalScope", + // defaultSeverity: DiagnosticSeverity.Error, + // isEnabledByDefault: true, + // helpLinkUri: DocsPath + "/DUR0503.md" + //); + +#pragma warning restore IDE1006 // Naming Styles + + /// + /// Documentation directory of the GlobalScope module. + /// + public static string DocsPath => GlobalInfo.Repository + "/tree/master/docs/GlobalScope"; +} diff --git a/src/Durian.GlobalScope/GlobalScopeGenerator.cs b/src/Durian.GlobalScope/GlobalScopeGenerator.cs index e523fdb..9e9308e 100644 --- a/src/Durian.GlobalScope/GlobalScopeGenerator.cs +++ b/src/Durian.GlobalScope/GlobalScopeGenerator.cs @@ -1,9 +1,101 @@ -using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.Collections.Immutable; +using Durian.Analysis.Logging; +using Durian.Info; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Durian.Analysis.GlobalFunction; +namespace Durian.Analysis.GlobalScope; -//[Generator] -//public sealed class GlobalScopeGenerator : DurianGeneratorBase -//{ +/// +/// Generates syntax tree of types required by the GlobalScope module. +/// +[Generator(LanguageNames.CSharp)] +[LoggingConfiguration( + SupportedLogs = GeneratorLogs.All, + LogDirectory = "GlobalScope", + SupportsDiagnostics = true, + RelativeToGlobal = true, + EnableExceptions = true)] +public sealed class GlobalScopeGenerator : DurianIncrementalGenerator +{ + /// + public override string GeneratorName => "GlobalScope"; -//} \ No newline at end of file + /// + public override string GeneratorVersion => "1.0.0"; + + /// + /// Initializes a new instance of the class. + /// + public GlobalScopeGenerator() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Configures how this is initialized. + public GlobalScopeGenerator(in GeneratorLogCreationContext context) : base(in context) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Determines how the source generator should behave when logging information. + public GlobalScopeGenerator(LoggingConfiguration? loggingConfiguration) : base(loggingConfiguration) + { + } + + /// + /// Returns a collection of used by this generator to create initial sources. + /// + public static IEnumerable GetSourceProviders() + { + return new ISourceTextProvider[] + { + new GlobalScopeAttributeProvider() + }; + } + + /// + protected override void Register(IncrementalValueProvider compilation, IncrementalGeneratorInitializationContext context) + { + IncrementalValuesProvider potential = context.SyntaxProvider.ForAttributeWithMetadataName( + GlobalScopeAttributeProvider.FullName, + static (node, _) => node is ClassDeclarationSyntax, + static (context, _) => new Data(context.TargetSymbol.GetFullyQualifiedName(), GlobalScopeDeclarationAnalyzer.Analyze(context.TargetSymbol)) + ); + + IncrementalValueProvider> valid = potential + .Where(x => x.IsValidTarget) + .Collect(); + + context.RegisterSourceOutput(valid, (context, data) => + { + CodeBuilder builder = new(); + + foreach (Data target in data) + { + builder.UsingStatic(target.FullName, true); + } + + AddSource("_DurianGlobalScopes.cs", builder.ToString(), context); + }); + } + + /// + protected internal override IEnumerable? GetInitialSources() + { + return GetSourceProviders(); + } + + /// + protected internal override DurianModule[] GetRequiredModules() + { + return new DurianModule[] { DurianModule.GlobalScope }; + } + + private record struct Data(string FullName, bool IsValidTarget); +} diff --git a/src/Durian.GlobalScope/README.md b/src/Durian.GlobalScope/README.md new file mode 100644 index 0000000..ec6858a --- /dev/null +++ b/src/Durian.GlobalScope/README.md @@ -0,0 +1,20 @@ + + +
+ Durian logo +
+ +## + +**GlobalScope provides support for top-level (global) access of type members, outside of the type hierarchy.** + +## + +*\(Written by Piotr Stenke\)* \ No newline at end of file diff --git a/src/Durian.InterfaceTargets/InterfaceTargetsAnalyzer.cs b/src/Durian.InterfaceTargets/InterfaceTargetsAnalyzer.cs index 908da2c..38df39a 100644 --- a/src/Durian.InterfaceTargets/InterfaceTargetsAnalyzer.cs +++ b/src/Durian.InterfaceTargets/InterfaceTargetsAnalyzer.cs @@ -1,7 +1,6 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -25,7 +24,7 @@ public class InterfaceTargetsAnalyzer : DurianAnalyzer ); /// - public override void Register(IDurianAnalysisContext context) + protected override void Register(IDurianAnalysisContext context) { context.RegisterCompilationStartAction(context => { diff --git a/src/Durian.TestServices/TestableCompilationData.cs b/src/Durian.TestServices/TestableCompilationData.cs index e2f3671..b7d5e89 100644 --- a/src/Durian.TestServices/TestableCompilationData.cs +++ b/src/Durian.TestServices/TestableCompilationData.cs @@ -3,8 +3,8 @@ using System.Linq; using System.Reflection; using System.Text; +using Durian.Analysis; using Durian.Analysis.Data; -using Durian.Analysis.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/tests/Durian.CopyFrom.Tests/Durian.CopyFrom.Tests.csproj b/tests/Durian.CopyFrom.Tests/Durian.CopyFrom.Tests.csproj index a29b620..9f2317d 100644 --- a/tests/Durian.CopyFrom.Tests/Durian.CopyFrom.Tests.csproj +++ b/tests/Durian.CopyFrom.Tests/Durian.CopyFrom.Tests.csproj @@ -3,6 +3,7 @@ net9.0 Durian.Analysis.CopyFrom.Tests + true diff --git a/tests/Durian.DefaultParam.Tests/Durian.DefaultParam.Tests.csproj b/tests/Durian.DefaultParam.Tests/Durian.DefaultParam.Tests.csproj index 80c6e6b..6b11fac 100644 --- a/tests/Durian.DefaultParam.Tests/Durian.DefaultParam.Tests.csproj +++ b/tests/Durian.DefaultParam.Tests/Durian.DefaultParam.Tests.csproj @@ -3,6 +3,7 @@ net9.0 Durian.Analysis.DefaultParam.Tests + true diff --git a/tests/Durian.FriendClass.Tests/Durian.FriendClass.Tests.csproj b/tests/Durian.FriendClass.Tests/Durian.FriendClass.Tests.csproj index 3db1422..28e2e80 100644 --- a/tests/Durian.FriendClass.Tests/Durian.FriendClass.Tests.csproj +++ b/tests/Durian.FriendClass.Tests/Durian.FriendClass.Tests.csproj @@ -3,6 +3,7 @@ net9.0 Durian.Analysis.InterfaceTargets.Tests + true diff --git a/tests/Durian.InterfaceTargets.Tests/Durian.InterfaceTargets.Tests.csproj b/tests/Durian.InterfaceTargets.Tests/Durian.InterfaceTargets.Tests.csproj index adcf9c3..0aabf70 100644 --- a/tests/Durian.InterfaceTargets.Tests/Durian.InterfaceTargets.Tests.csproj +++ b/tests/Durian.InterfaceTargets.Tests/Durian.InterfaceTargets.Tests.csproj @@ -3,6 +3,7 @@ net9.0 Durian.Analysis.InterfaceTargets.Tests + true diff --git a/tests/Durian.Tests/Durian.Tests.csproj b/tests/Durian.Tests/Durian.Tests.csproj index 52f528f..f81b192 100644 --- a/tests/Durian.Tests/Durian.Tests.csproj +++ b/tests/Durian.Tests/Durian.Tests.csproj @@ -3,6 +3,7 @@ net9.0 Durian.Tests + true