using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace CliFx.Analyzers.Utils.Extensions; internal static class RoslynExtensions { public static bool DisplayNameMatches(this ISymbol symbol, string name) => string.Equals( // Fully qualified name, without `global::` symbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat), name, StringComparison.Ordinal ); public static IEnumerable GetBaseTypes(this ITypeSymbol type) { var current = type.BaseType; while (current is not null) { yield return current; current = current.BaseType; } } public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) => type .AllInterfaces.FirstOrDefault(i => i.ConstructedFrom.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T ) ?.TypeArguments[0]; // Detect if the property is required through roundabout means so as to not have to take dependency // on higher versions of the C# compiler. public static bool IsRequired(this IPropertySymbol property) => property // Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user, // so we have to check for the presence of the `required` modifier in the syntax tree instead. .DeclaringSyntaxReferences.Select(r => r.GetSyntax()) .OfType() .SelectMany(p => p.Modifiers) .Any(m => m.IsKind((SyntaxKind)8447)); public static bool IsAssignable( this Compilation compilation, ITypeSymbol source, ITypeSymbol destination ) => compilation.ClassifyConversion(source, destination).Exists; public static void HandleClassDeclaration( this AnalysisContext analysisContext, Action analyze ) { analysisContext.RegisterSyntaxNodeAction( ctx => { if (ctx.Node is not ClassDeclarationSyntax classDeclaration) return; var type = ctx.SemanticModel.GetDeclaredSymbol(classDeclaration); if (type is null) return; analyze(ctx, classDeclaration, type); }, SyntaxKind.ClassDeclaration ); } public static void HandlePropertyDeclaration( this AnalysisContext analysisContext, Action analyze ) { analysisContext.RegisterSyntaxNodeAction( ctx => { if (ctx.Node is not PropertyDeclarationSyntax propertyDeclaration) return; var property = ctx.SemanticModel.GetDeclaredSymbol(propertyDeclaration); if (property is null) return; analyze(ctx, propertyDeclaration, property); }, SyntaxKind.PropertyDeclaration ); } }