ExtensionMethods.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Microsoft.CodeAnalysis;
  4. using Microsoft.CodeAnalysis.CSharp;
  5. using Microsoft.CodeAnalysis.CSharp.Syntax;
  6. namespace Godot.SourceGenerators.Internal;
  7. internal static class ExtensionMethods
  8. {
  9. public static AttributeData? GetGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol)
  10. => symbol.GetAttributes()
  11. .FirstOrDefault(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false);
  12. private static bool HasGenerateUnmanagedCallbacksAttribute(
  13. this ClassDeclarationSyntax cds, Compilation compilation,
  14. out INamedTypeSymbol? symbol
  15. )
  16. {
  17. var sm = compilation.GetSemanticModel(cds.SyntaxTree);
  18. var classTypeSymbol = sm.GetDeclaredSymbol(cds);
  19. if (classTypeSymbol == null)
  20. {
  21. symbol = null;
  22. return false;
  23. }
  24. if (!classTypeSymbol.GetAttributes()
  25. .Any(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false))
  26. {
  27. symbol = null;
  28. return false;
  29. }
  30. symbol = classTypeSymbol;
  31. return true;
  32. }
  33. private static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol)
  34. => symbol.FullQualifiedNameOmitGlobal() == GeneratorClasses.GenerateUnmanagedCallbacksAttr;
  35. public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectUnmanagedCallbacksClasses(
  36. this IEnumerable<ClassDeclarationSyntax> source,
  37. Compilation compilation
  38. )
  39. {
  40. foreach (var cds in source)
  41. {
  42. if (cds.HasGenerateUnmanagedCallbacksAttribute(compilation, out var symbol))
  43. yield return (cds, symbol!);
  44. }
  45. }
  46. public static bool IsNested(this TypeDeclarationSyntax cds)
  47. => cds.Parent is TypeDeclarationSyntax;
  48. public static bool IsPartial(this TypeDeclarationSyntax cds)
  49. => cds.Modifiers.Any(SyntaxKind.PartialKeyword);
  50. public static bool AreAllOuterTypesPartial(
  51. this TypeDeclarationSyntax cds,
  52. out TypeDeclarationSyntax? typeMissingPartial
  53. )
  54. {
  55. SyntaxNode? outerSyntaxNode = cds.Parent;
  56. while (outerSyntaxNode is TypeDeclarationSyntax outerTypeDeclSyntax)
  57. {
  58. if (!outerTypeDeclSyntax.IsPartial())
  59. {
  60. typeMissingPartial = outerTypeDeclSyntax;
  61. return false;
  62. }
  63. outerSyntaxNode = outerSyntaxNode.Parent;
  64. }
  65. typeMissingPartial = null;
  66. return true;
  67. }
  68. public static string GetDeclarationKeyword(this INamedTypeSymbol namedTypeSymbol)
  69. {
  70. string? keyword = namedTypeSymbol.DeclaringSyntaxReferences
  71. .OfType<TypeDeclarationSyntax>().FirstOrDefault()?
  72. .Keyword.Text;
  73. return keyword ?? namedTypeSymbol.TypeKind switch
  74. {
  75. TypeKind.Interface => "interface",
  76. TypeKind.Struct => "struct",
  77. _ => "class"
  78. };
  79. }
  80. public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
  81. {
  82. return symbol.IsGenericType ?
  83. string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") :
  84. symbol.Name;
  85. }
  86. private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
  87. SymbolDisplayFormat.FullyQualifiedFormat
  88. .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
  89. private static SymbolDisplayFormat FullyQualifiedFormatIncludeGlobal { get; } =
  90. SymbolDisplayFormat.FullyQualifiedFormat
  91. .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Included);
  92. public static string FullQualifiedNameOmitGlobal(this ITypeSymbol symbol)
  93. => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
  94. public static string FullQualifiedNameOmitGlobal(this INamespaceSymbol namespaceSymbol)
  95. => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
  96. public static string FullQualifiedNameIncludeGlobal(this ITypeSymbol symbol)
  97. => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatIncludeGlobal);
  98. public static string FullQualifiedNameIncludeGlobal(this INamespaceSymbol namespaceSymbol)
  99. => namespaceSymbol.ToDisplayString(FullyQualifiedFormatIncludeGlobal);
  100. public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName)
  101. => qualifiedName
  102. // AddSource() doesn't support angle brackets
  103. .Replace("<", "(Of ")
  104. .Replace(">", ")");
  105. }