2022-02-27 21:57:30 +01:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using Microsoft.CodeAnalysis ;
2022-11-27 10:40:40 +01:00
using Microsoft.CodeAnalysis.CSharp ;
2022-02-27 21:57:30 +01:00
using Microsoft.CodeAnalysis.CSharp.Syntax ;
using Microsoft.CodeAnalysis.Text ;
namespace Godot.SourceGenerators
{
[Generator]
public class ScriptPropertyDefValGenerator : ISourceGenerator
{
public void Initialize ( GeneratorInitializationContext context )
{
}
public void Execute ( GeneratorExecutionContext context )
{
2023-01-08 02:04:15 +01:00
if ( context . IsGodotSourceGeneratorDisabled ( "ScriptPropertyDefVal" ) )
2022-02-27 21:57:30 +01:00
return ;
INamedTypeSymbol [ ] godotClasses = context
. Compilation . SyntaxTrees
. SelectMany ( tree = >
tree . GetRoot ( ) . DescendantNodes ( )
. OfType < ClassDeclarationSyntax > ( )
. SelectGodotScriptClasses ( context . Compilation )
// Report and skip non-partial classes
. Where ( x = >
{
if ( x . cds . IsPartial ( ) )
{
2024-01-16 15:30:45 +01:00
if ( x . cds . IsNested ( ) & & ! x . cds . AreAllOuterTypesPartial ( out _ ) )
2022-02-27 21:57:30 +01:00
{
return false ;
}
return true ;
}
return false ;
} )
. Select ( x = > x . symbol )
)
. Distinct < INamedTypeSymbol > ( SymbolEqualityComparer . Default )
. ToArray ( ) ;
if ( godotClasses . Length > 0 )
{
2022-08-15 05:57:52 +02:00
var typeCache = new MarshalUtils . TypeCache ( context . Compilation ) ;
2022-02-27 21:57:30 +01:00
foreach ( var godotClass in godotClasses )
{
VisitGodotScriptClass ( context , typeCache , godotClass ) ;
}
}
}
private static void VisitGodotScriptClass (
GeneratorExecutionContext context ,
MarshalUtils . TypeCache typeCache ,
INamedTypeSymbol symbol
)
{
INamespaceSymbol namespaceSymbol = symbol . ContainingNamespace ;
2024-02-18 14:40:31 +01:00
string classNs = namespaceSymbol is { IsGlobalNamespace : false }
? namespaceSymbol . FullQualifiedNameOmitGlobal ( )
: string . Empty ;
2022-02-27 21:57:30 +01:00
bool hasNamespace = classNs . Length ! = 0 ;
2024-02-18 14:40:31 +01:00
bool isNode = symbol . InheritsFrom ( "GodotSharp" , GodotClasses . Node ) ;
2022-02-27 21:57:30 +01:00
bool isInnerClass = symbol . ContainingType ! = null ;
2022-11-24 01:04:15 +01:00
string uniqueHint = symbol . FullQualifiedNameOmitGlobal ( ) . SanitizeQualifiedNameForUniqueHint ( )
2022-10-22 23:13:52 +02:00
+ "_ScriptPropertyDefVal.generated" ;
2022-02-27 21:57:30 +01:00
var source = new StringBuilder ( ) ;
if ( hasNamespace )
{
source . Append ( "namespace " ) ;
source . Append ( classNs ) ;
source . Append ( " {\n\n" ) ;
}
if ( isInnerClass )
{
var containingType = symbol . ContainingType ;
2023-10-18 03:25:24 +02:00
AppendPartialContainingTypeDeclarations ( containingType ) ;
2022-02-27 21:57:30 +01:00
2023-10-18 03:25:24 +02:00
void AppendPartialContainingTypeDeclarations ( INamedTypeSymbol ? containingType )
2022-02-27 21:57:30 +01:00
{
2023-10-18 03:25:24 +02:00
if ( containingType = = null )
return ;
AppendPartialContainingTypeDeclarations ( containingType . ContainingType ) ;
2022-02-27 21:57:30 +01:00
source . Append ( "partial " ) ;
source . Append ( containingType . GetDeclarationKeyword ( ) ) ;
source . Append ( " " ) ;
source . Append ( containingType . NameWithTypeParameters ( ) ) ;
source . Append ( "\n{\n" ) ;
}
}
source . Append ( "partial class " ) ;
source . Append ( symbol . NameWithTypeParameters ( ) ) ;
source . Append ( "\n{\n" ) ;
var exportedMembers = new List < ExportedPropertyMetadata > ( ) ;
var members = symbol . GetMembers ( ) ;
var exportedProperties = members
2024-02-18 14:40:31 +01:00
. Where ( s = > s . Kind = = SymbolKind . Property )
2022-02-27 21:57:30 +01:00
. Cast < IPropertySymbol > ( )
. Where ( s = > s . GetAttributes ( )
. Any ( a = > a . AttributeClass ? . IsGodotExportAttribute ( ) ? ? false ) )
. ToArray ( ) ;
var exportedFields = members
2024-02-18 14:40:31 +01:00
. Where ( s = > s . Kind = = SymbolKind . Field & & ! s . IsImplicitlyDeclared )
2022-02-27 21:57:30 +01:00
. Cast < IFieldSymbol > ( )
. Where ( s = > s . GetAttributes ( )
. Any ( a = > a . AttributeClass ? . IsGodotExportAttribute ( ) ? ? false ) )
. ToArray ( ) ;
foreach ( var property in exportedProperties )
{
if ( property . IsStatic )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsStaticRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
2022-08-28 18:16:57 +02:00
if ( property . IsIndexer )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsIndexerRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2022-08-28 18:16:57 +02:00
continue ;
}
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
// TODO: We should still restore read-only properties after reloading assembly.
// Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
// Ignore properties without a getter, without a setter or with an init-only setter.
// Godot properties must be both readable and writable.
2022-02-27 21:57:30 +01:00
if ( property . IsWriteOnly )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedPropertyIsWriteOnlyRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
2022-12-23 18:59:08 +01:00
if ( property . IsReadOnly | | property . SetMethod ! . IsInitOnly )
2022-02-27 21:57:30 +01:00
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsReadOnlyRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
2023-03-04 19:16:48 +01:00
if ( property . ExplicitInterfaceImplementations . Length > 0 )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsExplicitInterfaceImplementationRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2023-03-04 19:16:48 +01:00
continue ;
}
2022-02-27 21:57:30 +01:00
var propertyType = property . Type ;
var marshalType = MarshalUtils . ConvertManagedTypeToMarshalType ( propertyType , typeCache ) ;
if ( marshalType = = null )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberTypeIsNotSupportedRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
property . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
2023-10-06 18:12:16 +02:00
if ( marshalType = = MarshalType . GodotObjectOrDerived )
{
2024-02-18 14:40:31 +01:00
if ( ! isNode & & propertyType . InheritsFrom ( "GodotSharp" , GodotClasses . Node ) )
2023-10-06 18:12:16 +02:00
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . OnlyNodesShouldExportNodesRule ,
property . Locations . FirstLocationWithSourceTreeOrDefault ( )
) ) ;
2024-02-18 14:40:31 +01:00
continue ;
2023-10-06 18:12:16 +02:00
}
}
2022-11-27 10:40:40 +01:00
var propertyDeclarationSyntax = property . DeclaringSyntaxReferences
. Select ( r = > r . GetSyntax ( ) as PropertyDeclarationSyntax ) . FirstOrDefault ( ) ;
2022-02-27 21:57:30 +01:00
2022-11-12 04:34:43 +01:00
// Fully qualify the value to avoid issues with namespaces.
string? value = null ;
2022-11-27 10:40:40 +01:00
if ( propertyDeclarationSyntax ! = null )
2022-11-12 04:34:43 +01:00
{
2022-11-27 10:40:40 +01:00
if ( propertyDeclarationSyntax . Initializer ! = null )
{
var sm = context . Compilation . GetSemanticModel ( propertyDeclarationSyntax . Initializer . SyntaxTree ) ;
value = propertyDeclarationSyntax . Initializer . Value . FullQualifiedSyntax ( sm ) ;
}
else
{
2022-11-29 01:01:36 +01:00
var propertyGet = propertyDeclarationSyntax . AccessorList ? . Accessors
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
. FirstOrDefault ( a = > a . Keyword . IsKind ( SyntaxKind . GetKeyword ) ) ;
2022-11-27 10:40:40 +01:00
if ( propertyGet ! = null )
{
if ( propertyGet . ExpressionBody ! = null )
{
if ( propertyGet . ExpressionBody . Expression is IdentifierNameSyntax identifierNameSyntax )
{
var sm = context . Compilation . GetSemanticModel ( identifierNameSyntax . SyntaxTree ) ;
var fieldSymbol = sm . GetSymbolInfo ( identifierNameSyntax ) . Symbol as IFieldSymbol ;
EqualsValueClauseSyntax ? initializer = fieldSymbol ? . DeclaringSyntaxReferences
. Select ( r = > r . GetSyntax ( ) )
. OfType < VariableDeclaratorSyntax > ( )
. Select ( s = > s . Initializer )
. FirstOrDefault ( i = > i ! = null ) ;
if ( initializer ! = null )
{
sm = context . Compilation . GetSemanticModel ( initializer . SyntaxTree ) ;
value = initializer . Value . FullQualifiedSyntax ( sm ) ;
}
}
}
else
{
var returns = propertyGet . DescendantNodes ( ) . OfType < ReturnStatementSyntax > ( ) ;
if ( returns . Count ( ) = = 1 )
2022-11-29 01:01:36 +01:00
{
// Generate only single return
2022-11-27 10:40:40 +01:00
var returnStatementSyntax = returns . Single ( ) ;
if ( returnStatementSyntax . Expression is IdentifierNameSyntax identifierNameSyntax )
{
var sm = context . Compilation . GetSemanticModel ( identifierNameSyntax . SyntaxTree ) ;
var fieldSymbol = sm . GetSymbolInfo ( identifierNameSyntax ) . Symbol as IFieldSymbol ;
EqualsValueClauseSyntax ? initializer = fieldSymbol ? . DeclaringSyntaxReferences
. Select ( r = > r . GetSyntax ( ) )
. OfType < VariableDeclaratorSyntax > ( )
. Select ( s = > s . Initializer )
. FirstOrDefault ( i = > i ! = null ) ;
if ( initializer ! = null )
{
sm = context . Compilation . GetSemanticModel ( initializer . SyntaxTree ) ;
value = initializer . Value . FullQualifiedSyntax ( sm ) ;
}
}
}
}
}
}
2022-11-12 04:34:43 +01:00
}
2022-02-27 21:57:30 +01:00
exportedMembers . Add ( new ExportedPropertyMetadata (
property . Name , marshalType . Value , propertyType , value ) ) ;
}
foreach ( var field in exportedFields )
{
if ( field . IsStatic )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsStaticRule ,
field . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
field . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
// TODO: We should still restore read-only fields after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
// Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
if ( field . IsReadOnly )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberIsReadOnlyRule ,
field . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
field . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
var fieldType = field . Type ;
var marshalType = MarshalUtils . ConvertManagedTypeToMarshalType ( fieldType , typeCache ) ;
if ( marshalType = = null )
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . ExportedMemberTypeIsNotSupportedRule ,
field . Locations . FirstLocationWithSourceTreeOrDefault ( ) ,
field . ToDisplayString ( )
) ) ;
2022-02-27 21:57:30 +01:00
continue ;
}
2023-10-06 18:12:16 +02:00
if ( marshalType = = MarshalType . GodotObjectOrDerived )
{
2024-02-18 14:40:31 +01:00
if ( ! isNode & & fieldType . InheritsFrom ( "GodotSharp" , GodotClasses . Node ) )
2023-10-06 18:12:16 +02:00
{
Clean diagnostic rules
Move the following diagnostics into static readonly fields: GD0101, GD0102, GD0103, GD0104, GD0105, GD0106, GD0107, GD0201, GD0202, GD0203, GD0301, GD0302, GD0303, GD0401, GD0402.
To be more consistent, the titles for the following diagnostics were modified: GD0101, GD0105, GD0106, GD0302, GD0303, GD0401, GD0402. A subsequent update of the documentation repo is needed.
Tests for the following diagnostics were created: GD0201, GD0202, GD0203.
2024-02-17 21:12:06 +01:00
context . ReportDiagnostic ( Diagnostic . Create (
Common . OnlyNodesShouldExportNodesRule ,
field . Locations . FirstLocationWithSourceTreeOrDefault ( )
) ) ;
2024-02-18 14:40:31 +01:00
continue ;
2023-10-06 18:12:16 +02:00
}
}
2022-02-27 21:57:30 +01:00
EqualsValueClauseSyntax ? initializer = field . DeclaringSyntaxReferences
. Select ( r = > r . GetSyntax ( ) )
. OfType < VariableDeclaratorSyntax > ( )
. Select ( s = > s . Initializer )
. FirstOrDefault ( i = > i ! = null ) ;
2022-11-12 04:34:43 +01:00
// This needs to be fully qualified to avoid issues with namespaces.
string? value = null ;
if ( initializer ! = null )
{
var sm = context . Compilation . GetSemanticModel ( initializer . SyntaxTree ) ;
value = initializer . Value . FullQualifiedSyntax ( sm ) ;
}
2022-02-27 21:57:30 +01:00
exportedMembers . Add ( new ExportedPropertyMetadata (
field . Name , marshalType . Value , fieldType , value ) ) ;
}
// Generate GetGodotExportedProperties
if ( exportedMembers . Count > 0 )
{
source . Append ( "#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n" ) ;
2023-07-09 14:14:36 +02:00
const string dictionaryType =
2022-11-29 01:01:36 +01:00
"global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>" ;
2022-02-27 21:57:30 +01:00
source . Append ( "#if TOOLS\n" ) ;
2023-07-09 14:14:36 +02:00
source . Append ( " /// <summary>\n" )
. Append ( " /// Get the default values for all properties declared in this class.\n" )
. Append ( " /// This method is used by Godot to determine the value that will be\n" )
. Append ( " /// used by the inspector when resetting properties.\n" )
. Append ( " /// Do not call this method.\n" )
. Append ( " /// </summary>\n" ) ;
source . Append ( " [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n" ) ;
2022-02-27 21:57:30 +01:00
source . Append ( " internal new static " ) ;
source . Append ( dictionaryType ) ;
source . Append ( " GetGodotPropertyDefaultValues()\n {\n" ) ;
source . Append ( " var values = new " ) ;
source . Append ( dictionaryType ) ;
source . Append ( "(" ) ;
source . Append ( exportedMembers . Count ) ;
source . Append ( ");\n" ) ;
foreach ( var exportedMember in exportedMembers )
{
string defaultValueLocalName = string . Concat ( "__" , exportedMember . Name , "_default_value" ) ;
source . Append ( " " ) ;
2022-11-24 01:04:15 +01:00
source . Append ( exportedMember . TypeSymbol . FullQualifiedNameIncludeGlobal ( ) ) ;
2022-02-27 21:57:30 +01:00
source . Append ( " " ) ;
source . Append ( defaultValueLocalName ) ;
source . Append ( " = " ) ;
source . Append ( exportedMember . Value ? ? "default" ) ;
source . Append ( ";\n" ) ;
2022-09-06 14:43:40 +02:00
source . Append ( " values.Add(PropertyName." ) ;
2022-02-27 21:57:30 +01:00
source . Append ( exportedMember . Name ) ;
source . Append ( ", " ) ;
2022-12-01 01:45:11 +01:00
source . AppendManagedToVariantExpr ( defaultValueLocalName ,
exportedMember . TypeSymbol , exportedMember . Type ) ;
2022-02-27 21:57:30 +01:00
source . Append ( ");\n" ) ;
}
source . Append ( " return values;\n" ) ;
source . Append ( " }\n" ) ;
2023-07-09 14:14:36 +02:00
source . Append ( "#endif // TOOLS\n" ) ;
2022-02-27 21:57:30 +01:00
source . Append ( "#pragma warning restore CS0109\n" ) ;
}
source . Append ( "}\n" ) ; // partial class
if ( isInnerClass )
{
var containingType = symbol . ContainingType ;
while ( containingType ! = null )
{
source . Append ( "}\n" ) ; // outer class
containingType = containingType . ContainingType ;
}
}
if ( hasNamespace )
{
source . Append ( "\n}\n" ) ;
}
context . AddSource ( uniqueHint , SourceText . From ( source . ToString ( ) , Encoding . UTF8 ) ) ;
}
private struct ExportedPropertyMetadata
{
public ExportedPropertyMetadata ( string name , MarshalType type , ITypeSymbol typeSymbol , string? value )
{
Name = name ;
Type = type ;
TypeSymbol = typeSymbol ;
Value = value ;
}
public string Name { get ; }
public MarshalType Type { get ; }
public ITypeSymbol TypeSymbol { get ; }
public string? Value { get ; }
}
}
}