Skip to content

Commit 8b94722

Browse files
authored
Merge pull request #984 from CommunityToolkit/dev/move-diagnostics-target-members
Improve locations resolution for new analyzers
2 parents 3393d30 + 4e6cf2b commit 8b94722

12 files changed

+89
-61
lines changed

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System.Collections.Generic;
66
using System.Collections.Immutable;
7-
using System.Linq;
87
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
98
using Microsoft.CodeAnalysis;
109
using Microsoft.CodeAnalysis.CSharp;
@@ -76,7 +75,7 @@ public override void Initialize(AnalysisContext context)
7675
typeSymbols.TryGetValue(attributeName, out INamedTypeSymbol? attributeSymbol) &&
7776
SymbolEqualityComparer.Default.Equals(attributeClass, attributeSymbol))
7877
{
79-
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.Locations.FirstOrDefault()));
78+
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.GetLocationFromAttributeDataOrDefault(attribute)));
8079

8180
// If we created a diagnostic for this symbol, we can stop. Even if there's multiple attributes, no need for repeated errors
8281
return;

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedRoslynVersionForPartialPropertyAnalyzer.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#if !ROSLYN_4_11_0_OR_GREATER
66

77
using System.Collections.Immutable;
8+
using System.Linq;
89
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
910
using Microsoft.CodeAnalysis;
1011
using Microsoft.CodeAnalysis.Diagnostics;
@@ -44,11 +45,11 @@ public override void Initialize(AnalysisContext context)
4445
}
4546

4647
// If the property has [ObservableProperty], emit an error in all cases
47-
if (propertySymbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
48+
if (propertySymbol.HasAttributeWithType(observablePropertySymbol))
4849
{
4950
context.ReportDiagnostic(Diagnostic.Create(
5051
UnsupportedRoslynVersionForObservablePartialPropertySupport,
51-
observablePropertyAttribute.GetLocation(),
52+
propertySymbol.Locations.FirstOrDefault(),
5253
propertySymbol.ContainingType,
5354
propertySymbol));
5455
}

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UseObservablePropertyOnPartialPropertyAnalyzer.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#if ROSLYN_4_11_0_OR_GREATER
66

77
using System.Collections.Immutable;
8+
using System.Linq;
89
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
910
using Microsoft.CodeAnalysis;
1011
using Microsoft.CodeAnalysis.Diagnostics;
@@ -57,7 +58,7 @@ public override void Initialize(AnalysisContext context)
5758
}
5859

