diff --git a/src/Microsoft.Unity.Analyzers.Tests/ConsistencyTests.cs b/src/Microsoft.Unity.Analyzers.Tests/ConsistencyTests.cs index 9735ec89..6674d9de 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/ConsistencyTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/ConsistencyTests.cs @@ -129,4 +129,46 @@ public async Task CheckHelpLinks() } } + [SkippableFact] + public void CheckCodeFixTestsHaveTriviaTests() + { + var assembly = typeof(ConsistencyTests).Assembly; + + var codeFixTestClasses = assembly + .GetTypes() + .Where(t => t is { IsClass: true, IsAbstract: false } && IsBaseCodeFixVerifierTest(t)) + .ToArray(); + + List missingTriviaTests = []; + + foreach (var testClass in codeFixTestClasses) + { + if (testClass + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m.GetCustomAttributes(typeof(FactAttribute), true).Any() || + m.GetCustomAttributes(typeof(TheoryAttribute), true).Any()) + .Any(m => m.Name.Contains("Trivia", StringComparison.OrdinalIgnoreCase))) + continue; + + missingTriviaTests.Add(testClass.Name); + } + + Skip.If(missingTriviaTests.Any(), $"The following CodeFix test classes ({(float)missingTriviaTests.Count / codeFixTestClasses.Length:0.00%}) are missing a Trivia test:\n\n{string.Join("\n", missingTriviaTests)}"); + } + + private static bool IsBaseCodeFixVerifierTest(Type type) + { + // IsAssignableFrom cannot be used with open generic types + var baseType = type.BaseType; + while (baseType != null) + { + if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(BaseCodeFixVerifierTest<,>)) + return true; + + baseType = baseType.BaseType; + } + + return false; + } + } diff --git a/src/Microsoft.Unity.Analyzers.Tests/CreateInstanceTests.cs b/src/Microsoft.Unity.Analyzers.Tests/CreateInstanceTests.cs index cbe889a2..fa750942 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/CreateInstanceTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/CreateInstanceTests.cs @@ -87,7 +87,7 @@ public void Method(Foo foo) { [Fact] - public async Task CreateComponentInstanceComments() + public async Task CreateComponentInstanceTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/EmptyUnityMessageTests.cs b/src/Microsoft.Unity.Analyzers.Tests/EmptyUnityMessageTests.cs index dd994bdc..db4ceea3 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/EmptyUnityMessageTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/EmptyUnityMessageTests.cs @@ -11,7 +11,7 @@ namespace Microsoft.Unity.Analyzers.Tests; public class EmptyUnityMessageTests : BaseCodeFixVerifierTest { [Fact] - public async Task EmptyFixedUpdate() + public async Task EmptyFixedUpdateTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/GetLocalPositionAndRotationTests.cs b/src/Microsoft.Unity.Analyzers.Tests/GetLocalPositionAndRotationTests.cs index 684f454a..4cb7c1bf 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/GetLocalPositionAndRotationTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/GetLocalPositionAndRotationTests.cs @@ -115,4 +115,52 @@ void Update() await VerifyCSharpDiagnosticAsync(test); } + + [SkippableFact] + public async Task UseGetLocalPositionAndRotationMethodTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Quaternion rotation; + // rotation comment + rotation = transform.localRotation; + // position comment + var position = transform.localPosition; + // trailing comment + } +} +"; + + var method = GetCSharpDiagnosticAnalyzer().ExpressionContext.PositionAndRotationMethodName; + var type = typeof(UnityEngine.Transform); + + Skip.IfNot(MethodExists("UnityEngine", type.FullName!, method), $"This Unity version does not support {type}.{method}"); + + var diagnostic = ExpectDiagnostic().WithLocation(10, 9); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Quaternion rotation; + // rotation comment + // position comment + transform.GetLocalPositionAndRotation(out var position, out rotation); + // trailing comment + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/GetPositionAndRotationTests.cs b/src/Microsoft.Unity.Analyzers.Tests/GetPositionAndRotationTests.cs index d96b0363..2d8a6ca7 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/GetPositionAndRotationTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/GetPositionAndRotationTests.cs @@ -242,4 +242,49 @@ void Update() // Implicit conversion incompatible with 'out' await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task UseGetPositionAndRotationMethodAssignmentTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 position; + Quaternion rotation; + // position comment + position = transform.position; + // rotation comment + rotation = transform.rotation; + // trailing comment + } +} +"; + + var diagnostic = ExpectDiagnostic().WithLocation(11, 9); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 position; + Quaternion rotation; + // position comment + // rotation comment + transform.GetPositionAndRotation(out position, out rotation); + // trailing comment + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/ImproperMenuItemMethodTests.cs b/src/Microsoft.Unity.Analyzers.Tests/ImproperMenuItemMethodTests.cs index 509964ff..99135d3d 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/ImproperMenuItemMethodTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/ImproperMenuItemMethodTests.cs @@ -47,7 +47,7 @@ private static void Menu1() } [Fact] - public async Task MissingStaticDeclarationComments() + public async Task MissingStaticDeclarationTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/ImproperMessageCaseTests.cs b/src/Microsoft.Unity.Analyzers.Tests/ImproperMessageCaseTests.cs index 14d27c90..dc7d0e9b 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/ImproperMessageCaseTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/ImproperMessageCaseTests.cs @@ -287,6 +287,43 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse { } } +"; + await VerifyCSharpFixAsync(test, fixedTest); + } + + [Fact] + public async Task ImproperlyCasedUpdateTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + // comment + private void /* inner */ UPDATE /* outer */ () + { + } + /* comment */ +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(7, 30) + .WithArguments("UPDATE"); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + // comment + private void /* inner */ Update /* outer */ () + { + } + /* comment */ +} "; await VerifyCSharpFixAsync(test, fixedTest); } diff --git a/src/Microsoft.Unity.Analyzers.Tests/ImproperSerializeFieldTests.cs b/src/Microsoft.Unity.Analyzers.Tests/ImproperSerializeFieldTests.cs index 63053c2f..b6ea740a 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/ImproperSerializeFieldTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/ImproperSerializeFieldTests.cs @@ -58,7 +58,7 @@ class Camera : MonoBehaviour } [Fact] - public async Task RedundantSerializeFieldComments() + public async Task RedundantSerializeFieldTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/IndirectionMessageTests.cs b/src/Microsoft.Unity.Analyzers.Tests/IndirectionMessageTests.cs index cbc3b138..fc323007 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/IndirectionMessageTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/IndirectionMessageTests.cs @@ -79,7 +79,7 @@ private void Method(GameObject argument) } [Fact] - public async Task RemoveGameObjectPropertyComments() + public async Task RemoveGameObjectPropertyTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/InitializeOnLoadStaticCtorTests.cs b/src/Microsoft.Unity.Analyzers.Tests/InitializeOnLoadStaticCtorTests.cs index 7538514f..31fcae37 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/InitializeOnLoadStaticCtorTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/InitializeOnLoadStaticCtorTests.cs @@ -77,6 +77,47 @@ static Camera() public static readonly int willGenerateImplicitStaticCtor = 666; } +"; + await VerifyCSharpFixAsync(test, fixedTest); + } + + [Fact] + public async Task InitializeOnLoadWithoutStaticCtorTrivia() + { + const string test = @" +using UnityEngine; +using UnityEditor; + +[InitializeOnLoad] +class Camera : MonoBehaviour +{ + // comment + private int field = 0; + /* comment */ +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(6, 7) + .WithArguments("Camera"); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; +using UnityEditor; + +[InitializeOnLoad] +class Camera : MonoBehaviour +{ + static Camera() + { + } + + // comment + private int field = 0; + /* comment */ +} "; await VerifyCSharpFixAsync(test, fixedTest); } diff --git a/src/Microsoft.Unity.Analyzers.Tests/LoadAttributeMethodTests.cs b/src/Microsoft.Unity.Analyzers.Tests/LoadAttributeMethodTests.cs index 5d443546..592c7fff 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/LoadAttributeMethodTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/LoadAttributeMethodTests.cs @@ -62,7 +62,7 @@ private static void OnLoad() } [Fact] - public async Task InitializeOnLoadMethodFixModifiersComments() + public async Task InitializeOnLoadMethodFixModifiersTrivia() { const string test = @" using UnityEditor; diff --git a/src/Microsoft.Unity.Analyzers.Tests/MeshArrayPropertyInLoopTests.cs b/src/Microsoft.Unity.Analyzers.Tests/MeshArrayPropertyInLoopTests.cs index fd421ecc..1c13505d 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/MeshArrayPropertyInLoopTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/MeshArrayPropertyInLoopTests.cs @@ -631,4 +631,53 @@ void Update() // The lambda is not considered inside the loop await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task VerticesInForLoopConditionTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Mesh mesh = GetComponent().mesh; + // loop start + for (int i = 0; i < /* vertices access */ mesh.vertices.Length /* end access */; i++) + { + // some work + } + // loop end + } +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(10, 51) + .WithArguments("vertices"); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Mesh mesh = GetComponent().mesh; + Vector3[] meshVertices = mesh.vertices; + // loop start + for (int i = 0; i < /* vertices access */ meshVertices.Length /* end access */; i++) + { + // some work + } + // loop end + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/MessageSignatureTests.cs b/src/Microsoft.Unity.Analyzers.Tests/MessageSignatureTests.cs index 2e9ea74c..1883337e 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/MessageSignatureTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/MessageSignatureTests.cs @@ -409,4 +409,39 @@ private void OnSceneGUI(object foo) // In this special case, we do not provide a codefix, given it would break the code as the message is -wrongly- used elsewhere await VerifyCSharpFixAsync(test, test); } + + [Fact] + public async Task MessageSignatureTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + // leading comment + private void OnApplicationPause(int foo, bool pause, string[] bar) // trailing comment + { + } +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(7, 18) + .WithArguments("OnApplicationPause"); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + // leading comment + private void OnApplicationPause(bool pause) // trailing comment + { + } +} +"; + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationDirectCallTests.cs b/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationDirectCallTests.cs index a3c8b9bb..b38da521 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationDirectCallTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationDirectCallTests.cs @@ -103,7 +103,7 @@ private IEnumerator InvokeMe() } [Fact] - public async Task TestStartCoroutineComments() + public async Task TestStartCoroutineTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationNameOfTests.cs b/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationNameOfTests.cs index 81963b68..12f04e5a 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationNameOfTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/MethodInvocationNameOfTests.cs @@ -53,7 +53,7 @@ private void InvokeMe() } [Fact] - public async Task TestInvokeComments() + public async Task TestInvokeTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/NonGenericGetComponentTests.cs b/src/Microsoft.Unity.Analyzers.Tests/NonGenericGetComponentTests.cs index 6c6cad8f..e2d6844b 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/NonGenericGetComponentTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/NonGenericGetComponentTests.cs @@ -85,7 +85,7 @@ private void Method(Rigidbody rb) } [Fact] - public async Task GetComponentAsComments() + public async Task GetComponentAsTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/PropertyDrawerOnGUITests.cs b/src/Microsoft.Unity.Analyzers.Tests/PropertyDrawerOnGUITests.cs index 8bb46179..4f557cce 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/PropertyDrawerOnGUITests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/PropertyDrawerOnGUITests.cs @@ -123,4 +123,41 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task TestBaseOnGUITrivia() + { + const string test = @" +using UnityEngine; +using UnityEditor; + +class MyDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + // comment expected to be removed + base.OnGUI(position, property, label); + // trailing comment + } +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(9, 3); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; +using UnityEditor; + +class MyDrawer : PropertyDrawer +{ + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { + // trailing comment + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/ProtectedUnityMessageTests.cs b/src/Microsoft.Unity.Analyzers.Tests/ProtectedUnityMessageTests.cs index 65747eed..5f576222 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/ProtectedUnityMessageTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/ProtectedUnityMessageTests.cs @@ -51,7 +51,7 @@ private void Foo() } [Fact] - public async Task FixDefaultUnityMessageComments() + public async Task FixDefaultUnityMessageTrivia() { const string test = @" using UnityEngine; @@ -93,7 +93,7 @@ void Foo() } [Fact] - public async Task FixPrivateUnityMessageComments() + public async Task FixPrivateUnityMessageTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/RequireComponentTests.cs b/src/Microsoft.Unity.Analyzers.Tests/RequireComponentTests.cs index da30fb55..01598f86 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/RequireComponentTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/RequireComponentTests.cs @@ -274,4 +274,40 @@ public void Update() await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task GetComponentTrivia() + { + const string test = @" +using UnityEngine; + +// class comment +public class PlayerScript : MonoBehaviour +{ + void Start() + { + var rb = GetComponent(); // trailing comment + } +}"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(9, 18); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +// class comment +[RequireComponent(typeof(Rigidbody))] +public class PlayerScript : MonoBehaviour +{ + void Start() + { + var rb = GetComponent(); // trailing comment + } +}"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/SetLocalPositionAndRotationTests.cs b/src/Microsoft.Unity.Analyzers.Tests/SetLocalPositionAndRotationTests.cs index 0ec1b4a2..1dfc5576 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/SetLocalPositionAndRotationTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/SetLocalPositionAndRotationTests.cs @@ -90,6 +90,50 @@ void Method() stub.SetLocalPositionAndRotation(new Vector3(0.0f, 1.0f, 0.0f), stub.localRotation); } } +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } + + [SkippableFact] + public async Task UpdateLocalPositionAndRotationMethodTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + // leading comment + transform.localPosition = new Vector3(0.0f, 1.0f, 0.0f); + transform.localRotation = transform.localRotation; + // trailing comment + } +} +"; + + var method = GetCSharpDiagnosticAnalyzer().ExpressionContext.PositionAndRotationMethodName; + var type = typeof(UnityEngine.Transform); + + Skip.IfNot(MethodExists("UnityEngine", type.FullName!, method), $"This Unity version does not support {type}.{method}"); + + var diagnostic = ExpectDiagnostic().WithLocation(9, 9); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + // leading comment + transform.SetLocalPositionAndRotation(new Vector3(0.0f, 1.0f, 0.0f), transform.localRotation); + // trailing comment + } +} "; await VerifyCSharpFixAsync(test, fixedTest); diff --git a/src/Microsoft.Unity.Analyzers.Tests/SetPositionAndRotationTests.cs b/src/Microsoft.Unity.Analyzers.Tests/SetPositionAndRotationTests.cs index 5b5db769..7076a12f 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/SetPositionAndRotationTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/SetPositionAndRotationTests.cs @@ -91,7 +91,7 @@ void Method() [Fact] - public async Task UpdatePositionAndRotationMethodComments() + public async Task UpdatePositionAndRotationMethodTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/TagComparisonTests.cs b/src/Microsoft.Unity.Analyzers.Tests/TagComparisonTests.cs index 9ea4f008..00eb8182 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/TagComparisonTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/TagComparisonTests.cs @@ -45,7 +45,7 @@ private void Update() } [Fact] - public async Task TagAsIdentifierComments() + public async Task TagAsIdentifierTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/UnityObjectNullHandlingTests.cs b/src/Microsoft.Unity.Analyzers.Tests/UnityObjectNullHandlingTests.cs index cf5c651e..3b250948 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/UnityObjectNullHandlingTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/UnityObjectNullHandlingTests.cs @@ -51,7 +51,7 @@ public Transform NC() } [Fact] - public async Task FixIdentifierCoalescingComments() + public async Task FixIdentifierCoalescingTrivia() { const string test = @" using UnityEngine; @@ -197,7 +197,7 @@ public Transform NP() } [Fact] - public async Task FixNullPropagationComments() + public async Task FixNullPropagationTrivia() { const string test = @" using UnityEngine; @@ -305,7 +305,7 @@ public Transform NP() } [Fact] - public async Task FixCoalescingAssignmentComments() + public async Task FixCoalescingAssignmentTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/UnusedCoroutineReturnValueTests.cs b/src/Microsoft.Unity.Analyzers.Tests/UnusedCoroutineReturnValueTests.cs index 6f0dfc0a..f3b5773a 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/UnusedCoroutineReturnValueTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/UnusedCoroutineReturnValueTests.cs @@ -59,6 +59,61 @@ private IEnumerator UnusedCoroutine(float waitTime) } } } +"; + await VerifyCSharpFixAsync(test, fixedTest); + } + + [Fact] + public async Task UnusedCoroutineReturnValueTrivia() + { + const string test = @" +using System.Collections; +using UnityEngine; + +public class UnusedCoroutineScript : MonoBehaviour +{ + void Start() + { + // leading comment + UnusedCoroutine(2.0f); // trailing comment + } + + private IEnumerator UnusedCoroutine(float waitTime) + { + for (int i = 0; i < 10; i++) + { + yield return new WaitForSeconds(waitTime); + } + } +} +"; + + var diagnostic = ExpectDiagnostic(UnusedCoroutineReturnValueAnalyzer.Rule.Id) + .WithLocation(10, 9) + .WithArguments("UnusedCoroutine"); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using System.Collections; +using UnityEngine; + +public class UnusedCoroutineScript : MonoBehaviour +{ + void Start() + { + // leading comment + StartCoroutine(UnusedCoroutine(2.0f)); // trailing comment + } + + private IEnumerator UnusedCoroutine(float waitTime) + { + for (int i = 0; i < 10; i++) + { + yield return new WaitForSeconds(waitTime); + } + } +} "; await VerifyCSharpFixAsync(test, fixedTest); } diff --git a/src/Microsoft.Unity.Analyzers.Tests/UpdateDeltaTimeTests.cs b/src/Microsoft.Unity.Analyzers.Tests/UpdateDeltaTimeTests.cs index 4480af9e..652d0689 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/UpdateDeltaTimeTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/UpdateDeltaTimeTests.cs @@ -49,7 +49,7 @@ public void FixedUpdate() } [Fact] - public async Task FixedUpdateWithDeltaTimeComments() + public async Task FixedUpdateWithDeltaTimeTrivia() { const string test = @" using UnityEngine; diff --git a/src/Microsoft.Unity.Analyzers.Tests/Vector2ConversionTests.cs b/src/Microsoft.Unity.Analyzers.Tests/Vector2ConversionTests.cs index 1f53247c..ce9f89f0 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/Vector2ConversionTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/Vector2ConversionTests.cs @@ -155,4 +155,47 @@ void Update() await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task UseConversionTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 v3 = Vector3.zero; + Vector2 v2 = Vector2.zero; + // leading comment + var distance = Vector3.Distance(v3, /* inner */ new Vector3(v2.x, v2.y, 0) /* outer */); + // trailing comment + } +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(11, 57); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 v3 = Vector3.zero; + Vector2 v2 = Vector2.zero; + // leading comment + var distance = Vector3.Distance(v3, /* inner */ v2 /* outer */); + // trailing comment + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers.Tests/Vector3ConversionTests.cs b/src/Microsoft.Unity.Analyzers.Tests/Vector3ConversionTests.cs index 75cf5fe6..49fe7f12 100644 --- a/src/Microsoft.Unity.Analyzers.Tests/Vector3ConversionTests.cs +++ b/src/Microsoft.Unity.Analyzers.Tests/Vector3ConversionTests.cs @@ -135,4 +135,47 @@ void Update() await VerifyCSharpDiagnosticAsync(test); } + + [Fact] + public async Task UseConversionTrivia() + { + const string test = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 v3 = Vector3.zero; + Vector2 v2 = Vector2.zero; + // leading comment + var distance = Vector2.Distance(v2, /* inner */ new Vector2(v3.x, v3.y) /* outer */); + // trailing comment + } +} +"; + + var diagnostic = ExpectDiagnostic() + .WithLocation(11, 57); + + await VerifyCSharpDiagnosticAsync(test, diagnostic); + + const string fixedTest = @" +using UnityEngine; + +class Camera : MonoBehaviour +{ + void Update() + { + Vector3 v3 = Vector3.zero; + Vector2 v2 = Vector2.zero; + // leading comment + var distance = Vector2.Distance(v2, /* inner */ v3 /* outer */); + // trailing comment + } +} +"; + + await VerifyCSharpFixAsync(test, fixedTest); + } } diff --git a/src/Microsoft.Unity.Analyzers/BaseGetPositionAndRotationContext.cs b/src/Microsoft.Unity.Analyzers/BaseGetPositionAndRotationContext.cs index ad81c414..49ebcaec 100644 --- a/src/Microsoft.Unity.Analyzers/BaseGetPositionAndRotationContext.cs +++ b/src/Microsoft.Unity.Analyzers/BaseGetPositionAndRotationContext.cs @@ -57,7 +57,7 @@ public override bool TryGetArgumentExpression(SemanticModel model, ExpressionSyn if (!IsOutRefCompatible(model, expression)) return false; - result = Argument(expression) + result = Argument(expression.WithoutLeadingTrivia()) .WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword)) .WithLeadingTrivia(assignment.OperatorToken.TrailingTrivia); diff --git a/src/Microsoft.Unity.Analyzers/BaseVectorConversion.cs b/src/Microsoft.Unity.Analyzers/BaseVectorConversion.cs index 71322439..c005b5da 100644 --- a/src/Microsoft.Unity.Analyzers/BaseVectorConversion.cs +++ b/src/Microsoft.Unity.Analyzers/BaseVectorConversion.cs @@ -166,6 +166,8 @@ private async Task SimplifyObjectCreationAsync(Document document, Obje var typeSyntax = SyntaxFactory.ParseTypeName(CastType.Name); SyntaxNode castedSyntax = IsCastRequired(ocOperation) ? SyntaxFactory.CastExpression(typeSyntax, identifierNameSyntax) : identifierNameSyntax; + castedSyntax = castedSyntax.WithTriviaFrom(ocSyntax); + var newRoot = root?.ReplaceNode(ocSyntax, castedSyntax); if (newRoot == null) return document; diff --git a/src/Microsoft.Unity.Analyzers/MeshArrayPropertyInLoop.cs b/src/Microsoft.Unity.Analyzers/MeshArrayPropertyInLoop.cs index b441f472..720fecf0 100644 --- a/src/Microsoft.Unity.Analyzers/MeshArrayPropertyInLoop.cs +++ b/src/Microsoft.Unity.Analyzers/MeshArrayPropertyInLoop.cs @@ -254,8 +254,9 @@ private static async Task CacheMeshPropertyAsync(Document document, Me ).NormalizeWhitespace(); var leadingTrivia = loop.GetLeadingTrivia(); + var indentation = leadingTrivia.LastOrDefault(t => t.IsKind(SyntaxKind.WhitespaceTrivia)); variableDeclaration = variableDeclaration - .WithLeadingTrivia(leadingTrivia) + .WithLeadingTrivia(indentation.IsKind(SyntaxKind.WhitespaceTrivia) ? SyntaxFactory.TriviaList(indentation) : leadingTrivia) .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); editor.InsertBefore(loop, variableDeclaration); diff --git a/src/Microsoft.Unity.Analyzers/MessageSignature.cs b/src/Microsoft.Unity.Analyzers/MessageSignature.cs index 3ce92ebb..5baafb4d 100644 --- a/src/Microsoft.Unity.Analyzers/MessageSignature.cs +++ b/src/Microsoft.Unity.Analyzers/MessageSignature.cs @@ -139,8 +139,12 @@ private static async Task FixMethodDeclarationSignatureAsync(Document return document; var builder = new MessageBuilder(syntaxGenerator); + var newParameterList = CreateParameterList(builder, message) + .WithCloseParenToken( + SyntaxFactory.Token(SyntaxKind.CloseParenToken) + .WithTrailingTrivia(methodSyntax.ParameterList.CloseParenToken.TrailingTrivia)); var newMethodSyntax = methodSyntax - .WithParameterList(CreateParameterList(builder, message)); + .WithParameterList(newParameterList); var newRoot = root?.ReplaceNode(methodSyntax, newMethodSyntax); if (newRoot == null) diff --git a/src/Microsoft.Unity.Analyzers/RequireComponent.cs b/src/Microsoft.Unity.Analyzers/RequireComponent.cs index 2e61418e..9a6e2dcd 100644 --- a/src/Microsoft.Unity.Analyzers/RequireComponent.cs +++ b/src/Microsoft.Unity.Analyzers/RequireComponent.cs @@ -155,8 +155,12 @@ private static async Task AddRequiredComponentAsync(Document document, SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseTypeName(typeName)))))) .WithAdditionalAnnotations(Simplifier.Annotation); - var newClassDeclaration = classDeclaration.AddAttributeLists( - SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attribute))); + var attributeList = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attribute)); + + var leadingTrivia = classDeclaration.GetLeadingTrivia(); + var newClassDeclaration = classDeclaration + .WithoutLeadingTrivia() + .AddAttributeLists(attributeList.WithLeadingTrivia(leadingTrivia)); var root = await document.GetSyntaxRootAsync(cancellationToken); if (root == null) diff --git a/src/Microsoft.Unity.Analyzers/UnusedCoroutineReturnValue.cs b/src/Microsoft.Unity.Analyzers/UnusedCoroutineReturnValue.cs index c09330aa..83488328 100644 --- a/src/Microsoft.Unity.Analyzers/UnusedCoroutineReturnValue.cs +++ b/src/Microsoft.Unity.Analyzers/UnusedCoroutineReturnValue.cs @@ -108,7 +108,8 @@ private static async Task WrapWithStartCoroutineAsync(Document documen IdentifierName("StartCoroutine"), ArgumentList( SingletonSeparatedList( - Argument(invocation))))); + Argument(invocation.WithoutTrivia()))))) + .WithTriviaFrom(parent); var newRoot = root?.ReplaceNode(parent, newExpressionStatement); if (newRoot == null)