Skip to content

Commit

Permalink
Add unit tests for code fixer, fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Dec 21, 2024
1 parent 3b72d1d commit 0f8019b
Show file tree
Hide file tree
Showing 4 changed files with 795 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
}

// Retrieve the properties passed by the analyzer
if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationModePropertyName], out int invalidationMode))
if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationTypePropertyName], out int invalidationType))
{
return;
}
Expand All @@ -80,7 +80,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
semanticModel,
root,
propertyDeclaration,
invalidationMode),
invalidationType),
equivalenceKey: "Use [GeneratedCanvasEffectProperty]"),
diagnostic);
}
Expand Down Expand Up @@ -122,18 +122,18 @@ private static bool TryGetGeneratedCanvasEffectPropertyAttributeList(
/// <param name="document">The original document being fixed.</param>
/// <param name="semanticModel">The <see cref="SemanticModel"/> instance for the current compilation.</param>
/// <param name="generatedCanvasEffectPropertyAttributeList">The <see cref="AttributeListSyntax"/> with the attribute to add.</param>
/// <param name="invalidationMode">The invalidation mode to use.</param>
/// <param name="invalidationType">The invalidation type to use.</param>
/// <returns>The updated attribute syntax.</returns>
private static AttributeListSyntax UpdateGeneratedCanvasEffectPropertyAttributeList(
Document document,
SemanticModel semanticModel,
AttributeListSyntax generatedCanvasEffectPropertyAttributeList,
int invalidationMode)
int invalidationType)
{
// If the invalidation mode is not the default, set it in the attribute.
// If the invalidation type is not the default, set it in the attribute.
// We extract the generated attribute so we can add the new argument.
// It's important to reuse it, as it has the "add usings" annotation.
if (invalidationMode == 1)
if (invalidationType == 1)
{
// Try to resolve the attribute type, if present (this should always be the case)
if (semanticModel.Compilation.GetTypeByMetadataName(WellKnownTypeNames.CanvasEffectInvalidationType) is INamedTypeSymbol enumTypeSymbol)
Expand All @@ -144,11 +144,11 @@ private static AttributeListSyntax UpdateGeneratedCanvasEffectPropertyAttributeL
SyntaxNode enumTypeSyntax = syntaxGenerator.TypeExpression(enumTypeSymbol).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation);

// Create the member access expression for the target enum type.
// We only ever take this path for the 'Creation' invalidation mode.
// We only ever take this path for the 'Creation' invalidation type.
SyntaxNode enumMemberAccessExpressionSyntax = syntaxGenerator.MemberAccessExpression(enumTypeSyntax, "Creation");

// Create the attribute argument to insert
SyntaxNode attributeArgumentSyntax = syntaxGenerator.AttributeArgument("InvalidationMode", enumMemberAccessExpressionSyntax);
SyntaxNode attributeArgumentSyntax = syntaxGenerator.AttributeArgument(enumMemberAccessExpressionSyntax);

// Actually add the argument to the existing attribute syntax
return (AttributeListSyntax)syntaxGenerator.AddAttributeArguments(generatedCanvasEffectPropertyAttributeList, [attributeArgumentSyntax]);
Expand All @@ -159,11 +159,11 @@ private static AttributeListSyntax UpdateGeneratedCanvasEffectPropertyAttributeL
AttributeList(SingletonSeparatedList(
generatedCanvasEffectPropertyAttributeList.Attributes[0]
.AddArgumentListArguments(
AttributeArgument(ParseExpression($"global::{WellKnownTypeNames.CanvasEffectInvalidationType}.Creation"))
.WithNameEquals(NameEquals(IdentifierName("InvalidationMode"))))));
AttributeArgument(ParseExpression(
$"global::{WellKnownTypeNames.CanvasEffectInvalidationType}.Creation")))));
}

// If we have no custom invalidation mode, we can just reuse the attribute with no changes
// If we have no custom invalidation type, we can just reuse the attribute with no changes
return generatedCanvasEffectPropertyAttributeList;
}

Expand All @@ -174,14 +174,14 @@ private static AttributeListSyntax UpdateGeneratedCanvasEffectPropertyAttributeL
/// <param name="semanticModel">The <see cref="SemanticModel"/> instance for the current compilation.</param>
/// <param name="root">The original tree root belonging to the current document.</param>
/// <param name="propertyDeclaration">The <see cref="PropertyDeclarationSyntax"/> for the property being updated.</param>
/// <param name="invalidationMode">The invalidation mode to use.</param>
/// <param name="invalidationType">The invalidation type to use.</param>
/// <returns>An updated document with the applied code fix, and <paramref name="propertyDeclaration"/> being replaced with a partial property.</returns>
private static async Task<Document> ConvertToPartialProperty(
Document document,
SemanticModel semanticModel,
SyntaxNode root,
PropertyDeclarationSyntax propertyDeclaration,
int invalidationMode)
int invalidationType)
{
await Task.CompletedTask;

Expand All @@ -200,7 +200,7 @@ private static async Task<Document> ConvertToPartialProperty(
propertyDeclaration,
generatedCanvasEffectPropertyAttributeList,
syntaxEditor,
invalidationMode);
invalidationType);

