14
14
import com .intellij .psi .impl .source .tree .AstBufferUtil ;
15
15
import com .jetbrains .lang .dart .DartLanguage ;
16
16
import com .jetbrains .lang .dart .DartTokenTypes ;
17
- import com .jetbrains .lang .dart .psi .DartArgumentList ;
18
- import com .jetbrains .lang .dart .psi .DartArguments ;
19
- import com .jetbrains .lang .dart .psi .DartExpression ;
20
- import com .jetbrains .lang .dart .psi .DartLiteralExpression ;
17
+ import com .jetbrains .lang .dart .psi .*;
21
18
import io .flutter .FlutterBundle ;
22
19
import org .jetbrains .annotations .NotNull ;
23
20
import org .jetbrains .annotations .Nullable ;
@@ -38,7 +35,7 @@ public Color getColorFrom(@NotNull PsiElement element) {
38
35
if (element .getNode ().getElementType () != DartTokenTypes .IDENTIFIER ) return null ;
39
36
40
37
final String name = element .getText ();
41
- if (!( name . equals ( "Colors" ) || name . equals ( "CupertinoColors" ) || name . equals ( "Color" )) ) return null ;
38
+ if (name == null ) return null ;
42
39
43
40
final PsiElement refExpr = topmostReferenceExpression (element );
44
41
if (refExpr == null ) return null ;
@@ -47,21 +44,66 @@ public Color getColorFrom(@NotNull PsiElement element) {
47
44
48
45
if (parent .getNode ().getElementType () == DartTokenTypes .ARRAY_ACCESS_EXPRESSION ) {
49
46
// Colors.blue[200]
47
+ if (name .equals (refExpr .getFirstChild ().getText ()) && refExpr .getChildren ().length > 1 ) {
48
+ // Avoid duplicate resolves.
49
+ return null ;
50
+ }
50
51
final String code = AstBufferUtil .getTextSkippingWhitespaceComments (parent .getNode ());
51
- return parseColorText (code .substring (code .indexOf (name ) + name . length () + 1 ), name );
52
+ return parseColorText (code .substring (code .indexOf (name )), name );
52
53
}
53
54
else if (parent .getNode ().getElementType () == DartTokenTypes .CALL_EXPRESSION ) {
54
55
// foo(Color.fromRGBO(0, 255, 0, 0.5))
56
+ if (name .matches ("fromARGB" ) || name .matches ("fromRGBO" )) {
57
+ // Avoid duplicate resolves.
58
+ return null ;
59
+ }
60
+ if (parent .getLastChild () instanceof DartArguments && !name .matches ("(Cupertino)?Color" )) {
61
+ // Avoid duplicate resolves.
62
+ final DartExpression colorExpression = ((DartArguments )parent .getLastChild ()).getArgumentList ().getExpressionList ().get (0 );
63
+ final Color color = parseColorElements (colorExpression , colorExpression .getFirstChild ());
64
+ if (color != null ) return null ;
65
+ }
66
+ // Color.fromRGBO(0, 255, 0, 0.5)
55
67
return parseColorElements (parent , refExpr );
56
68
}
57
69
else if (parent .getNode ().getElementType () == DartTokenTypes .SIMPLE_TYPE ) {
58
70
// const Color.fromARGB(100, 255, 0, 0)
71
+ if (name .matches ("fromARGB" ) || name .matches ("fromRGBO" )) {
72
+ // Avoid duplicate resolves.
73
+ return null ;
74
+ }
59
75
// parent.getParent().getParent() is a new expr
60
76
parent = getNewExprFromType (parent );
61
77
if (parent == null ) return null ;
62
78
return parseColorElements (parent , refExpr );
63
79
}
64
80
else {
81
+ if (parent .getNode ().getElementType () == DartTokenTypes .VAR_INIT ||
82
+ parent .getNode ().getElementType () == DartTokenTypes .FUNCTION_BODY ) {
83
+ if (name .equals (refExpr .getFirstChild ().getText ()) && refExpr .getChildren ().length > 1 ) {
84
+ // Avoid duplicate resolves.
85
+ return null ;
86
+ }
87
+ final PsiElement reference = resolveReferencedElement (refExpr );
88
+ if (reference != null && reference .getLastChild () != null ) {
89
+ Color tryParseColor = null ;
90
+ if (reference instanceof DartCallExpression ) {
91
+ final DartExpression expression = ((DartCallExpression )reference ).getExpression ();
92
+ if (expression != null && expression .getLastChild () instanceof DartReferenceExpression ) {
93
+ tryParseColor = parseColorElements (reference , expression );
94
+ if (tryParseColor != null ) return tryParseColor ;
95
+ }
96
+ }
97
+ final PsiElement lastChild = reference .getLastChild ();
98
+ if (lastChild instanceof DartArguments && reference .getParent () != null ) {
99
+ tryParseColor = parseColorElements (reference , reference .getParent ());
100
+ }
101
+ else {
102
+ tryParseColor = parseColorElements (reference , reference .getLastChild ());
103
+ }
104
+ if (tryParseColor != null ) return tryParseColor ;
105
+ }
106
+ }
65
107
// name.equals(refExpr.getFirstChild().getText()) -> Colors.blue
66
108
final PsiElement idNode = refExpr .getFirstChild ();
67
109
if (idNode == null ) return null ;
@@ -75,13 +117,46 @@ else if (parent.getNode().getElementType() == DartTokenTypes.SIMPLE_TYPE) {
75
117
final PsiElement child = refExpr .getLastChild ();
76
118
if (child == null ) return null ;
77
119
if (child .getText ().startsWith ("shade" )) {
78
- final String code = AstBufferUtil .getTextSkippingWhitespaceComments (refExpr .getNode ());
79
- return parseColorText (code .substring (code .indexOf (name ) + name .length () + 1 ), name );
120
+ if (idNode .getText ().contains (name )) return null ; // Avoid duplicate resolves.
121
+ String code = AstBufferUtil .getTextSkippingWhitespaceComments (refExpr .getNode ());
122
+ code = code .replaceFirst ("(Cupertino)?Colors\\ ." , "" );
123
+ return parseColorText (code , name );
80
124
}
81
125
}
82
126
return null ;
83
127
}
84
128
129
+ @ Nullable
130
+ private PsiElement resolveReferencedElement (@ NotNull PsiElement element ) {
131
+ if (element instanceof DartCallExpression && element .getFirstChild ().getText ().equals ("Color" )) {
132
+ return element ;
133
+ }
134
+ final PsiElement symbol = element .getLastChild ();
135
+ final PsiElement result ;
136
+ if (symbol instanceof DartReference ) {
137
+ result = ((DartReference )symbol ).resolve ();
138
+ }
139
+ else if (element instanceof DartReference ) {
140
+ result = ((DartReference )element ).resolve ();
141
+ }
142
+ else {
143
+ return null ;
144
+ }
145
+ if (!(result instanceof DartComponentName ) || result .getParent () == null ) return null ;
146
+ final PsiElement declaration = result .getParent ().getParent ();
147
+ if (declaration instanceof DartClassMembers ) return declaration ;
148
+ if (!(declaration instanceof DartVarDeclarationList )) return null ;
149
+ final PsiElement lastChild = declaration .getLastChild ();
150
+ if (!(lastChild instanceof DartVarInit )) return null ;
151
+
152
+ final PsiElement effectiveElement = lastChild .getLastChild ();
153
+ // Recursively determine reference if the initialization is still a `DartReference`.
154
+ if (effectiveElement instanceof DartReference && !(effectiveElement instanceof DartCallExpression )) {
155
+ return resolveReferencedElement (effectiveElement );
156
+ }
157
+ return effectiveElement ;
158
+ }
159
+
85
160
@ Nullable
86
161
private Color parseColorElements (@ NotNull PsiElement parent , @ NotNull PsiElement refExpr ) {
87
162
final PsiElement selectorNode = refExpr .getLastChild ();
@@ -91,7 +166,7 @@ private Color parseColorElements(@NotNull PsiElement parent, @NotNull PsiElement
91
166
final boolean isFromRGBO = "fromRGBO" .equals (selector );
92
167
if (isFromARGB || isFromRGBO ) {
93
168
String code = AstBufferUtil .getTextSkippingWhitespaceComments (parent .getNode ());
94
- if (code .startsWith ("constColor(" )) {
169
+ if (code .startsWith ("constColor(" ) || code . startsWith ( "constColor." ) ) {
95
170
code = code .substring (5 );
96
171
}
97
172
return ExpressionParsingUtils .parseColorComponents (code .substring (code .indexOf (selector )), selector + "(" , isFromARGB );
0 commit comments