private static void HandleInvocation(SyntaxNodeAnalysisContext context) { if (context.IsExcludedFromAnalysis()) { return; } var invocation = (InvocationExpressionSyntax)context.Node; var method = context.SemanticModel.GetSymbolSafe(invocation, context.CancellationToken) as IMethodSymbol; if (method == KnownSymbol.PropertyChangedEventHandler.Invoke || PropertyChanged.IsInvoker(method, context.SemanticModel, context.CancellationToken) != AnalysisResult.No) { if (PropertyChanged.TryGetInvokedPropertyChangedName(invocation, context.SemanticModel, context.CancellationToken, out ArgumentSyntax nameArg, out string propertyName) == AnalysisResult.Yes) { var type = invocation.Expression is IdentifierNameSyntax || (invocation.Expression as MemberAccessExpressionSyntax)?.Expression is ThisExpressionSyntax || (invocation.Expression as MemberAccessExpressionSyntax)?.Expression is BaseExpressionSyntax || context.SemanticModel.GetSymbolSafe(invocation, context.CancellationToken) as IMethodSymbol == KnownSymbol.PropertyChangedEventHandler.Invoke ? context.ContainingSymbol.ContainingType : context.SemanticModel.GetTypeInfoSafe((invocation.Expression as MemberAccessExpressionSyntax)?.Expression, context.CancellationToken) .Type; if (IsForExistingProperty(type, propertyName)) { return; } if (invocation.Span.Contains(nameArg.Span)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameArg.GetLocation())); return; } if (method == KnownSymbol.PropertyChangedEventHandler.Invoke) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocation.ArgumentList.Arguments[1].GetLocation())); return; } if (invocation.ArgumentList.Arguments.Count == 1) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocation.ArgumentList.Arguments[0].GetLocation())); return; } context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocation.GetLocation())); } } }
public void WhenTrue(string call) { var syntaxTree = CSharpSyntaxTree.ParseText( @" namespace RoslynSandbox { using System; using System.ComponentModel; using System.Linq.Expressions; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private static readonly PropertyChangedEventArgs Cached = new PropertyChangedEventArgs(""Bar""); private int bar; public event PropertyChangedEventHandler PropertyChanged; public int Bar { get { return this.bar; } set { if (value == this.bar) { return; } this.bar = value; this.OnPropertyChanged(); this.OnPropertyChanged(""Bar""); this.OnPropertyChanged(nameof(Bar)); this.OnPropertyChanged(nameof(this.Bar)); this.OnPropertyChanged(() => Bar); this.OnPropertyChanged(() => this.Bar); this.OnPropertyChanged(new PropertyChangedEventArgs(""Bar"")); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Bar))); this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(this.Bar))); this.OnPropertyChanged(Cached); var args = new PropertyChangedEventArgs(""Bar""); this.OnPropertyChanged(args); } } protected virtual void OnPropertyChanged<T>(Expression<Func<T>> property) { this.OnPropertyChanged(((MemberExpression)property.Body).Member.Name); } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { this.PropertyChanged?.Invoke(this, e); } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"); var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes()); var semanticModel = compilation.GetSemanticModel(syntaxTree); var invocation = syntaxTree.FindInvocation(call); Assert.AreEqual(call, invocation.ToString()); Assert.AreEqual(AnalysisResult.Yes, PropertyChanged.TryGetInvokedPropertyChangedName(invocation, semanticModel, CancellationToken.None, out var name)); Assert.AreEqual("Bar", name); }