1- using System ;
2- using System . Collections . Generic ;
3- using System . Linq ;
4- using System . Text ;
51using Microsoft . CodeAnalysis ;
62using Microsoft . CodeAnalysis . CSharp ;
73using Microsoft . CodeAnalysis . CSharp . Syntax ;
84using Microsoft . CodeAnalysis . Text ;
5+ using System . Collections . Generic ;
6+ using System . Linq ;
7+ using System . Text ;
98
109namespace ThunderDesign . Net_PCL . SourceGenerators
1110{
@@ -21,9 +20,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2120 )
2221 . Where ( static info => ! info . Equals ( default ( BindableFieldInfo ) ) ) ;
2322
24- context . RegisterSourceOutput ( fieldsWithAttribute , ( spc , info ) =>
23+ var compilationProvider = context . CompilationProvider ;
24+
25+ context . RegisterSourceOutput ( fieldsWithAttribute . Combine ( compilationProvider ) , ( spc , tuple ) =>
2526 {
26- GenerateBindableProperty ( spc , info ) ;
27+ var ( info , compilation ) = ( tuple . Left , tuple . Right ) ;
28+ GenerateBindableProperty ( spc , info , compilation ) ;
2729 } ) ;
2830 }
2931
@@ -56,7 +58,7 @@ private static BindableFieldInfo GetBindableField(GeneratorSyntaxContext context
5658 return default ( BindableFieldInfo ) ;
5759 }
5860
59- private static void GenerateBindableProperty ( SourceProductionContext context , BindableFieldInfo info )
61+ private static void GenerateBindableProperty ( SourceProductionContext context , BindableFieldInfo info , Compilation compilation )
6062 {
6163 var classSymbol = info . ContainingClass ;
6264 var fieldSymbol = info . FieldSymbol ;
@@ -71,10 +73,10 @@ private static void GenerateBindableProperty(SourceProductionContext context, Bi
7173 return ;
7274 }
7375
74- // Rule 2: Field must start with "_" or lowercase
76+ // Rule 2: Field must start with "_" followed by a letter, or a lowercase letter
7577 if ( ! PropertyGeneratorHelpers . IsValidFieldName ( fieldName ) )
7678 {
77- PropertyGeneratorHelpers . ReportDiagnostic ( context , info . FieldDeclaration . GetLocation ( ) , $ "Field '{ fieldName } ' must start with '_' or a lowercase letter to use [BindableProperty].") ;
79+ PropertyGeneratorHelpers . ReportDiagnostic ( context , info . FieldDeclaration . GetLocation ( ) , $ "Field '{ fieldName } ' must start with '_' followed by a letter, or a lowercase letter to use [BindableProperty].") ;
7880 return ;
7981 }
8082
@@ -93,10 +95,12 @@ private static void GenerateBindableProperty(SourceProductionContext context, Bi
9395 // Check for INotifyPropertyChanged, IBindableObject, ThreadObject
9496 var implementsINotify = ImplementsInterface ( classSymbol , "System.ComponentModel.INotifyPropertyChanged" ) ;
9597 var implementsIBindable = ImplementsInterface ( classSymbol , "ThunderDesign.Net.Threading.Interfaces.IBindableObject" ) ;
96-
97- // Check for ThreadObject
9898 var inheritsThreadObject = PropertyGeneratorHelpers . InheritsFrom ( classSymbol , "ThunderDesign.Net.Threading.Objects.ThreadObject" ) ;
9999
100+ var stringTypeSymbol = compilation . GetSpecialType ( SpecialType . System_String ) ;
101+ var voidTypeSymbol = compilation . GetSpecialType ( SpecialType . System_Void ) ;
102+ var propertyChangedEventType = compilation . GetTypeByMetadataName ( "System.ComponentModel.PropertyChangedEventHandler" ) ;
103+
100104 var source = new StringBuilder ( ) ;
101105 var ns = classSymbol . ContainingNamespace . IsGlobalNamespace ? null : classSymbol . ContainingNamespace . ToDisplayString ( ) ;
102106
@@ -108,7 +112,7 @@ private static void GenerateBindableProperty(SourceProductionContext context, Bi
108112 source . AppendLine ( "using ThunderDesign.Net.Threading.Extentions;" ) ;
109113 source . AppendLine ( "using ThunderDesign.Net.Threading.Interfaces;" ) ;
110114 source . AppendLine ( "using ThunderDesign.Net.Threading.Objects;" ) ;
111-
115+
112116 source . AppendLine ( $ "partial class { classSymbol . Name } ") ;
113117
114118 // Add interface if needed
@@ -121,15 +125,32 @@ private static void GenerateBindableProperty(SourceProductionContext context, Bi
121125 source . AppendLine ( "{" ) ;
122126
123127 // Add event if needed
124- if ( ! implementsINotify )
125- source . AppendLine ( " public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;" ) ;
128+ if ( ! implementsINotify && ! PropertyGeneratorHelpers . EventExists ( classSymbol , "PropertyChanged" , propertyChangedEventType ) )
129+ {
130+ if ( PropertyGeneratorHelpers . EventExists ( classSymbol , "PropertyChanged" ) )
131+ {
132+ PropertyGeneratorHelpers . ReportDiagnostic (
133+ context ,
134+ info . FieldDeclaration . GetLocation ( ) ,
135+ $ "Event PropertyChanged already exists in '{ classSymbol . Name } ' with a different type. Expected: System.ComponentModel.PropertyChangedEventHandler."
136+ ) ;
137+ }
138+ else
139+ {
140+ source . AppendLine ( " public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;" ) ;
141+ }
142+ }
126143
127144 // Add _Locker if needed
128- if ( ! inheritsThreadObject )
145+ if ( ! inheritsThreadObject && ! PropertyGeneratorHelpers . FieldExists ( classSymbol , "_Locker" ) )
129146 source . AppendLine ( " protected readonly object _Locker = new object();" ) ;
130147
131148 // Add OnPropertyChanged if needed
132- if ( ! implementsIBindable )
149+ if ( ! implementsIBindable && ! PropertyGeneratorHelpers . MethodExists (
150+ classSymbol ,
151+ "OnPropertyChanged" ,
152+ new ITypeSymbol [ ] { stringTypeSymbol } ,
153+ voidTypeSymbol ) )
133154 {
134155 source . AppendLine ( @"
135156 public virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = """")
0 commit comments