1- namespace WpfAnalyzers
2- {
3- using System . Collections . Immutable ;
1+ namespace WpfAnalyzers ;
42
5- using Gu . Roslyn . AnalyzerExtensions ;
3+ using System . Collections . Immutable ;
64
7- using Microsoft . CodeAnalysis ;
8- using Microsoft . CodeAnalysis . CSharp ;
9- using Microsoft . CodeAnalysis . CSharp . Syntax ;
10- using Microsoft . CodeAnalysis . Diagnostics ;
5+ using Gu . Roslyn . AnalyzerExtensions ;
116
12- [ DiagnosticAnalyzer ( LanguageNames . CSharp ) ]
13- internal class ClrPropertyDeclarationAnalyzer : DiagnosticAnalyzer
14- {
15- public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } = ImmutableArray . Create (
16- Descriptors . WPF0003ClrPropertyShouldMatchRegisteredName ,
17- Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
18- Descriptors . WPF0032ClrPropertyGetAndSetSameDependencyProperty ,
19- Descriptors . WPF0035ClrPropertyUseSetValueInSetter ,
20- Descriptors . WPF0036AvoidSideEffectsInClrAccessors ) ;
7+ using Microsoft . CodeAnalysis ;
8+ using Microsoft . CodeAnalysis . CSharp ;
9+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
10+ using Microsoft . CodeAnalysis . Diagnostics ;
2111
22- public override void Initialize ( AnalysisContext context )
23- {
24- context . ConfigureGeneratedCodeAnalysis ( GeneratedCodeAnalysisFlags . None ) ;
25- context . EnableConcurrentExecution ( ) ;
26- context . RegisterSyntaxNodeAction ( x => Handle ( x ) , SyntaxKind . PropertyDeclaration ) ;
27- }
12+ [ DiagnosticAnalyzer ( LanguageNames . CSharp ) ]
13+ internal class ClrPropertyDeclarationAnalyzer : DiagnosticAnalyzer
14+ {
15+ public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } = ImmutableArray . Create (
16+ Descriptors . WPF0003ClrPropertyShouldMatchRegisteredName ,
17+ Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
18+ Descriptors . WPF0032ClrPropertyGetAndSetSameDependencyProperty ,
19+ Descriptors . WPF0035ClrPropertyUseSetValueInSetter ,
20+ Descriptors . WPF0036AvoidSideEffectsInClrAccessors ) ;
2821
29- private static void Handle ( SyntaxNodeAnalysisContext context )
22+ public override void Initialize ( AnalysisContext context )
23+ {
24+ context . ConfigureGeneratedCodeAnalysis ( GeneratedCodeAnalysisFlags . None ) ;
25+ context . EnableConcurrentExecution ( ) ;
26+ context . RegisterSyntaxNodeAction ( x => Handle ( x ) , SyntaxKind . PropertyDeclaration ) ;
27+ }
28+
29+ private static void Handle ( SyntaxNodeAnalysisContext context )
30+ {
31+ if ( ! context . IsExcludedFromAnalysis ( ) &&
32+ context . ContainingSymbol is IPropertySymbol { IsStatic : false } property &&
33+ context . Node is PropertyDeclarationSyntax propertyDeclaration &&
34+ propertyDeclaration . Getter ( ) is { } getter &&
35+ propertyDeclaration . Setter ( ) is { } setter )
3036 {
31- if ( ! context . IsExcludedFromAnalysis ( ) &&
32- context . ContainingSymbol is IPropertySymbol { IsStatic : false } property &&
33- context . Node is PropertyDeclarationSyntax propertyDeclaration &&
34- propertyDeclaration . Getter ( ) is { } getter &&
35- propertyDeclaration . Setter ( ) is { } setter )
37+ if ( ClrProperty . Match ( property , context . SemanticModel , context . CancellationToken ) is { SetValue : { } setValue , BackingSet : { } backingSet , GetValue : { } getValue , BackingGet : { } backingGet } )
3638 {
37- if ( ClrProperty . Match ( property , context . SemanticModel , context . CancellationToken ) is { SetValue : { } setValue , BackingSet : { } backingSet , GetValue : { } getValue , BackingGet : { } backingGet } )
39+ if ( getter . Body is { Statements : { } getStatements } &&
40+ getStatements . Count > 1 &&
41+ getStatements . TryFirst ( x => ! x . Contains ( getValue ) , out var statement ) )
3842 {
39- if ( getter . Body is { Statements : { } getStatements } &&
40- getStatements . Count > 1 &&
41- getStatements . TryFirst ( x => ! x . Contains ( getValue ) , out var statement ) )
42- {
43- context . ReportDiagnostic ( Diagnostic . Create ( Descriptors . WPF0036AvoidSideEffectsInClrAccessors , statement . GetLocation ( ) ) ) ;
44- }
43+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptors . WPF0036AvoidSideEffectsInClrAccessors , statement . GetLocation ( ) ) ) ;
44+ }
4545
46- if ( setter . Body is { Statements : { } setStatements } &&
47- setStatements . Count > 1 &&
48- setStatements . TryFirst ( x => ! x . Contains ( setValue ) , out var sideEffect ) )
49- {
50- context . ReportDiagnostic ( Diagnostic . Create ( Descriptors . WPF0036AvoidSideEffectsInClrAccessors , sideEffect . GetLocation ( ) ) ) ;
51- }
46+ if ( setter . Body is { Statements : { } setStatements } &&
47+ setStatements . Count > 1 &&
48+ setStatements . TryFirst ( x => ! x . Contains ( setValue ) , out var sideEffect ) )
49+ {
50+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptors . WPF0036AvoidSideEffectsInClrAccessors , sideEffect . GetLocation ( ) ) ) ;
51+ }
5252
53- if ( IsGettingAndSettingDifferent ( ) )
53+ if ( IsGettingAndSettingDifferent ( ) )
54+ {
55+ context . ReportDiagnostic (
56+ Diagnostic . Create (
57+ Descriptors . WPF0032ClrPropertyGetAndSetSameDependencyProperty ,
58+ propertyDeclaration . GetLocation ( ) ,
59+ context . ContainingSymbol . Name ) ) ;
60+ }
61+
62+ if ( backingGet . RegisteredName ( context . SemanticModel , context . CancellationToken ) is { Value : { } registeredName } &&
63+ registeredName != property . Name )
64+ {
65+ context . ReportDiagnostic (
66+ Diagnostic . Create (
67+ Descriptors . WPF0003ClrPropertyShouldMatchRegisteredName ,
68+ propertyDeclaration . Identifier . GetLocation ( ) ,
69+ ImmutableDictionary < string , string ? > . Empty . Add ( "ExpectedName" , registeredName ) ,
70+ property . Name ,
71+ registeredName ) ) ;
72+ }
73+
74+ if ( backingGet . RegisteredType ( context . SemanticModel , context . CancellationToken ) is { Value : { } registeredType } )
75+ {
76+ if ( ! TypeSymbolComparer . Equal ( property . Type , registeredType ) )
5477 {
5578 context . ReportDiagnostic (
5679 Diagnostic . Create (
57- Descriptors . WPF0032ClrPropertyGetAndSetSameDependencyProperty ,
58- propertyDeclaration . GetLocation ( ) ,
59- context . ContainingSymbol . Name ) ) ;
80+ Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
81+ propertyDeclaration . Type . GetLocation ( ) ,
82+ ImmutableDictionary < string , string ? > . Empty . Add ( nameof ( TypeSyntax ) , registeredType . ToMinimalDisplayString ( context . SemanticModel , context . Node . SpanStart ) ) ,
83+ property ,
84+ registeredType ) ) ;
6085 }
61-
62- if ( backingGet . RegisteredName ( context . SemanticModel , context . CancellationToken ) is { Value : { } registeredName } &&
63- registeredName != property . Name )
86+ else if ( getValue is { Parent : CastExpressionSyntax { Type : { } type } } &&
87+ context . SemanticModel . GetType ( type , context . CancellationToken ) is { } castType &&
88+ ! TypeSymbolComparer . Equal ( registeredType , castType ) )
6489 {
6590 context . ReportDiagnostic (
6691 Diagnostic . Create (
67- Descriptors . WPF0003ClrPropertyShouldMatchRegisteredName ,
68- propertyDeclaration . Identifier . GetLocation ( ) ,
69- ImmutableDictionary < string , string ? > . Empty . Add ( "ExpectedName" , registeredName ) ,
70- property . Name ,
71- registeredName ) ) ;
92+ Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
93+ type . GetLocation ( ) ,
94+ ImmutableDictionary < string , string ? > . Empty . Add ( nameof ( TypeSyntax ) , registeredType . ToMinimalDisplayString ( context . SemanticModel , context . Node . SpanStart ) ) ,
95+ property ,
96+ registeredType ) ) ;
7297 }
98+ }
7399
74- if ( backingGet . RegisteredType ( context . SemanticModel , context . CancellationToken ) is { Value : { } registeredType } )
100+ bool IsGettingAndSettingDifferent ( )
101+ {
102+ if ( DependencyProperty . Register . FindRecursive ( backingGet , context . SemanticModel , context . CancellationToken ) is { Invocation : { } getRegistration } &&
103+ DependencyProperty . Register . FindRecursive ( backingSet , context . SemanticModel , context . CancellationToken ) is { Invocation : { } setRegistration } )
75104 {
76- if ( ! TypeSymbolComparer . Equal ( property . Type , registeredType ) )
77- {
78- context . ReportDiagnostic (
79- Diagnostic . Create (
80- Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
81- propertyDeclaration . Type . GetLocation ( ) ,
82- ImmutableDictionary < string , string ? > . Empty . Add ( nameof ( TypeSyntax ) , registeredType . ToMinimalDisplayString ( context . SemanticModel , context . Node . SpanStart ) ) ,
83- property ,
84- registeredType ) ) ;
85- }
86- else if ( getValue is { Parent : CastExpressionSyntax { Type : { } type } } &&
87- context . SemanticModel . GetType ( type , context . CancellationToken ) is { } castType &&
88- ! TypeSymbolComparer . Equal ( registeredType , castType ) )
89- {
90- context . ReportDiagnostic (
91- Diagnostic . Create (
92- Descriptors . WPF0012ClrPropertyShouldMatchRegisteredType ,
93- type . GetLocation ( ) ,
94- ImmutableDictionary < string , string ? > . Empty . Add ( nameof ( TypeSyntax ) , registeredType . ToMinimalDisplayString ( context . SemanticModel , context . Node . SpanStart ) ) ,
95- property ,
96- registeredType ) ) ;
97- }
105+ return getRegistration != setRegistration ;
98106 }
99107
100- bool IsGettingAndSettingDifferent ( )
101- {
102- if ( DependencyProperty . Register . FindRecursive ( backingGet , context . SemanticModel , context . CancellationToken ) is { Invocation : { } getRegistration } &&
103- DependencyProperty . Register . FindRecursive ( backingSet , context . SemanticModel , context . CancellationToken ) is { Invocation : { } setRegistration } )
104- {
105- return getRegistration != setRegistration ;
106- }
107-
108- return false ;
109- }
108+ return false ;
110109 }
110+ }
111111
112- if ( DependencyObject . SetCurrentValue . Find ( MethodOrAccessor . Create ( setter ) , context . SemanticModel , context . CancellationToken ) is { Invocation : { } setCurrentValue } )
113- {
114- context . ReportDiagnostic (
115- Diagnostic . Create (
116- Descriptors . WPF0035ClrPropertyUseSetValueInSetter ,
117- setCurrentValue . GetLocation ( ) ,
118- context . ContainingSymbol . Name ) ) ;
119- }
112+ if ( DependencyObject . SetCurrentValue . Find ( MethodOrAccessor . Create ( setter ) , context . SemanticModel , context . CancellationToken ) is { Invocation : { } setCurrentValue } )
113+ {
114+ context . ReportDiagnostic (
115+ Diagnostic . Create (
116+ Descriptors . WPF0035ClrPropertyUseSetValueInSetter ,
117+ setCurrentValue . GetLocation ( ) ,
118+ context . ContainingSymbol . Name ) ) ;
120119 }
121120 }
122121 }
123- }
122+ }
0 commit comments