1- using Microsoft . CodeAnalysis ;
1+ using System ;
2+ using Microsoft . CodeAnalysis ;
23using Microsoft . CodeAnalysis . CSharp ;
34using Microsoft . CodeAnalysis . CSharp . Syntax ;
45using Microsoft . CodeAnalysis . Text ;
@@ -71,6 +72,11 @@ static bool IsCandidateClass(SyntaxNode node)
7172 return true ;
7273 }
7374
75+ // I need to analyse the base class in the semantic model
76+ if ( HasBaseClass ( classDecl ) ) {
77+ return true ;
78+ }
79+
7480 // Check if any property has SQLite Property Attribute
7581 return classDecl . Members
7682 . OfType < PropertyDeclarationSyntax > ( )
@@ -81,77 +87,174 @@ static bool IsCandidateClass(SyntaxNode node)
8187 } ) ) ) ;
8288 }
8389
84- static ClassInfo ? GetClassInfo ( GeneratorSyntaxContext context )
90+ static bool HasBaseClass ( ClassDeclarationSyntax classDecl )
8591 {
86- var classDecl = ( ClassDeclarationSyntax ) context . Node ;
87- var semanticModel = context . SemanticModel ;
92+ var baseList = classDecl . BaseList ;
93+ if ( baseList == null )
94+ return false ;
8895
89- var classSymbol = semanticModel . GetDeclaredSymbol ( classDecl ) ;
96+ return baseList . Types . Count > 0 ;
97+ }
98+
99+ static ClassInfo ? GetClassInfo ( INamedTypeSymbol ? classSymbol )
100+ {
90101 if ( classSymbol is null )
91102 return null ;
92-
103+
93104 // Return null if the class is private
94105 if ( classSymbol . DeclaredAccessibility == Accessibility . Private )
95106 return null ;
96107
97- if ( classSymbol . IsGenericType )
108+ if ( classSymbol . IsGenericType )
109+ return null ;
110+
111+ var hasSqliteAttributes = HasTableAttribute ( classSymbol ) ;
112+ if ( ! hasSqliteAttributes ) {
113+ hasSqliteAttributes = HasSQLiteAttribute ( classSymbol ) ;
114+ }
115+
116+ if ( ! hasSqliteAttributes ) {
98117 return null ;
99-
100- var hasTableAttribute = classSymbol . GetAttributes ( )
101- . Any ( attr => attr . AttributeClass ? . ContainingNamespace . Name == "SQLite" && attr . AttributeClass ? . Name == "TableAttribute" ) ;
118+ }
102119
103- var properties = new List < PropertyInfo > ( ) ;
120+ var properties = new List < PropertyInfo > ( ) ;
104121
105122 // Iterate through the class hierarchy to get all properties
106123 var currentType = classSymbol ;
107- while ( currentType != null )
108- {
124+ while ( currentType != null ) {
109125 foreach ( var member in currentType . GetMembers ( ) . OfType < IPropertySymbol > ( ) ) {
110126 if ( ! member . IsReadOnly ) {
111- var hasSqliteAttributes = member . GetAttributes ( )
112- . Any ( attr =>
113- attr . AttributeClass ? . Name != null &&
114- attr . AttributeClass . ContainingNamespace . Name == "SQLite" &&
115- attr . AttributeClass . Name != "IgnoreAttribute" &&
116- SQLitePropertyFullAttributes . Contains ( attr . AttributeClass ? . Name ! ) ) ;
117-
118- // Include property if class has TableAttribute or property has ColumnAttribute
119- if ( hasTableAttribute || hasSqliteAttributes ) {
127+ var ignore = member . GetAttributes ( )
128+ . Any ( attr => IsIgnoreAttribute ( attr . AttributeClass ) ) ;
129+
130+ // Include property if not ignored
131+ if ( ! ignore ) {
120132 var columnName = GetColumnName ( member ) ;
121133 properties . Add ( new PropertyInfo ( member . Name , member . Type . ToDisplayString ( ) , columnName ) ) ;
122134 }
123135 }
124136 }
125-
137+
126138 // Move to base type
127139 currentType = currentType . BaseType ;
128-
140+
129141 // Stop at System.Object or if we hit a null base type
130142 if ( currentType ? . SpecialType == SpecialType . System_Object )
131143 break ;
132-
133144 }
134145
135146 if ( properties . Count == 0 )
136147 return null ;
137148
138149 // Handle nested classes by building the full containing type path
139- var containingTypes = new List < string > ( ) ;
150+ var containingTypes = new List < string > ( ) ;
140151 var currentContaining = classSymbol . ContainingType ;
141- while ( currentContaining != null )
142- {
143- containingTypes . Insert ( 0 , currentContaining . Name ) ;
152+ while ( currentContaining != null ) {
153+ containingTypes . Insert ( 0 , currentContaining . Name ) ;
144154 currentContaining = currentContaining . ContainingType ;
145155 }
146156
147- var fullClassName = containingTypes . Count > 0
148- ? $ "{ string . Join ( "." , containingTypes ) } .{ classSymbol . Name } "
157+ var fullClassName = containingTypes . Count > 0
158+ ? $ "{ string . Join ( "." , containingTypes ) } .{ classSymbol . Name } "
149159 : classSymbol . Name ;
150160
151- return new ClassInfo (
161+ return new ClassInfo (
152162 fullClassName ,
153- classSymbol . ContainingNamespace ? . ToDisplayString ( ) ?? string . Empty ,
163+ classSymbol . ContainingNamespace ? . ToDisplayString ( ) ?? string . Empty ,
154164 properties ) ;
165+ }
166+
167+ private static bool HasSQLiteAttribute ( INamedTypeSymbol ? classSymbol )
168+ {
169+ while ( true ) {
170+ if ( classSymbol == null || classSymbol . SpecialType == SpecialType . System_Object ) {
171+ return false ;
172+ }
173+
174+ var members = classSymbol . GetMembers ( ) ;
175+ foreach ( var member in members ) {
176+ if ( member . GetAttributes ( ) . Any ( attr => IsSQLiteAttribute ( attr . AttributeClass ) ) )
177+ {
178+ return true ;
179+ }
180+ }
181+
182+ classSymbol = classSymbol . BaseType ;
183+ }
184+ }
185+
186+ private static bool HasTableAttribute ( INamedTypeSymbol ? classSymbol )
187+ {
188+ while ( true ) {
189+ if ( classSymbol == null || classSymbol . SpecialType == SpecialType . System_Object ) {
190+ return false ;
191+ }
192+
193+ var hasTableAttribute = classSymbol . GetAttributes ( )
194+ . Any ( attr => IsTableAttribute ( attr . AttributeClass ) ) ;
195+ if ( hasTableAttribute ) return true ;
196+
197+ classSymbol = classSymbol . BaseType ;
198+ }
199+ }
200+
201+ static ClassInfo ? GetClassInfo ( GeneratorSyntaxContext context )
202+ {
203+ var classDecl = ( ClassDeclarationSyntax ) context . Node ;
204+ var semanticModel = context . SemanticModel ;
205+
206+ var classSymbol = semanticModel . GetDeclaredSymbol ( classDecl ) ;
207+ return GetClassInfo ( classSymbol ) ;
208+ }
209+
210+ private static bool IsTableAttribute ( INamedTypeSymbol ? attributeClass )
211+ {
212+ while ( true ) {
213+ if ( attributeClass == null ) {
214+ return false ;
215+ }
216+
217+ if ( IsSQLiteNamespace ( attributeClass ) && attributeClass . Name == "TableAttribute" ) {
218+ return true ;
219+ }
220+
221+ attributeClass = attributeClass . BaseType ;
222+ }
223+ }
224+
225+ private static bool IsIgnoreAttribute ( INamedTypeSymbol ? attributeClass )
226+ {
227+ while ( true ) {
228+ if ( attributeClass == null ) {
229+ return false ;
230+ }
231+
232+ if ( IsSQLiteNamespace ( attributeClass ) && attributeClass . Name == "IgnoreAttribute" ) {
233+ return true ;
234+ }
235+
236+ attributeClass = attributeClass . BaseType ;
237+ }
238+ }
239+
240+ private static bool IsSQLiteAttribute ( INamedTypeSymbol ? attributeClass )
241+ {
242+ while ( true ) {
243+ if ( attributeClass == null ) {
244+ return false ;
245+ }
246+
247+ if ( IsSQLiteNamespace ( attributeClass ) && SQLitePropertyFullAttributes . Contains ( attributeClass . Name ) ) {
248+ return true ;
249+ }
250+
251+ attributeClass = attributeClass . BaseType ;
252+ }
253+ }
254+
255+ private static bool IsSQLiteNamespace ( INamedTypeSymbol attributeClass )
256+ {
257+ return attributeClass . ContainingNamespace . Name == "SQLite" ;
155258 }
156259
157260 static string GetColumnName ( IPropertySymbol property )
@@ -300,7 +403,7 @@ static void GeneratePropertySetter(StringBuilder sb, PropertyInfo property)
300403 case "decimal" :
301404 case "Decimal" :
302405 case "System.Decimal" :
303- sb . AppendLine ( $ " typedObj.{ property . PropertyName } = SQLite3.ColumnDouble(stmt, index);") ;
406+ sb . AppendLine ( $ " typedObj.{ property . PropertyName } = System.Convert.ToDecimal( SQLite3.ColumnDouble(stmt, index) );") ;
304407 break ;
305408
306409 case "float" :
0 commit comments