@@ -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
@@ -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 ());
@@ -138,11 +172,10 @@ private static boolean isResolvedTo(@Nullable PsiElement e, @Nullable PsiElement
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,16 @@ 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 ;
219
264
GoLiteralValue literalValue = structLiteral .getLiteralValue ();
220
265
PsiElement resolve = fieldReferenceExpression .resolve ();
221
266
return literalValue != null && isFieldDefinition (resolve ) &&
@@ -238,19 +283,31 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
238
283
public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239
284
Data data = getData (element );
240
285
if (data == null ) return ;
241
- moveFieldReferenceExpressions (data );
286
+
287
+ boolean needReplaceDeclarationWithShortVar = data .getCompositeLit () == null ;
288
+ GoCompositeLit compositeLit =
289
+ needReplaceDeclarationWithShortVar ? createStructLiteral (data .getStructDefinition (), project ) : data .getCompositeLit ();
290
+ if (compositeLit == null || needReplaceDeclarationWithShortVar && data .getStructDeclaration () == null ) return ;
291
+
292
+ moveFieldReferenceExpressions (data .getReferenceExpressions (), compositeLit , data .getAssignment ());
293
+ if (!needReplaceDeclarationWithShortVar ) return ;
294
+ GoStatement shortVarStatement =
295
+ GoElementFactory .createShortVarDeclarationStatement (project , data .getStructDefinition ().getText (), compositeLit .getText ());
296
+ data .getStructDeclaration ().replace (shortVarStatement );
242
297
}
243
298
244
- private static void moveFieldReferenceExpressions (@ NotNull Data data ) {
245
- GoLiteralValue literalValue = data .getCompositeLit ().getLiteralValue ();
299
+ private static void moveFieldReferenceExpressions (@ NotNull List <GoReferenceExpression > referenceExpressions ,
300
+ @ NotNull GoCompositeLit compositeLit ,
301
+ @ NotNull GoAssignmentStatement parentAssignment ) {
302
+ GoLiteralValue literalValue = compositeLit .getLiteralValue ();
246
303
if (literalValue == null ) return ;
247
304
248
- for (GoReferenceExpression expression : data . getReferenceExpressions () ) {
305
+ for (GoReferenceExpression expression : referenceExpressions ) {
249
306
GoExpression anchor = getTopmostExpression (expression );
250
- GoExpression fieldValue = GoPsiImplUtil .getRightExpression (data . getAssignment () , anchor );
307
+ GoExpression fieldValue = GoPsiImplUtil .getRightExpression (parentAssignment , anchor );
251
308
if (fieldValue == null ) continue ;
252
309
253
- GoPsiImplUtil .deleteExpressionFromAssignment (data . getAssignment () , anchor );
310
+ GoPsiImplUtil .deleteExpressionFromAssignment (parentAssignment , anchor );
254
311
addFieldDefinition (literalValue , expression .getIdentifier ().getText (), fieldValue .getText ());
255
312
}
256
313
}
@@ -272,25 +329,46 @@ private static class Data {
272
329
private final GoCompositeLit myCompositeLit ;
273
330
private final GoAssignmentStatement myAssignment ;
274
331
private final List <GoReferenceExpression > myReferenceExpressions ;
332
+ private final GoStatement myStructDeclaration ;
333
+ private final GoVarDefinition myStructDefinition ;
275
334
276
335
public Data (@ NotNull GoAssignmentStatement assignment ,
277
- @ NotNull GoCompositeLit compositeLit ,
278
- @ NotNull List <GoReferenceExpression > referenceExpressions ) {
336
+ @ Nullable GoCompositeLit compositeLit ,
337
+ @ NotNull List <GoReferenceExpression > referenceExpressions ,
338
+ @ Nullable GoStatement structDeclaration ,
339
+ @ NotNull GoVarDefinition structDefinition ) {
279
340
myCompositeLit = compositeLit ;
280
341
myAssignment = assignment ;
281
342
myReferenceExpressions = referenceExpressions ;
343
+ myStructDeclaration = structDeclaration ;
344
+ myStructDefinition = structDefinition ;
282
345
}
283
346
347
+ @ Nullable
284
348
public GoCompositeLit getCompositeLit () {
285
349
return myCompositeLit ;
286
350
}
287
351
352
+ @ NotNull
288
353
public GoAssignmentStatement getAssignment () {
289
354
return myAssignment ;
290
355
}
291
356
357
+ @ NotNull
292
358
public List <GoReferenceExpression > getReferenceExpressions () {
293
359
return myReferenceExpressions ;
294
360
}
361
+
362
+ @ Nullable
363
+ public GoStatement getStructDeclaration () {
364
+ return myStructDeclaration ;
365
+ }
366
+
367
+ @ NotNull
368
+ public GoVarDefinition getStructDefinition () {
369
+ return myStructDefinition ;
370
+ }
295
371
}
296
372
}
373
+
374
+
0 commit comments