@@ -61,11 +61,29 @@ private static Data getData(@NotNull PsiElement element) {
61
61
if (!element .isValid () || !element .isWritable ()) return null ;
62
62
GoAssignmentStatement assignment = getValidAssignmentParent (element );
63
63
GoReferenceExpression selectedFieldReference = assignment != null ? getFieldReferenceExpression (element , assignment ) : null ;
64
- GoCompositeLit compositeLit = selectedFieldReference != null ? getStructLiteralByReference (selectedFieldReference , assignment ) : null ;
65
- if (compositeLit == null ) return null ;
64
+ if (selectedFieldReference == null ) return null ;
66
65
67
- List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , selectedFieldReference , compositeLit );
68
- return !references .isEmpty () ? new Data (assignment , compositeLit , references ) : null ;
66
+ GoVarDefinition structDefinition = getDefinition (selectedFieldReference );
67
+ GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
68
+ boolean needReplaceDeclarationWithShortVar = isUnassigned (getSingleVarSpecByDefinition (previousStatement , structDefinition ));
69
+
70
+ GoCompositeLit compositeLit = getStructLiteralByReference (selectedFieldReference , assignment );
71
+ if (compositeLit == null && !needReplaceDeclarationWithShortVar || structDefinition == null ) return null ;
72
+
73
+ List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , structDefinition , compositeLit );
74
+ return !references .isEmpty () ? new Data (assignment , compositeLit , references , previousStatement , structDefinition ) : null ;
75
+ }
76
+
77
+ @ Nullable
78
+ private static GoCompositeLit createStructLiteral (@ NotNull GoVarDefinition definition , @ NotNull Project project ) {
79
+ GoType type = definition .getGoType (null );
80
+ return type != null ? GoElementFactory .createCompositeLit (project , type ) : null ;
81
+ }
82
+
83
+ @ Nullable
84
+ @ Contract ("null -> null" )
85
+ private static GoVarDefinition getDefinition (@ Nullable GoReferenceExpression referenceExpressions ) {
86
+ return ObjectUtils .tryCast (resolveQualifier (referenceExpressions ), GoVarDefinition .class );
69
87
}
70
88
71
89
@ Nullable
@@ -86,8 +104,8 @@ private static GoReferenceExpression getFieldReferenceExpression(@NotNull PsiEle
86
104
List <GoReferenceExpression > fieldReferenceExpressions = getFieldReferenceExpressions (assignment );
87
105
if (exists (fieldReferenceExpressions , expression -> isAssignedInPreviousStatement (expression , assignment ))) return null ;
88
106
89
- Set <PsiElement > resolvedFields = map2Set (fieldReferenceExpressions , GoMoveToStructInitializationIntention ::resolveQualifier );
90
- return resolvedFields .size () == 1 ? getFirstItem (fieldReferenceExpressions ) : null ;
107
+ Set <PsiElement > resolvedQualifiers = map2Set (fieldReferenceExpressions , GoMoveToStructInitializationIntention ::resolveQualifier );
108
+ return resolvedQualifiers .size () == 1 ? getFirstItem (fieldReferenceExpressions ) : null ;
91
109
}
92
110
93
111
@ NotNull
@@ -104,6 +122,22 @@ private static GoReferenceExpression unwrapParensAndCast(@Nullable PsiElement e)
104
122
return ObjectUtils .tryCast (e , GoReferenceExpression .class );
105
123
}
106
124
125
+ @ Nullable
126
+ @ Contract ("_, null -> null; null, _ -> null" )
127
+ private static GoVarSpec getSingleVarSpecByDefinition (@ Nullable GoStatement statement ,
128
+ @ Nullable GoVarDefinition definition ) {
129
+ GoVarDeclaration declaration = statement != null ? statement .getVarDeclaration () : null ;
130
+ List <GoVarSpec > varSpecs = declaration != null ? declaration .getVarSpecList () : emptyList ();
131
+ GoVarSpec singleVarSpec = varSpecs .size () == 1 ? getFirstItem (varSpecs ) : null ;
132
+ List <GoVarDefinition > varDefinitions = singleVarSpec != null ? singleVarSpec .getVarDefinitionList () : emptyList ();
133
+ return varDefinitions .size () == 1 && definition == getFirstItem (varDefinitions ) ? singleVarSpec : null ;
134
+ }
135
+
136
+ @ Contract ("null -> false" )
137
+ private static boolean isUnassigned (@ Nullable GoVarSpec varSpec ) {
138
+ return varSpec != null && varSpec .getExpressionList ().isEmpty ();
139
+ }
140
+
107
141
@ Contract ("null -> false" )
108
142
private static boolean isFieldReferenceExpression (@ Nullable PsiElement element ) {
109
143
return element instanceof GoReferenceExpression && isFieldDefinition (((GoReferenceExpression )element ).resolve ());
@@ -129,20 +163,19 @@ private static GoExpression getTopmostExpression(@NotNull GoExpression expressio
129
163
return ObjectUtils .notNull (PsiTreeUtil .getTopmostParentOfType (expression , GoExpression .class ), expression );
130
164
}
131
165
132
- private static boolean isResolvedTo (@ Nullable PsiElement e , @ Nullable PsiElement resolve ) {
133
- if (e instanceof GoVarDefinition ) return resolve == e ;
166
+ private static boolean isResolvedTo (@ Nullable PsiElement element , @ Nullable PsiElement resolve ) {
167
+ if (element instanceof GoVarDefinition ) return resolve == element ;
134
168
135
- GoReferenceExpression refExpression = unwrapParensAndCast (e );
169
+ GoReferenceExpression refExpression = unwrapParensAndCast (element );
136
170
return refExpression != null && refExpression .resolve () == resolve ;
137
171
}
138
172
139
173
@ NotNull
140
174
private static List <GoReferenceExpression > getUninitializedSingleFieldReferences (@ NotNull GoAssignmentStatement assignment ,
141
- @ NotNull GoReferenceExpression fieldReferenceExpression ,
142
- @ NotNull GoCompositeLit compositeLit ) {
143
- PsiElement resolve = resolveQualifier (fieldReferenceExpression );
175
+ @ Nullable GoVarDefinition definition ,
176
+ @ Nullable GoCompositeLit compositeLit ) {
144
177
List <GoReferenceExpression > uninitializedFieldReferencesByQualifier =
145
- filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), resolve ));
178
+ filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), definition ));
146
179
MultiMap <PsiElement , GoReferenceExpression > resolved = groupBy (uninitializedFieldReferencesByQualifier , GoReferenceExpression ::resolve );
147
180
return map (filter (resolved .entrySet (), set -> set .getValue ().size () == 1 ), set -> getFirstItem (set .getValue ()));
148
181
}
@@ -151,13 +184,15 @@ private static List<GoReferenceExpression> getUninitializedSingleFieldReferences
151
184
private static GoCompositeLit getStructLiteralByReference (@ NotNull GoReferenceExpression fieldReferenceExpression ,
152
185
@ NotNull GoAssignmentStatement assignment ) {
153
186
GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
187
+ if (previousStatement == null ) return null ;
188
+
154
189
if (previousStatement instanceof GoSimpleStatement ) {
155
190
return getStructLiteral (fieldReferenceExpression , (GoSimpleStatement )previousStatement );
156
191
}
157
192
if (previousStatement instanceof GoAssignmentStatement ) {
158
193
return getStructLiteral (fieldReferenceExpression , (GoAssignmentStatement )previousStatement );
159
194
}
160
- return null ;
195
+ return getStructLiteral ( previousStatement , fieldReferenceExpression ) ;
161
196
}
162
197
163
198
@ Nullable
@@ -172,15 +207,16 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
172
207
}
173
208
174
209
@ Nullable
175
- private static PsiElement resolveQualifier (@ NotNull GoReferenceExpression fieldReferenceExpression ) {
176
- GoReferenceExpression qualifier = fieldReferenceExpression .getQualifier ();
210
+ @ Contract ("null -> null" )
211
+ private static PsiElement resolveQualifier (@ Nullable GoReferenceExpression fieldReferenceExpression ) {
212
+ GoReferenceExpression qualifier = fieldReferenceExpression != null ? fieldReferenceExpression .getQualifier () : null ;
177
213
return qualifier != null ? qualifier .resolve () : null ;
178
214
}
179
215
180
216
@ Nullable
181
217
private static GoCompositeLit getStructLiteral (@ NotNull GoReferenceExpression fieldReferenceExpression ,
182
218
@ NotNull GoAssignmentStatement structAssignment ) {
183
- GoVarDefinition varDefinition = ObjectUtils . tryCast ( resolveQualifier ( fieldReferenceExpression ), GoVarDefinition . class );
219
+ GoVarDefinition varDefinition = getDefinition ( fieldReferenceExpression );
184
220
PsiElement field = fieldReferenceExpression .resolve ();
185
221
if (varDefinition == null || !isFieldDefinition (field ) || !hasStructTypeWithField (varDefinition , (GoNamedElement )field )) {
186
222
return null ;
@@ -193,6 +229,14 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
193
229
return ObjectUtils .tryCast (compositeLit , GoCompositeLit .class );
194
230
}
195
231
232
+ @ Nullable
233
+ private static GoCompositeLit getStructLiteral (@ NotNull GoStatement statement ,
234
+ @ NotNull GoReferenceExpression fieldReferenceExpression ) {
235
+ GoVarDefinition definition = getDefinition (fieldReferenceExpression );
236
+ GoVarSpec varSpec = definition != null ? getSingleVarSpecByDefinition (statement , definition ) : null ;
237
+ return varSpec != null ? ObjectUtils .tryCast (getFirstItem (varSpec .getRightExpressionsList ()), GoCompositeLit .class ) : null ;
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 ;
@@ -207,15 +251,17 @@ private static boolean isFieldInitialization(@NotNull GoElement element, @NotNul
207
251
208
252
@ NotNull
209
253
private static List <GoReferenceExpression > getUninitializedFieldReferenceExpressions (@ NotNull GoAssignmentStatement assignment ,
210
- @ NotNull GoCompositeLit structLiteral ) {
254
+ @ Nullable GoCompositeLit structLiteral ) {
211
255
return filter (getFieldReferenceExpressions (assignment ), expression ->
212
256
isUninitializedFieldReferenceExpression (expression , structLiteral ) && !isAssignedInPreviousStatement (expression , assignment ));
213
257
}
214
258
215
- @ Contract ("null, _-> false" )
259
+ @ Contract ("null, _-> false; !null, null -> true " )
216
260
private static boolean isUninitializedFieldReferenceExpression (@ Nullable GoReferenceExpression fieldReferenceExpression ,
217
- @ NotNull GoCompositeLit structLiteral ) {
261
+ @ Nullable GoCompositeLit structLiteral ) {
218
262
if (fieldReferenceExpression == null ) return false ;
263
+ if (structLiteral == null ) return true ;
264
+
219
265
GoLiteralValue literalValue = structLiteral .getLiteralValue ();
220
266
PsiElement resolve = fieldReferenceExpression .resolve ();
221
267
return literalValue != null && isFieldDefinition (resolve ) &&
@@ -238,19 +284,31 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
238
284
public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239
285
Data data = getData (element );
240
286
if (data == null ) return ;
241
- moveFieldReferenceExpressions (data );
287
+
288
+ boolean needReplaceDeclarationWithShortVar = data .getCompositeLit () == null ;
289
+ GoCompositeLit compositeLit =
290
+ needReplaceDeclarationWithShortVar ? createStructLiteral (data .getStructDefinition (), project ) : data .getCompositeLit ();
291
+ if (compositeLit == null || needReplaceDeclarationWithShortVar && data .getStructDeclaration () == null ) return ;
292
+
293
+ moveFieldReferenceExpressions (data .getReferenceExpressions (), compositeLit , data .getAssignment ());
294
+ if (!needReplaceDeclarationWithShortVar ) return ;
295
+ GoStatement shortVarStatement =
296
+ GoElementFactory .createShortVarDeclarationStatement (project , data .getStructDefinition ().getText (), compositeLit .getText ());
297
+ data .getStructDeclaration ().replace (shortVarStatement );
242
298
}
243
299
244
- private static void moveFieldReferenceExpressions (@ NotNull Data data ) {
245
- GoLiteralValue literalValue = data .getCompositeLit ().getLiteralValue ();
300
+ private static void moveFieldReferenceExpressions (@ NotNull List <GoReferenceExpression > referenceExpressions ,
301
+ @ NotNull GoCompositeLit compositeLit ,
302
+ @ NotNull GoAssignmentStatement parentAssignment ) {
303
+ GoLiteralValue literalValue = compositeLit .getLiteralValue ();
246
304
if (literalValue == null ) return ;
247
305
248
- for (GoReferenceExpression expression : data . getReferenceExpressions () ) {
306
+ for (GoReferenceExpression expression : referenceExpressions ) {
249
307
GoExpression anchor = getTopmostExpression (expression );
250
- GoExpression fieldValue = GoPsiImplUtil .getRightExpression (data . getAssignment () , anchor );
308
+ GoExpression fieldValue = GoPsiImplUtil .getRightExpression (parentAssignment , anchor );
251
309
if (fieldValue == null ) continue ;
252
310
253
- GoPsiImplUtil .deleteExpressionFromAssignment (data . getAssignment () , anchor );
311
+ GoPsiImplUtil .deleteExpressionFromAssignment (parentAssignment , anchor );
254
312
addFieldDefinition (literalValue , expression .getIdentifier ().getText (), fieldValue .getText ());
255
313
}
256
314
}
@@ -272,25 +330,46 @@ private static class Data {
272
330
private final GoCompositeLit myCompositeLit ;
273
331
private final GoAssignmentStatement myAssignment ;
274
332
private final List <GoReferenceExpression > myReferenceExpressions ;
333
+ private final GoStatement myStructDeclaration ;
334
+ private final GoVarDefinition myStructDefinition ;
275
335
276
336
public Data (@ NotNull GoAssignmentStatement assignment ,
277
- @ NotNull GoCompositeLit compositeLit ,
278
- @ NotNull List <GoReferenceExpression > referenceExpressions ) {
337
+ @ Nullable GoCompositeLit compositeLit ,
338
+ @ NotNull List <GoReferenceExpression > referenceExpressions ,
339
+ @ Nullable GoStatement structDeclaration ,
340
+ @ NotNull GoVarDefinition structDefinition ) {
279
341
myCompositeLit = compositeLit ;
280
342
myAssignment = assignment ;
281
343
myReferenceExpressions = referenceExpressions ;
344
+ myStructDeclaration = structDeclaration ;
345
+ myStructDefinition = structDefinition ;
282
346
}
283
347
348
+ @ Nullable
284
349
public GoCompositeLit getCompositeLit () {
285
350
return myCompositeLit ;
286
351
}
287
352
353
+ @ NotNull
288
354
public GoAssignmentStatement getAssignment () {
289
355
return myAssignment ;
290
356
}
291
357
358
+ @ NotNull
292
359
public List <GoReferenceExpression > getReferenceExpressions () {
293
360
return myReferenceExpressions ;
294
361
}
362
+
363
+ @ Nullable
364
+ public GoStatement getStructDeclaration () {
365
+ return myStructDeclaration ;
366
+ }
367
+
368
+ @ NotNull
369
+ public GoVarDefinition getStructDefinition () {
370
+ return myStructDefinition ;
371
+ }
295
372
}
296
373
}
374
+
375
+
0 commit comments