Skip to content
This repository has been archived by the owner on Jul 23, 2022. It is now read-only.

Commit

Permalink
Merge branch 'develop' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
esnya committed Jul 22, 2021
2 parents ebaf420 + 912786f commit 1254f84
Show file tree
Hide file tree
Showing 33 changed files with 1,355 additions and 15 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/automatic-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ jobs:

- uses: actions/upload-artifact@v2
with:
name: UdonRabbit.Analyzer.VisualStudio.vsix
path: Source/UdonRabbit.Analyzer.VisualStudio/bin/Release/**/UdonRabbit.Analyzer.VisualStudio.vsix
name: UdonRabbit.Analyzer.VisualStudio.2019.vsix
path: Source/UdonRabbit.Analyzer.VisualStudio/bin/Release/**/UdonRabbit.Analyzer.VisualStudio.2019.vsix

- name: Publish the package to Releases
uses: softprops/action-gh-release@v1
with:
files: Source/UdonRabbit.Analyzer.VisualStudio/bin/Release/**/UdonRabbit.Analyzer.VisualStudio.vsix
files: Source/UdonRabbit.Analyzer.VisualStudio/bin/Release/**/UdonRabbit.Analyzer.VisualStudio.2019.vsix
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down
18 changes: 18 additions & 0 deletions Source/UdonRabbit.Analyzer.CodeFixes/CodeFixResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Source/UdonRabbit.Analyzer.CodeFixes/CodeFixResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,10 @@
<data name="URA0047CodeFixTitle" xml:space="preserve">
<value>Generic method of GetComponent&lt;T&gt; is currently broken in Udon, use the GetComponent(Type) instead of GetComponent&lt;T&gt;()</value>
</data>
<data name="URA0052CodeFixTitle" xml:space="preserve">
<value>Use property setter assignment instead of field assignment</value>
</data>
<data name="URA0053CodeFixTitle" xml:space="preserve">
<value>Create a new property</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

using UdonRabbit.Analyzer.Abstractions;
using UdonRabbit.Analyzer.Extensions;
using UdonRabbit.Analyzer.Udon;

namespace UdonRabbit.Analyzer
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(InvalidTargetPropertyForFieldChangeCallbackCodeFixProvider))]
[Shared]
public class InvalidTargetPropertyForFieldChangeCallbackCodeFixProvider : CodeFixProviderBase
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(InvalidTargetPropertyForFieldChangeCallback.ComponentId);

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (!TryFindFirstAncestorOrSelf<FieldDeclarationSyntax>(root, context.Span, out var declaration))
return;

var document = context.Document;
var diagnostic = context.Diagnostics[0];
var action = CreateCodeAction(CodeFixResources.URA0053CodeFixTitle, ct => CreatePropertyDeclaration(document, declaration, ct), diagnostic.Id);
context.RegisterCodeFix(action, diagnostic);
}

private static async Task<Document> CreatePropertyDeclaration(Document document, FieldDeclarationSyntax fieldDeclaration, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var backingField = fieldDeclaration.Declaration.Variables.First().Identifier.ValueText;
var type = fieldDeclaration.Declaration.Type;
var attribute = fieldDeclaration.AttributeLists.SelectMany(w => w.Attributes)
.First(w => UdonSharpBehaviourUtility.PrettyTypeName(semanticModel.GetSymbolInfo(w).Symbol) == UdonConstants.UdonSharpFieldChangeCallbackFullName);
var targetProperty = attribute.ArgumentList.Arguments.First().Expression.ParseValue();

var modifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
var getter = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, default, default, SyntaxFactory.ArrowExpressionClause(SyntaxFactory.IdentifierName(backingField)))
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
var setterBlock = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(backingField), SyntaxFactory.IdentifierName("value"));
var setter = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration, SyntaxFactory.Block(SyntaxFactory.ExpressionStatement(setterBlock)));
var accessors = SyntaxFactory.List(new[] { getter, setter });
var property = SyntaxFactory.PropertyDeclaration(type, targetProperty).WithModifiers(modifiers).WithAccessorList(SyntaxFactory.AccessorList(accessors));

var oldNode = fieldDeclaration.FirstAncestorOrSelf<ClassDeclarationSyntax>();
var newNode = oldNode.AddMembers(property);

return await document.ReplaceNodeAsync(oldNode, newNode, cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

using UdonRabbit.Analyzer.Abstractions;
using UdonRabbit.Analyzer.Extensions;
using UdonRabbit.Analyzer.Udon;

namespace UdonRabbit.Analyzer
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(NotAllowDirectlySetValueWithFieldChangeCallbackCodeFixProvider))]
[Shared]
public class NotAllowDirectlySetValueWithFieldChangeCallbackCodeFixProvider : CodeFixProviderBase
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(NotAllowDirectlySetValueWithFieldChangeCallback.ComponentId);

public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (!TryFindFirstAncestorOrSelf<AssignmentExpressionSyntax>(root, context.Span, out var assignment))
return;

var document = context.Document;
var diagnostic = context.Diagnostics[0];
var action = CreateCodeAction(CodeFixResources.URA0052CodeFixTitle, ct => UsePropertyAssignment(document, assignment, ct), diagnostic.Id);
context.RegisterCodeFix(action, diagnostic);
}

