19
19
import com .goide .psi .*;
20
20
import com .goide .psi .impl .GoElementFactory ;
21
21
import com .goide .psi .impl .GoPsiImplUtil ;
22
+ import com .goide .psi .impl .GoStatementImpl ;
22
23
import com .intellij .codeInsight .intention .BaseElementAtCaretIntentionAction ;
23
24
import com .intellij .openapi .editor .Editor ;
24
25
import com .intellij .openapi .project .Project ;
@@ -53,19 +54,29 @@ public String getFamilyName() {
53
54
54
55
@ Override
55
56
public boolean isAvailable (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) {
56
- return getData (element ) != null ;
57
+ return getData (element , project ) != null ;
57
58
}
58
59
59
60
@ Nullable
60
- private static Data getData (@ NotNull PsiElement element ) {
61
+ private static Data getData (@ NotNull PsiElement element , @ NotNull Project project ) {
61
62
if (!element .isValid () || !element .isWritable ()) return null ;
62
63
GoAssignmentStatement assignment = getValidAssignmentParent (element );
63
64
GoReferenceExpression selectedFieldReference = assignment != null ? getFieldReferenceExpression (element , assignment ) : null ;
64
- GoCompositeLit compositeLit = selectedFieldReference != null ? getStructLiteralByReference (selectedFieldReference , assignment ) : null ;
65
- if (compositeLit == null ) return null ;
65
+ GoCompositeLit compositeLit =
66
+ selectedFieldReference != null ? getStructLiteralByReference (selectedFieldReference , assignment , project ) : null ;
67
+ GoVarDefinition structDefinition = getDefinition (selectedFieldReference );
68
+ if (compositeLit == null || structDefinition == null ) return null ;
69
+
70
+ List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , structDefinition , compositeLit );
71
+ GoStatementImpl previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatementImpl .class );
72
+ return !references .isEmpty () ? new Data (assignment , compositeLit , references , previousStatement , structDefinition .getText (),
73
+ isUnassigned (getSingleVarSpecByDefinition (previousStatement , structDefinition ))) : null ;
74
+ }
66
75
67
- List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , selectedFieldReference , compositeLit );
68
- return !references .isEmpty () ? new Data (assignment , compositeLit , references ) : null ;
76
+ @ Nullable
77
+ @ Contract ("null -> null" )
78
+ private static GoVarDefinition getDefinition (@ Nullable GoReferenceExpression referenceExpressions ) {
79
+ return ObjectUtils .tryCast (resolveQualifier (referenceExpressions ), GoVarDefinition .class );
69
80
}
70
81
71
82
@ Nullable
@@ -104,6 +115,22 @@ private static GoReferenceExpression unwrapParensAndCast(@Nullable PsiElement e)
104
115
return ObjectUtils .tryCast (e , GoReferenceExpression .class );
105
116
}
106
117
118
+ @ Nullable
119
+ @ Contract ("_, null -> null; null, _ -> null" )
120
+ private static GoVarSpec getSingleVarSpecByDefinition (@ Nullable GoStatementImpl statement ,
121
+ @ Nullable GoVarDefinition definition ) {
122
+ GoVarDeclaration declaration = statement != null ? statement .getVarDeclaration () : null ;
123
+ List <GoVarSpec > varSpecs = declaration != null ? declaration .getVarSpecList () : emptyList ();
124
+ GoVarSpec singleVarSpec = varSpecs .size () == 1 ? getFirstItem (varSpecs ) : null ;
125
+ List <GoVarDefinition > varDefinitions = singleVarSpec != null ? singleVarSpec .getVarDefinitionList () : emptyList ();
126
+ return varDefinitions .size () == 1 && isResolvedTo (definition , getFirstItem (varDefinitions )) ? singleVarSpec : null ;
127
+ }
128
+
129
+ @ Contract ("null -> false" )
130
+ private static boolean isUnassigned (@ Nullable GoVarSpec varSpec ) {
131
+ return varSpec != null && varSpec .getExpressionList ().isEmpty ();
132
+ }
133
+
107
134
@ Contract ("null -> false" )
108
135
private static boolean isFieldReferenceExpression (@ Nullable PsiElement element ) {
109
136
return element instanceof GoReferenceExpression && isFieldDefinition (((GoReferenceExpression )element ).resolve ());
@@ -138,25 +165,28 @@ private static boolean isResolvedTo(@Nullable PsiElement e, @Nullable PsiElement
138
165
139
166
@ NotNull
140
167
private static List <GoReferenceExpression > getUninitializedSingleFieldReferences (@ NotNull GoAssignmentStatement assignment ,
141
- @ NotNull GoReferenceExpression fieldReferenceExpression ,
168
+ @ Nullable GoVarDefinition definition ,
142
169
@ NotNull GoCompositeLit compositeLit ) {
143
- PsiElement resolve = resolveQualifier (fieldReferenceExpression );
144
170
List <GoReferenceExpression > uninitializedFieldReferencesByQualifier =
145
- filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), resolve ));
171
+ filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), definition ));
146
172
MultiMap <PsiElement , GoReferenceExpression > resolved = groupBy (uninitializedFieldReferencesByQualifier , GoReferenceExpression ::resolve );
147
173
return map (filter (resolved .entrySet (), set -> set .getValue ().size () == 1 ), set -> getFirstItem (set .getValue ()));
148
174
}
149
175
150
176
@ Nullable
151
177
private static GoCompositeLit getStructLiteralByReference (@ NotNull GoReferenceExpression fieldReferenceExpression ,
152
- @ NotNull GoAssignmentStatement assignment ) {
178
+ @ NotNull GoAssignmentStatement assignment ,
179
+ @ NotNull Project project ) {
153
180
GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
154
181
if (previousStatement instanceof GoSimpleStatement ) {
155
182
return getStructLiteral (fieldReferenceExpression , (GoSimpleStatement )previousStatement );
156
183
}
157
184
if (previousStatement instanceof GoAssignmentStatement ) {
158
185
return getStructLiteral (fieldReferenceExpression , (GoAssignmentStatement )previousStatement );
159
186
}
187
+ if (previousStatement instanceof GoStatementImpl ) {
188
+ return getStructLiteral ((GoStatementImpl )previousStatement , fieldReferenceExpression , project );
189
+ }
160
190
return null ;
161
191
}
162
192
@@ -172,15 +202,16 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
172
202
}
173
203
174
204
@ Nullable
175
- private static PsiElement resolveQualifier (@ NotNull GoReferenceExpression fieldReferenceExpression ) {
176
- GoReferenceExpression qualifier = fieldReferenceExpression .getQualifier ();
205
+ @ Contract ("null -> null" )
206
+ private static PsiElement resolveQualifier (@ Nullable GoReferenceExpression fieldReferenceExpression ) {
207
+ GoReferenceExpression qualifier = fieldReferenceExpression != null ? fieldReferenceExpression .getQualifier () : null ;
177
208
return qualifier != null ? qualifier .resolve () : null ;
178
209
}
179
210
180
211
@ Nullable
181
212
private static GoCompositeLit getStructLiteral (@ NotNull GoReferenceExpression fieldReferenceExpression ,
182
213
@ NotNull GoAssignmentStatement structAssignment ) {
183
- GoVarDefinition varDefinition = ObjectUtils . tryCast ( resolveQualifier ( fieldReferenceExpression ), GoVarDefinition . class );
214
+ GoVarDefinition varDefinition = getDefinition ( fieldReferenceExpression );
184
215
PsiElement field = fieldReferenceExpression .resolve ();
185
216
if (varDefinition == null || !isFieldDefinition (field ) || !hasStructTypeWithField (varDefinition , (GoNamedElement )field )) {
186
217
return null ;
@@ -193,6 +224,19 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
193
224
return ObjectUtils .tryCast (compositeLit , GoCompositeLit .class );
194
225
}
195
226
227
+ @ Nullable
228
+ private static GoCompositeLit getStructLiteral (@ NotNull GoStatementImpl statement ,
229
+ @ NotNull GoReferenceExpression fieldReferenceExpression ,
230
+ @ NotNull Project project ) {
231
+ GoVarDefinition definition = getDefinition (fieldReferenceExpression );
232
+ GoVarSpec varSpec = definition != null ? getSingleVarSpecByDefinition (statement , definition ) : null ;
233
+ if (varSpec == null ) return null ;
234
+ GoType structType = isUnassigned (varSpec ) ? definition .getGoType (null ) : null ;
235
+ return structType != null
236
+ ? GoElementFactory .createCompositeLit (project , structType )
237
+ : ObjectUtils .tryCast (getFirstItem (varSpec .getRightExpressionsList ()), GoCompositeLit .class );
238
+ }
239
+
196
240
private static boolean hasStructTypeWithField (@ NotNull GoVarDefinition structVarDefinition , @ NotNull GoNamedElement field ) {
197
241
GoType type = structVarDefinition .getGoType (null );
198
242
GoStructType structType = type != null ? ObjectUtils .tryCast (type .getUnderlyingType (), GoStructType .class ) : null ;
@@ -236,9 +280,13 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
236
280
237
281
@ Override
238
282
public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239
- Data data = getData (element );
283
+ Data data = getData (element , project );
240
284
if (data == null ) return ;
241
285
moveFieldReferenceExpressions (data );
286
+
287
+ if (!data .needReplaceDeclarationWithShortVar ()) return ;
288
+ data .getStructDeclaration ()
289
+ .replace (GoElementFactory .createShortVarDeclarationStatement (project , data .getStructVarName (), data .getCompositeLit ().getText ()));
242
290
}
243
291
244
292
private static void moveFieldReferenceExpressions (@ NotNull Data data ) {
@@ -272,13 +320,22 @@ private static class Data {
272
320
private final GoCompositeLit myCompositeLit ;
273
321
private final GoAssignmentStatement myAssignment ;
274
322
private final List <GoReferenceExpression > myReferenceExpressions ;
323
+ private final GoStatementImpl myStructDeclaration ;
324
+ private final String myStructVarName ;
325
+ private final boolean myNeedReplaceDeclarationWithShortVar ;
275
326
276
327
public Data (@ NotNull GoAssignmentStatement assignment ,
277
- @ NotNull GoCompositeLit compositeLit ,
278
- @ NotNull List <GoReferenceExpression > referenceExpressions ) {
328
+ @ Nullable GoCompositeLit compositeLit ,
329
+ @ NotNull List <GoReferenceExpression > referenceExpressions ,
330
+ @ Nullable GoStatementImpl structDeclaration ,
331
+ @ Nullable String structVarName ,
332
+ boolean needReplaceDeclarationWithShortVar ) {
279
333
myCompositeLit = compositeLit ;
280
334
myAssignment = assignment ;
281
335
myReferenceExpressions = referenceExpressions ;
336
+ myStructDeclaration = structDeclaration ;
337
+ myStructVarName = structVarName ;
338
+ myNeedReplaceDeclarationWithShortVar = needReplaceDeclarationWithShortVar ;
282
339
}
283
340
284
341
public GoCompositeLit getCompositeLit () {
@@ -292,5 +349,19 @@ public GoAssignmentStatement getAssignment() {
292
349
public List <GoReferenceExpression > getReferenceExpressions () {
293
350
return myReferenceExpressions ;
294
351
}
352
+
353
+ public GoStatementImpl getStructDeclaration () {
354
+ return myStructDeclaration ;
355
+ }
356
+
357
+ public String getStructVarName () {
358
+ return myStructVarName ;
359
+ }
360
+
361
+ public boolean needReplaceDeclarationWithShortVar () {
362
+ return myNeedReplaceDeclarationWithShortVar ;
363
+ }
295
364
}
296
365
}
366
+
367
+
0 commit comments