Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using NUnit.Framework;
using RoslynNUnitLight;
using UnityEngineAnalyzer.Material;

namespace UnityEngineAnalyzer.Test.Material
{

[TestFixture]
sealed class DoNotUseStringPropertyNamesAnalyzerTests : AnalyzerTestFixture
{
protected override string LanguageName => LanguageNames.CSharp;
protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseStringPropertyNamesAnalyzer();

[Test]
public void MaterialGetFloatWithStringProperty()
{
const string code = @"
using UnityEngine;

class C : MonoBehaviour
{
Material material;

void Start()
{
[|material.GetFloat(""_Shininess"")|];
}
}";

Document document;
TextSpan span;
TestHelpers.TryGetDocumentAndSpanFromMarkup(code, LanguageName, MetadataReferenceHelper.UsingUnityEngine, out document, out span);

HasDiagnostic(document, span, DiagnosticIDs.DoNotUseStringPropertyNamesInMaterial);
}

[Test]
public void MaterialSetFloatWithStringProperty()
{
const string code = @"
using UnityEngine;

class C : MonoBehaviour
{
Material material;

void Start()
{
[|material.SetFloat(""_Shininess"", 1.2f)|];
}
}";

Document document;
TextSpan span;
TestHelpers.TryGetDocumentAndSpanFromMarkup(code, LanguageName, MetadataReferenceHelper.UsingUnityEngine, out document, out span);

HasDiagnostic(document, span, DiagnosticIDs.DoNotUseStringPropertyNamesInMaterial);
}

[Test]
public void MaterialSetMatrixWithStringProperty()
{
const string code = @"
using UnityEngine;

class C : MonoBehaviour
{
Material material;

void Start()
{
[|material.SetVector(""_WaveAndDistance"", Vector3.one)|];
}
}";

Document document;
TextSpan span;
TestHelpers.TryGetDocumentAndSpanFromMarkup(code, LanguageName, MetadataReferenceHelper.UsingUnityEngine, out document, out span);

HasDiagnostic(document, span, DiagnosticIDs.DoNotUseStringPropertyNamesInMaterial);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
<Compile Include="EmptyMonoBehaviourMethods\EmptyMonoBehaviourMethodsAnalyzerTests.cs" />
<Compile Include="FindMethodsInUpdate\DoNotUseFindMethodsInUpdateAnalyzerTests.cs" />
<Compile Include="ForEachInUpdate\DoNotUseForeachInUpdateAnalyzerTests.cs" />
<Compile Include="Material\DoNotUseStringPropertyNamesTests.cs" />
<Compile Include="MetadataReferenceHelper.cs" />
<Compile Include="OnGUI\DoNotUseOnGUIAnalyzerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
11 changes: 11 additions & 0 deletions UnityEngineAnalyzer/UnityEngineAnalyzer/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using UnityEngineAnalyzer.FindMethodsInUpdate;
using UnityEngineAnalyzer.ForEachInUpdate;
using UnityEngineAnalyzer.IL2CPP;
using UnityEngineAnalyzer.Material;
using UnityEngineAnalyzer.OnGUI;
using UnityEngineAnalyzer.StringMethods;

Expand Down Expand Up @@ -147,5 +148,15 @@ static class DiagnosticDescriptors
isEnabledByDefault: true,
description: new LocalizableResourceString(nameof(DoNotUseStateNameResource.Description), DoNotUseStateNameResource.ResourceManager, typeof(DoNotUseStateNameResource))
);

public static readonly DiagnosticDescriptor DoNotUseStringPropertyNames = new DiagnosticDescriptor(
id: DiagnosticIDs.DoNotUseStringPropertyNamesInMaterial,
title: new LocalizableResourceString(nameof(DoNotUseStringPropertyNamesResource.Title), DoNotUseStringPropertyNamesResource.ResourceManager, typeof(DoNotUseStringPropertyNamesResource)),
messageFormat: new LocalizableResourceString(nameof(DoNotUseStringPropertyNamesResource.MessageFormat), DoNotUseStringPropertyNamesResource.ResourceManager, typeof(DoNotUseStringPropertyNamesResource)),
category: DiagnosticCategories.Performance,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: new LocalizableResourceString(nameof(DoNotUseStringPropertyNamesResource.Description), DoNotUseStringPropertyNamesResource.ResourceManager, typeof(DoNotUseStringPropertyNamesResource))
);
}
}
1 change: 1 addition & 0 deletions UnityEngineAnalyzer/UnityEngineAnalyzer/DiagnosticIDs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class DiagnosticIDs
public const string UnsealedDerivedClass = "UEA0008";
public const string InvokeFunctionMissing = "UEA0009";
public const string DoNotUseStateNameInAnimator = "UEA0010";
public const string DoNotUseStringPropertyNamesInMaterial = "UEA0011";

//NOTES: These should probably be on their own analyzer - as they are not specific to Unity
public const string DoNotUseRemoting = "AOT0001";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;

namespace UnityEngineAnalyzer.Material
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class DoNotUseStringPropertyNamesAnalyzer : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseStringPropertyNames);

private static readonly ImmutableHashSet<string> materialStringPropertyMethods = ImmutableHashSet.Create(
"GetColor",
"GetColorArray",
"GetFloat",
"GetFloatArray",
"GetInt",
"GetMatrix",
"GetMatrixArray",
"GetTexture",
"GetTextureOffset",
"GetTextureScale",
"GetVector",
"GetVectorArray",
"SetBuffer",
"SetColor",
"SetColorArray",
"SetFloat",
"SetFloatArray",
"SetInt",
"SetMatrix",
"SetMatrixArray",
"SetTexture",
"SetTextureOffset",
"SetTextureScale",
"SetVector",
"SetVectorArray");

public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression);
}

private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var invocation = context.Node as InvocationExpressionSyntax;
if (invocation == null)
{
return;
}

var name = invocation.MethodName();

// check if any of the methods are used
if (!materialStringPropertyMethods.Contains(name)) { return; }

var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation);
var methodSymbol = symbolInfo.Symbol as IMethodSymbol;

var containingClass = methodSymbol.ContainingType;

// check if the method is the one from UnityEngine.Animator
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a copy+paste issue on the name

if (containingClass.ContainingNamespace.Name.Equals("UnityEngine") && containingClass.Name.Equals("Material"))
{
if (methodSymbol.Parameters[0].Type.MetadataName == "String")
{
var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseStringPropertyNames, invocation.GetLocation(), containingClass.Name, methodSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
}

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

Loading