Skip to content

Commit 4e6cf2b

Browse files
committed
Improve logic to find target symbol locations
1 parent 50d8ff5 commit 4e6cf2b

5 files changed

+34
-11
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/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: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
using System.Collections.Generic;
88
using System.Collections.Immutable;
9-
using System.Linq;
109
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
1110
using Microsoft.CodeAnalysis;
1211
using Microsoft.CodeAnalysis.Diagnostics;
@@ -56,7 +55,7 @@ public override void Initialize(AnalysisContext context)
5655
}
5756

5857
// We only care about it if it's using [GeneratedBindableCustomProperty]
59-
if (!typeSymbol.HasAttributeWithType(generatedBindableCustomPropertySymbol))
58+
if (!typeSymbol.TryGetAttributeWithType(generatedBindableCustomPropertySymbol, out AttributeData? generatedBindableCustomPropertyAttribute))
6059
{
6160
return;
6261
}
@@ -66,7 +65,7 @@ public override void Initialize(AnalysisContext context)
6665
{
6766
context.ReportDiagnostic(Diagnostic.Create(
6867
WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField,
69-
typeSymbol.Locations.FirstOrDefault(),
68+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
7069
typeSymbol,
7170
fieldSymbol.ContainingType,
7271
fieldSymbol.Name));
@@ -77,7 +76,7 @@ public override void Initialize(AnalysisContext context)
7776
{
7877
context.ReportDiagnostic(Diagnostic.Create(
7978
WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand,
80-
typeSymbol.Locations.FirstOrDefault(),
79+
typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
8180
typeSymbol,
8281
methodSymbol));
8382
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections.Immutable;
6-
using System.Linq;
76
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
87
using Microsoft.CodeAnalysis;
98
using Microsoft.CodeAnalysis.Diagnostics;
@@ -50,7 +49,7 @@ public override void Initialize(AnalysisContext context)
5049
}
5150

5251
// If the method is not using [RelayCommand], we can skip it
53-
if (!methodSymbol.HasAttributeWithType(relayCommandSymbol))
52+
if (!methodSymbol.TryGetAttributeWithType(relayCommandSymbol, out AttributeData? relayCommandAttribute))
5453
{
5554
return;
5655
}
@@ -60,7 +59,7 @@ public override void Initialize(AnalysisContext context)
6059
{
6160
context.ReportDiagnostic(Diagnostic.Create(
6261
WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible,
63-
methodSymbol.Locations.FirstOrDefault(),
62+
methodSymbol.GetLocationFromAttributeDataOrDefault(relayCommandAttribute),
6463
methodSymbol));
6564
}
6665
}, 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
}

0 commit comments

Comments
 (0)