Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onpropertychangedfixes #353

Merged
merged 4 commits into from Jan 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -404,5 +404,278 @@ protected void OnPropertyChanged(string propertyName, bool someBoolean)
VerifyDiagnostic(original, string.Format(OnPropertyChangedWithoutNameOfOperatorAnalyzer.Rule.MessageFormat.ToString(), "IsEnabled"));
VerifyFix(original, expected);
}

[TestMethod]
public void OnPropertyChangedWithoutNameOfOperator_WithPartialClass()
{
var original = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
partial class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged(""IsEnabled"");
}
}
}

partial class MyClass
{
public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

var expected = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
partial class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged(nameof(IsEnabled));
}
}
}

partial class MyClass
{
public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

VerifyDiagnostic(original, string.Format(OnPropertyChangedWithoutNameOfOperatorAnalyzer.Rule.MessageFormat.ToString(), "IsEnabled"));
VerifyFix(original, expected);
}

[TestMethod]
public void OnPropertyChangedWithoutNameOfOperator_ParenthesizedExpression()
{
var original = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged((""IsEnabled""));
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

var expected = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged((nameof(IsEnabled)));
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

VerifyDiagnostic(original, string.Format(OnPropertyChangedWithoutNameOfOperatorAnalyzer.Rule.MessageFormat.ToString(), "IsEnabled"));
VerifyFix(original, expected);
}

[TestMethod]
public void OnPropertyChangedWithoutNameOfOperator_WithPartialClass_AndDifferentProperty()
{
var original = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
partial class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged(""OtherBoolean"");
}
}
}

partial class MyClass
{
public event PropertyChangedEventHandler PropertyChanged;

public bool OtherBoolean { get; set; }

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

var expected = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
partial class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged(nameof(OtherBoolean));
}
}
}

partial class MyClass
{
public event PropertyChangedEventHandler PropertyChanged;

public bool OtherBoolean { get; set; }

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";

VerifyDiagnostic(original, string.Format(OnPropertyChangedWithoutNameOfOperatorAnalyzer.Rule.MessageFormat.ToString(), "OtherBoolean"));
VerifyFix(original, expected);
}

[TestMethod]
public void OnPropertyChangedWithoutNameOfOperator_ParenthesizedExpression_WithNameof()
{
var original = @"
using System;
using System.Text;

namespace ConsoleApplication1
{
class MyClass : INotifyPropertyChanged
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
OnPropertyChanged(((nameof(IsEnabled))));
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;

if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}";
VerifyDiagnostic(original);
}
}
}
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand All @@ -23,7 +25,9 @@ public class OnPropertyChangedWithoutNameOfOperatorAnalyzer : DiagnosticAnalyzer
VSDiagnosticsResources.OnPropertyChangedWithoutNameOfOperatorAnalyzerTitle;

internal static DiagnosticDescriptor Rule
=> new DiagnosticDescriptor(DiagnosticId.OnPropertyChangedWithoutNameofOperator, Title, Message, Category, Severity, true);
=>
new DiagnosticDescriptor(DiagnosticId.OnPropertyChangedWithoutNameofOperator, Title, Message, Category,
Severity, true);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

Expand Down Expand Up @@ -54,26 +58,48 @@ private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
}

var invokedProperty = invocation.ArgumentList.Arguments.FirstOrDefault();
var argumentLiteralExpression = invokedProperty.Expression as LiteralExpressionSyntax;
if (argumentLiteralExpression == null)
if (invokedProperty == null)
{
return;
}

var invocationArgument = argumentLiteralExpression.Token.ValueText;
// We use the descendent nodes in case it's wrapped in another level. For example: OnPropertyChanged(((nameof(MyProperty))))
if (invokedProperty.DescendantNodesAndSelf().OfType<InvocationExpressionSyntax>().Any(x => x.IsNameofInvocation()))
{
return;
}

var invocationArgument = context.SemanticModel.GetConstantValue(invokedProperty.Expression);
if (!invocationArgument.HasValue)
{
return;
}

// Get all the properties defined in this type
// We can't just get all the descendents of the classdeclaration because that would pass by some of a partial class' properties
var classDeclaration = invocation.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault();
if (classDeclaration == null)
{
return;
}

var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration);
if (classSymbol == null)
{
return;
}

var properties =
invocation.Ancestors()
.OfType<ClassDeclarationSyntax>()
.FirstOrDefault()
.ChildNodes()
.OfType<PropertyDeclarationSyntax>();
foreach (var property in properties)
foreach (var property in classSymbol.GetMembers().OfType<IPropertySymbol>())
{
if (string.Equals(property.Identifier.ValueText, invocationArgument, StringComparison.OrdinalIgnoreCase))
if (string.Equals(property.Name, (string) invocationArgument.Value, StringComparison.OrdinalIgnoreCase))
{
context.ReportDiagnostic(Diagnostic.Create(Rule, invokedProperty.GetLocation(),
property.Identifier.ValueText));
var location = invokedProperty.Expression.DescendantNodesAndSelf().Last().GetLocation();
var data = ImmutableDictionary.CreateRange(new[]
{
new KeyValuePair<string, string>("parameterName", property.Name),
new KeyValuePair<string, string>("startLocation", location.SourceSpan.Start.ToString(CultureInfo.InvariantCulture)),
});
context.ReportDiagnostic(Diagnostic.Create(Rule, location, data, property.Name));
}
}
}
Expand Down