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

Handle [ObservableProperty] fields with keyword identifiers #720

Merged
merged 2 commits into from Jun 21, 2023
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 @@ -795,13 +795,33 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
// Get the property type syntax
TypeSyntax propertyType = IdentifierName(propertyInfo.TypeNameWithNullabilityAnnotations);

string getterFieldIdentifierName;
ExpressionSyntax getterFieldExpression;
ExpressionSyntax setterFieldExpression;

// In case the backing field is exactly named "value", we need to add the "this." prefix to ensure that comparisons and assignments
// with it in the generated setter body are executed correctly and without conflicts with the implicit value parameter.
ExpressionSyntax fieldExpression = propertyInfo.FieldName switch
if (propertyInfo.FieldName == "value")
{
"value" => MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("value")),
string name => IdentifierName(name)
};
// We only need to add "this." when referencing the field in the setter (getter and XML docs are not ambiguous)
getterFieldIdentifierName = "value";
getterFieldExpression = IdentifierName(getterFieldIdentifierName);
setterFieldExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), (IdentifierNameSyntax)getterFieldExpression);
}
else if (SyntaxFacts.GetKeywordKind(propertyInfo.FieldName) != SyntaxKind.None ||
SyntaxFacts.GetContextualKeywordKind(propertyInfo.FieldName) != SyntaxKind.None)
{
// If the identifier for the field could potentially be a keyword, we must escape it.
// This usually happens if the annotated field was escaped as well (eg. "@event").
// In this case, we must always escape the identifier, in all cases.
getterFieldIdentifierName = $"@{propertyInfo.FieldName}";
getterFieldExpression = setterFieldExpression = IdentifierName(getterFieldIdentifierName);
}
else
{
getterFieldIdentifierName = propertyInfo.FieldName;
getterFieldExpression = setterFieldExpression = IdentifierName(getterFieldIdentifierName);
}

if (propertyInfo.NotifyPropertyChangedRecipients || propertyInfo.IsOldPropertyValueDirectlyReferenced)
{
Expand All @@ -813,7 +833,7 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
VariableDeclaration(propertyType)
.AddVariables(
VariableDeclarator(Identifier("__oldValue"))
.WithInitializer(EqualsValueClause(fieldExpression)))));
.WithInitializer(EqualsValueClause(setterFieldExpression)))));
}

// Add the OnPropertyChanging() call first:
Expand Down Expand Up @@ -863,7 +883,7 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
fieldExpression,
setterFieldExpression,
IdentifierName("value"))));

// If validation is requested, add a call to ValidateProperty:
Expand Down Expand Up @@ -959,7 +979,7 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
IdentifierName("Default")),
IdentifierName("Equals")))
.AddArgumentListArguments(
Argument(fieldExpression),
Argument(setterFieldExpression),
Argument(IdentifierName("value")))),
Block(setterStatements.AsEnumerable()));

Expand Down Expand Up @@ -1009,13 +1029,13 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
.AddArgumentListArguments(
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ObservablePropertyGenerator).FullName))),
AttributeArgument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(typeof(ObservablePropertyGenerator).Assembly.GetName().Version.ToString()))))))
.WithOpenBracketToken(Token(TriviaList(Comment($"/// <inheritdoc cref=\"{propertyInfo.FieldName}\"/>")), SyntaxKind.OpenBracketToken, TriviaList())),
.WithOpenBracketToken(Token(TriviaList(Comment($"/// <inheritdoc cref=\"{getterFieldIdentifierName}\"/>")), SyntaxKind.OpenBracketToken, TriviaList())),
AttributeList(SingletonSeparatedList(Attribute(IdentifierName("global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage")))))
.AddAttributeLists(forwardedAttributes.ToArray())
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithExpressionBody(ArrowExpressionClause(IdentifierName(propertyInfo.FieldName)))
.WithExpressionBody(ArrowExpressionClause(getterFieldExpression))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
setAccessor);
}
Expand Down