Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP, Highlighting: hot methods and invocation of costly methods #816

Merged
merged 6 commits into from
Oct 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -446,4 +446,5 @@
<Range>Expression.GetHighlightingRange()</Range>
<Behavour overlapResolvePolicy="WARNING" />
</Warning>

</Errors>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using JetBrains.Annotations;
using JetBrains.DocumentModel;
using JetBrains.ReSharper.Daemon.BuildScripts.DaemonStage.Highlightings;
using JetBrains.ReSharper.Feature.Services.Daemon;
using JetBrains.ReSharper.Plugins.Unity.CSharp.Daemon.Stages.PerformanceCriticalCodeAnalysis;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.Resolve;
[assembly:
RegisterConfigurableSeverity(
PerformanceCriticalCodeInvocationHighlighting.SEVERITY_ID,
null,
PerformanceCriticalCodeHighlightingAttributeIds.GroupID,
"Expensive method call in frequently called method",
"Expensive method call in frequently called method",
Severity.INFO
),
RegisterConfigurableSeverity(
PerformanceCriticalCodeInvocationReachableHighlighting.SEVERITY_ID,
null,
PerformanceCriticalCodeHighlightingAttributeIds.GroupID,
"Expensive method is indirectly invoked from the frequently called method",
"Expensive method is indirectly invoked from the frequently called method",
Severity.INFO
),
]

