diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs
index 42312904..cbfa6ecd 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Linq;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -76,7 +75,7 @@ public sealed class UnsupportedCSharpLanguageVersionAnalyzer : DiagnosticAnalyze
typeSymbols.TryGetValue(attributeName, out INamedTypeSymbol? attributeSymbol) &&
SymbolEqualityComparer.Default.Equals(attributeClass, attributeSymbol))
{
- context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.Locations.FirstOrDefault()));
+ context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.GetLocationFromAttributeDataOrDefault(attribute)));
// If we created a diagnostic for this symbol, we can stop. Even if there's multiple attributes, no need for repeated errors
return;
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer.cs
index b96c5844..2b0621dc 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Linq;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
@@ -79,7 +78,7 @@ public sealed class WinRTClassUsingNotifyPropertyChangedAttributesAnalyzer : Dia
{
context.ReportDiagnostic(Diagnostic.Create(
GeneratorAttributeNamesToDiagnosticsMap[attributeClass.Name],
- context.Symbol.Locations.FirstOrDefault(),
+ context.Symbol.GetLocationFromAttributeDataOrDefault(attribute),
context.Symbol));
}
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs
index 891e8455..f76cb4bc 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer.cs
@@ -6,7 +6,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Linq;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
@@ -56,7 +55,7 @@ public sealed class WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer
}
// We only care about it if it's using [GeneratedBindableCustomProperty]
- if (!typeSymbol.HasAttributeWithType(generatedBindableCustomPropertySymbol))
+ if (!typeSymbol.TryGetAttributeWithType(generatedBindableCustomPropertySymbol, out AttributeData? generatedBindableCustomPropertyAttribute))
{
return;
}
@@ -66,7 +65,7 @@ public sealed class WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer
{
context.ReportDiagnostic(Diagnostic.Create(
WinRTGeneratedBindableCustomPropertyWithBaseObservablePropertyOnField,
- typeSymbol.Locations.FirstOrDefault(),
+ typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
typeSymbol,
fieldSymbol.ContainingType,
fieldSymbol.Name));
@@ -77,7 +76,7 @@ public sealed class WinRTGeneratedBindableCustomPropertyWithBasesMemberAnalyzer
{
context.ReportDiagnostic(Diagnostic.Create(
WinRTGeneratedBindableCustomPropertyWithBaseRelayCommand,
- typeSymbol.Locations.FirstOrDefault(),
+ typeSymbol.GetLocationFromAttributeDataOrDefault(generatedBindableCustomPropertyAttribute),
typeSymbol,
methodSymbol));
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs
index 3c92eb9e..7cbcf136 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatibleAnalyzer.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
-using System.Linq;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
@@ -50,7 +49,7 @@ public sealed class WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompati
}
// If the method is not using [RelayCommand], we can skip it
- if (!methodSymbol.HasAttributeWithType(relayCommandSymbol))
+ if (!methodSymbol.TryGetAttributeWithType(relayCommandSymbol, out AttributeData? relayCommandAttribute))
{
return;
}
@@ -60,7 +59,7 @@ public sealed class WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompati
{
context.ReportDiagnostic(Diagnostic.Create(
WinRTRelayCommandIsNotGeneratedBindableCustomPropertyCompatible,
- methodSymbol.Locations.FirstOrDefault(),
+ methodSymbol.GetLocationFromAttributeDataOrDefault(relayCommandAttribute),
methodSymbol));
}
}, SymbolKind.Method);
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
index a825454f..964e4daf 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
@@ -175,4 +175,31 @@ internal static class ISymbolExtensions
accessibility == Accessibility.Public ||
accessibility == Accessibility.Internal && symbol.ContainingAssembly.GivesAccessTo(assembly);
}
+
+ ///
+ /// Gets the location of a given symbol that is in the same syntax tree of a specified attribute, or the first one.
+ ///
+ /// The input instance to check.
+ /// The target instance.
+ /// The best match.
+ public static Location? GetLocationFromAttributeDataOrDefault(this ISymbol symbol, AttributeData attributeData)
+ {
+ Location? firstLocation = null;
+
+ // Get the syntax tree where the attribute application is located. We use
+ // it to try to find the symbol location that belongs to the same file.
+ SyntaxTree? attributeTree = attributeData.ApplicationSyntaxReference?.SyntaxTree;
+
+ foreach (Location location in symbol.Locations)
+ {
+ if (location.SourceTree == attributeTree)
+ {
+ return location;
+ }
+
+ firstLocation ??= location;
+ }
+
+ return firstLocation;
+ }
}