5960
// Check that we are in fact using [ObservableProperty]
60-
if (!fieldSymbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
61+
if (!fieldSymbol.HasAttributeWithType(observablePropertySymbol))
6162
{
6263
return;
6364
}
@@ -74,7 +75,7 @@ public override void Initialize(AnalysisContext context)
7475
// Emit the diagnostic for this field to suggest changing to a partial property instead
7576
context.ReportDiagnostic(Diagnostic.Create(
7677
UseObservablePropertyOnPartialProperty,
77-
observablePropertyAttribute.GetLocation(),
78+
fieldSymbol.Locations.FirstOrDefault(),
7879
ImmutableDictionary.Create<string, string?>()
7980
.Add(FieldReferenceForObservablePropertyFieldAnalyzer.FieldNameKey, fieldSymbol.Name)
8081
.Add(FieldReferenceForObservablePropertyFieldAnalyzer.PropertyNameKey, ObservablePropertyGenerator.Execute.GetGeneratedPropertyName(fieldSymbol)),

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System.Collections.Generic;
66
using System.Collections.Immutable;
7-
using System.Linq;
87
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
98
using Microsoft.CodeAnalysis;
109
using Microsoft.CodeAnalysis.Diagnostics;
@@ -79,7 +78,7 @@ public override void Initialize(AnalysisContext context)
7978
{
8079
context.ReportDiagnostic(Diagnostic.Create(
8180
GeneratorAttributeNamesToDiagnosticsMap[attributeClass.Name],
82-
context.Symbol.Locations.FirstOrDefault(),
81+
context.Symbol.GetLocationFromAttributeDataOrDefault(attribute),
8382
context.Symbol));
8483
}
8584
}

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public override void Initialize(AnalysisContext context)
6565
{
6666
context.ReportDiagnostic(Diagnostic.Create(
6767
WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField,
68-
generatedBindableCustomPropertyAttribute.GetLocation(),
68+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
6969
typeSymbol,
7070
fieldSymbol.ContainingType,
7171
fieldSymbol.Name));
@@ -76,7 +76,7 @@ public override void Initialize(AnalysisContext context)
7676
{
7777
context.ReportDiagnostic(Diagnostic.Create(
7878
WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand,
79-
generatedBindableCustomPropertyAttribute.GetLocation(),
79+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
8080
typeSymbol,
8181
methodSymbol));
8282
}

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTObservablePropertyOnFieldsIsNotAotCompatibleAnalyzer.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#if ROSLYN_4_11_0_OR_GREATER
66

77
using System.Collections.Immutable;
8+
using System.Linq;
89
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
910
using Microsoft.CodeAnalysis;
1011
using Microsoft.CodeAnalysis.Diagnostics;
@@ -50,11 +51,11 @@ public override void Initialize(AnalysisContext context)
5051
}
5152

5253
// Emit a diagnostic if the field is using the [ObservableProperty] attribute
53-
if (fieldSymbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
54+
if (fieldSymbol.HasAttributeWithType(observablePropertySymbol))
5455
{
5556
context.ReportDiagnostic(Diagnostic.Create(
5657
WinRTObservablePropertyOnFieldsIsNotAotCompatible,
57-
observablePropertyAttribute.GetLocation(),
58+
fieldSymbol.Locations.FirstOrDefault(),
5859
ImmutableDictionary.Create<string, string?>()
5960
.Add(FieldReferenceForObservablePropertyFieldAnalyzer.FieldNameKey, fieldSymbol.Name)
6061
.Add(FieldReferenceForObservablePropertyFieldAnalyzer.PropertyNameKey, ObservablePropertyGenerator.Execute.GetGeneratedPropertyName(fieldSymbol)),

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public override void Initialize(AnalysisContext context)
5959
{
6060
context.ReportDiagnostic(Diagnostic.Create(
6161
WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible,
62-
relayCommandAttribute.GetLocation(),
62+
methodSymbol.GetLocationFromAttributeDataOrDefault(relayCommandAttribute),
6363
methodSymbol));
6464
}
6565
}, SymbolKind.Method);

src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,31 @@ public static bool CanBeAccessedFrom(this ISymbol symbol, IAssemblySymbol assemb
175175
accessibility == Accessibility.Public ||
176176
accessibility == Accessibility.Internal && symbol.ContainingAssembly.GivesAccessTo(assembly);
177177
}
178+
179+
/// <summary>
180+
/// Gets the location of a given symbol that is in the same syntax tree of a specified attribute, or the first one.
181+
/// </summary>
182+
/// <param name="symbol">The input <see cref="ISymbol"/> instance to check.</param>
183+
/// <param name="attributeData">The target <see cref="AttributeData"/> instance.</param>
184+
/// <returns>The best <see cref="Location"/> match.</returns>
185+
public static Location? GetLocationFromAttributeDataOrDefault(this ISymbol symbol, AttributeData attributeData)
186+
{
187+
Location? firstLocation = null;
188+
189+
// Get the syntax tree where the attribute application is located. We use
190+
// it to try to find the symbol location that belongs to the same file.
191+
SyntaxTree? attributeTree = attributeData.ApplicationSyntaxReference?.SyntaxTree;
192+
193+
foreach (Location location in symbol.Locations)
194+
{
195+
if (location.SourceTree == attributeTree)
196+
{
197+
return location;
198+
}
199+
200+
firstLocation ??= location;
201+
}
202+
203+
return firstLocation;
204+
}
178205
}

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.UnitTests/Test_UnsupportedRoslynVersionForPartialPropertyAnalyzer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ namespace MyApp
2121
{
2222
public partial class SampleViewModel : ObservableObject
2323
{
24-
[{|MVVMTK0044:ObservableProperty|}]
25-
public string Bar { get; set; }
24+
[ObservableProperty]
25+
public string {|MVVMTK0044:Bar|} { get; set; }
2626
}
2727
}
2828
""";

tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4110.UnitTests/Test_SourceGeneratorsDiagnostics.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ namespace MyApp
7878
{
7979
public partial class SampleViewModel : ObservableObject
8080
{
81-
[{|MVVMTK0042:ObservableProperty|}]
82-
private string name;
81+
[ObservableProperty]
82+
private string {|MVVMTK0042:name|};
8383
}
8484
}
8585
""";
@@ -371,8 +371,8 @@ namespace MyApp
371371
{
372372
public partial class SampleViewModel : ObservableObject
373373
{
374-
[{|MVVMTK0045:ObservableProperty|}]
375-
private string name;
374+
[ObservableProperty]
375+
private string {|MVVMTK0045:name|};
376376
}
377377
}
378378
""";
@@ -415,8 +415,8 @@ namespace MyApp
415415
{
416416
public partial class SampleViewModel : ObservableObject
417417
{
418-
[{|MVVMTK0045:ObservableProperty|}]
419-
private string name;
418+
[ObservableProperty]
419+
private string {|MVVMTK0045:name|};
420420
}
421421
}
422422
""";
@@ -437,8 +437,8 @@ namespace MyApp
437437
{
438438
public partial class SampleViewModel : ObservableObject
439439
{
440-
[{|MVVMTK0045:ObservableProperty|}]
441-
private string name;
440+
[ObservableProperty]
441+
private string {|MVVMTK0045:name|};
442442
}
443443
}
444444
""";
@@ -459,8 +459,8 @@ namespace MyApp
459459
{
460460
public partial class SampleViewModel : ObservableObject
461461
{
462-
[{|MVVMTK0045:ObservableProperty|}]
463-
private string name;
462+
[ObservableProperty]
463+
private string {|MVVMTK0045:name|};
464464
}
465465
}
466466
@@ -486,8 +486,8 @@ namespace MyApp
486486
{
487487
public partial class SampleViewModel : ObservableObject
488488
{
489-
[{|MVVMTK0045:ObservableProperty|}]
490-
private string name;
489+
[ObservableProperty]
490+
private string {|MVVMTK0045:name|};
491491
}
492492
}
493493
@@ -585,8 +585,8 @@ public async Task WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer_Ta
585585
586586
namespace MyApp
587587
{
588-
[{|MVVMTK0047:GeneratedBindableCustomProperty|}]
589-
public partial class SampleViewModel : BaseViewModel
588+
[GeneratedBindableCustomProperty]
589+
public partial class {|MVVMTK0047:SampleViewModel|} : BaseViewModel
590590
{
591591
}
592592
@@ -620,8 +620,8 @@ public async Task WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer_Ta
620620
621621
namespace MyApp
622622
{
623-
[{|MVVMTK0048:GeneratedBindableCustomProperty|}]
624-
public partial class SampleViewModel : BaseViewModel
623+
[GeneratedBindableCustomProperty]
624+
public partial class {|MVVMTK0048:SampleViewModel|} : BaseViewModel
625625
{
626626
}
627627

0 commit comments

Comments
 (0)