namespace JetBrains.ReSharper.Plugins.Unity.CSharp.Daemon.Stages.PerformanceCriticalCodeAnalysis
{
[StaticSeverityHighlighting(
Severity.INFO, CSharpLanguage.Name,
AttributeId = PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_INVOCATION,
ShowToolTipInStatusBar = false,
ToolTipFormatString = MESSAGE)]
public class PerformanceCriticalCodeInvocationHighlighting : PerformanceCriticalCodeHighlightingBase
{
public const string SEVERITY_ID = "Unity.PerformanceCriticalCodeInvocation";
public const string MESSAGE = "Costly method is invoked from performance context";

public PerformanceCriticalCodeInvocationHighlighting(IReference reference) :
base(PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_INVOCATION, reference, MESSAGE) { }
}

[StaticSeverityHighlighting(
Severity.INFO, CSharpLanguage.Name,
AttributeId = PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_REACHABLE,
ShowToolTipInStatusBar = false,
ToolTipFormatString = MESSAGE)]
public class PerformanceCriticalCodeInvocationReachableHighlighting : PerformanceCriticalCodeHighlightingBase
{
public const string SEVERITY_ID = "Unity.PerformanceCriticalCodeInvocationReachable";
public const string MESSAGE = "Invocation of this method indirectly calls costly method";

public PerformanceCriticalCodeInvocationReachableHighlighting(IReference reference) :
base(PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_REACHABLE,reference, MESSAGE) { }
}


public abstract class PerformanceCriticalCodeHighlightingBase : ICustomAttributeIdHighlighting
{
private readonly IReference myReference;

protected PerformanceCriticalCodeHighlightingBase([NotNull] string attributeId, [NotNull] IReference reference, [NotNull] string message)
{
myReference = reference;
ToolTip = message;
AttributeId = attributeId;
}

public bool IsValid() => myReference.IsValid();
public DocumentRange CalculateRange() => myReference.GetDocumentRange();

[NotNull] public string ToolTip { get; }
[NotNull] public string ErrorStripeToolTip => ToolTip;
public string AttributeId { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using JetBrains.ReSharper.Feature.Services.Daemon;
using JetBrains.ReSharper.Plugins.Unity.CSharp.Daemon.Stages.PerformanceCriticalCodeAnalysis;
using JetBrains.ReSharper.Plugins.Unity.ShaderLab.Daemon.Stages;
using JetBrains.TextControl.DocumentMarkup;

[assembly:

RegisterConfigurableHighlightingsGroup(PerformanceCriticalCodeHighlightingAttributeIds.GroupID, "Unity Costly Highlighters"),
RegisterHighlighter(PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_REACHABLE,
GroupId = PerformanceCriticalCodeHighlightingAttributeIds.GroupID,
EffectType = EffectType.SOLID_UNDERLINE,
EffectColor = "#ffd070",
Layer = HighlighterLayer.SYNTAX + 1),
RegisterHighlighter(PerformanceCriticalCodeHighlightingAttributeIds.COSTLY_METHOD_INVOCATION,
GroupId = PerformanceCriticalCodeHighlightingAttributeIds.GroupID,
EffectType = EffectType.SOLID_UNDERLINE,
EffectColor = "#ff7526",
Layer = HighlighterLayer.SYNTAX + 1),

]
namespace JetBrains.ReSharper.Plugins.Unity.CSharp.Daemon.Stages.PerformanceCriticalCodeAnalysis
{

public static class PerformanceCriticalCodeHighlightingAttributeIds
{
public const string GroupID = "ReSharper Unity CostlyHighlighters";

public const string COSTLY_METHOD_REACHABLE = "Resharper Unity CostlyMethodReachable";
public const string COSTLY_METHOD_INVOCATION = "Resharper Unity CostlyMethodInvocation";
}
}
2 changes: 2 additions & 0 deletions resharper/src/resharper-unity/KnownTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public static class KnownTypes
public static readonly IClrTypeName SerializeField = new ClrTypeName("UnityEngine.SerializeField");
public static readonly IClrTypeName Physics = new ClrTypeName("UnityEngine.Physics");
public static readonly IClrTypeName Physics2D = new ClrTypeName("UnityEngine.Physics2D");
public static readonly IClrTypeName Transform = new ClrTypeName("UnityEngine.Transform");
public static readonly IClrTypeName Resources = new ClrTypeName("UnityEngine.Resources");

// UnityEngine.Networking
public static readonly IClrTypeName NetworkBehaviour = new ClrTypeName("UnityEngine.Networking.NetworkBehaviour");
Expand Down
6 changes: 5 additions & 1 deletion resharper/src/resharper-unity/Rider/UnityOptionsPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ public UnityOptionsPage(Lifetime lifetime, OptionsSettingsSmartContext settingsS
"Parse Cg files for syntax errors. Only works in internal mode.");
AddText("Requires solution reopen.");
}


Header("C# code analysis");
CheckBox((UnitySettings s) => s.EnablePerformanceCriticalCodeHighlighting,
"Enable highlighting of costly methods and indirect calls for these methods in performance critical code sections");

FinishPage();
}

Expand Down
3 changes: 3 additions & 0 deletions resharper/src/resharper-unity/Settings/UnitySettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ public class UnitySettings

[SettingsEntry(false, "Enables syntax error highlighting of CG blocks in ShaderLab files.")]
public bool EnableCgErrorHighlighting;

[SettingsEntry(true, "Enables underscore highlighting of costly methods and indirect calls of these methods.")]
public bool EnablePerformanceCriticalCodeHighlighting;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using UnityEngine;

namespace DefaultNamespace
{
public class CommonTest : MonoBehaviour
{
private RigidBody2D myRigidBody2D;

public void Test()
{
Update();
}

public void Update()
{
if (myRigidBody2D == null)
{
myRigidBody2D = GetComponent<RigidBody2D>();
}

Test();
IndirectCostly();

Test2();
Test2();
Test2();
Test2();
}

private void IndirectCostly()
{
var temp = gameObject.GetComponent<RigidBody2D>();
}

private void Test2()
{
IndirectCostly();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using UnityEngine;

namespace DefaultNamespace
{
public class CommonTest : MonoBehaviour
{
private RigidBody2D myRigidBody2D;

public void Test()
{
|Update|(0)();
}

public void Update()
{
if (myRigidBody2D == null)
{
myRigidBody2D = |GetComponent|(1)<RigidBody2D>();
}

|Test|(2)();
|IndirectCostly|(3)();

|Test2|(4)();
|Test2|(5)();
|Test2|(6)();
|Test2|(7)();
}

private void IndirectCostly()
{
var temp = gameObject.|GetComponent|(8)<RigidBody2D>();
}

private void Test2()
{
|IndirectCostly|(9)();
}
}
}
---------------------------------------------------------
(0): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(1): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
(2): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(3): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(4): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(5): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(6): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(7): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(8): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
(9): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using UnityEngine;
using System.Collections;

namespace DefaultNamespace
{
public class CoroutineTest : MonoBehaviour
{
public void Start()
{
StartCoroutine("HotMethod");
StartCoroutine(HotMethod2());
}

public void HotMethod()
{
var x = gameObject.GetComponent<Transform>();
}

public IEnumerator HotMethod2()
{
var x = GetComponent<Transform>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using UnityEngine;
using System.Collections;

namespace DefaultNamespace
{
public class CoroutineTest : MonoBehaviour
{
public void Start()
{
StartCoroutine("HotMethod");
StartCoroutine(HotMethod2());
}

public void HotMethod()
{
var x = gameObject.|GetComponent|(0)<Transform>();
}

public IEnumerator HotMethod2()
{
var x = |GetComponent|(1)<Transform>();
}
}
}
---------------------------------------------------------
(0): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
(1): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using UnityEngine;

namespace DefaultNamespace
{
public class IndirectCostlyTest : MonoBehaviour
{
private Object[] container = null;
public void Update()
{
IndirectCostly();
}

private void IndirectCostly()
{
if (container == null)
{
container = Object.FindObjectsOfType<SimpleTest>();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using UnityEngine;

namespace DefaultNamespace
{
public class IndirectCostlyTest : MonoBehaviour
{
private Object[] container = null;
public void Update()
{
|IndirectCostly|(0)();
}

private void IndirectCostly()
{
if (container == null)
{
container = Object.|FindObjectsOfType|(1)<SimpleTest>();
}
}
}
}
---------------------------------------------------------
(0): Resharper Unity CostlyMethodReachable: Invocation of this method indirectly calls costly method
(1): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using UnityEngine;

namespace DefaultNamespace
{
public class SimpleTest : MonoBehaviour
{
private RigidBody2D myRigidBody2D;
public void Update()
{
if (myRigidBody2D == null)
{
myRigidBody2D = GetComponent<RigidBody2D>();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using UnityEngine;

namespace DefaultNamespace
{
public class SimpleTest : MonoBehaviour
{
private RigidBody2D myRigidBody2D;
public void Update()
{
if (myRigidBody2D == null)
{
myRigidBody2D = |GetComponent|(0)<RigidBody2D>();
}
}
}
}
---------------------------------------------------------
(0): Resharper Unity CostlyMethodInvocation: Costly method is invoked from performance context
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using UnityEngine;

namespace DefaultNamespace
{
public class SimpleTest : MonoBehaviour
{
private RigidBody2D myRigidBody2D;
public void FixedUpdate()
{
if (myRigidBody2D == null)
{
myRigidBody2D = GetComponent<RigidBody2D>();
}
}
}
}
Loading