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

Fix colour highlighting for target typed new #2250

Merged
merged 2 commits into from
Jan 22, 2022
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ Since 2018.1, the version numbers and release cycle match Rider's versions and r
* [Commits](https://github.com/JetBrains/resharper-unity/compare/net213...net221)
* [Milestone](https://github.com/JetBrains/resharper-unity/milestone/50?closed=1)

### Added

- Rider: Add new run configuration to run Unity tests in batch mode ([RIDER-70675](https://youtrack.jetbrains.com/issue/RIDER-70675), [#2231](https://github.com/JetBrains/resharper-unity/pull/2231))

### Changed

- Show preview for target typed new instances of `Color` ([RIDER-64151](https://youtrack.jetbrains.com/issue/RIDER-64151), [#2250](https://github.com/JetBrains/resharper-unity/pull/2250))
- Unity editor: Expand Find Usages editor window by default ([#2239](https://github.com/JetBrains/resharper-unity/pull/2239))

### Fixed

- Rider: Fix incorrectly showing both Unity and Unity DLL project action groups ([#2219](https://github.com/JetBrains/resharper-unity/pull/2219))
- Rider: Fix incorrectly showing "switch to full UI" action when already in full UI ([RIDER-71185](https://youtrack.jetbrains.com/issue/RIDER-71185), [#2220](https://github.com/JetBrains/resharper-unity/pull/2220))
- Rider: Fix debugging unit test when debugger is already attached to the editor ([RIDER-70660](https://youtrack.jetbrains.com/issue/RIDER-70660), [#2232](https://github.com/JetBrains/resharper-unity/pull/2232))
- Rider: Fix issues displaying the "advanced integration unavailable" notification ([#73086](https://youtrack.jetbrains.com/issue/RIDER-73086), [#2240](https://github.com/JetBrains/resharper-unity/pull/2240))
- Rider: Fix exception when showing Quick Doc tooltip ([DEXP-619767](https://youtrack.jetbrains.com/issue/DEXP-619767), [#2240](https://github.com/JetBrains/resharper-unity/pull/2240))



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,83 +14,85 @@
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.Util.Media;
using JetBrains.Util.Special;

#nullable enable

namespace JetBrains.ReSharper.Plugins.Unity.CSharp.Daemon.Stages.Color
{
public class UnityColorHighlighterProcess : CSharpIncrementalDaemonStageProcessBase
{
public UnityColorHighlighterProcess(IDaemonProcess process, IContextBoundSettingsStore settingsStore,
ICSharpFile file)
ICSharpFile file)
: base(process, settingsStore, file)
{
}

public override void VisitNode(ITreeNode element, IHighlightingConsumer consumer)
{
var tokenNode = element as ITokenNode;
if (tokenNode != null && tokenNode.GetTokenType().IsWhitespace) return;
if (element is ITokenNode tokenNode && tokenNode.GetTokenType().IsWhitespace) return;

var colorInfo = CreateColorHighlightingInfo(element);
if (colorInfo != null)
consumer.AddHighlighting(colorInfo.Highlighting, colorInfo.Range);
}

private HighlightingInfo CreateColorHighlightingInfo(ITreeNode element)
private HighlightingInfo? CreateColorHighlightingInfo(ITreeNode element)
{
var colorReference = GetColorReference(element);
var constantRange = colorReference?.ColorConstantRange;
if (constantRange == null) return null;

var documentRange = constantRange.Value;
if (!documentRange.IsValid()) return null;

return new HighlightingInfo(documentRange, new ColorHighlighting(colorReference));
var range = colorReference?.ColorConstantRange;
return range?.IsValid() == true
? new HighlightingInfo(range.Value, new ColorHighlighting(colorReference))
: null;
}

private IColorReference GetColorReference(ITreeNode element)
private static IColorReference? GetColorReference(ITreeNode element)
{
var constructorExpression = element as IObjectCreationExpression;
if (constructorExpression != null)
if (element is IObjectCreationExpression constructorExpression)
return ReferenceFromConstructor(constructorExpression);

var referenceExpression = element as IReferenceExpression;
var qualifier = referenceExpression?.QualifierExpression as IReferenceExpression;
if (qualifier == null) return null;
if (referenceExpression?.QualifierExpression is not IReferenceExpression qualifier)
return null;

return ReferenceFromInvocation(qualifier, referenceExpression)
?? ReferenceFromProperty(qualifier, referenceExpression);
}

private static IColorReference ReferenceFromConstructor(IObjectCreationExpression constructorExpression)
private static IColorReference? ReferenceFromConstructor(IObjectCreationExpression constructorExpression)
{
var constructedType = constructorExpression.TypeReference?.Resolve().DeclaredElement as ITypeElement;
if (constructedType == null) return null;
// Get the type from the constructor, which allows us to support target typed new. This will fail to resolve
// if the parameters don't match (e.g. calling new Color32(r, g, b) without passing a), so fall back to the
// expression's type, if available.
// Note that we don't do further validation of the parameters, so we'll still show a colour preview for
// Color32(r, g, b) even though it's an invalid method call.
var constructedType =
(constructorExpression.ConstructorReference.Resolve().DeclaredElement as IConstructor)?.ContainingType
?? constructorExpression.TypeReference?.Resolve().DeclaredElement as ITypeElement;
if (constructedType == null)
return null;

var unityColorTypes = UnityColorTypes.GetInstance(constructedType.Module);
if (!unityColorTypes.IsUnityColorType(constructedType)) return null;

var arguments = constructorExpression.Arguments;
if (arguments.Count < 3 || arguments.Count > 4) return null;
if (arguments.Count is < 3 or > 4) return null;

JetRgbaColor? color = null;
if (unityColorTypes.UnityColorType != null && unityColorTypes.UnityColorType.Equals(constructedType))
{
var baseColor = GetColorFromFloatARGB(arguments);
if (baseColor == null) return null;

color = baseColor.Item1.HasValue
? baseColor.Item2.WithA((byte)(255.0 * baseColor.Item1.Value))
: baseColor.Item2;
var (a, rgb) = baseColor.Value;
color = a.HasValue ? rgb.WithA((byte)(255.0 * a)) : rgb;
}
else if (unityColorTypes.UnityColor32Type != null && unityColorTypes.UnityColor32Type.Equals(constructedType))
{
var baseColor = GetColorFromIntARGB(arguments);
if (baseColor == null) return null;

color = baseColor.Item1.HasValue
? baseColor.Item2.WithA((byte)baseColor.Item1.Value)
: baseColor.Item2;
var (a, rgb) = baseColor.Value;
color = a.HasValue ? rgb.WithA((byte)a) : rgb;
}

if (color == null) return null;
Expand All @@ -100,22 +102,20 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
return new UnityColorReference(colorElement, constructorExpression, argumentList, argumentList.GetDocumentRange());
}

private static IColorReference ReferenceFromInvocation(IReferenceExpression qualifier,
IReferenceExpression methodReferenceExpression)
private static IColorReference? ReferenceFromInvocation(IReferenceExpression qualifier,
IReferenceExpression methodReferenceExpression)
{
var invocationExpression = InvocationExpressionNavigator.GetByInvokedExpression(methodReferenceExpression);
if (invocationExpression == null || invocationExpression.Arguments.IsEmpty)
{
return null;
}

var methodReference = methodReferenceExpression.Reference;

var name = methodReference.GetName();
if (!string.Equals(name, "HSVToRGB", StringComparison.Ordinal)) return null;

var arguments = invocationExpression.Arguments;
if (arguments.Count < 3 || arguments.Count > 4) return null;
if (arguments.Count is < 3 or > 4) return null;

var color = GetColorFromHSV(arguments);
if (color == null) return null;
Expand All @@ -132,8 +132,8 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
argumentList, argumentList.GetDocumentRange());
}

private static IColorReference ReferenceFromProperty(IReferenceExpression qualifier,
IReferenceExpression colorQualifiedMemberExpression)
private static IColorReference? ReferenceFromProperty(IReferenceExpression qualifier,
IReferenceExpression colorQualifiedMemberExpression)
{
var name = colorQualifiedMemberExpression.Reference.GetName();

Expand All @@ -154,7 +154,7 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
colorQualifiedMemberExpression, colorQualifiedMemberExpression.NameIdentifier.GetDocumentRange());
}

private static Tuple<float?, JetRgbaColor> GetColorFromFloatARGB(ICollection<ICSharpArgument> arguments)
private static (float? alpha, JetRgbaColor)? GetColorFromFloatARGB(ICollection<ICSharpArgument> arguments)
{
var a = GetArgumentAsFloatConstant(arguments, "a", 0, 1);
var r = GetArgumentAsFloatConstant(arguments, "r", 0, 1);
Expand All @@ -164,10 +164,10 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
if (!r.HasValue || !g.HasValue || !b.HasValue)
return null;

return Tuple.Create(a, JetRgbaColor.FromRgb((byte)(255.0 * r.Value), (byte)(255.0 * g.Value), (byte)(255.0 * b.Value)));
return (a, JetRgbaColor.FromRgb((byte)(255.0 * r.Value), (byte)(255.0 * g.Value), (byte)(255.0 * b.Value)));
}

private static Tuple<int?, JetRgbaColor> GetColorFromIntARGB(ICollection<ICSharpArgument> arguments)
private static (int? alpha, JetRgbaColor)? GetColorFromIntARGB(ICollection<ICSharpArgument> arguments)
{
var a = GetArgumentAsIntConstant(arguments, "a", 0, 255);
var r = GetArgumentAsIntConstant(arguments, "r", 0, 255);
Expand All @@ -177,7 +177,7 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
if (!r.HasValue || !g.HasValue || !b.HasValue)
return null;

return Tuple.Create(a, JetRgbaColor.FromRgb((byte)r.Value, (byte)g.Value, (byte)b.Value));
return (a, JetRgbaColor.FromRgb((byte)r.Value, (byte)g.Value, (byte)b.Value));
}

private static JetRgbaColor? GetColorFromHSV(ICollection<ICSharpArgument> arguments)
Expand Down Expand Up @@ -266,14 +266,10 @@ private static IColorReference ReferenceFromConstructor(IObjectCreationExpressio
return value.Value;
}

private static ICSharpArgument GetNamedArgument(IEnumerable<ICSharpArgument> arguments, string parameterName)
private static ICSharpArgument? GetNamedArgument(IEnumerable<ICSharpArgument> arguments, string parameterName)
{
var namedArgument =
arguments.FirstOrDefault(
a =>
a.MatchingParameter.IfNotNull(
p => parameterName.Equals(p.Element.ShortName, StringComparison.Ordinal)));
return namedArgument;
return arguments.FirstOrDefault(a =>
parameterName.Equals(a.MatchingParameter?.Element.ShortName, StringComparison.Ordinal));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public Class1()
var c12 = Color.HSVToRGB(0, 1, 1, false);

var c13 = Color.HSVToRGB(0, 1, 1, 1, 1);

Color c14 = new(1, 0, 0);
Color c15 = new(0, 1, 1, 0.5f);
Color c16 = new(10, 20, -2);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ namespace UnityTest
var c12 = Color.HSVToRGB(|0, 1, 1, false|(9));

var c13 = Color.HSVToRGB(0, 1, 1, 1, 1);

Color c14 = new(|1, 0, 0|(10));
Color c15 = new(|0, 1, 1, 0.5f|(11));
Color c16 = new(10, 20, -2);
}
}
}
Expand Down Expand Up @@ -59,3 +63,9 @@ HEX: FF, 7F, 7F, 7F' (E) ''
(9): : (T) '| |
ARGB: 255, 255, 0, 0
HEX: FF, FF, 0, 0' (E) ''
(10): : (T) '| |
ARGB: 255, 255, 0, 0
HEX: FF, FF, 0, 0' (E) ''
(11): : (T) '| |
ARGB: 127, 0, 255, 255
HEX: 7F, 0, FF, FF' (E) ''
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ public class Class1
{
public Class1()
{
// Color32 doesn't have an overload that takes 3 parameters, but we recognise it because it's the same as Color(r,g,b)
var c1 = new Color32(255, 0, 0);
var c2 = new Color32(0, 255, 255, 127);
var c3 = new Color32(10, 20, -2);

var c4 = new Color32(255, 0, 0, 0, 0);
var c5 = new Color32(0xFF / 2, 128, 128);

Color32 c6 = new(200, 180, 190, 255);
Color32 c7 = new(1, 3, 0.5f, 0.8f);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ namespace UnityTest
{
public Class1()
{
// Color32 doesn't have an overload that takes 3 parameters, but we recognise it because it's the same as Color(r,g,b)
var c1 = new Color32(|255, 0, 0|(0));
var c2 = new Color32(|0, 255, 255, 127|(1));
var c3 = new Color32(10, 20, -2);

var c4 = new Color32(255, 0, 0, 0, 0);
var c5 = new Color32(|0xFF / 2, 128, 128|(2));

Color32 c6 = new(|200, 180, 190, 255|(3));
Color32 c7 = new(1, 3, 0.5f, 0.8f);
}
}
}
Expand All @@ -26,3 +30,6 @@ HEX: 7F, 0, FF, FF' (E) ''
(2): : (T) '| |
ARGB: 255, 127, 128, 128
HEX: FF, 7F, 80, 80' (E) ''
(3): : (T) '| |
ARGB: 255, 200, 180, 190
HEX: FF, C8, B4, BE' (E) ''
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using JetBrains.ReSharper.Daemon.VisualElements;
using JetBrains.ReSharper.Plugins.Tests.Unity.CSharp.Daemon.Stages.Analysis;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.TestFramework;
using NUnit.Framework;

namespace JetBrains.ReSharper.Plugins.Tests.Unity.CSharp.Daemon.Stages.Color
{
[Category("ColorHighlighting")]
[TestUnity]
[CSharpLanguageLevel(CSharpLanguageLevel.CSharp90)]
public class UnityColorHighlightingTest : CSharpHighlightingTestBase<ColorHighlighting>
{
protected override bool ColorIdentifiers => true;
Expand Down