@@ -767,4 +767,232 @@ public void M()
767
767
768
768
await test . RunAsync ( ) ;
769
769
}
770
+
771
+ [ TestMethod ]
772
+ public async Task SimpleFields_WithMultipleAttributes_SingleProperty ( )
773
+ {
774
+ string original = """
775
+ using System;
776
+ using CommunityToolkit.Mvvm.ComponentModel;
777
+
778
+ public partial class Class1 : ObservableObject
779
+ {
780
+ [ObservableProperty, NotifyPropertyChangedFor("Age")] private string name = String.Empty;
781
+ }
782
+ """ ;
783
+
784
+ string @fixed = """
785
+ using System;
786
+ using CommunityToolkit.Mvvm.ComponentModel;
787
+
788
+ public partial class Class1 : ObservableObject
789
+ {
790
+ [ObservableProperty, NotifyPropertyChangedFor("Age")]
791
+ public partial string Name { get; set; } = String.Empty;
792
+ }
793
+ """ ;
794
+
795
+ CSharpCodeFixTest test = new ( LanguageVersion . Preview )
796
+ {
797
+ TestCode = original ,
798
+ FixedCode = @fixed ,
799
+ ReferenceAssemblies = ReferenceAssemblies . Net . Net80 ,
800
+ } ;
801
+
802
+ test . TestState . AdditionalReferences . Add ( typeof ( ObservableObject ) . Assembly ) ;
803
+ test . ExpectedDiagnostics . AddRange ( new [ ]
804
+ {
805
+ // /0/Test0.cs(6,74): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
806
+ CSharpCodeFixVerifier . Diagnostic ( ) . WithSpan ( 6 , 74 , 6 , 78 ) . WithArguments ( "Class1" , "name" ) ,
807
+ } ) ;
808
+
809
+ test . FixedState . ExpectedDiagnostics . AddRange ( new [ ]
810
+ {
811
+ // /0/Test0.cs(7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
812
+ DiagnosticResult . CompilerError ( "CS8050" ) . WithSpan ( 7 , 27 , 7 , 31 ) ,
813
+
814
+ // /0/Test0.cs(7,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
815
+ DiagnosticResult . CompilerError ( "CS9248" ) . WithSpan ( 7 , 27 , 7 , 31 ) . WithArguments ( "Class1.Name" ) ,
816
+ } ) ;
817
+
818
+ await test . RunAsync ( ) ;
819
+ }
820
+
821
+ // See https://github.com/CommunityToolkit/dotnet/issues/1007
822
+ [ TestMethod ]
823
+ public async Task SimpleFields_WithMultipleAttributes_WithNoBlankLines ( )
824
+ {
825
+ string original = """
826
+ using System;
827
+ using CommunityToolkit.Mvvm.ComponentModel;
828
+
829
+ public partial class Class1 : ObservableObject
830
+ {
831
+ [ObservableProperty, NotifyPropertyChangedFor("Age")] private string name = String.Empty;
832
+ [ObservableProperty] private int age;
833
+ }
834
+ """ ;
835
+
836
+ string @fixed = """
837
+ using System;
838
+ using CommunityToolkit.Mvvm.ComponentModel;
839
+
840
+ public partial class Class1 : ObservableObject
841
+ {
842
+ [ObservableProperty, NotifyPropertyChangedFor("Age")]
843
+ public partial string Name { get; set; } = String.Empty;
844
+
845
+ [ObservableProperty]
846
+ public partial int Age { get; set; }
847
+ }
848
+ """ ;
849
+
850
+ CSharpCodeFixTest test = new ( LanguageVersion . Preview )
851
+ {
852
+ TestCode = original ,
853
+ FixedCode = @fixed ,
854
+ ReferenceAssemblies = ReferenceAssemblies . Net . Net80 ,
855
+ } ;
856
+
857
+ test . TestState . AdditionalReferences . Add ( typeof ( ObservableObject ) . Assembly ) ;
858
+ test . ExpectedDiagnostics . AddRange ( new [ ]
859
+ {
860
+ // /0/Test0.cs(6,74): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
861
+ CSharpCodeFixVerifier . Diagnostic ( ) . WithSpan ( 6 , 74 , 6 , 78 ) . WithArguments ( "Class1" , "name" ) ,
862
+
863
+ // /0/Test0.cs(7,38): info MVVMTK0042: The field Class1.age using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
864
+ CSharpCodeFixVerifier . Diagnostic ( ) . WithSpan ( 7 , 38 , 7 , 41 ) . WithArguments ( "Class1" , "age" ) ,
865
+ } ) ;
866
+
867
+ test . FixedState . ExpectedDiagnostics . AddRange ( new [ ]
868
+ {
869
+ // /0/Test0.cs(7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
870
+ DiagnosticResult . CompilerError ( "CS8050" ) . WithSpan ( 7 , 27 , 7 , 31 ) ,
871
+
872
+ // /0/Test0.cs(7,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
873
+ DiagnosticResult . CompilerError ( "CS9248" ) . WithSpan ( 7 , 27 , 7 , 31 ) . WithArguments ( "Class1.Name" ) ,
874
+
875
+ // /0/Test0.cs(10,24): error CS9248: Partial property 'Class1.Age' must have an implementation part.
876
+ DiagnosticResult . CompilerError ( "CS9248" ) . WithSpan ( 10 , 24 , 10 , 27 ) . WithArguments ( "Class1.Age" ) ,
877
+ } ) ;
878
+
879
+ await test . RunAsync ( ) ;
880
+ }
881
+
882
+ [ TestMethod ]
883
+ public async Task SimpleFields_WithMultipleAttributes_WithMixedBuckets_1 ( )
884
+ {
885
+ string original = """
886
+ using System;
887
+ using System.ComponentModel.DataAnnotations;
888
+ using CommunityToolkit.Mvvm.ComponentModel;
889
+
890
+ public partial class Class1 : ObservableObject
891
+ {
892
+ // Leading trivia
893
+ [ObservableProperty, NotifyPropertyChangedFor("A"), Display]
894
+ [NotifyPropertyChangedFor("B")]
895
+ private string _name;
896
+ }
897
+ """ ;
898
+
899
+ string @fixed = """
900
+ using System;
901
+ using System.ComponentModel.DataAnnotations;
902
+ using CommunityToolkit.Mvvm.ComponentModel;
903
+
904
+ public partial class Class1 : ObservableObject
905
+ {
906
+ // Leading trivia
907
+ [ObservableProperty, NotifyPropertyChangedFor("A"), Display]
908
+ [NotifyPropertyChangedFor("B")]
909
+ public partial string Name { get; set; }
910
+ }
911
+ """ ;
912
+
913
+ CSharpCodeFixTest test = new ( LanguageVersion . Preview )
914
+ {
915
+ TestCode = original ,
916
+ FixedCode = @fixed ,
917
+ ReferenceAssemblies = ReferenceAssemblies . Net . Net80 ,
918
+ } ;
919
+
920
+ test . TestState . AdditionalReferences . Add ( typeof ( ObservableObject ) . Assembly ) ;
921
+ test . ExpectedDiagnostics . AddRange ( new [ ]
922
+ {
923
+ // /0/Test0.cs(10,20): info MVVMTK0042: The field Class1._name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
924
+ CSharpCodeFixVerifier . Diagnostic ( ) . WithSpan ( 10 , 20 , 10 , 25 ) . WithArguments ( "Class1" , "_name" ) ,
925
+ } ) ;
926
+
927
+ test . FixedState . ExpectedDiagnostics . AddRange ( new [ ]
928
+ {
929
+ // /0/Test0.cs(10,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
930
+ DiagnosticResult . CompilerError ( "CS9248" ) . WithSpan ( 10 , 27 , 10 , 31 ) . WithArguments ( "Class1.Name" ) ,
931
+ } ) ;
932
+
933
+ await test . RunAsync ( ) ;
934
+ }
935
+
936
+ [ TestMethod ]
937
+ public async Task SimpleFields_WithMultipleAttributes_WithMixedBuckets_2 ( )
938
+ {
939
+ string original = """
940
+ using System;
941
+ using System.ComponentModel.DataAnnotations;
942
+ using CommunityToolkit.Mvvm.ComponentModel;
943
+
944
+ public partial class Class1 : ObservableObject
945
+ {
946
+ // Leading trivia
947
+ [NotifyPropertyChangedFor("B")]
948
+ [ObservableProperty, NotifyPropertyChangedFor("A"), Display, Test]
949
+ [NotifyPropertyChangedFor("C")]
950
+ [property: UIHint("name"), Test]
951
+ private string name;
952
+ }
953
+
954
+ public class TestAttribute : Attribute;
955
+ """ ;
956
+
957
+ string @fixed = """
958
+ using System;
959
+ using System.ComponentModel.DataAnnotations;
960
+ using CommunityToolkit.Mvvm.ComponentModel;
961
+
962
+ public partial class Class1 : ObservableObject
963
+ {
964
+ // Leading trivia
965
+ [NotifyPropertyChangedFor("B")]
966
+ [ObservableProperty, NotifyPropertyChangedFor("A"), Display]
967
+ [field: Test]
968
+ [NotifyPropertyChangedFor("C")]
969
+ [UIHint("name"), Test]
970
+ public partial string Name { get; set; }
971
+ }
972
+
973
+ public class TestAttribute : Attribute;
974
+ """ ;
975
+
976
+ CSharpCodeFixTest test = new ( LanguageVersion . Preview )
977
+ {
978
+ TestCode = original ,
979
+ FixedCode = @fixed ,
980
+ ReferenceAssemblies = ReferenceAssemblies . Net . Net80 ,
981
+ } ;
982
+
983
+ test . TestState . AdditionalReferences . Add ( typeof ( ObservableObject ) . Assembly ) ;
984
+ test . ExpectedDiagnostics . AddRange ( new [ ]
985
+ {
986
+ // /0/Test0.cs(12,20): info MVVMTK0042: The field Class1.name using [ObservableProperty] can be converted to a partial property instead, which is recommended (doing so improves the developer experience and allows other generators and analyzers to correctly see the generated property as well)
987
+ CSharpCodeFixVerifier . Diagnostic ( ) . WithSpan ( 12 , 20 , 12 , 24 ) . WithArguments ( "Class1" , "name" ) ,
988
+ } ) ;
989
+
990
+ test . FixedState . ExpectedDiagnostics . AddRange ( new [ ]
991
+ {
992
+ // /0/Test0.cs(13,27): error CS9248: Partial property 'Class1.Name' must have an implementation part.
993
+ DiagnosticResult . CompilerError ( "CS9248" ) . WithSpan ( 13 , 27 , 13 , 31 ) . WithArguments ( "Class1.Name" ) ,
994
+ } ) ;
995
+
996
+ await test . RunAsync ( ) ;
997
+ }
770
998
}
0 commit comments