// Create the new document with the single change
return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot());
Expand All @@ -214,22 +214,22 @@ private static async Task<Document> ConvertToPartialProperty(
/// <param name="propertyDeclaration">The <see cref="PropertyDeclarationSyntax"/> for the property being updated.</param>
/// <param name="generatedCanvasEffectPropertyAttributeList">The <see cref="AttributeListSyntax"/> with the attribute to add.</param>
/// <param name="syntaxEditor">The <see cref="SyntaxEditor"/> instance to use.</param>
/// <param name="invalidationMode">The invalidation mode to use.</param>
/// <param name="invalidationType">The invalidation type to use.</param>
/// <returns>An updated document with the applied code fix, and <paramref name="propertyDeclaration"/> being replaced with a partial property.</returns>
private static void ConvertToPartialProperty(
Document document,
SemanticModel semanticModel,
PropertyDeclarationSyntax propertyDeclaration,
AttributeListSyntax generatedCanvasEffectPropertyAttributeList,
SyntaxEditor syntaxEditor,
int invalidationMode)
int invalidationType)
{
// Update the attribute to insert with the invalidation mode, if needed
// Update the attribute to insert with the invalidation type, if needed
generatedCanvasEffectPropertyAttributeList = UpdateGeneratedCanvasEffectPropertyAttributeList(
document,
semanticModel,
generatedCanvasEffectPropertyAttributeList,
invalidationMode);
invalidationType);

// Start setting up the updated attribute lists
SyntaxList<AttributeListSyntax> attributeLists = propertyDeclaration.AttributeLists;
Expand Down Expand Up @@ -330,7 +330,7 @@ private sealed class FixAllProvider : DocumentBasedFixAllProvider
}

// Retrieve the properties passed by the analyzer
if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationModePropertyName], out int invalidationMode))
if (!int.TryParse(diagnostic.Properties[UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer.InvalidationTypePropertyName], out int invalidationType))
{
continue;
}
Expand All @@ -341,7 +341,7 @@ private sealed class FixAllProvider : DocumentBasedFixAllProvider
propertyDeclaration,
generatedCanvasEffectPropertyAttributeList,
syntaxEditor,
invalidationMode);
invalidationType);
}

return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public sealed class UseGeneratedCanvasEffectPropertyOnSemiAutoPropertyAnalyzer :
private static readonly ObjectPool<Stack<byte[]>> PropertyFlagsStackPool = new(CreatePropertyFlagsStack);

/// <summary>
/// The property name for the serialized invalidation mode.
/// The property name for the serialized invalidation type.
/// </summary>
public const string InvalidationModePropertyName = "InvalidationMode";
public const string InvalidationTypePropertyName = "InvalidationType";

/// <inheritdoc/>
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [UseGeneratedCanvasEffectPropertyOnSemiAutoProperty];
Expand Down Expand Up @@ -205,7 +205,7 @@ public override void Initialize(AnalysisContext context)
}

// We matched the method, now let's validate the arguments
if (invocationOperation.Arguments is not [{ } locationArgument, { } valueArgument, { } invalidationModeArgument])
if (invocationOperation.Arguments is not [{ } locationArgument, { } valueArgument, { } invalidationTypeArgument])
{
return;
}
Expand All @@ -229,11 +229,11 @@ public override void Initialize(AnalysisContext context)
}

// The invalidation mode can either be the default value...
if (invalidationModeArgument is { IsImplicit: true, ArgumentKind: ArgumentKind.DefaultValue })
if (invalidationTypeArgument is { IsImplicit: true, ArgumentKind: ArgumentKind.DefaultValue })
{
validFlags[1] = 1;
}
else if (invalidationModeArgument is { ConstantValue: { HasValue: true, Value: byte mode } } && mode is 0 or 1)
else if (invalidationTypeArgument is { Value.ConstantValue: { HasValue: true, Value: byte mode } } && mode is 0 or 1)
{
// ...Or is has to be set explicitly to one of the two supported values
validFlags[1] = (byte)(mode + 1);
Expand Down Expand Up @@ -289,7 +289,7 @@ public override void Initialize(AnalysisContext context)
context.ReportDiagnostic(Diagnostic.Create(
UseGeneratedCanvasEffectPropertyOnSemiAutoProperty,
pair.Key.Locations.FirstOrDefault(),
ImmutableDictionary.Create<string, string?>().Add(InvalidationModePropertyName, invalidationType.ToString()),
ImmutableDictionary.Create<string, string?>().Add(InvalidationTypePropertyName, invalidationType.ToString()),
pair.Key));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ internal sealed class CSharpCodeFixTest<TAnalyzer, TCodeFixer> : CSharpCodeFixTe
public CSharpCodeFixTest(LanguageVersion languageVersion)
{
this.languageVersion = languageVersion;

TestState.AnalyzerConfigFiles.Add(("/.editorconfig", "[*]\nend_of_line = lf"));
}

/// <inheritdoc/>
Expand Down
Loading

0 comments on commit 0f8019b

Please sign in to comment.