Common.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. using System.Linq;
  2. using Microsoft.CodeAnalysis;
  3. using Microsoft.CodeAnalysis.CSharp.Syntax;
  4. namespace Godot.SourceGenerators
  5. {
  6. public static class Common
  7. {
  8. public static void ReportNonPartialGodotScriptClass(
  9. GeneratorExecutionContext context,
  10. ClassDeclarationSyntax cds, INamedTypeSymbol symbol
  11. )
  12. {
  13. string message =
  14. "Missing partial modifier on declaration of type '" +
  15. $"{symbol.FullQualifiedName()}' which is a subclass of '{GodotClasses.Object}'";
  16. string description = $"{message}. Subclasses of '{GodotClasses.Object}' " +
  17. "must be declared with the partial modifier.";
  18. context.ReportDiagnostic(Diagnostic.Create(
  19. new DiagnosticDescriptor(id: "GODOT-G0001",
  20. title: message,
  21. messageFormat: message,
  22. category: "Usage",
  23. DiagnosticSeverity.Error,
  24. isEnabledByDefault: true,
  25. description),
  26. cds.GetLocation(),
  27. cds.SyntaxTree.FilePath));
  28. }
  29. public static void ReportNonPartialGodotScriptOuterClass(
  30. GeneratorExecutionContext context,
  31. TypeDeclarationSyntax outerTypeDeclSyntax
  32. )
  33. {
  34. var outerSymbol = context.Compilation
  35. .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree)
  36. .GetDeclaredSymbol(outerTypeDeclSyntax);
  37. string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
  38. namedTypeSymbol.FullQualifiedName() :
  39. "type not found";
  40. string message =
  41. $"Missing partial modifier on declaration of type '{fullQualifiedName}', " +
  42. $"which contains one or more subclasses of '{GodotClasses.Object}'";
  43. string description = $"{message}. Subclasses of '{GodotClasses.Object}' and their " +
  44. "containing types must be declared with the partial modifier.";
  45. context.ReportDiagnostic(Diagnostic.Create(
  46. new DiagnosticDescriptor(id: "GODOT-G0002",
  47. title: message,
  48. messageFormat: message,
  49. category: "Usage",
  50. DiagnosticSeverity.Error,
  51. isEnabledByDefault: true,
  52. description),
  53. outerTypeDeclSyntax.GetLocation(),
  54. outerTypeDeclSyntax.SyntaxTree.FilePath));
  55. }
  56. public static void ReportExportedMemberIsStatic(
  57. GeneratorExecutionContext context,
  58. ISymbol exportedMemberSymbol
  59. )
  60. {
  61. var locations = exportedMemberSymbol.Locations;
  62. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  63. bool isField = exportedMemberSymbol is IFieldSymbol;
  64. string message = $"Attempted to export static {(isField ? "field" : "property")}: " +
  65. $"'{exportedMemberSymbol.ToDisplayString()}'";
  66. string description = $"{message}. Only instance fields and properties can be exported." +
  67. " Remove the 'static' modifier or the '[Export]' attribute.";
  68. context.ReportDiagnostic(Diagnostic.Create(
  69. new DiagnosticDescriptor(id: "GODOT-G0101",
  70. title: message,
  71. messageFormat: message,
  72. category: "Usage",
  73. DiagnosticSeverity.Error,
  74. isEnabledByDefault: true,
  75. description),
  76. location,
  77. location?.SourceTree?.FilePath));
  78. }
  79. public static void ReportExportedMemberTypeNotSupported(
  80. GeneratorExecutionContext context,
  81. ISymbol exportedMemberSymbol
  82. )
  83. {
  84. var locations = exportedMemberSymbol.Locations;
  85. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  86. bool isField = exportedMemberSymbol is IFieldSymbol;
  87. string message = $"The type of the exported {(isField ? "field" : "property")} " +
  88. $"is not supported: '{exportedMemberSymbol.ToDisplayString()}'";
  89. string description = $"{message}. Use a supported type or remove the '[Export]' attribute.";
  90. context.ReportDiagnostic(Diagnostic.Create(
  91. new DiagnosticDescriptor(id: "GODOT-G0102",
  92. title: message,
  93. messageFormat: message,
  94. category: "Usage",
  95. DiagnosticSeverity.Error,
  96. isEnabledByDefault: true,
  97. description),
  98. location,
  99. location?.SourceTree?.FilePath));
  100. }
  101. public static void ReportExportedMemberIsReadOnly(
  102. GeneratorExecutionContext context,
  103. ISymbol exportedMemberSymbol
  104. )
  105. {
  106. var locations = exportedMemberSymbol.Locations;
  107. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  108. bool isField = exportedMemberSymbol is IFieldSymbol;
  109. string message = $"The exported {(isField ? "field" : "property")} " +
  110. $"is read-only: '{exportedMemberSymbol.ToDisplayString()}'";
  111. string description = isField ?
  112. $"{message}. Exported fields cannot be read-only." :
  113. $"{message}. Exported properties must be writable.";
  114. context.ReportDiagnostic(Diagnostic.Create(
  115. new DiagnosticDescriptor(id: "GODOT-G0103",
  116. title: message,
  117. messageFormat: message,
  118. category: "Usage",
  119. DiagnosticSeverity.Error,
  120. isEnabledByDefault: true,
  121. description),
  122. location,
  123. location?.SourceTree?.FilePath));
  124. }
  125. public static void ReportExportedMemberIsWriteOnly(
  126. GeneratorExecutionContext context,
  127. ISymbol exportedMemberSymbol
  128. )
  129. {
  130. var locations = exportedMemberSymbol.Locations;
  131. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  132. string message = $"The exported property is write-only: '{exportedMemberSymbol.ToDisplayString()}'";
  133. string description = $"{message}. Exported properties must be readable.";
  134. context.ReportDiagnostic(Diagnostic.Create(
  135. new DiagnosticDescriptor(id: "GODOT-G0104",
  136. title: message,
  137. messageFormat: message,
  138. category: "Usage",
  139. DiagnosticSeverity.Error,
  140. isEnabledByDefault: true,
  141. description),
  142. location,
  143. location?.SourceTree?.FilePath));
  144. }
  145. public static void ReportSignalDelegateMissingSuffix(
  146. GeneratorExecutionContext context,
  147. INamedTypeSymbol delegateSymbol)
  148. {
  149. var locations = delegateSymbol.Locations;
  150. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  151. string message = "The name of the delegate must end with 'EventHandler': " +
  152. delegateSymbol.ToDisplayString() +
  153. $". Did you mean '{delegateSymbol.Name}EventHandler'?";
  154. string description = $"{message}. Rename the delegate accordingly or remove the '[Signal]' attribute.";
  155. context.ReportDiagnostic(Diagnostic.Create(
  156. new DiagnosticDescriptor(id: "GODOT-G0201",
  157. title: message,
  158. messageFormat: message,
  159. category: "Usage",
  160. DiagnosticSeverity.Error,
  161. isEnabledByDefault: true,
  162. description),
  163. location,
  164. location?.SourceTree?.FilePath));
  165. }
  166. public static void ReportSignalDelegateSignatureNotSupported(
  167. GeneratorExecutionContext context,
  168. INamedTypeSymbol delegateSymbol)
  169. {
  170. var locations = delegateSymbol.Locations;
  171. var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
  172. string message = "The delegate signature of the signal " +
  173. $"is not supported: '{delegateSymbol.ToDisplayString()}'";
  174. string description = $"{message}. Use supported types only or remove the '[Signal]' attribute.";
  175. context.ReportDiagnostic(Diagnostic.Create(
  176. new DiagnosticDescriptor(id: "GODOT-G0202",
  177. title: message,
  178. messageFormat: message,
  179. category: "Usage",
  180. DiagnosticSeverity.Error,
  181. isEnabledByDefault: true,
  182. description),
  183. location,
  184. location?.SourceTree?.FilePath));
  185. }
  186. }
  187. }