├── .gitattributes ├── .gitignore ├── Documents ├── analyzers │ ├── AOT0001.md │ ├── AOT0002.md │ ├── AOT0003.md │ ├── UEA0001.md │ ├── UEA0002.md │ ├── UEA0003.md │ ├── UEA0004.md │ ├── UEA0005.md │ ├── UEA0006.md │ ├── UEA0007.md │ ├── UEA0008.md │ ├── UEA0009.md │ ├── UEA0010.md │ ├── UEA0011.md │ ├── UEA0012.md │ ├── UEA0013.md │ ├── UEA0014.md │ ├── UEA0015.md │ └── UEA0016.md └── configuration.png ├── LICENSE ├── Linty.CLI ├── AnalyzerReport.cs ├── ConfigurationFileGenerator.cs ├── Linty.CLI.csproj ├── Options.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Reporting │ ├── AnalyzerExporter.cs │ ├── ConsoleAnalyzerExporter.cs │ ├── DiagnosticInfo.cs │ ├── IAnalyzerExporter.cs │ ├── JsonAnalyzerExporter.cs │ └── StandardOutputAnalyzerReporter.cs ├── SolutionAnalyzer.cs ├── UnityReport.html ├── UnityVersionResolver.cs └── analyzerConfiguration.json ├── Test Projects └── Linty Test Case 5.6 │ ├── .gitignore │ ├── Assets │ ├── Main.unity │ ├── Scripts │ │ └── UEA0008.cs │ └── UEA0003.cs │ └── ProjectSettings │ ├── AudioManager.asset │ ├── ClusterInputManager.asset │ ├── DynamicsManager.asset │ ├── EditorBuildSettings.asset │ ├── EditorSettings.asset │ ├── GraphicsSettings.asset │ ├── InputManager.asset │ ├── NavMeshAreas.asset │ ├── NetworkManager.asset │ ├── Physics2DSettings.asset │ ├── ProjectSettings.asset │ ├── ProjectVersion.txt │ ├── QualitySettings.asset │ ├── TagManager.asset │ ├── TimeManager.asset │ └── UnityConnectSettings.asset ├── UnityEngineAnalyzer.UnitTest ├── AOT │ ├── DoNotUseReflectionEmitAnalyzerTests.cs │ ├── DoNotUseRemotingAnalyzerTests.cs │ └── TypeGetTypeAnalyzerTests.cs ├── Animator │ └── DoNotUseStateNameAnalyzerTests.cs ├── Audio │ └── AudioSourceAnalyzerTests.cs ├── Camera │ └── CameraMainAnalyzerTests.cs ├── CompareTag │ └── UseCompareTagAnalyzerTests.cs ├── Coroutines │ └── DoNotUseCoroutinesAnalyzerTests.cs ├── EmptyMonoBehaviourMethods │ └── EmptyMonoBehaviourMethodsAnalyzerTests.cs ├── FindMethodsInUpdate │ └── DoNotUseFindMethodsInUpdateAnalyzerTests.cs ├── ForEachInUpdate │ └── DoNotUseForeachInUpdateAnalyzerTests.cs ├── Material │ └── DoNotUseStringPropertyNamesTests.cs ├── MetadataReferenceHelper.cs ├── OnGUI │ └── DoNotUseOnGUIAnalyzerTests.cs ├── Physics │ └── UseNonAllocMethodsTests.cs ├── RoslynNUnitLight │ ├── AnalyzerTestFixture.cs │ ├── BaseTestFixture.cs │ ├── License.txt │ ├── ReflectionExtensions.cs │ ├── TestHelpers.cs │ └── readme.md ├── Shader │ └── DoNotUseStringPropertyNamesTests.cs ├── StringMethods │ ├── DoNotUseStringMethodsAnalyzerTests.cs │ └── InvokeFunctionMissingAnalyzerTests.cs ├── Transform │ └── InstantiateAnalyzerTests.cs ├── UnityEngineAnalyzer.UnitTest.csproj └── Vector │ └── VectorAnalyzerTests.cs ├── UnityEngineAnalyzer.sln ├── UnityEngineAnalyzer ├── Linty.Analyzers │ ├── AOT │ │ ├── DoNotUseReflectionEmitAnalyzer.cs │ │ ├── DoNotUseReflectionEmitResources.Designer.cs │ │ ├── DoNotUseReflectionEmitResources.resx │ │ ├── DoNotUseRemotingAnalyzer.cs │ │ ├── DoNotUseRemotingResources.Designer.cs │ │ ├── DoNotUseRemotingResources.resx │ │ ├── TypeGetTypeAnalyzer.cs │ │ ├── TypeGetTypeResources.Designer.cs │ │ └── TypeGetTypeResources.resx │ ├── Animator │ │ ├── DoNotUseStateNameAnalyzer.cs │ │ ├── DoNotUseStateNameResource.Designer.cs │ │ └── DoNotUseStateNameResource.resx │ ├── Audio │ │ ├── AudioSourceAnalyzer.cs │ │ ├── AudioSourceResource.Designer.cs │ │ └── AudioSourceResource.resx │ ├── Camera │ │ ├── CameraMainAnalyzer.cs │ │ ├── CameraMainResource.Designer.cs │ │ └── CameraMainResource.resx │ ├── CompareTag │ │ ├── UseCompareTagAnalyzer.cs │ │ ├── UseCompareTagResources.Designer.cs │ │ └── UseCompareTagResources.resx │ ├── Coroutines │ │ ├── DoNotUseCoroutinesAnalyzer.cs │ │ ├── DoNotUseCoroutinesResources.Designer.cs │ │ └── DoNotUseCoroutinesResources.resx │ ├── Diagnostic.nuspec │ ├── DiagnosticCategories.cs │ ├── DiagnosticDescriptors.cs │ ├── DiagnosticIDs.cs │ ├── EmptyMonoBehaviourMethods │ │ ├── EmptyMonoBehaviourMethodsAnalyzer.cs │ │ ├── EmptyMonoBehaviourMethodsResources.Designer.cs │ │ └── EmptyMonoBehaviourMethodsResources.resx │ ├── FindMethodsInUpdate │ │ ├── DoNotUseFindMethodsInUpdateAnalyzer.cs │ │ ├── DoNotUseFindMethodsInUpdateResources.Designer.cs │ │ └── DoNotUseFindMethodsInUpdateResources.resx │ ├── ForEachInUpdate │ │ ├── DoNotUseForEachInUpdate.cs │ │ ├── DoNotUseForEachInUpdateResources.Designer.cs │ │ └── DoNotUseForEachInUpdateResources.resx │ ├── IL2CPP │ │ ├── UnsealedDerivedClassAnalyzer.cs │ │ ├── UnsealedDerivedClassResources.Designer.cs │ │ └── UnsealedDerivedClassResources.resx │ ├── Linty.Analyzers.csproj │ ├── LintyAnalyzer.cs │ ├── Material │ │ ├── DoNotUseStringPropertyNamesAnalyzer.cs │ │ ├── DoNotUseStringPropertyNamesResource.Designer.cs │ │ └── DoNotUseStringPropertyNamesResource.resx │ ├── MonoBehaviourInfo.cs │ ├── OnGUI │ │ ├── DoNotUseOnGUIAnalyzer.cs │ │ ├── DoNotUseOnGUIResources.Designer.cs │ │ └── DoNotUseOnGUIResources.resx │ ├── Physics │ │ ├── UseNonAllocMethodsAnalyzer.cs │ │ ├── UseNonAllocMethodsResources.Designer.cs │ │ └── UseNonAllocMethodsResources.resx │ ├── ReadMe.txt │ ├── RolsynExtensions.cs │ ├── Shader │ │ └── DoNotUseStringPropertyNamesShaderAnalyzer.cs │ ├── StringMethods │ │ ├── DoNotUseStringMethodsAnalyzer.cs │ │ ├── DoNotUseStringMethodsResources.Designer.cs │ │ ├── DoNotUseStringMethodsResources.resx │ │ ├── InvokeFunctionMissingAnalyzer.cs │ │ ├── InvokeFunctionMissingResources.Designer.cs │ │ └── InvokeFunctionMissingResources.resx │ ├── Transform │ │ ├── InstantiateAnalyzer.cs │ │ ├── InstantiateResource.Designer.cs │ │ └── InstantiateResource.resx │ ├── UnityVersions.cs │ ├── Vector │ │ ├── VectorAnalyzer.cs │ │ ├── VectorAnalyzerResource.Designer.cs │ │ └── VectorAnalyzerResource.resx │ └── tools │ │ ├── install.ps1 │ │ └── uninstall.ps1 └── UnityEngineAnalyzer.Vsix │ ├── LICENSE.txt │ ├── UnityEngineAnalyzer.Vsix.csproj │ └── source.extension.vsixmanifest └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | * text=auto 3 | 4 | *.cs diff=csharp 5 | 6 | # Custom for Visual Studio 7 | *.sln text eol=crlf 8 | *.csproj text eol=crlf 9 | *.vbproj text eol=crlf 10 | *.fsproj text eol=crlf 11 | *.dbproj text eol=crlf 12 | 13 | *.vcxproj text eol=crlf 14 | *.vcxitems text eol=crlf 15 | *.props text eol=crlf 16 | *.filters text eol=crlf 17 | -------------------------------------------------------------------------------- /Documents/analyzers/AOT0001.md: -------------------------------------------------------------------------------- 1 | # AOT0001: DoNotUseRemoting 2 | 3 | | Property | Value | 4 | | -------- | ----------- | 5 | | Id | AOT0001 | 6 | | Category | AOT | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | // AOT0001: System.Runtime.Remoting is not suppported 15 | using System.Runtime.Remoting; 16 | ``` 17 | 18 | ### Code with Fix 19 | 20 | ```csharp 21 | 22 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/AOT0002.md: -------------------------------------------------------------------------------- 1 | # AOT0002: DoNotUseReflectionEmit 2 | 3 | | Property | Value | 4 | | -------- | ----------- | 5 | | Id | AOT0002 | 6 | | Category | AOT | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | // AOT0002: System.Reflection.Emit is not supported 15 | using System.Reflection.Emit; 16 | ``` 17 | 18 | ### Code with Fix 19 | 20 | ```csharp 21 | 22 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/AOT0003.md: -------------------------------------------------------------------------------- 1 | # AOT0003: TypeGetType 2 | 3 | | Property | Value | 4 | | -------- | ----------- | 5 | | Id | AOT0003 | 6 | | Category | AOT | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | // AOT0003: Reflection only works for looking up existing types 15 | Type.GetType(""); 16 | ``` 17 | 18 | ### Code with Fix 19 | 20 | ```csharp 21 | 22 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0001.md: -------------------------------------------------------------------------------- 1 | # UEA0001: DoNotUseOnGUI 2 | 3 | | Property | Value | 4 | | -------- | ----------- | 5 | | Id | UEA0001 | 6 | | Category | GC | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | // UEA0001: Using OnGUI causes allocations and GC spikes 15 | void OnGUI() 16 | { 17 | 18 | } 19 | ``` 20 | 21 | ### Code with Fix 22 | 23 | ```csharp 24 | 25 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0002.md: -------------------------------------------------------------------------------- 1 | # UEA0002: DoNotUseStringMethods 2 | 3 | | Property | Value | 4 | | -------- | ----------- | 5 | | Id | UEA0002 | 6 | | Category | GC | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | public class Example : MonoBehaviour 17 | { 18 | void Start() 19 | { 20 | // UEA0002: Using string methods can lead to code that is hard to maintain 21 | gameObject.SendMessage("ApplyDamage", 5.0); 22 | } 23 | } 24 | 25 | public class Example2 : MonoBehaviour 26 | { 27 | public void ApplyDamage(float damage) 28 | { 29 | print(damage); 30 | } 31 | } 32 | ``` 33 | 34 | ### Code with Fix 35 | 36 | Use of SendMessage, SendMessageUpwards, BroadcastMessage, Invoke or InvokeRepeating leads to code that is hard to maintain. Consider using UnityEvent, C# event, delegates or a direct method call. 37 | 38 | ```csharp 39 | using UnityEngine; 40 | 41 | public class Example : MonoBehaviour 42 | { 43 | void Start() 44 | { 45 | var obj = GetComponent(); 46 | obj.ApplyDamage(5.0); 47 | } 48 | } 49 | 50 | public class Example2 : MonoBehaviour 51 | { 52 | public void ApplyDamage(float damage) 53 | { 54 | print(damage); 55 | } 56 | } 57 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0003.md: -------------------------------------------------------------------------------- 1 | # UEA0003: EmptyMonoBehaviourMethod 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0003 | 6 | | Category | Miscellaneous | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | public class Example : MonoBehaviour 15 | { 16 | // UEA0003: Empty MonoBehaviour methods are executed and incur a small overhead 17 | void FixedUpdate() 18 | { 19 | 20 | } 21 | } 22 | ``` 23 | 24 | ### Code with Fix 25 | 26 | Remove empty monobehaviour methods 27 | 28 | ```csharp 29 | 30 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0004.md: -------------------------------------------------------------------------------- 1 | # UEA0004: UseCompareTag 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0004 | 6 | | Category | GC | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | public class Example : MonoBehaviour 17 | { 18 | void OnTriggerEnter(Collider other) 19 | { 20 | // UEA0004: Using CompareTag for tag comparison does not cause allocations 21 | if (other.tag == "Player") 22 | { 23 | 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | ### Code with Fix 30 | 31 | 32 | ```csharp 33 | public class Example : MonoBehaviour 34 | { 35 | void OnTriggerEnter(Collider other) 36 | { 37 | if (other.gameObject.CompareTag("Player")) 38 | { 39 | 40 | } 41 | } 42 | } 43 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0005.md: -------------------------------------------------------------------------------- 1 | # UEA0005: DoNotUseFindMethodsInUpdate 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0005 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | public class Example : MonoBehaviour 17 | { 18 | void Update() 19 | { 20 | // UEA0005: Warning to cache the result of find in Start or Awake 21 | GameObject.Find(""); 22 | } 23 | } 24 | ``` 25 | 26 | ### Code with Fix 27 | 28 | 29 | ```csharp 30 | using UnityEngine; 31 | 32 | public class Example : MonoBehaviour 33 | { 34 | GameObject cachedObj; 35 | 36 | void Start() 37 | { 38 | cachedObj = GameObject.Find(""); 39 | } 40 | } 41 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0006.md: -------------------------------------------------------------------------------- 1 | # UEA0006: DoNotUseCoroutines 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0006 | 6 | | Category | GC | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | public class Example : MonoBehaviour 17 | { 18 | void Update() 19 | { 20 | // UEA0006: Use of coroutines cause some allocations 21 | StartCoroutine(""); 22 | } 23 | } 24 | ``` 25 | 26 | ### Code with Fix 27 | 28 | 29 | ```csharp 30 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0007.md: -------------------------------------------------------------------------------- 1 | # UEA0007: DoNotUseForEachInUpdate 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0007 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | | Versions affected | 1.0 - 5.5 | 9 | 10 | ## Example 11 | 12 | ### Code with Diagnostic 13 | 14 | ```csharp 15 | using UnityEngine; 16 | 17 | class ExampleC : MonoBehaviour 18 | { 19 | void Update() 20 | { 21 | var colors = new[] {""red"", ""white"", ""blue""}; 22 | var result = string.Empty; 23 | foreach (var color in colors) 24 | { 25 | result += color; 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | ### Code with Fix 32 | 33 | 34 | ```csharp 35 | using UnityEngine; 36 | 37 | class ExampleC : MonoBehaviour 38 | { 39 | void Update() 40 | { 41 | var colors = new[] {""red"", ""white"", ""blue""}; 42 | var result = string.Empty; 43 | for (int i = 0; i < colors.length; i++) 44 | { 45 | result += colors[i]; 46 | } 47 | } 48 | } 49 | ``` 50 | 51 | ### See also 52 | 53 | https://forum.unity.com/threads/upgraded-c-compiler-on-5-3-5p8.417363/#n21 -------------------------------------------------------------------------------- /Documents/analyzers/UEA0008.md: -------------------------------------------------------------------------------- 1 | # UEA0008: UnsealedDerivedClass 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0008 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | public abstract class Animal { 17 | public abstract string Speak(); 18 | } 19 | 20 | public class Cow : Animal { 21 | public override string Speak() { 22 | return "Moo"; 23 | } 24 | } 25 | ``` 26 | 27 | ### Code with Fix 28 | 29 | 30 | ```csharp 31 | using UnityEngine; 32 | 33 | public abstract class Animal { 34 | public abstract string Speak(); 35 | } 36 | 37 | public sealed class Cow : Animal { 38 | public override string Speak() { 39 | return "Moo"; 40 | } 41 | } 42 | ``` 43 | 44 | ## See also 45 | https://blogs.unity3d.com/2016/07/26/il2cpp-optimizations-devirtualization/ -------------------------------------------------------------------------------- /Documents/analyzers/UEA0009.md: -------------------------------------------------------------------------------- 1 | # UEA0009: InvokeFunctionMissing 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0009 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | class CC : MonoBehaviour { } 17 | 18 | class C : MonoBehaviour 19 | { 20 | private CC cc; 21 | void Start() { cc.InvokeRepeating("DoSomething", 0f, 0f); } 22 | } 23 | ``` 24 | 25 | ### Code with Fix 26 | 27 | 28 | ```csharp 29 | using UnityEngine; 30 | 31 | class CC : MonoBehaviour 32 | { 33 | public void DoSomething() { } 34 | } 35 | 36 | class C : MonoBehaviour 37 | { 38 | private CC cc; 39 | void Start() { cc.InvokeRepeating("DoSomething", 0f, 0f); } 40 | } 41 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0010.md: -------------------------------------------------------------------------------- 1 | # UEA0010: DoNotUseStateNameInAnimator 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0010 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | class Example : MonoBehaviour 17 | { 18 | Animator animator; 19 | 20 | void Update() 21 | { 22 | animator.SetInteger("Walk", 1); 23 | } 24 | } 25 | ``` 26 | 27 | ### Code with Fix 28 | 29 | 30 | ```csharp 31 | using UnityEngine; 32 | 33 | class Example : MonoBehaviour 34 | { 35 | Animator animator; 36 | int walkHash; 37 | 38 | void Start() 39 | { 40 | var walkHash = Animator.StringToHash("Walk"); 41 | } 42 | 43 | void Update() 44 | { 45 | animator.SetInteger(walkHash, 1); 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0011.md: -------------------------------------------------------------------------------- 1 | # UEA0011: DoNotUseStringPropertyNames 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0011 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | This is for both Material and Shader class methods. 12 | Both can be fixed by using Shader.PropertyToID() method. 13 | 14 | ### Code with Diagnostic 15 | 16 | ```csharp 17 | class A : MonoBehaviour 18 | { 19 | Shader shader; 20 | 21 | void Update() 22 | { 23 | shader.GetGlobalFloat("_Speed", 1f); 24 | } 25 | } 26 | ``` 27 | 28 | ```csharp 29 | class C : MonoBehaviour 30 | { 31 | Material material; 32 | 33 | void Update() 34 | { 35 | material.SetVector("_WaveAndDistance", Vector3.one); 36 | } 37 | } 38 | ``` 39 | 40 | ### Code with Fix 41 | 42 | ```csharp 43 | using UnityEngine; 44 | 45 | class A : MonoBehaviour 46 | { 47 | Shader shader; 48 | int speedHash; 49 | 50 | void Start() 51 | { 52 | speedHash = Shader.PropertyToID("_Speed"); 53 | } 54 | 55 | void Update() 56 | { 57 | shader.GetGlobalFloat(speedHash, 1f); 58 | } 59 | } 60 | ``` 61 | 62 | 63 | ```csharp 64 | using UnityEngine; 65 | 66 | class C : MonoBehaviour 67 | { 68 | Material material; 69 | int waveAndDistanceHash; 70 | 71 | void Start() 72 | { 73 | waveAndDistanceHash = Shader.PropertyToID("_WaveAndDistance"); 74 | } 75 | 76 | void Update() 77 | { 78 | material.SetVector(waveAndDistanceHash, Vector3.one); 79 | } 80 | } 81 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0012.md: -------------------------------------------------------------------------------- 1 | # UEA0012: CameraMainIsSlow 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0012 | 6 | | Category | GC | 7 | | Severity | Warning | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | class Example : MonoBehaviour 17 | { 18 | void Update() 19 | { 20 | var orthographicSize = Camera.main.orthographicSize; 21 | } 22 | } 23 | ``` 24 | 25 | ### Code with Fix 26 | 27 | 28 | ```csharp 29 | using UnityEngine; 30 | 31 | class Example : MonoBehaviour 32 | { 33 | Camera cachedCamera; 34 | 35 | void Start() 36 | { 37 | cachedCamera = Camera.main; 38 | } 39 | 40 | void Update() 41 | { 42 | var orthographicSize = cachedCamera.orthographicSize; 43 | } 44 | } 45 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0013.md: -------------------------------------------------------------------------------- 1 | # UEA0013: UseNonAllocMethods 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0013 | 6 | | Category | GC | 7 | | Severity | Warning | 8 | | Version | 5.3 -> | 9 | 10 | ## Example 11 | 12 | ### Code with Diagnostic 13 | 14 | ```csharp 15 | using UnityEngine; 16 | 17 | class Example : MonoBehaviour 18 | { 19 | void Start() 20 | { 21 | Physics2D.CircleCastAll(Vector2.zero, 5, Vector2.one); 22 | } 23 | } 24 | ``` 25 | 26 | ### Code with Fix 27 | 28 | 29 | ```csharp 30 | using UnityEngine; 31 | 32 | class Example : MonoBehaviour 33 | { 34 | void Start() 35 | { 36 | var results = new RaycastHit2D[X]; 37 | Physics2D.CircleCastNonAlloc(Vector2.zero, 5, Vector2.one, results); 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0014.md: -------------------------------------------------------------------------------- 1 | # UEA0014: AudioSourceMuteUsesCPU 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0014 | 6 | | Category | Performance | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | class Example : MonoBehaviour 17 | { 18 | AudioSource audioSource; 19 | 20 | void Update() 21 | { 22 | audioSource.mute = true; 23 | } 24 | } 25 | ``` 26 | 27 | ### Code with Fix 28 | 29 | 30 | ```csharp 31 | using UnityEngine; 32 | 33 | class Example : MonoBehaviour 34 | { 35 | AudioSource audioSource; 36 | 37 | void Update() 38 | { 39 | audioSource.enabled = false; 40 | } 41 | } 42 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0015.md: -------------------------------------------------------------------------------- 1 | # UEA0015: InstantiateTakeParent 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0015 | 6 | | Category | Performance | 7 | | Severity | Warning | 8 | | Version | 5.4 -> | 9 | 10 | ## Example 11 | 12 | ### Code with Diagnostic 13 | 14 | ```csharp 15 | using UnityEngine; 16 | 17 | class ExampleC : MonoBehaviour 18 | { 19 | GameObject prefabObject; 20 | GameObject newParent; 21 | 22 | void Update() 23 | { 24 | var newGameobject = Instantiate(prefabObject, Vector3.zero, Quaternion.identity); 25 | newGameobject.transform.SetParent(newParent.transform, false); 26 | } 27 | } 28 | ``` 29 | 30 | ### Code with Fix 31 | 32 | 33 | ```csharp 34 | using UnityEngine; 35 | 36 | class ExampleC : MonoBehaviour 37 | { 38 | GameObject prefabObject; 39 | GameObject newParent; 40 | 41 | void Update() 42 | { 43 | var newGameobject = Instantiate(prefabObject, Vector3.zero, Quaternion.identity, newParent.transform); 44 | } 45 | } 46 | ``` -------------------------------------------------------------------------------- /Documents/analyzers/UEA0016.md: -------------------------------------------------------------------------------- 1 | # UEA0016: VectorMagnitudeIsSlow 2 | 3 | | Property | Value | 4 | | -------- | ------------- | 5 | | Id | UEA0016 | 6 | | Category | Performance | 7 | | Severity | Info | 8 | 9 | ## Example 10 | 11 | ### Code with Diagnostic 12 | 13 | ```csharp 14 | using UnityEngine; 15 | 16 | class C : MonoBehaviour 17 | { 18 | public Transform other; 19 | private float farDistance = 5.0f; 20 | 21 | void Update() 22 | { 23 | if ((other.position - transform.position).magnitude > farDistance) 24 | { 25 | //OPTIMIZE THIS CALL BY USING sqrMagnitude 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | ### Code with Fix 32 | 33 | 34 | ```csharp 35 | using UnityEngine; 36 | 37 | class C : MonoBehaviour 38 | { 39 | public Transform other; 40 | private float farDistance = 5.0f; 41 | 42 | void Update() 43 | { 44 | if ((other.position - transform.position).sqrMagnitude > farDistance * farDistance) 45 | { 46 | 47 | } 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /Documents/configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vad710/UnityEngineAnalyzer/562ff51626b6808cb4ee5410057f2c078c38609b/Documents/configuration.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Meng Hui Koh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Linty.CLI/AnalyzerReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.CodeAnalysis; 4 | using Linty.CLI.Reporting; 5 | using Linty.Analyzers; 6 | 7 | namespace Linty.CLI 8 | { 9 | public class AnalyzerReport 10 | { 11 | //TODO: Add support for Solutions with multiple Projects 12 | 13 | private readonly List _exporters = new List(); 14 | 15 | public void AddExporter(IAnalyzerExporter exporter) 16 | { 17 | _exporters.Add(exporter); 18 | } 19 | 20 | public int GetExporterCount() 21 | { 22 | return _exporters.Count; 23 | } 24 | 25 | public void AppendDiagnostics(IEnumerable diagnosticResults) 26 | { 27 | if (_exporters.Count == 0) 28 | { 29 | return; 30 | } 31 | 32 | foreach (var diagnostic in diagnosticResults) 33 | { 34 | var location = diagnostic.Location; 35 | var lineNumber = 0; 36 | var characterPosition = 0; 37 | var fileName = string.Empty; 38 | 39 | if (location != Location.None) 40 | { 41 | var locationSpan = location.SourceSpan; 42 | var lineSpan = location.SourceTree.GetLineSpan(locationSpan); 43 | lineNumber = lineSpan.StartLinePosition.Line; 44 | characterPosition = lineSpan.StartLinePosition.Character; 45 | fileName = location.SourceTree?.FilePath; 46 | } 47 | 48 | var diagnosticInfo = new DiagnosticInfo 49 | { 50 | Id = diagnostic.Id, 51 | Message = diagnostic.GetMessage(), 52 | FileName = fileName, 53 | LineNumber = lineNumber, 54 | CharacterPosition = characterPosition, 55 | Severity = (DiagnosticInfo.DiagnosticInfoSeverity)diagnostic.Severity, 56 | VersionSpan = DiagnosticDescriptors.GetVersion(diagnostic.Descriptor) 57 | }; 58 | 59 | foreach (var exporter in _exporters) 60 | { 61 | exporter.AppendDiagnostic(diagnosticInfo); 62 | } 63 | } 64 | } 65 | 66 | public void FinalizeReport(TimeSpan duration) 67 | { 68 | foreach (var exporter in _exporters) 69 | { 70 | exporter.FinalizeExporter(duration); 71 | } 72 | } 73 | 74 | public void InitializeReport(Options options) 75 | { 76 | foreach (var exporter in _exporters) 77 | { 78 | exporter.InitializeExporter(options); 79 | } 80 | } 81 | 82 | public void NotifyException(Exception exception) 83 | { 84 | foreach (var exporter in _exporters) 85 | { 86 | exporter.NotifyException(exception); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Linty.CLI/ConfigurationFileGenerator.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.Diagnostics; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using System.IO; 5 | using Linty.Analyzers.ForEachInUpdate; 6 | using Microsoft.Build.Utilities; 7 | 8 | namespace Linty.CLI 9 | { 10 | /// 11 | /// TODO:: This Task should be run after build so the analyzerConfiguration.json gets generated with latets analyzers automatically 12 | /// 13 | public class ConfigurationFileGenerator : Task 14 | { 15 | private const string configurationFileName = "analyzerConfiguration.json"; 16 | 17 | public override bool Execute() 18 | { 19 | var assembly = typeof(DoNotUseForEachInUpdate).Assembly; 20 | var allTypes = assembly.DefinedTypes; 21 | 22 | var rootJson = new JObject(); 23 | 24 | foreach (var typeInfo in allTypes) 25 | { 26 | if (typeInfo.IsSubclassOf(typeof(DiagnosticAnalyzer)) && !typeInfo.IsAbstract) 27 | { 28 | rootJson.Add(new JProperty(typeInfo.Name, true)); //TODO SupportedDiagnostics.IsEnabledByDefault; 29 | } 30 | } 31 | 32 | var projectDir = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName; 33 | var filePath = Path.Combine(projectDir, configurationFileName); 34 | 35 | using (StreamWriter sw = File.CreateText(filePath)) 36 | { 37 | using (JsonTextWriter writer = new JsonTextWriter(sw)) 38 | { 39 | writer.Formatting = Formatting.Indented; 40 | rootJson.WriteTo(writer); 41 | } 42 | } 43 | 44 | return true; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Linty.CLI/Linty.CLI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Linty.CLI/Options.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using System.Collections.Generic; 3 | using UnityEngineAnalyzer; 4 | using static Linty.CLI.Reporting.DiagnosticInfo; 5 | 6 | namespace Linty.CLI 7 | { 8 | public class Options 9 | { 10 | [Value(0, Required = true)] 11 | public string ProjectFile { get; set; } 12 | 13 | [Option('e', "exporter", HelpText = "Exporters to be used.")] 14 | public IEnumerable Exporters { get; set; } 15 | 16 | [Option('c', "configuration", HelpText = "Custom json configuration to be used.")] 17 | public string ConfigurationFile { get; set; } 18 | 19 | [Option('s', "severity", Default = DiagnosticInfoSeverity.Warning, HelpText = "Minimal severity to be reported.")] 20 | public DiagnosticInfoSeverity MinimalSeverity { get; set; } 21 | 22 | [Option('v', "version", Default = UnityVersion.NONE, HelpText = "Check against spesific Unity version.")] 23 | public UnityVersion Version { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /Linty.CLI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using CommandLine; 6 | using Linty.CLI.Reporting; 7 | 8 | namespace Linty.CLI 9 | { 10 | class Program 11 | { 12 | private static readonly Dictionary AvailableExporters = new Dictionary(); 13 | 14 | static Program() 15 | { 16 | AvailableExporters.Add(nameof(JsonAnalyzerExporter), typeof(JsonAnalyzerExporter)); 17 | AvailableExporters.Add(nameof(StandardOutputAnalyzerReporter), typeof(StandardOutputAnalyzerReporter)); 18 | AvailableExporters.Add(nameof(ConsoleAnalyzerExporter), typeof(ConsoleAnalyzerExporter)); 19 | } 20 | 21 | public static void Main(string[] args) 22 | { 23 | try 24 | { 25 | Parser.Default.ParseArguments(args).WithParsed(options => 26 | { 27 | var unityVersionResolver = new UnityVersionResolver(); 28 | options.Version = unityVersionResolver.ResolveVersion(options); 29 | 30 | var startTime = DateTime.Now; 31 | 32 | var fileName = options.ProjectFile; 33 | var projectFileInfo = new FileInfo(fileName); 34 | 35 | //NOTE: This could be configurable via the CLI at some point 36 | var report = new AnalyzerReport(); 37 | 38 | if (options.Exporters != null) 39 | { 40 | foreach (var exporter in options.Exporters) 41 | { 42 | if (AvailableExporters.ContainsKey(exporter)) 43 | { 44 | var exporterInstance = Activator.CreateInstance(AvailableExporters[exporter]); 45 | report.AddExporter(exporterInstance as IAnalyzerExporter); 46 | } 47 | } 48 | } 49 | 50 | if (report.GetExporterCount() == 0) 51 | { 52 | //It's generally a good idea to make sure that the Console Exporter is last since it is interactive 53 | report.AddExporter(new JsonAnalyzerExporter(options)); 54 | report.AddExporter(new ConsoleAnalyzerExporter(options)); 55 | } 56 | 57 | report.InitializeReport(options); 58 | 59 | var tasks = new List(); 60 | if (projectFileInfo.Exists) 61 | { 62 | FileInfo configFileInfo = null; 63 | 64 | if (options.ConfigurationFile != null) 65 | { 66 | configFileInfo = new FileInfo(options.ConfigurationFile); 67 | } 68 | 69 | var solutionAnalyzer = new SolutionAnalyzer(); 70 | var analyzeTask = solutionAnalyzer.LoadAndAnalyzeProjectAsync(projectFileInfo, configFileInfo, report); 71 | tasks.Add(analyzeTask); 72 | } 73 | 74 | Task.WaitAll(tasks.ToArray()); 75 | 76 | var endTime = DateTime.Now; 77 | var duration = endTime - startTime; 78 | 79 | report.FinalizeReport(duration); 80 | }); 81 | 82 | } 83 | catch (Exception generalException) 84 | { 85 | 86 | Console.WriteLine("There was an exception running the analysis"); 87 | Console.WriteLine(generalException.ToString()); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Linty.CLI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Linty.CLI": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /Linty.CLI/Reporting/AnalyzerExporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Linty.CLI.Reporting 4 | { 5 | public abstract class AnalyzerExporter : IAnalyzerExporter 6 | { 7 | private readonly Options options; 8 | 9 | public AnalyzerExporter(Options options) 10 | { 11 | this.options = options; 12 | } 13 | 14 | public bool IsAnalyzerRelevant(DiagnosticInfo diagnosticInfo) 15 | { 16 | if (options.MinimalSeverity > diagnosticInfo.Severity) 17 | { 18 | return false; 19 | } 20 | 21 | if (options.Version < diagnosticInfo.VersionSpan.First || options.Version > diagnosticInfo.VersionSpan.Last) 22 | { 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | public abstract void AppendDiagnostic(DiagnosticInfo diagnosticInfo); 30 | public abstract void FinalizeExporter(TimeSpan duration); 31 | public abstract void InitializeExporter(Options options); 32 | public abstract void NotifyException(Exception exception); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Linty.CLI/Reporting/ConsoleAnalyzerExporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngineAnalyzer; 3 | 4 | namespace Linty.CLI.Reporting 5 | { 6 | public class ConsoleAnalyzerExporter : StandardOutputAnalyzerReporter 7 | { 8 | public ConsoleAnalyzerExporter(Options options) : base(options) 9 | { 10 | } 11 | 12 | public override void FinalizeExporter(TimeSpan duration) 13 | { 14 | Console.ForegroundColor = ConsoleColor.Green; 15 | Console.WriteLine("Console Export Finished ({0})", duration); 16 | Console.ResetColor(); 17 | 18 | Console.WriteLine("Press any key to exit"); 19 | Console.ReadKey(); 20 | } 21 | 22 | public override void InitializeExporter(Options options) 23 | { 24 | Console.ForegroundColor = ConsoleColor.Green; 25 | Console.WriteLine("Unity Syntax Analyzer"); 26 | Console.WriteLine(); 27 | Console.WriteLine("Analyzing: {0}", options.ProjectFile); 28 | Console.WriteLine("With Unity version: " + Enum.GetName((typeof(UnityVersion)), options.Version)); 29 | Console.WriteLine(); 30 | Console.ResetColor(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Linty.CLI/Reporting/DiagnosticInfo.cs: -------------------------------------------------------------------------------- 1 | using UnityEngineAnalyzer; 2 | 3 | namespace Linty.CLI.Reporting 4 | { 5 | public class DiagnosticInfo 6 | { 7 | //TODO: Rename this to something like AnalysisResult 8 | 9 | public string Id { get; set; } 10 | public string Message { get; set; } 11 | public string FileName { get; set; } 12 | public int LineNumber { get; set; } 13 | public int CharacterPosition { get; set; } 14 | public DiagnosticInfoSeverity Severity { get; set; } 15 | public UnityVersionSpan VersionSpan { get; set; } 16 | 17 | public enum DiagnosticInfoSeverity 18 | { 19 | Hidden = 0, 20 | Info = 1, 21 | Warning = 2, 22 | Error = 3 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Linty.CLI/Reporting/IAnalyzerExporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Linty.CLI.Reporting 4 | { 5 | public interface IAnalyzerExporter 6 | { 7 | void AppendDiagnostic(DiagnosticInfo diagnosticInfo); 8 | void FinalizeExporter(TimeSpan duration); 9 | void InitializeExporter(Options options); 10 | void NotifyException(Exception exception); 11 | } 12 | } -------------------------------------------------------------------------------- /Linty.CLI/Reporting/JsonAnalyzerExporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Newtonsoft.Json; 5 | 6 | namespace Linty.CLI.Reporting 7 | { 8 | public class JsonAnalyzerExporter : AnalyzerExporter 9 | { 10 | private const string JsonReportFileName = "report.json"; 11 | private const string HtmlReportFileName = "UnityReport.html"; 12 | 13 | private JsonTextWriter _jsonWriter; 14 | private readonly JsonSerializer _jsonSerializer = new JsonSerializer(); 15 | private readonly List _exceptions = new List(); 16 | private string _destinationReportFile; 17 | 18 | public JsonAnalyzerExporter(Options options) : base(options) 19 | { 20 | } 21 | 22 | public override void AppendDiagnostic(DiagnosticInfo diagnosticInfo) 23 | { 24 | if (IsAnalyzerRelevant(diagnosticInfo)) 25 | { 26 | _jsonSerializer.Serialize(_jsonWriter, diagnosticInfo); 27 | } 28 | } 29 | 30 | public override void FinalizeExporter(TimeSpan duration) 31 | { 32 | _jsonWriter.WriteEndArray(); 33 | 34 | _jsonWriter.WritePropertyName("Exceptions"); 35 | _jsonWriter.WriteStartArray(); 36 | 37 | foreach (var exception in _exceptions) 38 | { 39 | _jsonSerializer.Serialize(_jsonWriter, exception); 40 | } 41 | _jsonWriter.WriteEndArray(); 42 | 43 | _jsonWriter.WriteEndObject(); 44 | _jsonWriter.Close(); 45 | 46 | //Console.WriteLine(Process.GetCurrentProcess().StartInfo.WorkingDirectory); 47 | File.Copy(HtmlReportFileName, _destinationReportFile, true); 48 | 49 | //NOTE: This code might be temporary as it assumes that the CLI is being executed interactively 50 | //Process.Start(_destinationReportFile); 51 | } 52 | 53 | public override void InitializeExporter(Options options) 54 | { 55 | var projectFile = new FileInfo(options.ProjectFile); 56 | if (!projectFile.Exists) 57 | { 58 | throw new ArgumentException("Project file does not exist"); 59 | } 60 | 61 | _destinationReportFile = Path.Combine(projectFile.DirectoryName, HtmlReportFileName); 62 | var jsonFilePath = Path.Combine(projectFile.DirectoryName, JsonReportFileName); 63 | var jsonFile = new FileInfo(jsonFilePath); 64 | 65 | if (jsonFile.Exists) 66 | { 67 | jsonFile.Delete(); 68 | } 69 | 70 | TextWriter textWriter = new StreamWriter(jsonFile.FullName); 71 | _jsonWriter = new JsonTextWriter(textWriter); 72 | 73 | _jsonWriter.WriteStartObject(); 74 | _jsonWriter.WritePropertyName("File"); 75 | _jsonWriter.WriteValue(projectFile.FullName); 76 | _jsonWriter.WritePropertyName("Date"); 77 | _jsonWriter.WriteValue(DateTime.Now); 78 | _jsonWriter.WritePropertyName("Diagnostics"); 79 | _jsonWriter.WriteStartArray(); 80 | 81 | 82 | _jsonSerializer.Formatting = Formatting.Indented; 83 | } 84 | 85 | public override void NotifyException(Exception exception) 86 | { 87 | _exceptions.Add(exception); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Linty.CLI/Reporting/StandardOutputAnalyzerReporter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static Linty.CLI.Reporting.DiagnosticInfo; 3 | 4 | namespace Linty.CLI.Reporting 5 | { 6 | public class StandardOutputAnalyzerReporter : AnalyzerExporter 7 | { 8 | protected const string ConsoleSeparator = "\t"; 9 | protected const string FailurePrefix = "# "; 10 | 11 | public StandardOutputAnalyzerReporter(Options options) : base(options) 12 | { 13 | } 14 | 15 | public override void AppendDiagnostic(DiagnosticInfo diagnosticInfo) 16 | { 17 | if (IsAnalyzerRelevant(diagnosticInfo) == false) 18 | { 19 | return; 20 | } 21 | 22 | Console.Write(diagnosticInfo.Id); 23 | Console.Write(ConsoleSeparator); 24 | 25 | Console.ForegroundColor = ConsoleColorFromSeverity(diagnosticInfo.Severity); 26 | Console.Write(diagnosticInfo.Severity.ToString()); 27 | Console.Write(ConsoleSeparator); 28 | 29 | Console.ForegroundColor = ConsoleColor.Cyan; 30 | Console.Write(diagnosticInfo.Message); 31 | Console.ResetColor(); 32 | Console.WriteLine(@"{0}{1}{0}{2},{3}", ConsoleSeparator,diagnosticInfo.FileName, diagnosticInfo.LineNumber, diagnosticInfo.CharacterPosition); 33 | } 34 | 35 | private ConsoleColor ConsoleColorFromSeverity(DiagnosticInfoSeverity severity) 36 | { 37 | switch (severity) 38 | { 39 | case DiagnosticInfoSeverity.Hidden: 40 | return ConsoleColor.Gray; 41 | case DiagnosticInfoSeverity.Info: 42 | return ConsoleColor.Green; 43 | case DiagnosticInfoSeverity.Warning: 44 | return ConsoleColor.Yellow; 45 | case DiagnosticInfoSeverity.Error: 46 | return ConsoleColor.Red; 47 | default: 48 | return ConsoleColor.White; 49 | } 50 | } 51 | 52 | public override void NotifyException(Exception exception) 53 | { 54 | Console.ForegroundColor = ConsoleColor.Red; 55 | 56 | var delimeters = new[] {"\r", "\n", Environment.NewLine }; 57 | var exceptionLines = exception.ToString().Split(delimeters, StringSplitOptions.RemoveEmptyEntries); 58 | 59 | foreach (var exceptionLine in exceptionLines) 60 | { 61 | Console.WriteLine(FailurePrefix + exceptionLine); 62 | } 63 | 64 | Console.WriteLine(FailurePrefix); 65 | 66 | Console.ResetColor(); 67 | } 68 | 69 | public override void FinalizeExporter(TimeSpan duration) 70 | { 71 | } 72 | 73 | public override void InitializeExporter(Options options) 74 | { 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Linty.CLI/SolutionAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.Diagnostics; 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Linq; 9 | using System.Collections.Generic; 10 | using Linty.Analyzers.ForEachInUpdate; 11 | using Buildalyzer.Workspaces; 12 | using Buildalyzer; 13 | 14 | namespace Linty.CLI 15 | { 16 | public class SolutionAnalyzer 17 | { 18 | public async Task LoadAndAnalyzeProjectAsync(FileInfo projectFile, FileInfo configFileInfo, AnalyzerReport report) 19 | { 20 | AnalyzerManager manager = new AnalyzerManager(); 21 | ProjectAnalyzer analyzer = manager.GetProject(projectFile.FullName); 22 | 23 | AdhocWorkspace workspace = new AdhocWorkspace(); 24 | Project project = analyzer.AddToWorkspace(workspace); 25 | 26 | var analyzerDictionary = LoadConfigFile(configFileInfo); 27 | var analyzers = this.GetAnalyzers(analyzerDictionary); 28 | 29 | await AnalyzeProject(project, analyzers, report); 30 | } 31 | 32 | private Dictionary LoadConfigFile(FileInfo configFile) 33 | { 34 | if (configFile == null || configFile.Exists == false) 35 | { 36 | return null; 37 | } 38 | 39 | Dictionary analyzerDictionary = new Dictionary(); 40 | 41 | var config = File.ReadAllText(configFile.FullName); //TODO: read async? 42 | var jsonObject = JsonConvert.DeserializeObject(config); 43 | 44 | foreach (var item in jsonObject) 45 | { 46 | analyzerDictionary.Add(item.Key, (bool)item.Value); 47 | } 48 | 49 | return analyzerDictionary; 50 | } 51 | 52 | private bool IsAnalyzerAllowedInConfiguration(Dictionary analyzerDictionary, string analyzerName) 53 | { 54 | if (analyzerDictionary == null || analyzerDictionary.ContainsKey(analyzerName) == false) 55 | { 56 | return true; 57 | } 58 | 59 | return analyzerDictionary[analyzerName]; 60 | } 61 | 62 | private ImmutableArray GetAnalyzers(Dictionary analyzerDictionary) 63 | { 64 | var listBuilder = ImmutableArray.CreateBuilder(); 65 | 66 | var assembly = typeof(DoNotUseForEachInUpdate).Assembly; 67 | var allTypes = assembly.DefinedTypes; 68 | 69 | foreach (var type in allTypes) 70 | { 71 | if (type.IsSubclassOf(typeof(DiagnosticAnalyzer)) && !type.IsAbstract) 72 | { 73 | if (IsAnalyzerAllowedInConfiguration(analyzerDictionary, type.Name)) 74 | { 75 | var instance = Activator.CreateInstance(type) as DiagnosticAnalyzer; 76 | listBuilder.Add(instance); 77 | } 78 | } 79 | } 80 | 81 | var analyzers = listBuilder.ToImmutable(); 82 | return analyzers; 83 | } 84 | 85 | private async Task AnalyzeProject(Project project, ImmutableArray analyzers, 86 | AnalyzerReport report) 87 | { 88 | try 89 | { 90 | var compilation = await project.GetCompilationAsync(); 91 | 92 | var diagnosticResults = await compilation.WithAnalyzers(analyzers).GetAnalyzerDiagnosticsAsync(); 93 | 94 | report.AppendDiagnostics(diagnosticResults); 95 | } 96 | catch (Exception exception) 97 | { 98 | report.NotifyException(exception); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Linty.CLI/UnityReport.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Unity Engine Analyzer Report 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 |
23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
IdSeverityMessageFileLine Number
{{diagnostic.Id}}{{diagnostic.Severity}}{{diagnostic.Message}}{{diagnostic.FileName}}{{diagnostic.LineNumber}}
48 |
49 | 50 | 51 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Linty.CLI/UnityVersionResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using UnityEngineAnalyzer; 6 | 7 | namespace Linty.CLI 8 | { 9 | //NOTE: This class would benefit from UnitTests specially: TryParseUnityVersion 10 | internal class UnityVersionResolver 11 | { 12 | private const UnityVersion DEFAULT_UNITY_VERSION = UnityVersion.LATEST; 13 | 14 | public UnityVersion ResolveVersion(Options options) 15 | { 16 | if (options.Version != UnityVersion.NONE) 17 | { 18 | return options.Version; 19 | } 20 | 21 | //THIS ONLY WORKS ON UNITY >= 5, before that ProjectVersion.txt did not exists 22 | if (ResolveProjectVersionFilePath(options) != null) 23 | { 24 | var projectVersionString = File.ReadAllText(ResolveProjectVersionFilePath(options)); 25 | return TryParseUnityVersion(projectVersionString); 26 | } 27 | 28 | return DEFAULT_UNITY_VERSION; 29 | } 30 | 31 | private string ResolveProjectVersionFilePath(Options options) 32 | { 33 | var projectPath = new FileInfo(options.ProjectFile).Directory; 34 | var path = Path.Combine(projectPath.FullName, "ProjectSettings", "ProjectVersion.txt"); 35 | var projectVersionFile = new FileInfo(path); 36 | 37 | if (projectVersionFile.Exists) 38 | { 39 | return projectVersionFile.FullName; 40 | } 41 | 42 | return null; 43 | } 44 | 45 | private UnityVersion TryParseUnityVersion(string version) 46 | { 47 | string editorText = "m_EditorVersion: "; 48 | var match = Regex.Match(version, editorText + "[0-9.a-z]*"); 49 | 50 | string src = match.Value.Substring(editorText.Length); 51 | src = src.Replace('.', '_'); 52 | src = src.Substring(0, src.IndexOf('_') + 2); 53 | 54 | var unityVersions = Enum.GetValues(typeof(UnityVersion)).Cast(); 55 | foreach (var unityVersion in unityVersions) 56 | { 57 | if (Enum.GetName(typeof(UnityVersion), unityVersion).Contains(src)) 58 | { 59 | return unityVersion; 60 | } 61 | } 62 | 63 | return DEFAULT_UNITY_VERSION; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Linty.CLI/analyzerConfiguration.json: -------------------------------------------------------------------------------- 1 | { 2 | "DoNotUseStringMethodsAnalyzer": true, 3 | "InvokeFunctionMissingAnalyzer": true, 4 | "UseNonAllocMethodsAnalyzer": true, 5 | "DoNotUseOnGUIAnalyzer": true, 6 | "DoNotUseStringPropertyNamesAnalyzer": true, 7 | "UnsealedDerivedClassAnalyzer": true, 8 | "DoNotUseForEachInUpdate": true, 9 | "DoNotUseFindMethodsInUpdateAnalyzer": true, 10 | "EmptyMonoBehaviourMethodsAnalyzer": true, 11 | "DoNotUseCoroutinesAnalyzer": true, 12 | "UseCompareTagAnalyzer": true, 13 | "CameraMainAnalyzer": true, 14 | "AudioSourceAnalyzer": true, 15 | "DoNotUseReflectionEmitAnalyzer": true, 16 | "DoNotUseRemotingAnalyzer": true, 17 | "TypeGetTypeAnalyzer": true, 18 | "DoNotUseStateNameAnalyzer": true 19 | } -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/Assets/Scripts/UEA0008.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Assets.Scripts 4 | { 5 | public abstract class Animal 6 | { 7 | public abstract string Speak(); 8 | } 9 | 10 | public class Cow : Animal 11 | { 12 | public override string Speak() 13 | { 14 | return "Moo"; 15 | } 16 | } 17 | 18 | public class Pig : Animal 19 | { 20 | public override string Speak() 21 | { 22 | return "Oink"; 23 | } 24 | } 25 | 26 | public class Farm : MonoBehaviour 27 | { 28 | public void Start() 29 | { 30 | Animal[] animals = { new Cow(), new Pig() }; 31 | 32 | foreach (var animal in animals) 33 | { 34 | Debug.LogFormat("Some animal says '{0}'", animal.Speak()); 35 | } 36 | 37 | var cow = new Cow(); 38 | Debug.LogFormat("The cow says '{0}'", cow.Speak()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/Assets/UEA0003.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class UEA0003 : MonoBehaviour { 6 | 7 | // Use this for initialization 8 | void Start () { 9 | 10 | } 11 | 12 | // Update is called once per frame 13 | void Update () { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 0 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_DisableAudio: 0 16 | m_VirtualizeEffects: 1 17 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_EnablePCM: 1 18 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 19 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_DefaultBehaviorMode: 0 10 | m_SpritePackerMode: 0 11 | m_SpritePackerPaddingPower: 1 12 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd 13 | m_ProjectGenerationRootNamespace: 14 | m_UserGeneratedProjectSuffix: 15 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | m_SettingNames: 89 | - Humanoid 90 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!149 &1 4 | NetworkManager: 5 | m_ObjectHideFlags: 0 6 | m_DebugLevel: 0 7 | m_Sendrate: 15 8 | m_AssetToPrefab: {} 9 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 3 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_QueriesHitTriggers: 1 23 | m_QueriesStartInColliders: 1 24 | m_ChangeStopsCallbacks: 0 25 | m_CallbacksOnDisable: 1 26 | m_AlwaysShowColliders: 0 27 | m_ShowColliderSleep: 1 28 | m_ShowColliderContacts: 0 29 | m_ShowColliderAABB: 0 30 | m_ContactArrowScale: 0.2 31 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 32 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 33 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 34 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 35 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 36 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.6.1f1 2 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /Test Projects/Linty Test Case 5.6/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | m_Enabled: 0 7 | m_TestMode: 0 8 | m_TestEventUrl: 9 | m_TestConfigUrl: 10 | m_TestInitMode: 0 11 | CrashReportingSettings: 12 | m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes 13 | m_Enabled: 0 14 | m_CaptureEditorExceptions: 1 15 | UnityPurchasingSettings: 16 | m_Enabled: 0 17 | m_TestMode: 0 18 | UnityAnalyticsSettings: 19 | m_Enabled: 0 20 | m_InitializeOnStartup: 1 21 | m_TestMode: 0 22 | m_TestEventUrl: 23 | m_TestConfigUrl: 24 | UnityAdsSettings: 25 | m_Enabled: 0 26 | m_InitializeOnStartup: 1 27 | m_TestMode: 0 28 | m_EnabledPlatforms: 4294967295 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | PerformanceReportingSettings: 32 | m_Enabled: 0 33 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/AOT/DoNotUseReflectionEmitAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.AOT; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | 8 | namespace UnityEngineAnalyzer.Test.AOT 9 | { 10 | [TestFixture] 11 | sealed class DoNotUseReflectionEmitAnalyzerTests : AnalyzerTestFixture 12 | { 13 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseReflectionEmitAnalyzer(); 14 | 15 | [Test] 16 | public void UsingReflectionEmit() 17 | { 18 | const string code = @" 19 | [|using System.Reflection.Emit;|] 20 | 21 | class C { } 22 | "; 23 | HasDiagnostic(code, DiagnosticIDs.DoNotUseReflectionEmit); 24 | } 25 | 26 | [Test] 27 | public void UsingReflectionEmitNested() 28 | { 29 | const string code = @" 30 | namespace N 31 | { 32 | [|using System.Reflection.Emit;|] 33 | 34 | class C { } 35 | }"; 36 | HasDiagnostic(code, DiagnosticIDs.DoNotUseReflectionEmit); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/AOT/DoNotUseRemotingAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.AOT; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.AOT 8 | { 9 | [TestFixture] 10 | sealed class DoNotUseRemotingAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseRemotingAnalyzer(); 13 | 14 | [Test] 15 | public void UsingRemoting() 16 | { 17 | const string code = @" 18 | [|using System.Runtime.Remoting;|] 19 | 20 | class C { } 21 | "; 22 | HasDiagnostic(code, DiagnosticIDs.DoNotUseRemoting); 23 | } 24 | 25 | [Test] 26 | public void UsingRemotingNested() 27 | { 28 | const string code = @" 29 | namespace N 30 | { 31 | [|using System.Runtime.Remoting;|] 32 | 33 | class C { } 34 | }"; 35 | HasDiagnostic(code, DiagnosticIDs.DoNotUseRemoting); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/AOT/TypeGetTypeAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.AOT; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.CodeAnalysis.Text; 6 | using NUnit.Framework; 7 | using RoslynNUnitLight; 8 | 9 | namespace UnityEngineAnalyzer.Test.AOT 10 | { 11 | [TestFixture] 12 | sealed class TypeGetTypeAnalyzerTests : AnalyzerTestFixture 13 | { 14 | protected override DiagnosticAnalyzer CreateAnalyzer() => new TypeGetTypeAnalyzer(); 15 | 16 | [Test] 17 | public void TypeGetTypeIsUsed() 18 | { 19 | const string code = @" 20 | using UnityEngine; 21 | using System; 22 | 23 | class C : MonoBehaviour 24 | { 25 | void Start() 26 | { 27 | var theType = [|Type.GetType("""")|]; 28 | } 29 | }"; 30 | 31 | HasDiagnostic(code, DiagnosticIDs.TypeGetType); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Animator/DoNotUseStateNameAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Animator; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.CodeAnalysis.Text; 6 | using NUnit.Framework; 7 | using RoslynNUnitLight; 8 | 9 | namespace UnityEngineAnalyzer.Test.Animator 10 | { 11 | 12 | [TestFixture] 13 | sealed class DoNotSetAnimatorParameterWithNameAnalyzerTests : AnalyzerTestFixture 14 | { 15 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseStateNameAnalyzer(); 16 | 17 | [Test] 18 | public void AnimatorSetFloatStringName() 19 | { 20 | const string code = @" 21 | using UnityEngine; 22 | 23 | class C : MonoBehaviour 24 | { 25 | Animator animator; 26 | 27 | void Start() 28 | { 29 | [|animator.SetFloat(""Run"", 1.2f)|]; 30 | } 31 | }"; 32 | 33 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStateNameInAnimator); 34 | } 35 | 36 | [Test] 37 | public void AnimatorSetIntStringName() 38 | { 39 | const string code = @" 40 | using UnityEngine; 41 | 42 | class C : MonoBehaviour 43 | { 44 | Animator animator; 45 | 46 | void Start() 47 | { 48 | [|animator.SetInteger(""Walk"", 1)|]; 49 | } 50 | }"; 51 | 52 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStateNameInAnimator); 53 | } 54 | 55 | [Test] 56 | public void AnimatorSetBoolStringName() 57 | { 58 | const string code = @" 59 | using UnityEngine; 60 | 61 | class C : MonoBehaviour 62 | { 63 | Animator animator; 64 | 65 | void Start() 66 | { 67 | [|animator.SetBool(""Fly"", true)|]; 68 | } 69 | }"; 70 | 71 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStateNameInAnimator); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Audio/AudioSourceAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Audio; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.CodeAnalysis.Text; 6 | using NUnit.Framework; 7 | using RoslynNUnitLight; 8 | 9 | namespace UnityEngineAnalyzer.Test.Audio 10 | { 11 | [TestFixture] 12 | sealed class AudioSourceAnalyzerTests : AnalyzerTestFixture 13 | { 14 | protected override DiagnosticAnalyzer CreateAnalyzer() => new AudioSourceAnalyzer(); 15 | 16 | [Test] 17 | public void AudioSourceShouldRaiseInfoTextAboutAudioSourceMuteUsingCPUCycles() 18 | { 19 | const string code = @" 20 | using UnityEngine; 21 | 22 | class C : MonoBehaviour 23 | { 24 | AudioSource audioSource; 25 | 26 | void Update() 27 | { 28 | [|audioSource.mute = true;|] 29 | } 30 | }"; 31 | 32 | HasDiagnostic(code, DiagnosticIDs.AudioSourceMuteUsesCPU); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Camera/CameraMainAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Camera; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.Camera 8 | { 9 | [TestFixture] 10 | sealed class CameraMainAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new CameraMainAnalyzer(); 13 | 14 | [Test] 15 | public void CameraMainShouldRaiseWarningOnMemberExpression() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | void Update() 23 | { 24 | var orthographicSize = [|Camera.main.orthographicSize|]; 25 | } 26 | }"; 27 | 28 | HasDiagnostic(code, DiagnosticIDs.CameraMainIsSlow); 29 | } 30 | 31 | [Test] 32 | public void CameraMainShouldRaiseWarningOnMethod() 33 | { 34 | const string code = @" 35 | using UnityEngine; 36 | 37 | class C : MonoBehaviour 38 | { 39 | void Update() 40 | { 41 | var size = [|Camera.main.ScreenPointToRay|](new Vector3(200, 200, 0)); 42 | } 43 | }"; 44 | 45 | HasDiagnostic(code, DiagnosticIDs.CameraMainIsSlow); 46 | } 47 | 48 | [Test] 49 | public void CameraMainShouldThrowWarningFromCalledMethods() 50 | { 51 | const string code = @" 52 | using UnityEngine; 53 | 54 | class C : MonoBehaviour 55 | { 56 | void Update() 57 | { 58 | Call(); 59 | 60 | //Camera.main.transform.position = Vector3.one; 61 | } 62 | 63 | public void Call() 64 | { 65 | var size = [|Camera.main.ScreenPointToRay|](new Vector3(200, 200, 0)); 66 | } 67 | }"; 68 | 69 | HasDiagnostic(code, DiagnosticIDs.CameraMainIsSlow); 70 | } 71 | 72 | [Test] 73 | public void CameraMainShouldThrowWarningOnlyInHotPath() 74 | { 75 | const string code = @" 76 | using UnityEngine; 77 | 78 | class C : MonoBehaviour 79 | { 80 | void Start() 81 | { 82 | var size = [|Camera.main.ScreenPointToRay|](new Vector3(200, 200, 0)); 83 | } 84 | }"; 85 | 86 | NoDiagnostic(code, DiagnosticIDs.CameraMainIsSlow); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/CompareTag/UseCompareTagAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.CompareTag; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.CompareTag 8 | { 9 | [TestFixture] 10 | sealed class UseCompareTagAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new UseCompareTagAnalyzer(); 13 | 14 | [Test] 15 | public void UseTagForComparison() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | void Start() 23 | { 24 | var a = [|tag == ""Enemy""|]; 25 | } 26 | }"; 27 | 28 | HasDiagnostic(code, DiagnosticIDs.UseCompareTag); 29 | } 30 | 31 | [Test] 32 | public void UseGameObjectTagForComparison() 33 | { 34 | const string code = @" 35 | using UnityEngine; 36 | 37 | class C : MonoBehaviour 38 | { 39 | void Start() 40 | { 41 | var a = [|gameObject.tag == ""Enemy""|]; 42 | } 43 | }"; 44 | 45 | HasDiagnostic(code, DiagnosticIDs.UseCompareTag); 46 | } 47 | 48 | [Test] 49 | public void UseMonoBehaviourTagForComparison() 50 | { 51 | const string code = @" 52 | using UnityEngine; 53 | 54 | class CC : MonoBehaviour { } 55 | 56 | class C : MonoBehaviour 57 | { 58 | private CC cc; 59 | void Start() 60 | { 61 | var a = [|""Enemy"".Equals(cc.tag)|]; 62 | } 63 | }"; 64 | 65 | HasDiagnostic(code, DiagnosticIDs.UseCompareTag); 66 | } 67 | 68 | [Test] 69 | public void OtherEqualsComparison() 70 | { 71 | const string code = @" 72 | using UnityEngine; 73 | 74 | class C : MonoBehaviour 75 | { 76 | void Start() 77 | { 78 | var a = [|""Player"".Equals(""Enemy"")|]; 79 | } 80 | }"; 81 | 82 | NoDiagnostic(code, DiagnosticIDs.UseCompareTag); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Coroutines/DoNotUseCoroutinesAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Coroutines; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.Coroutines 8 | { 9 | [TestFixture] 10 | sealed class DoNotUseCoroutinesAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseCoroutinesAnalyzer(); 13 | 14 | [Test] 15 | public void StartCoroutineUsedInMonoBehaviourClass() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | void M() 23 | { 24 | [|StartCoroutine(""MyCoroutine"")|]; 25 | } 26 | }"; 27 | HasDiagnostic(code, DiagnosticIDs.DoNotUseCoroutines); 28 | } 29 | 30 | [Test] 31 | public void StartCoroutineUsedByMonoBehaviourClass() 32 | { 33 | const string code = @" 34 | using UnityEngine; 35 | 36 | class CC : MonoBehaviour { } 37 | 38 | class C : MonoBehaviour 39 | { 40 | private CC cc; 41 | void M() 42 | { 43 | [|cc.StartCoroutine(""MyCoroutine"")|]; 44 | } 45 | }"; 46 | HasDiagnostic(code, DiagnosticIDs.DoNotUseCoroutines); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/EmptyMonoBehaviourMethods/EmptyMonoBehaviourMethodsAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.Diagnostics; 2 | using NUnit.Framework; 3 | using RoslynNUnitLight; 4 | using Linty.Analyzers; 5 | using Linty.Analyzers.EmptyMonoBehaviourMethods; 6 | 7 | namespace UnityEngineAnalyzer.Test.EmptyMonoBehaviourMethods 8 | { 9 | [TestFixture] 10 | sealed class EmptyMonoBehaviourMethodsAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new EmptyMonoBehaviourMethodsAnalyzer(); 13 | 14 | [Test] 15 | public void EmptyUpdateInMonoBehaviour() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | [|void Update() { }|] 23 | }"; 24 | 25 | HasDiagnostic(code, DiagnosticIDs.EmptyMonoBehaviourMethod); 26 | } 27 | 28 | [Test] 29 | public void EmptyUpdateInNormalClass() 30 | { 31 | const string code = @" 32 | using UnityEngine; 33 | 34 | class C 35 | { 36 | [|void Update() { }|] 37 | }"; 38 | 39 | NoDiagnostic(code, DiagnosticIDs.EmptyMonoBehaviourMethod); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/FindMethodsInUpdate/DoNotUseFindMethodsInUpdateAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.FindMethodsInUpdate; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.FindMethodsInUpdate 8 | { 9 | [TestFixture] 10 | sealed class DoNotUseFindMethodsInUpdateAnalyzerTests : AnalyzerTestFixture 11 | { 12 | 13 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseFindMethodsInUpdateAnalyzer(); 14 | 15 | [Test] 16 | public void GameObjectFindInUpdate() 17 | { 18 | var code = @" 19 | using UnityEngine; 20 | 21 | class C : MonoBehaviour 22 | { 23 | void Update() 24 | { 25 | [|GameObject.Find(""param"")|]; 26 | 27 | //var result = GameObject.Find(""param""); 28 | } 29 | }"; 30 | 31 | 32 | HasDiagnostic(code, DiagnosticIDs.DoNotUseFindMethodsInUpdate); 33 | } 34 | 35 | [Test] 36 | public void GameObjectFindInStart() 37 | { 38 | const string code = @" 39 | using UnityEngine; 40 | 41 | class C : MonoBehaviour 42 | { 43 | void Start() 44 | { 45 | [|GameObject.Find("")|]; 46 | } 47 | }"; 48 | 49 | NoDiagnostic(code, DiagnosticIDs.EmptyMonoBehaviourMethod); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/ForEachInUpdate/DoNotUseForeachInUpdateAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.ForEachInUpdate; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.ForEachInUpdate 8 | { 9 | [TestFixture] 10 | sealed class DoNotUseForeachInUpdateAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseForEachInUpdate(); 13 | 14 | [Test] 15 | public void ForEachInUpdate() 16 | { 17 | var code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | void Update() 23 | { 24 | var colors = new[] {""red"", ""white"", ""blue""}; 25 | var result = string.Empty; 26 | [|foreach|] (var color in colors) 27 | { 28 | result += color; 29 | } 30 | } 31 | }"; 32 | 33 | 34 | HasDiagnostic(code, DiagnosticIDs.DoNotUseForEachInUpdate); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Material/DoNotUseStringPropertyNamesTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Material; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.CodeAnalysis.Text; 6 | using NUnit.Framework; 7 | using RoslynNUnitLight; 8 | 9 | namespace UnityEngineAnalyzer.Test.Material 10 | { 11 | 12 | [TestFixture] 13 | sealed class DoNotUseStringPropertyNamesAnalyzerTests : AnalyzerTestFixture 14 | { 15 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseStringPropertyNamesAnalyzer(); 16 | 17 | [Test] 18 | public void MaterialGetFloatWithStringProperty() 19 | { 20 | const string code = @" 21 | using UnityEngine; 22 | 23 | class C : MonoBehaviour 24 | { 25 | Material material; 26 | 27 | void Start() 28 | { 29 | [|material.GetFloat(""_Shininess"")|]; 30 | } 31 | }"; 32 | 33 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 34 | } 35 | 36 | [Test] 37 | public void MaterialSetFloatWithStringProperty() 38 | { 39 | const string code = @" 40 | using UnityEngine; 41 | 42 | class C : MonoBehaviour 43 | { 44 | Material material; 45 | 46 | void Start() 47 | { 48 | [|material.SetFloat(""_Shininess"", 1.2f)|]; 49 | } 50 | }"; 51 | 52 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 53 | } 54 | 55 | [Test] 56 | public void MaterialSetMatrixWithStringProperty() 57 | { 58 | const string code = @" 59 | using UnityEngine; 60 | 61 | class C : MonoBehaviour 62 | { 63 | Material material; 64 | 65 | void Start() 66 | { 67 | [|material.SetVector(""_WaveAndDistance"", Vector3.one)|]; 68 | } 69 | }"; 70 | 71 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/MetadataReferenceHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.CodeAnalysis; 3 | using System.Collections.Immutable; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using Microsoft.Extensions.DependencyModel; 8 | 9 | namespace UnityEngineAnalyzer.Test 10 | { 11 | static class MetadataReferenceHelper 12 | { 13 | public static readonly ImmutableList UsingUnityEngine = getRequiredMetadataReferences(); 14 | 15 | private static ImmutableList getRequiredMetadataReferences() 16 | { 17 | var builder = ImmutableList.CreateBuilder(); 18 | builder.Add(GetUnityMetadataReference()); 19 | builder.AddRange(GetSystemString()); 20 | 21 | return builder.ToImmutable(); 22 | } 23 | 24 | private static MetadataReference GetUnityMetadataReference() 25 | { 26 | const string unityEngineFilePath = @"Editor\Data\Managed\UnityEngine.dll"; 27 | var programFilesFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); 28 | 29 | var unityDirectories = 30 | Directory.EnumerateDirectories(programFilesFolderPath, "*Unity*", SearchOption.TopDirectoryOnly); 31 | 32 | foreach (var unityDirectory in unityDirectories) 33 | { 34 | var unityEngineFullPath = Path.Combine(unityDirectory, unityEngineFilePath); 35 | 36 | if (File.Exists(unityEngineFullPath)) 37 | { 38 | return MetadataReference.CreateFromFile(unityEngineFullPath); 39 | } 40 | } 41 | 42 | throw new FileNotFoundException("Unable to locate UnityEngine.dll"); 43 | } 44 | 45 | private static MetadataReference[] GetSystemString() 46 | { 47 | return 48 | DependencyContext.Default.CompileLibraries 49 | .First(cl => cl.Name == "Microsoft.NETCore.App") 50 | .ResolveReferencePaths() 51 | .Select(asm => MetadataReference.CreateFromFile(asm)) 52 | .ToArray(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/OnGUI/DoNotUseOnGUIAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.OnGUI; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.CodeAnalysis.Text; 6 | using NUnit.Framework; 7 | using RoslynNUnitLight; 8 | 9 | namespace UnityEngineAnalyzer.Test.OnGUI 10 | { 11 | [TestFixture] 12 | sealed class DoNotUseOnGUIAnalyzerTests : AnalyzerTestFixture 13 | { 14 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseOnGUIAnalyzer(); 15 | 16 | [Test] 17 | public void OnGUIUsedInMonoBehaviour() 18 | { 19 | const string code = @" 20 | using UnityEngine; 21 | 22 | class C : MonoBehaviour 23 | { 24 | void [|OnGUI|]() { } 25 | }"; 26 | 27 | HasDiagnostic(code, DiagnosticIDs.DoNotUseOnGUI); 28 | } 29 | 30 | [Test] 31 | public void OnGUIUsedInClass() 32 | { 33 | const string code = @" 34 | class C 35 | { 36 | void [|OnGUI|]() { } 37 | }"; 38 | 39 | NoDiagnostic(code, DiagnosticIDs.DoNotUseOnGUI); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Physics/UseNonAllocMethodsTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Physics; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.Physics 8 | { 9 | 10 | [TestFixture] 11 | sealed class UseNonAllocMethodsTests : AnalyzerTestFixture 12 | { 13 | protected override DiagnosticAnalyzer CreateAnalyzer() => new UseNonAllocMethodsAnalyzer(); 14 | 15 | [Test] 16 | public void PhysicsRaycastAll() 17 | { 18 | const string code = @" 19 | using UnityEngine; 20 | 21 | class C : MonoBehaviour 22 | { 23 | void Update() 24 | { 25 | RaycastHit[] hits; 26 | hits = [|Physics.RaycastAll(transform.position, transform.forward, 100.0F)|]; 27 | } 28 | }"; 29 | 30 | HasDiagnostic(code, DiagnosticIDs.PhysicsUseNonAllocMethods); 31 | } 32 | 33 | [Test] 34 | public void Physics2DRaycastAll() 35 | { 36 | const string code = @" 37 | using UnityEngine; 38 | 39 | class C : MonoBehaviour 40 | { 41 | void Update() 42 | { 43 | RaycastHit2D[] hits; 44 | hits = [|Physics2D.RaycastAll(Vector2.zero, Vector2.one)|]; 45 | } 46 | }"; 47 | 48 | HasDiagnostic(code, DiagnosticIDs.PhysicsUseNonAllocMethods); 49 | } 50 | 51 | [Test] 52 | public void Physics2DCircleCastAll() 53 | { 54 | const string code = @" 55 | using UnityEngine; 56 | 57 | class C : MonoBehaviour 58 | { 59 | void Start() 60 | { 61 | [|Physics2D.CircleCastAll(Vector2.zero, 5, Vector2.one)|]; 62 | } 63 | }"; 64 | 65 | HasDiagnostic(code, DiagnosticIDs.PhysicsUseNonAllocMethods); 66 | } 67 | 68 | [Test] 69 | public void PhysicsUseNonAllocMethods_Should_Notice_Multiple_Calls() 70 | { 71 | const string code = @" 72 | using UnityEngine; 73 | 74 | class C : MonoBehaviour 75 | { 76 | Animator animator; 77 | 78 | void Start() 79 | { 80 | [|Physics2D.CircleCastAll(Vector2.zero, 5, Vector2.one)|]; 81 | 82 | [|Physics2D.LinecastAll(Vector2.zero, Vector2.one)|]; 83 | } 84 | }"; 85 | 86 | HasDiagnostic(code, DiagnosticIDs.PhysicsUseNonAllocMethods); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/AnalyzerTestFixture.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Linq; 3 | using System.Threading; 4 | using Microsoft.CodeAnalysis; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | using Microsoft.CodeAnalysis.Text; 7 | using NUnit.Framework; 8 | using UnityEngineAnalyzer.Test; 9 | 10 | namespace RoslynNUnitLight 11 | { 12 | public abstract class AnalyzerTestFixture : BaseTestFixture 13 | { 14 | protected abstract DiagnosticAnalyzer CreateAnalyzer(); 15 | 16 | protected override string LanguageName => LanguageNames.CSharp; 17 | 18 | protected void NoDiagnostic(string code, string diagnosticId) 19 | { 20 | Document document; 21 | TextSpan span; 22 | TestHelpers.TryGetDocumentAndSpanFromMarkup(code, LanguageName, MetadataReferenceHelper.UsingUnityEngine, out document, out span); 23 | 24 | NoDiagnostic(document, diagnosticId); 25 | } 26 | 27 | private void NoDiagnostic(Document document, string diagnosticId) 28 | { 29 | var diagnostics = GetDiagnostics(document); 30 | 31 | Assert.That(diagnostics.Any(d => d.Id == diagnosticId), Is.False); 32 | } 33 | 34 | protected void HasDiagnostic(string markupCode, string diagnosticId) 35 | { 36 | Document document; 37 | TextSpan span; 38 | Assert.That(TestHelpers.TryGetDocumentAndSpanFromMarkup(markupCode, LanguageName, MetadataReferenceHelper.UsingUnityEngine, out document, out span), Is.True); 39 | 40 | HasDiagnostic(document, span, diagnosticId); 41 | } 42 | 43 | private void HasDiagnostic(Document document, TextSpan span, string diagnosticId) 44 | { 45 | var diagnostics = GetDiagnostics(document); 46 | Assert.That(diagnostics.Length, Is.EqualTo(1)); 47 | 48 | var diagnostic = diagnostics[0]; 49 | Assert.That(diagnostic.Id, Is.EqualTo(diagnosticId)); 50 | Assert.That(diagnostic.Location.IsInSource, Is.True); 51 | Assert.That(diagnostic.Location.SourceSpan, Is.EqualTo(span)); 52 | } 53 | 54 | private ImmutableArray GetDiagnostics(Document document) 55 | { 56 | var analyzers = ImmutableArray.Create(CreateAnalyzer()); 57 | var compilation = document.Project.GetCompilationAsync(CancellationToken.None).Result; 58 | var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, cancellationToken: CancellationToken.None); 59 | var discarded = compilation.GetDiagnostics(CancellationToken.None); 60 | 61 | var tree = document.GetSyntaxTreeAsync(CancellationToken.None).Result; 62 | 63 | var builder = ImmutableArray.CreateBuilder(); 64 | foreach (var diagnostic in compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result) 65 | { 66 | var location = diagnostic.Location; 67 | if (location.IsInSource && location.SourceTree == tree) 68 | { 69 | builder.Add(diagnostic); 70 | } 71 | } 72 | 73 | return builder.ToImmutable(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/BaseTestFixture.cs: -------------------------------------------------------------------------------- 1 | namespace RoslynNUnitLight 2 | { 3 | public abstract class BaseTestFixture 4 | { 5 | protected abstract string LanguageName { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2015 Dustin Campbell 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/ReflectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace RoslynNUnitLight.Reflection 5 | { 6 | internal static class ReflectionExtensions 7 | { 8 | private static class AssemblyLightUp 9 | { 10 | internal static readonly Type Type = typeof(Assembly); 11 | 12 | internal static readonly Func get_Location = Type 13 | .GetTypeInfo() 14 | .GetDeclaredMethod("get_Location") 15 | .CreateDelegate>(); 16 | } 17 | 18 | public static string GetLocation(this Assembly assembly) 19 | { 20 | if (AssemblyLightUp.get_Location == null) 21 | { 22 | throw new PlatformNotSupportedException(); 23 | } 24 | 25 | return AssemblyLightUp.get_Location(assembly); 26 | } 27 | 28 | public static T CreateDelegate(this MethodInfo methodInfo) 29 | { 30 | if (methodInfo == null) 31 | { 32 | return default(T); 33 | } 34 | 35 | return (T)(object)methodInfo.CreateDelegate(typeof(T)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/TestHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Text; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.Text; 7 | using RoslynNUnitLight.Reflection; 8 | 9 | namespace RoslynNUnitLight 10 | { 11 | public static class TestHelpers 12 | { 13 | public static bool TryGetCodeAndSpanFromMarkup(string markupCode, out string code, out TextSpan span) 14 | { 15 | code = null; 16 | span = default(TextSpan); 17 | 18 | var builder = new StringBuilder(); 19 | 20 | var start = markupCode.IndexOf("[|"); 21 | if (start < 0) 22 | { 23 | return false; 24 | } 25 | 26 | builder.Append(markupCode.Substring(0, start)); 27 | 28 | var end = markupCode.IndexOf("|]"); 29 | if (end < 0) 30 | { 31 | return false; 32 | } 33 | 34 | builder.Append(markupCode.Substring(start + 2, end - start - 2)); 35 | builder.Append(markupCode.Substring(end + 2)); 36 | 37 | code = builder.ToString(); 38 | span = TextSpan.FromBounds(start, end - 2); 39 | 40 | return true; 41 | } 42 | 43 | public static bool TryGetDocumentAndSpanFromMarkup(string markupCode, string languageName, out Document document, out TextSpan span) 44 | { 45 | return TryGetDocumentAndSpanFromMarkup(markupCode, languageName, null, out document, out span); 46 | } 47 | 48 | public static bool TryGetDocumentAndSpanFromMarkup(string markupCode, string languageName, ImmutableList references, out Document document, out TextSpan span) 49 | { 50 | string code; 51 | if (!TryGetCodeAndSpanFromMarkup(markupCode, out code, out span)) 52 | { 53 | document = null; 54 | return false; 55 | } 56 | 57 | document = GetDocument(code, languageName, references); 58 | return true; 59 | } 60 | 61 | public static Document GetDocument(string code, string languageName, ImmutableList references = null) 62 | { 63 | references = references ?? ImmutableList.Create( 64 | MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.GetLocation()), 65 | MetadataReference.CreateFromFile(typeof(Enumerable).GetTypeInfo().Assembly.GetLocation())); 66 | 67 | return new AdhocWorkspace() 68 | .AddProject("TestProject", languageName) 69 | .AddMetadataReferences(references) 70 | .AddDocument("TestDocument", code); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/RoslynNUnitLight/readme.md: -------------------------------------------------------------------------------- 1 | ! RoslynNUnitLight 2 | 3 | The contents of this folder is from a project on GitHub called RoslynNUnitLight. This testing framework is used in the test suite for the UnityEngineAnalyzer project. 4 | 5 | UnityEngineAnalyzer is in the process of getting converted to use DotNet standard for future cross-platform compatibility. There is currently no version of the RoslynNUnitLight library available on NuGet that is compatible with DotNet Standard 2.0 6 | 7 | For this reason, the dependent files of the project have been copied into this Repo. Please see the license file for appropriate license and copyright. -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Shader/DoNotUseStringPropertyNamesTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Shader; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.Shader 8 | { 9 | 10 | [TestFixture] 11 | sealed class DoNotUseStringPropertyNamesInShaderAnalyzerTests : AnalyzerTestFixture 12 | { 13 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseStringPropertyNamesShaderAnalyzer(); 14 | 15 | [Test] 16 | public void ShaderGetGlobalFloatWithIntProperty() 17 | { 18 | const string code = @" 19 | using UnityEngine; 20 | 21 | class A : MonoBehaviour 22 | { 23 | Shader shader; 24 | 25 | void Start() 26 | { 27 | [|shader.GetGlobalFloat(1)|]; 28 | } 29 | }"; 30 | 31 | NoDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 32 | } 33 | 34 | [Test] 35 | public void ShaderGetGlobalFloatWithStringProperty() 36 | { 37 | const string code = @" 38 | using UnityEngine; 39 | 40 | class A : MonoBehaviour 41 | { 42 | Shader shader; 43 | 44 | void Start() 45 | { 46 | [|shader.GetGlobalFloat(""_Shininess"")|]; 47 | } 48 | }"; 49 | 50 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 51 | } 52 | 53 | [Test] 54 | public void ShaderSetGlobalFloatWithStringProperty() 55 | { 56 | const string code = @" 57 | using UnityEngine; 58 | 59 | class B : MonoBehaviour 60 | { 61 | Shader shader; 62 | 63 | void Start() 64 | { 65 | [|shader.SetGlobalFloat(""_Shininess"", 1.2f)|]; 66 | } 67 | }"; 68 | 69 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 70 | } 71 | 72 | [Test] 73 | public void ShaderSetGlobalFloatArrayWithStringProperty() 74 | { 75 | const string code = @" 76 | using UnityEngine; 77 | 78 | class C : MonoBehaviour 79 | { 80 | Shader shader; 81 | 82 | void Start() 83 | { 84 | [|shader.SetGlobalFloatArray(""_WaveAndDistance"", new float[] { 1 })|]; 85 | } 86 | }"; 87 | 88 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringPropertyNames); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/StringMethods/DoNotUseStringMethodsAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.StringMethods; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.StringMethods 8 | { 9 | [TestFixture] 10 | sealed class DoNotUseStringMethodsAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new DoNotUseStringMethodsAnalyzer(); 13 | 14 | [Test] 15 | public void SendMessageUsedInMonoBehaviourClass() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class C : MonoBehaviour 21 | { 22 | void Start() { [|SendMessage(string.Empty)|]; } 23 | }"; 24 | 25 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 26 | } 27 | 28 | [Test] 29 | public void SendMessageUpwardsUsedInMonoBehaviourClass() 30 | { 31 | const string code = @" 32 | using UnityEngine; 33 | 34 | class C : MonoBehaviour 35 | { 36 | void Start() { [|SendMessageUpwards(string.Empty)|]; } 37 | }"; 38 | 39 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 40 | } 41 | 42 | [Test] 43 | public void BroadcastMessageUsedInMonoBehaviourClass() 44 | { 45 | const string code = @" 46 | using UnityEngine; 47 | 48 | class C : MonoBehaviour 49 | { 50 | void Start() { [|BroadcastMessage(string.Empty)|]; } 51 | }"; 52 | 53 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 54 | } 55 | 56 | [Test] 57 | public void SendMessageUsedByGameObject() 58 | { 59 | const string code = @" 60 | using UnityEngine; 61 | 62 | class C : MonoBehaviour 63 | { 64 | private GameObject go; 65 | void Start() { [|go.SendMessage(string.Empty)|]; } 66 | }"; 67 | 68 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 69 | } 70 | 71 | [Test] 72 | public void SendMessageUpwardsUsedByGameObject() 73 | { 74 | const string code = @" 75 | using UnityEngine; 76 | 77 | class C : MonoBehaviour 78 | { 79 | private GameObject go; 80 | void Start() { [|go.SendMessageUpwards(string.Empty)|]; } 81 | }"; 82 | 83 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 84 | } 85 | 86 | [Test] 87 | public void BroadcastMessageUsedByGameObject() 88 | { 89 | const string code = @" 90 | using UnityEngine; 91 | 92 | class C : MonoBehaviour 93 | { 94 | private GameObject go; 95 | void Start() { [|go.BroadcastMessage(string.Empty)|]; } 96 | }"; 97 | 98 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 99 | } 100 | 101 | [Test] 102 | public void SendMessageUsedByMonoBehaviourClass() 103 | { 104 | const string code = @" 105 | using UnityEngine; 106 | 107 | class CC : MonoBehaviour { } 108 | 109 | class C : MonoBehaviour 110 | { 111 | private CC cc; 112 | void Start() { [|cc.SendMessage(string.Empty)|]; } 113 | }"; 114 | 115 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 116 | } 117 | 118 | [Test] 119 | public void SendMessageUpwardsUsedByMonoBehaviourClass() 120 | { 121 | const string code = @" 122 | using UnityEngine; 123 | 124 | class CC : MonoBehaviour { } 125 | 126 | class C : MonoBehaviour 127 | { 128 | private CC cc; 129 | void Start() { [|cc.SendMessageUpwards(string.Empty)|]; } 130 | }"; 131 | 132 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 133 | } 134 | 135 | [Test] 136 | public void BroadcastMessageUsedByMonoBehaviourClass() 137 | { 138 | const string code = @" 139 | using UnityEngine; 140 | 141 | class CC : MonoBehaviour { } 142 | 143 | class C : MonoBehaviour 144 | { 145 | private CC cc; 146 | void Start() { [|cc.BroadcastMessage(string.Empty)|]; } 147 | }"; 148 | 149 | HasDiagnostic(code, DiagnosticIDs.DoNotUseStringMethods); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/StringMethods/InvokeFunctionMissingAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.StringMethods; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.StringMethods 8 | { 9 | 10 | //TODO: this test suite needs to be more thorough - check for positive/negative cases 11 | // 1. the param is a constant 12 | // 2. the param is a variable 13 | // 3. the param is a literal 14 | 15 | [TestFixture] 16 | sealed class InvokeFunctionMissingAnalyzerTests : AnalyzerTestFixture 17 | { 18 | protected override DiagnosticAnalyzer CreateAnalyzer() => new InvokeFunctionMissingAnalyzer(); 19 | 20 | [Test] 21 | public void InvokeUsedInMonoBehaviourClass() 22 | { 23 | const string code = @" 24 | using UnityEngine; 25 | 26 | class C : MonoBehaviour 27 | { 28 | void Start() { Invoke([|string.Empty|], 0f); } 29 | }"; 30 | 31 | HasDiagnostic(code, DiagnosticIDs.InvokeFunctionMissing); 32 | } 33 | 34 | [Test] 35 | public void InvokeUsedByMonoBehaviourClass() 36 | { 37 | const string code = @" 38 | using UnityEngine; 39 | 40 | class CC : MonoBehaviour { } 41 | 42 | class C : MonoBehaviour 43 | { 44 | private CC cc; 45 | void Start() { cc.Invoke([|string.Empty|], 0f); } 46 | }"; 47 | 48 | HasDiagnostic(code, DiagnosticIDs.InvokeFunctionMissing); 49 | } 50 | 51 | [Test] 52 | public void InvokeRepeatingUsedInMonoBehaviourClass() 53 | { 54 | const string code = @" 55 | using UnityEngine; 56 | 57 | class C : MonoBehaviour 58 | { 59 | void Start() { InvokeRepeating([|string.Empty|], 0f, 0f); } 60 | }"; 61 | 62 | HasDiagnostic(code, DiagnosticIDs.InvokeFunctionMissing); 63 | } 64 | 65 | [Test] 66 | public void InvokeRepeatingUsedByMonoBehaviourClass() 67 | { 68 | const string code = @" 69 | using UnityEngine; 70 | 71 | class CC : MonoBehaviour { } 72 | 73 | class C : MonoBehaviour 74 | { 75 | private CC cc; 76 | void Start() { cc.InvokeRepeating([|string.Empty|], 0f, 0f); } 77 | }"; 78 | 79 | HasDiagnostic(code, DiagnosticIDs.InvokeFunctionMissing); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/UnityEngineAnalyzer.UnitTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.1 5 | true 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.UnitTest/Vector/VectorAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | using Linty.Analyzers; 2 | using Linty.Analyzers.Vector; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using NUnit.Framework; 5 | using RoslynNUnitLight; 6 | 7 | namespace UnityEngineAnalyzer.Test.Vector 8 | { 9 | [TestFixture] 10 | sealed class VectorAnalyzerTests : AnalyzerTestFixture 11 | { 12 | protected override DiagnosticAnalyzer CreateAnalyzer() => new VectorAnalyzer(); 13 | 14 | [Test] 15 | public void Vector2magnitudeShouldSetDiagnostics() 16 | { 17 | const string code = @" 18 | using UnityEngine; 19 | 20 | class A : MonoBehaviour 21 | { 22 | Vector2 pos2D; 23 | 24 | void Update() 25 | { 26 | var magnitude = [|pos2D.magnitude|]; 27 | } 28 | }"; 29 | HasDiagnostic(code, DiagnosticIDs.VectorMagnitudeIsSlow); 30 | } 31 | 32 | [Test] 33 | public void Vector3magnitudeShouldSetDiagnostics() 34 | { 35 | const string code = @" 36 | using UnityEngine; 37 | 38 | class B : MonoBehaviour 39 | { 40 | void Update() 41 | { 42 | var magnitude = [|transform.position.magnitude|]; 43 | } 44 | }"; 45 | HasDiagnostic(code, DiagnosticIDs.VectorMagnitudeIsSlow); 46 | } 47 | 48 | [Test] 49 | public void Vector3magnitudeShouldSetDiagnosticsInsideIfStatement() 50 | { 51 | const string code = @" 52 | using UnityEngine; 53 | 54 | class C : MonoBehaviour 55 | { 56 | public Transform other; 57 | private float farDistance = 5.0f; 58 | 59 | void Update() 60 | { 61 | if ([|(other.position - transform.position).magnitude|] > farDistance) 62 | { 63 | //OPTIMIZE THIS CALL BY USING sqrMagnitude 64 | } 65 | } 66 | }"; 67 | HasDiagnostic(code, DiagnosticIDs.VectorMagnitudeIsSlow); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29324.140 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEngineAnalyzer.Vsix", "UnityEngineAnalyzer\UnityEngineAnalyzer.Vsix\UnityEngineAnalyzer.Vsix.csproj", "{23A41489-857C-4FC7-9B96-2F20D8EE380B}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Linty.Analyzers", "UnityEngineAnalyzer\Linty.Analyzers\Linty.Analyzers.csproj", "{D43EFDFB-BB7F-4A9B-9A60-C79B9404342A}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Linty.CLI", "Linty.CLI\Linty.CLI.csproj", "{616BA250-393A-4F44-AB95-5C511969B242}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnityEngineAnalyzer.UnitTest", "UnityEngineAnalyzer.UnitTest\UnityEngineAnalyzer.UnitTest.csproj", "{80876DFE-9DEE-411C-B5EE-B64EA218877A}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {23A41489-857C-4FC7-9B96-2F20D8EE380B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {23A41489-857C-4FC7-9B96-2F20D8EE380B}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {23A41489-857C-4FC7-9B96-2F20D8EE380B}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {23A41489-857C-4FC7-9B96-2F20D8EE380B}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {D43EFDFB-BB7F-4A9B-9A60-C79B9404342A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {D43EFDFB-BB7F-4A9B-9A60-C79B9404342A}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {D43EFDFB-BB7F-4A9B-9A60-C79B9404342A}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {D43EFDFB-BB7F-4A9B-9A60-C79B9404342A}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {616BA250-393A-4F44-AB95-5C511969B242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {616BA250-393A-4F44-AB95-5C511969B242}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {616BA250-393A-4F44-AB95-5C511969B242}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {616BA250-393A-4F44-AB95-5C511969B242}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {80876DFE-9DEE-411C-B5EE-B64EA218877A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {80876DFE-9DEE-411C-B5EE-B64EA218877A}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {80876DFE-9DEE-411C-B5EE-B64EA218877A}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {80876DFE-9DEE-411C-B5EE-B64EA218877A}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {665F3B36-1593-4F2F-9AD1-8633CAEDDC89} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/DoNotUseReflectionEmitAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers.AOT 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public sealed class DoNotUseReflectionEmitAnalyzer : DiagnosticAnalyzer 11 | { 12 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseReflectionEmit); 13 | 14 | public override void Initialize(AnalysisContext context) 15 | { 16 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.UsingDirective); 17 | } 18 | 19 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 20 | { 21 | // retrieve using syntax node 22 | var syntax = context.Node as UsingDirectiveSyntax; 23 | // and check if it is System.Reflection.Emit 24 | if (syntax.Name.ToString().Equals("System.Reflection.Emit")) 25 | { 26 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseReflectionEmit, syntax.GetLocation()); 27 | context.ReportDiagnostic(diagnostic); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/DoNotUseReflectionEmitResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.AOT { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class DoNotUseReflectionEmitResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal DoNotUseReflectionEmitResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.AOT.DoNotUseReflectionEmitResources", typeof(DoNotUseReflectionEmitResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to AOT Limitation: System.Reflection.Emit is not supported.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to AOT Limitation: System.Reflection.Emit is not supported.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to AOT Limitation: System.Reflection.Emit is not supported.. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/DoNotUseRemotingAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers.AOT 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public sealed class DoNotUseRemotingAnalyzer : DiagnosticAnalyzer 11 | { 12 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseRemoting); 13 | 14 | public override void Initialize(AnalysisContext context) 15 | { 16 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.UsingDirective); 17 | } 18 | 19 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 20 | { 21 | // retrieve using syntax node 22 | var syntax = context.Node as UsingDirectiveSyntax; 23 | // and check if it is System.Runtime.Remoting 24 | if (syntax.Name.ToString().Equals("System.Runtime.Remoting")) 25 | { 26 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseRemoting, syntax.GetLocation()); 27 | context.ReportDiagnostic(diagnostic); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/DoNotUseRemotingResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.AOT { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class DoNotUseRemotingResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal DoNotUseRemotingResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.AOT.DoNotUseRemotingResources", typeof(DoNotUseRemotingResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to AOT Limitation: System.Runtime.Remoting is not supported. . 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to AOT Limitation: System.Runtime.Remoting is not supported. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to AOT Limitation: System.Runtime.Remoting is not supported. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/TypeGetTypeAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers.AOT 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public sealed class TypeGetTypeAnalyzer : DiagnosticAnalyzer 11 | { 12 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.TypeGetType); 13 | public override void Initialize(AnalysisContext context) 14 | { 15 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 16 | } 17 | 18 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 19 | { 20 | var invocationExpression = context.Node as InvocationExpressionSyntax; 21 | var methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; 22 | if (methodSymbol == null) { return; } 23 | 24 | if (methodSymbol.Name.Equals("GetType") && 25 | methodSymbol.ContainingSymbol.ToString().Equals("System.Type")) 26 | { 27 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.TypeGetType, invocationExpression.GetLocation()); 28 | context.ReportDiagnostic(diagnostic); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/AOT/TypeGetTypeResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.AOT { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class TypeGetTypeResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal TypeGetTypeResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.AOT.TypeGetTypeResources", typeof(TypeGetTypeResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to AOT Limitation: Only works for looking up existing types.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to AOT Limitation: Only works for looking up existing types.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to AOT Limitation: Only works for looking up existing types.. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Animator/DoNotUseStateNameAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | 6 | namespace Linty.Analyzers.Animator 7 | { 8 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 9 | public sealed class DoNotUseStateNameAnalyzer : DiagnosticAnalyzer 10 | { 11 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseStateName); 12 | 13 | private static readonly ImmutableHashSet animatorStateNameMethods = ImmutableHashSet.Create( 14 | "GetBool", 15 | "GetFloat", 16 | "GetInteger", 17 | "GetVector", 18 | "GetQuaternion", 19 | "SetBool", 20 | "SetFloat", 21 | "SetInteger", 22 | "SetVector", 23 | "SetQuaternion", 24 | "SetTrigger", 25 | "PlayInFixedTime", 26 | "Play", 27 | "IsParameterControlledByCurve", 28 | "CrossFade", 29 | "CrossFadeInFixedTime"); 30 | 31 | public override void Initialize(AnalysisContext context) 32 | { 33 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 34 | } 35 | 36 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 37 | { 38 | var monoBehaviourInfo = new MonoBehaviourInfo(); 39 | monoBehaviourInfo.IsStringMethod(DiagnosticDescriptors.DoNotUseStateName, "Animator", animatorStateNameMethods, context); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Animator/DoNotUseStateNameResource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Animator { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class DoNotUseStateNameResource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal DoNotUseStateNameResource() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Animator.DoNotUseStateNameResource", typeof(DoNotUseStateNameResource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Animator.StringToHash can convert your state name to hash, it's faster than string comparison. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Use stateNameHash instead of stateName. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Use stateNameHash instead of stateName. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Audio/AudioSourceAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers.Audio 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public class AudioSourceAnalyzer : DiagnosticAnalyzer 11 | { 12 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.AudioSourceMuteUsesCPU); 13 | 14 | public override void Initialize(AnalysisContext context) 15 | { 16 | context.RegisterSyntaxNodeAction(AnalyzeExpressionSyntax, SyntaxKind.ExpressionStatement); 17 | } 18 | 19 | public void AnalyzeExpressionSyntax(SyntaxNodeAnalysisContext context) 20 | { 21 | var method = context.Node as ExpressionStatementSyntax; 22 | 23 | if (method == null) 24 | { 25 | return; 26 | } 27 | 28 | var assigment = method.Expression as AssignmentExpressionSyntax; 29 | 30 | if (assigment?.Left == null) 31 | { 32 | return; 33 | } 34 | 35 | SymbolInfo symbolInfo; 36 | if (!context.TryGetSymbolInfo(assigment.Left, out symbolInfo)) 37 | { 38 | return; 39 | } 40 | 41 | if (symbolInfo.Symbol == null) 42 | { 43 | return; 44 | } 45 | 46 | var containingClass = symbolInfo.Symbol.ContainingType; 47 | var assigmentName = symbolInfo.Symbol.Name; 48 | 49 | // check if the assigment is the one from UnityEngine.AudioSource.mute 50 | if (containingClass.ContainingNamespace.Name.Equals("UnityEngine") && containingClass.Name.Equals("AudioSource") && assigmentName.Equals("mute")) 51 | { 52 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.AudioSourceMuteUsesCPU, method.GetLocation(), containingClass.Name, method.ToString()); 53 | context.ReportDiagnostic(diagnostic); 54 | } 55 | 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Audio/AudioSourceResource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Audio { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class AudioSourceResource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal AudioSourceResource() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Audio.AudioSourceResource", typeof(AudioSourceResource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Audio Source mute sets volume to 0. Use AudioSouce.enabled = false instead to save some CPU cyles. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Audio Source mute uses resources. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Audio Source mute uses resources. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Camera/CameraMainResource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Camera { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class CameraMainResource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal CameraMainResource() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Camera.CameraMainResource", typeof(CameraMainResource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Camera.main uses FindByTag<"MainCamera"> cache this call instead.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Camera.main is slow. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Camera.main is slow. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/CompareTag/UseCompareTagAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using System.Collections.Immutable; 6 | 7 | namespace Linty.Analyzers.CompareTag 8 | { 9 | //TODO: Create a CodeFix provider for this 10 | 11 | 12 | 13 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 14 | public sealed class UseCompareTagAnalyzer : DiagnosticAnalyzer 15 | { 16 | private static readonly ImmutableHashSet ContainingSymbols = ImmutableHashSet.Create("UnityEngine.Component", "UnityEngine.GameObject"); 17 | 18 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.UseCompareTag); 19 | public override void Initialize(AnalysisContext context) 20 | { 21 | context.RegisterSyntaxNodeAction(AnalyzeInvocationExpressionNode, SyntaxKind.InvocationExpression); 22 | context.RegisterSyntaxNodeAction(AnalyzeBinaryExpressionNode, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression); 23 | } 24 | 25 | private static void AnalyzeInvocationExpressionNode(SyntaxNodeAnalysisContext context) 26 | { 27 | // look for an InvocationExpressionSyntax of the form tag.Equals("") or "".Equals(tag) 28 | var invocationExpression = context.Node as InvocationExpressionSyntax; 29 | // check that number of arguments is one 30 | if (invocationExpression.ArgumentList?.Arguments.Count != 1) { return; } 31 | // retrieve the MemberAccessExpression and check that is it "Equals", check that number of arguments is one 32 | var equalsMemberAccessExpression = invocationExpression.Expression as MemberAccessExpressionSyntax; 33 | if (!(equalsMemberAccessExpression?.Name.Identifier.Text.Equals("Equals") ?? false)) { return; } 34 | 35 | // at this point we have an .Equals member access with one argument 36 | // check on both sides if there is a tag member access 37 | if (ProcessPotentialTagMemberAccessExpression(context, equalsMemberAccessExpression.Expression) || 38 | ProcessPotentialTagMemberAccessExpression(context, invocationExpression.ArgumentList.Arguments[0].Expression)) 39 | { 40 | ReportDiagnostic(context, invocationExpression.GetLocation()); 41 | } 42 | } 43 | 44 | private static void AnalyzeBinaryExpressionNode(SyntaxNodeAnalysisContext context) 45 | { 46 | // look for tag == "" or tag != "" 47 | var binaryExpression = context.Node as BinaryExpressionSyntax; 48 | if (ProcessPotentialTagMemberAccessExpression(context, binaryExpression.Left) || 49 | ProcessPotentialTagMemberAccessExpression(context, binaryExpression.Right)) 50 | { 51 | ReportDiagnostic(context, binaryExpression.GetLocation()); 52 | } 53 | } 54 | 55 | private static bool ProcessPotentialTagMemberAccessExpression(SyntaxNodeAnalysisContext context, ExpressionSyntax expression) 56 | { 57 | // check for member access or identifier access 58 | if (expression is MemberAccessExpressionSyntax || expression is IdentifierNameSyntax) 59 | { 60 | // check for property access 61 | var propertySymbol = context.SemanticModel.GetSymbolInfo(expression).Symbol as IPropertySymbol; 62 | // check that property accessed is tag and belongs to UnityEngine 63 | if (propertySymbol?.Name.Equals("tag") ?? false && //TODO: Either fix this statement or remove this check 64 | ContainingSymbols.Contains(propertySymbol.ContainingSymbol.ToString())) 65 | { return true; } 66 | } 67 | 68 | return false; 69 | } 70 | 71 | private static void ReportDiagnostic(SyntaxNodeAnalysisContext context, Location location) 72 | { 73 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.UseCompareTag, location); 74 | context.ReportDiagnostic(diagnostic); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/CompareTag/UseCompareTagResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.CompareTag { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class UseCompareTagResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal UseCompareTagResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.CompareTag.UseCompareTagResources", typeof(UseCompareTagResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Comparing a Tag using Equals operator can cause unecessary memory allocation. Use the CompareTag function Instead.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Use CompareTag instead of using the Equals operator. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Use CompareTag. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Coroutines/DoNotUseCoroutinesAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers.Coroutines 8 | { 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public sealed class DoNotUseCoroutinesAnalyzer : DiagnosticAnalyzer 11 | { 12 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseCoroutines); 13 | public override void Initialize(AnalysisContext context) 14 | { 15 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 16 | } 17 | 18 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 19 | { 20 | // check if we have a method invocation 21 | var invocationExpression = context.Node as InvocationExpressionSyntax; 22 | var methodSymbol = context.SemanticModel.GetSymbolInfo(invocationExpression).Symbol as IMethodSymbol; 23 | if (methodSymbol == null) { return; } 24 | 25 | // check that the method is StartCoroutine from UnityEngine 26 | if (methodSymbol.Name.Equals("StartCoroutine") && 27 | methodSymbol.ContainingSymbol.ToString().Equals("UnityEngine.MonoBehaviour")) 28 | { 29 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseCoroutines, invocationExpression.GetLocation()); 30 | context.ReportDiagnostic(diagnostic); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Coroutines/DoNotUseCoroutinesResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Coroutines { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class DoNotUseCoroutinesResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal DoNotUseCoroutinesResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Coroutines.DoNotUseCoroutinesResources", typeof(DoNotUseCoroutinesResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Use of coroutines is known to cause some allocations.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Use of coroutines is known to cause some allocations.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Use of coroutines is known to cause some allocations.. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Diagnostic.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | UnityEngineAnalyzer 5 | 1.0.0.0 6 | UnityEngineAnalyzer 7 | Meng Hui Koh 8 | Meng Hui Koh 9 | https://raw.githubusercontent.com/meng-hui/UnityEngineAnalyzer/master/LICENSE 10 | https://github.com/meng-hui/UnityEngineAnalyzer 11 | false 12 | UnityEngineAnalyzer is a set of Roslyn analyzers that aim to detect common problems in Unity3D C# code. Unity3D makes it easy for us to make cross platform games, but there are hidden rules about performance and AOT, which might only come with experience, testing or reading the forums. It is hoped that such problems can be caught before compilation. 13 | Initial Release. 14 | Copyright © Meng Hui Koh 2016 15 | UnityEngineAnalyzer, analyzers, UnityEngine, Roslyn 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/DiagnosticCategories.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Linty.Analyzers 3 | { 4 | static class DiagnosticCategories 5 | { 6 | public const string GC = "GC"; 7 | public const string Miscellaneous = "Miscellaneous"; 8 | public const string Performance = "Performance"; 9 | 10 | public const string AOT = "AOT"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/DiagnosticIDs.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace Linty.Analyzers 3 | { 4 | public static class DiagnosticIDs 5 | { 6 | public const string DoNotUseOnGUI = "UEA0001"; 7 | public const string DoNotUseStringMethods = "UEA0002"; 8 | public const string EmptyMonoBehaviourMethod = "UEA0003"; 9 | public const string UseCompareTag = "UEA0004"; 10 | public const string DoNotUseFindMethodsInUpdate = "UEA0005"; 11 | public const string DoNotUseCoroutines = "UEA0006"; 12 | public const string DoNotUseForEachInUpdate = "UEA0007"; 13 | public const string UnsealedDerivedClass = "UEA0008"; 14 | public const string InvokeFunctionMissing = "UEA0009"; 15 | public const string DoNotUseStateNameInAnimator = "UEA0010"; 16 | public const string DoNotUseStringPropertyNames = "UEA0011"; 17 | public const string CameraMainIsSlow = "UEA0012"; 18 | public const string PhysicsUseNonAllocMethods = "UEA0013"; 19 | public const string AudioSourceMuteUsesCPU = "UEA0014"; 20 | public const string InstantiateShouldTakeParentArgument = "UEA0015"; 21 | public const string VectorMagnitudeIsSlow = "UEA0016"; 22 | 23 | //NOTES: These should probably be on their own analyzer - as they are not specific to Unity 24 | public const string DoNotUseRemoting = "AOT0001"; 25 | public const string DoNotUseReflectionEmit = "AOT0002"; 26 | public const string TypeGetType = "AOT0003"; 27 | 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/EmptyMonoBehaviourMethods/EmptyMonoBehaviourMethodsAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.Diagnostics; 3 | 4 | namespace Linty.Analyzers.EmptyMonoBehaviourMethods 5 | { 6 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 7 | public sealed class EmptyMonoBehaviourMethodsAnalyzer : LintyAnalyzer 8 | { 9 | public EmptyMonoBehaviourMethodsAnalyzer() 10 | { 11 | this.ForEachMonoBehaviour(AnalyzeMonoBehaviour); 12 | } 13 | 14 | private void AnalyzeMonoBehaviour(MonoBehaviourInfo monoBehaviour) 15 | { 16 | monoBehaviour.ForEachMonoBehaviourMethod(m => 17 | { 18 | // from the method syntax, check if there is a body and if there are statements in it 19 | if (m.Body?.Statements.Count == 0) 20 | { 21 | var methodName = m.Identifier.ValueText; 22 | 23 | base.ReportDiagnostic(m.GetLocation(), monoBehaviour.ClassName, methodName); 24 | } 25 | }); 26 | } 27 | 28 | public override DiagnosticDescriptor GetDiagnosticDescriptor() 29 | { 30 | return DiagnosticDescriptors.EmptyMonoBehaviourMethod; 31 | } 32 | 33 | // public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.EmptyMonoBehaviourMethod); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/ForEachInUpdate/DoNotUseForEachInUpdate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Immutable; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | using Microsoft.CodeAnalysis.Diagnostics; 9 | 10 | namespace Linty.Analyzers.ForEachInUpdate 11 | { 12 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 13 | public sealed class DoNotUseForEachInUpdate : DiagnosticAnalyzer 14 | { 15 | 16 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseForEachInUpdate); 17 | public override void Initialize(AnalysisContext context) 18 | { 19 | context.RegisterSyntaxNodeAction(AnalyzeClassSyntax, SyntaxKind.ClassDeclaration); 20 | } 21 | 22 | public static void AnalyzeClassSyntax(SyntaxNodeAnalysisContext context) 23 | { 24 | var monoBehaviourInfo = new MonoBehaviourInfo(context); 25 | 26 | var searched = new Dictionary(); 27 | monoBehaviourInfo.ForEachUpdateMethod((updateMethod) => 28 | { 29 | var forEachStatements = SearchForForEach(context, updateMethod, searched); 30 | 31 | foreach (var forEachStatement in forEachStatements) 32 | { 33 | Debug.WriteLine("Found a bad call! " + forEachStatement); 34 | 35 | var location = forEachStatement.ForEachKeyword.GetLocation(); 36 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseForEachInUpdate, location, monoBehaviourInfo.ClassName ,updateMethod.Identifier); 37 | context.ReportDiagnostic(diagnostic); 38 | } 39 | }); 40 | } 41 | 42 | 43 | private static IEnumerable SearchForForEach(SyntaxNodeAnalysisContext context, MethodDeclarationSyntax method, IDictionary searched) 44 | { 45 | var invocations = method.DescendantNodes().OfType(); 46 | 47 | foreach (var invocation in invocations) 48 | { 49 | yield return invocation; 50 | } 51 | 52 | //TODO: Keep Searching recurively to other methods... 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/IL2CPP/UnsealedDerivedClassAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Linq; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.CSharp.Syntax; 6 | using Microsoft.CodeAnalysis.Diagnostics; 7 | 8 | namespace Linty.Analyzers.IL2CPP 9 | { 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public class UnsealedDerivedClassAnalyzer : DiagnosticAnalyzer 12 | { 13 | public override void Initialize(AnalysisContext context) 14 | { 15 | context.RegisterSyntaxNodeAction(AnalyzeClassSyntax, SyntaxKind.ClassDeclaration); 16 | } 17 | 18 | private void AnalyzeClassSyntax(SyntaxNodeAnalysisContext context) 19 | { 20 | var classDeclaration = (ClassDeclarationSyntax)context.Node; 21 | 22 | if (classDeclaration.IsDerived() && !classDeclaration.IsSealed()) 23 | { 24 | var methods = classDeclaration.Members.OfType(); 25 | 26 | foreach (var method in methods) 27 | { 28 | 29 | if (method.IsOverriden() && !method.IsSealed()) 30 | { 31 | var diagnostic = Diagnostic.Create(SupportedDiagnostics.First(), method.GetLocation(), 32 | method.Identifier.ToString(), classDeclaration.Identifier.ToString()); 33 | 34 | context.ReportDiagnostic(diagnostic); 35 | } 36 | } 37 | } 38 | } 39 | 40 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.UnsealedDerivedClass); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/IL2CPP/UnsealedDerivedClassResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.IL2CPP { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class UnsealedDerivedClassResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal UnsealedDerivedClassResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.IL2CPP.UnsealedDerivedClassResources", typeof(UnsealedDerivedClassResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Unsealed Methods in Derived classes can impact performance. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Method {0} in Derived Class {1} is not sealed. Sealing the method or class improves performance.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Unsealed Derived Class. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/LintyAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace Linty.Analyzers 8 | { 9 | public abstract class LintyAnalyzer : DiagnosticAnalyzer 10 | { 11 | private Action _forEachMonoBehaviourCallback; 12 | private SyntaxNodeAnalysisContext? _context; 13 | 14 | public abstract DiagnosticDescriptor GetDiagnosticDescriptor(); 15 | 16 | public override void Initialize(AnalysisContext context) 17 | { 18 | if (_forEachMonoBehaviourCallback != null) 19 | { 20 | context.RegisterSyntaxNodeAction(AnalyzeMonoBehavourClassSyntax, SyntaxKind.ClassDeclaration); 21 | } 22 | } 23 | 24 | private void AnalyzeMonoBehavourClassSyntax(SyntaxNodeAnalysisContext context) 25 | { 26 | _context = context; 27 | 28 | var monoBehaviour = new MonoBehaviourInfo(context); 29 | 30 | if (monoBehaviour.IsMonoBehaviour()) 31 | { 32 | _forEachMonoBehaviourCallback(monoBehaviour); 33 | } 34 | } 35 | 36 | internal void ReportDiagnostic(Location location, string className, string methodName) 37 | { 38 | if (_context != null) 39 | { 40 | var diagnostic = Diagnostic.Create(this.GetDiagnosticDescriptor(), location, className, methodName); 41 | _context?.ReportDiagnostic(diagnostic); 42 | } 43 | } 44 | 45 | 46 | 47 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(this.GetDiagnosticDescriptor()); 48 | 49 | /// 50 | /// Allows Analyis of a Unity MonoBehaviour 51 | /// 52 | /// Function to call to analyze each MonoBehaviour 53 | public void ForEachMonoBehaviour(Action callback) 54 | { 55 | _forEachMonoBehaviourCallback = callback; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Material/DoNotUseStringPropertyNamesAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | 6 | namespace Linty.Analyzers.Material 7 | { 8 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 9 | public class DoNotUseStringPropertyNamesAnalyzer : DiagnosticAnalyzer 10 | { 11 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseStringPropertyNames); 12 | 13 | private static readonly ImmutableHashSet materialStringPropertyMethods = ImmutableHashSet.Create( 14 | "GetColor", 15 | "GetColorArray", 16 | "GetFloat", 17 | "GetFloatArray", 18 | "GetInt", 19 | "GetMatrix", 20 | "GetMatrixArray", 21 | "GetTexture", 22 | "GetTextureOffset", 23 | "GetTextureScale", 24 | "GetVector", 25 | "GetVectorArray", 26 | "SetBuffer", 27 | "SetColor", 28 | "SetColorArray", 29 | "SetFloat", 30 | "SetFloatArray", 31 | "SetInt", 32 | "SetMatrix", 33 | "SetMatrixArray", 34 | "SetTexture", 35 | "SetTextureOffset", 36 | "SetTextureScale", 37 | "SetVector", 38 | "SetVectorArray"); 39 | 40 | public override void Initialize(AnalysisContext context) 41 | { 42 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 43 | } 44 | 45 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 46 | { 47 | var monoBehaviourInfo = new MonoBehaviourInfo(); 48 | monoBehaviourInfo.IsStringMethod(DiagnosticDescriptors.DoNotUseStringPropertyNames, "Material", materialStringPropertyMethods, context); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/OnGUI/DoNotUseOnGUIAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | 5 | namespace Linty.Analyzers.OnGUI 6 | { 7 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 8 | public sealed class DoNotUseOnGUIAnalyzer : DiagnosticAnalyzer 9 | { 10 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseOnGUI); 11 | 12 | public override void Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext context) 13 | { 14 | context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method); 15 | } 16 | 17 | private static void AnalyzeSymbol(SymbolAnalysisContext context) 18 | { 19 | // check if the method is name OnGUI 20 | var methodSymbol = context.Symbol as IMethodSymbol; 21 | if (!methodSymbol.Name.Equals("OnGUI")) { return; } 22 | 23 | // check that it is contained in a class extended by UnityEngine.MonoBehaviour 24 | var containingClass = methodSymbol.ContainingType; 25 | var baseClass = containingClass.BaseType; 26 | if (baseClass.ContainingNamespace.Name.Equals("UnityEngine") && 27 | baseClass.Name.Equals("MonoBehaviour")) 28 | { 29 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseOnGUI, methodSymbol.Locations[0], containingClass.Name); 30 | context.ReportDiagnostic(diagnostic); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/OnGUI/DoNotUseOnGUIResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.OnGUI { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class DoNotUseOnGUIResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal DoNotUseOnGUIResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.OnGUI.DoNotUseOnGUIResources", typeof(DoNotUseOnGUIResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Usage of OnGUI is known to cause GC and/or performance issues.. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to '{0}' implements OnGUI. This is known to cause GC and/or performance issues.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Do not use OnGUI in MonoBehaviours.. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Physics/UseNonAllocMethodsAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Immutable; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.CSharp.Syntax; 6 | using Microsoft.CodeAnalysis.Diagnostics; 7 | 8 | namespace Linty.Analyzers.Physics 9 | { 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public sealed class UseNonAllocMethodsAnalyzer : DiagnosticAnalyzer 12 | { 13 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.UseNonAllocMethods); 14 | 15 | private static readonly ImmutableHashSet PhysicsAllocatingCasts = ImmutableHashSet.Create( 16 | "BoxCastAll", 17 | "CapsuleCastAll", 18 | "OverlapBox", 19 | "OverlapCapsule", 20 | "OverlapSphere", 21 | "RaycastAll", 22 | "SphereCastAll"); 23 | 24 | private static readonly ImmutableHashSet Physics2DAllocatingCasts = ImmutableHashSet.Create( 25 | "BoxCastAll", 26 | "CapsuleCastAll", 27 | "CircleCastAll", 28 | "GetRayIntersectionAll", 29 | "LinecastAll", 30 | "OverlapAreaAll", 31 | "OverlapBoxAll", 32 | "OverlapCapsuleAll", 33 | "OverlapCircleAll", 34 | "OverlapPointAll", 35 | "RaycastAll"); 36 | 37 | public override void Initialize(AnalysisContext context) 38 | { 39 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 40 | } 41 | 42 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 43 | { 44 | var invocation = context.Node as InvocationExpressionSyntax; 45 | if (invocation == null) 46 | { 47 | return; 48 | } 49 | 50 | var name = invocation.MethodName(); 51 | 52 | List containingClassName = new List(); 53 | 54 | // check if any of the methods are used 55 | if (PhysicsAllocatingCasts.Contains(name)) 56 | { 57 | containingClassName.Add("Physics"); 58 | } 59 | 60 | if (Physics2DAllocatingCasts.Contains(name)) 61 | { 62 | containingClassName.Add("Physics2D"); 63 | } 64 | 65 | if (containingClassName.Count == 0) 66 | { 67 | return; 68 | } 69 | 70 | var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation); 71 | var methodSymbol = symbolInfo.Symbol as IMethodSymbol; 72 | 73 | var containingType = methodSymbol.ContainingType; 74 | 75 | // check if the method is the one from UnityEngine.Physics 76 | if (containingType.ContainingNamespace.Name.Equals("UnityEngine") && containingClassName.Contains(containingType.Name)) 77 | { 78 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.UseNonAllocMethods, invocation.GetLocation(), containingType.Name, methodSymbol.Name); 79 | context.ReportDiagnostic(diagnostic); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Physics/UseNonAllocMethodsResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Physics { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class UseNonAllocMethodsResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal UseNonAllocMethodsResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Physics.UseNonAllocMethodsResources", typeof(UseNonAllocMethodsResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to These calls have NonAlloc version since Unity 5.3. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to '{0}' has non allocating version.. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to This call has non allocating version.. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/ReadMe.txt: -------------------------------------------------------------------------------- 1 |  2 | Building this project will produce an analyzer .dll, as well as the 3 | following two ways you may wish to package that analyzer: 4 | * A NuGet package (.nupkg file) that will add your assembly as a 5 | project-local analyzer that participates in builds. 6 | * A VSIX extension (.vsix file) that will apply your analyzer to all projects 7 | and works just in the IDE. 8 | 9 | To debug your analyzer, make sure the default project is the VSIX project and 10 | start debugging. This will deploy the analyzer as a VSIX into another instance 11 | of Visual Studio, which is useful for debugging, even if you intend to produce 12 | a NuGet package. 13 | 14 | 15 | TRYING OUT YOUR NUGET PACKAGE 16 | 17 | To try out the NuGet package: 18 | 1. Create a local NuGet feed by following the instructions here: 19 | > http://docs.nuget.org/docs/creating-packages/hosting-your-own-nuget-feeds 20 | 2. Copy the .nupkg file into that folder. 21 | 3. Open the target project in Visual Studio 2015. 22 | 4. Right-click on the project node in Solution Explorer and choose Manage 23 | NuGet Packages. 24 | 5. Select the NuGet feed you created on the left. 25 | 6. Choose your analyzer from the list and click Install. 26 | 27 | If you want to automatically deploy the .nupkg file to the local feed folder 28 | when you build this project, follow these steps: 29 | 1. Right-click on this project in Solution Explorer and choose 'Unload Project'. 30 | 2. Right-click on this project and click "Edit". 31 | 3. Scroll down to the "AfterBuild" target. 32 | 4. In the "Exec" task, change the value inside "Command" after the -OutputDirectory 33 | path to point to your local NuGet feed folder. -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Shader/DoNotUseStringPropertyNamesShaderAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using System.Collections.Immutable; 5 | 6 | namespace Linty.Analyzers.Shader 7 | { 8 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 9 | public class DoNotUseStringPropertyNamesShaderAnalyzer : DiagnosticAnalyzer 10 | { 11 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseStringPropertyNames); 12 | 13 | private static readonly ImmutableHashSet shaderStringPropertyMethods = ImmutableHashSet.Create( 14 | "GetGlobalColor", 15 | "GetGlobalFloat", 16 | "GetGlobalFloatArray", 17 | "GetGlobalInt", 18 | "GetGlobalMatrix", 19 | "GetGlobalMatrixArray", 20 | "GetGlobalTexture", 21 | "GetGlobalVector", 22 | "GetGlobalVectorArray", 23 | "SetGlobalBuffer", 24 | "SetGlobalColor", 25 | "SetGlobalFloat", 26 | "SetGlobalFloatArray", 27 | "SetGlobalInt", 28 | "SetGlobalMatrix", 29 | "SetGlobalMatrixArray", 30 | "SetGlobalTexture", 31 | "SetGlobalVector", 32 | "SetGlobalVectorArray"); 33 | 34 | public override void Initialize(AnalysisContext context) 35 | { 36 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 37 | } 38 | 39 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 40 | { 41 | var monoBehaviourInfo = new MonoBehaviourInfo(); 42 | monoBehaviourInfo.IsStringMethod(DiagnosticDescriptors.DoNotUseStringPropertyNames, "Shader", shaderStringPropertyMethods, context); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/StringMethods/DoNotUseStringMethodsAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using System.Collections.Immutable; 6 | using System.Linq; 7 | 8 | namespace Linty.Analyzers.StringMethods 9 | { 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public sealed class DoNotUseStringMethodsAnalyzer : DiagnosticAnalyzer 12 | { 13 | private static readonly ImmutableHashSet StringMethods = ImmutableHashSet.Create("SendMessage", "SendMessageUpwards", "BroadcastMessage"); 14 | private static readonly ImmutableHashSet Namespaces = ImmutableHashSet.Create("UnityEngine.Component", "UnityEngine.GameObject", "UnityEngine.MonoBehaviour"); 15 | 16 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.DoNotUseStringMethods); 17 | 18 | public override void Initialize(AnalysisContext context) 19 | { 20 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression); 21 | } 22 | 23 | private static void AnalyzeNode(SyntaxNodeAnalysisContext context) 24 | { 25 | var invocation = context.Node as InvocationExpressionSyntax; 26 | if (invocation == null) 27 | { 28 | return; 29 | } 30 | 31 | var name = invocation.MethodName(); 32 | 33 | 34 | // check if any of the "string" methods are used 35 | if (!StringMethods.Contains(name)) { return; } 36 | 37 | 38 | // check if the method is the one from UnityEngine 39 | var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation); 40 | var methodSymbol = symbolInfo.Symbol as IMethodSymbol; 41 | 42 | if (Namespaces.Any(ns => methodSymbol?.ToString().StartsWith(ns) ?? false)) 43 | { 44 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.DoNotUseStringMethods, invocation.GetLocation()); 45 | context.ReportDiagnostic(diagnostic); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/StringMethods/InvokeFunctionMissingAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | using Microsoft.CodeAnalysis.Diagnostics; 9 | 10 | namespace Linty.Analyzers.StringMethods 11 | { 12 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 13 | public class InvokeFunctionMissingAnalyzer : DiagnosticAnalyzer 14 | { 15 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.InvokeFunctionMissing); 16 | private static readonly ImmutableHashSet InvokeMethods = ImmutableHashSet.Create("Invoke", "InvokeRepeating"); 17 | private static readonly string InvokeMethodTypeName = "UnityEngine.MonoBehaviour"; 18 | 19 | public override void Initialize(AnalysisContext context) 20 | { 21 | context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression); 22 | } 23 | 24 | private void AnalyzeInvocation(SyntaxNodeAnalysisContext context) 25 | { 26 | var invocation = context.Node as InvocationExpressionSyntax; 27 | if (invocation == null) 28 | { 29 | return; 30 | } 31 | 32 | var methodName = invocation.MethodName(); 33 | 34 | if (InvokeMethods.Contains(methodName)) 35 | { 36 | // check if the method is the one from UnityEngine 37 | var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation); 38 | var methodSymbol = symbolInfo.Symbol as IMethodSymbol; 39 | 40 | var fullTypeName = methodSymbol?.ContainingType.ToString(); 41 | 42 | if (fullTypeName == InvokeMethodTypeName && invocation.ArgumentList.Arguments.Count > 0) 43 | { 44 | var firstArgumentExpression = invocation.ArgumentList.Arguments[0]; 45 | 46 | var invokedMethodName = firstArgumentExpression.GetArgumentValue(); 47 | 48 | var containingClassDeclaration = invocation.Ancestors().FirstOrDefault(a => a is ClassDeclarationSyntax) as ClassDeclarationSyntax; 49 | 50 | var allMethods = containingClassDeclaration?.Members.OfType(); 51 | 52 | var invokeEndPoint = allMethods.FirstOrDefault(m => m.Identifier.ValueText == invokedMethodName); 53 | 54 | if (invokeEndPoint == null) 55 | { 56 | var diagnostic = Diagnostic.Create(DiagnosticDescriptors.InvokeFunctionMissing, firstArgumentExpression.GetLocation(), methodName, invokedMethodName); 57 | 58 | context.ReportDiagnostic(diagnostic); 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/StringMethods/InvokeFunctionMissingResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.StringMethods { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class InvokeFunctionMissingResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal InvokeFunctionMissingResources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.StringMethods.InvokeFunctionMissingResources", typeof(InvokeFunctionMissingResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to The function being invoked does not exist. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to The function "{0}" is invoking the method "{1}" that does not exist. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Invoke Function is Missing. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Transform/InstantiateResource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Linty.Analyzers.Transform { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class InstantiateResource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal InstantiateResource() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Linty.Analyzers.Transform.InstantiateResource", typeof(InstantiateResource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Instantiate can take parent as parameter, so setParent don't dirty the transform hierarchy. 65 | /// 66 | internal static string Description { 67 | get { 68 | return ResourceManager.GetString("Description", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Instantiate should take the parent as parameter. 74 | /// 75 | internal static string MessageFormat { 76 | get { 77 | return ResourceManager.GetString("MessageFormat", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Instantiate should take the parent as parameter. 83 | /// 84 | internal static string Title { 85 | get { 86 | return ResourceManager.GetString("Title", resourceCulture); 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/UnityVersions.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngineAnalyzer 2 | { 3 | public class UnityVersionSpan 4 | { 5 | public UnityVersion First { get; set; } 6 | public UnityVersion Last { get; set; } 7 | 8 | public UnityVersionSpan (UnityVersion first, UnityVersion last) 9 | { 10 | First = first; 11 | Last = last; 12 | } 13 | } 14 | 15 | public enum UnityVersion 16 | { 17 | NONE, 18 | UNITY_1_0, 19 | UNITY_2_0, 20 | UNITY_3_0, 21 | UNITY_3_5, 22 | UNITY_4_0, 23 | UNITY_4_1, 24 | UNITY_4_2, 25 | UNITY_4_3, 26 | UNITY_4_4, 27 | UNITY_4_5, 28 | UNITY_4_6, 29 | UNITY_4_7, 30 | UNITY_5_0, 31 | UNITY_5_1, 32 | UNITY_5_2, 33 | UNITY_5_3, 34 | UNITY_5_4, 35 | UNITY_5_5, 36 | UNITY_5_6, 37 | UNITY_2017_0, 38 | UNITY_2017_1, 39 | UNITY_2017_2, 40 | UNITY_2017_3, 41 | LATEST, 42 | } 43 | } -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/Vector/VectorAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using System.Collections.Immutable; 6 | using System.Linq; 7 | 8 | namespace Linty.Analyzers.Vector 9 | { 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public sealed class VectorAnalyzer : DiagnosticAnalyzer 12 | { 13 | public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptors.VectorMagnitudeIsSlow); 14 | 15 | public override void Initialize(AnalysisContext context) 16 | { 17 | context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.SimpleMemberAccessExpression); 18 | } 19 | 20 | public void AnalyzeNode(SyntaxNodeAnalysisContext context) 21 | { 22 | var memberAccess = (context.Node as MemberAccessExpressionSyntax); 23 | 24 | if (memberAccess == null) 25 | { 26 | return; 27 | } 28 | 29 | SymbolInfo symbolInfo; 30 | if (!context.TryGetSymbolInfo(memberAccess, out symbolInfo)) 31 | { 32 | return; 33 | } 34 | 35 | var containingClass = symbolInfo.Symbol?.ContainingType; 36 | 37 | if (containingClass != null && containingClass.ContainingNamespace.Name.Equals("UnityEngine") && (containingClass.Name.Equals("Vector3") || containingClass.Name.Equals("Vector2"))) 38 | { 39 | if (symbolInfo.Symbol.Name.Equals("magnitude")) 40 | { 41 | var diagnostic = Diagnostic.Create(SupportedDiagnostics[0], memberAccess.GetLocation(), memberAccess.Name, symbolInfo.Symbol.Name); 42 | context.ReportDiagnostic(diagnostic); 43 | } 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Install the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | # $project.Type gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Install language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /UnityEngineAnalyzer/Linty.Analyzers/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Uninstall the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | # $project.Type gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Uninstall language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | try 46 | { 47 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 48 | } 49 | catch 50 | { 51 | 52 | } 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /UnityEngineAnalyzer/UnityEngineAnalyzer.Vsix/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Meng Hui Koh, Vinny DaSilva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/UnityEngineAnalyzer.Vsix/UnityEngineAnalyzer.Vsix.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 15.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | 14.0 11 | 12 | 13 | 14 | 15 | Debug 16 | AnyCPU 17 | 2.0 18 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | {23A41489-857C-4FC7-9B96-2F20D8EE380B} 20 | Library 21 | Properties 22 | UnityEngineAnalyzer.Vsix 23 | UnityEngineAnalyzer.Vsix 24 | v4.6.1 25 | false 26 | false 27 | false 28 | false 29 | false 30 | false 31 | Roslyn 32 | 33 | 34 | true 35 | full 36 | false 37 | bin\Debug\ 38 | DEBUG;TRACE 39 | prompt 40 | 4 41 | 42 | 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | 50 | 51 | Program 52 | $(DevEnvDir)devenv.exe 53 | /rootsuffix Roslyn 54 | 55 | 56 | 57 | Designer 58 | 59 | 60 | 61 | 62 | Always 63 | true 64 | 65 | 66 | 67 | 68 | {d43efdfb-bb7f-4a9b-9a60-c79b9404342a} 69 | Linty.Analyzers 70 | 71 | 72 | 73 | 74 | 81 | -------------------------------------------------------------------------------- /UnityEngineAnalyzer/UnityEngineAnalyzer.Vsix/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Linty.Analyzers 6 | Linty aims to provide Roslyn diagnostics for common problems and performance issues in Unity3D code. (Formerly UnityEngineAnalyzer) 7 | LICENSE.txt 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------