private static async Task<Document> UsePropertyAssignment(Document document, AssignmentExpressionSyntax assignment, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var memberAccess = assignment.Left as MemberAccessExpressionSyntax;
if (memberAccess == null)
return document;

var symbol = ModelExtensions.GetSymbolInfo(semanticModel, memberAccess);
if (symbol.Symbol is not IFieldSymbol field)
return document;

var attributes = field.GetAttributes();
var attribute = attributes.First(w => w.AttributeClass.ToClassString() == UdonConstants.UdonSharpFieldChangeCallbackFullName);
var reference = await attribute.ApplicationSyntaxReference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false) as AttributeSyntax;
if (reference == null)
return document;

var targetProperty = reference.ArgumentList.Arguments[0].Expression.ParseValue();
var t = semanticModel.GetTypeInfo(memberAccess.Expression);
var members = t.Type.GetMembers(targetProperty);
var property = members.FirstOrDefault(w => w is IPropertySymbol p && p.Name == targetProperty) as IPropertySymbol;
if (property == null)
return document;

if (property.SetMethod is { DeclaredAccessibility: Accessibility.Public })
{
var oldNode = assignment.FirstAncestorOrSelf<AssignmentExpressionSyntax>();
var newNode = assignment.WithLeft(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, memberAccess.Expression, SyntaxFactory.IdentifierName(targetProperty)));

return await document.ReplaceNodeAsync(oldNode, newNode, cancellationToken).ConfigureAwait(false);
}
else
{
var oldNode = assignment.FirstAncestorOrSelf<AssignmentExpressionSyntax>();

var ma = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, memberAccess.Expression, SyntaxFactory.IdentifierName("SetProgramVariable"));
var arguments = new List<ArgumentSyntax>
{
SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(memberAccess.Name.Identifier.ValueText))),
SyntaxFactory.Argument(assignment.Right)
};
var newNode = SyntaxFactory.InvocationExpression(ma, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments)));

return await document.ReplaceNodeAsync(oldNode, newNode, cancellationToken).ConfigureAwait(false);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<PropertyGroup>
<PackageId>UdonRabbit.Analyzer</PackageId>
<PackageVersion>0.13.0</PackageVersion>
<PackageVersion>0.14.0</PackageVersion>
<Authors>esnya</Authors>
<PackageLicenseUrl>https://github.com/esnya/UdonRabbit.Analyzer/blob/develop/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/esnya/UdonRabbit.Analyzer</PackageProjectUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public async Task RunAnalyzerAsync(CancellationToken cancellationToken)
Diagnostics.Clear();
Diagnostics.AddRange(diagnostics);

VerifyDiagnosticsResults(diagnostics.ToArray(), ExpectedDiagnostics.ToArray());
VerifyDiagnosticsResults(diagnostics.OrderBy(w => w.Location.GetLineSpan().StartLinePosition).ThenBy(w => w.Location.GetLineSpan().Span.Start).ToArray(), ExpectedDiagnostics.ToArray());
}

public async Task RunCodeFixAsync<TCodeFix>(string fixedSource, CancellationToken cancellationToken) where TCodeFix : CodeFixProvider, new()
Expand All @@ -177,7 +177,7 @@ public async Task RunCodeFixAsync<TCodeFix>(string fixedSource, CancellationToke
return;
}

const string filename = "TestBehaviour";
const string filename = "TestBehaviour.cs";

var codeFix = new TCodeFix();
var documentId = DocumentId.CreateNewId(_solution.ProjectIds.First(), filename);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;

using UdonRabbit.Analyzer.Test.Infrastructure;

using Xunit;

namespace UdonRabbit.Analyzer.Test
{
public class InvalidTargetPropertyForFieldChangeCallbackTest : CodeFixVerifier<InvalidTargetPropertyForFieldChangeCallback, InvalidTargetPropertyForFieldChangeCallbackCodeFixProvider>
{
[Fact]
public async Task UdonSharpBehaviourSpecifyDeclaredPropertyInFieldChangeCallbackHasNoDiagnosticsReport()
{
const string source = @"
using UdonSharp;
namespace UdonRabbit
{
public class TestBehaviour : UdonSharpBehaviour
{
[FieldChangeCallback(""Property"")]
public string _bkProperty;
public string Property { get; set; }
}
}
";

DisableVerifierOn("0.20.0", Comparision.LesserThan);
await VerifyAnalyzerAsync(source);
}

[Fact]
public async Task UdonSharpBehaviourSpecifyNoDeclaredPropertyInFieldChangeCallbackHasDiagnosticsReport()
{
var diagnostic = ExpectDiagnostic(InvalidTargetPropertyForFieldChangeCallback.ComponentId)
.WithSeverity(DiagnosticSeverity.Error)
.WithArguments("TestBehaviour");

const string source = @"
using UdonSharp;
namespace UdonRabbit
{
public class TestBehaviour : UdonSharpBehaviour
{
[|[FieldChangeCallback(""Property"")]
public string _bkProperty;|]
}
}
";

const string newSource = @"
using UdonSharp;
namespace UdonRabbit
{
public class TestBehaviour : UdonSharpBehaviour
{
[FieldChangeCallback(""Property"")]
public string _bkProperty;
public string Property
{
get => _bkProperty;
set
{
_bkProperty = value;
}
}
}
}
";

DisableVerifierOn("0.20.0", Comparision.LesserThan);
await VerifyCodeFixAsync(source, new[] { diagnostic }, newSource);
}
}
}
Loading

0 comments on commit 1254f84

Please sign in to comment.