@@ -61,11 +61,29 @@ private static Data getData(@NotNull PsiElement element) {
6161 if (!element .isValid () || !element .isWritable ()) return null ;
6262 GoAssignmentStatement assignment = getValidAssignmentParent (element );
6363 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 ;
6665
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 );
6987 }
7088
7189 @ Nullable
@@ -104,6 +122,22 @@ private static GoReferenceExpression unwrapParensAndCast(@Nullable PsiElement e)
104122 return ObjectUtils .tryCast (e , GoReferenceExpression .class );
105123 }
106124
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+
107141 @ Contract ("null -> false" )
108142 private static boolean isFieldReferenceExpression (@ Nullable PsiElement element ) {
109143 return element instanceof GoReferenceExpression && isFieldDefinition (((GoReferenceExpression )element ).resolve ());
@@ -138,11 +172,10 @@ private static boolean isResolvedTo(@Nullable PsiElement e, @Nullable PsiElement
138172
139173 @ NotNull
140174 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 ) {
144177 List <GoReferenceExpression > uninitializedFieldReferencesByQualifier =
145- filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), resolve ));
178+ filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), definition ));
146179 MultiMap <PsiElement , GoReferenceExpression > resolved = groupBy (uninitializedFieldReferencesByQualifier , GoReferenceExpression ::resolve );
147180 return map (filter (resolved .entrySet (), set -> set .getValue ().size () == 1 ), set -> getFirstItem (set .getValue ()));
148181 }
@@ -151,13 +184,15 @@ private static List<GoReferenceExpression> getUninitializedSingleFieldReferences
151184 private static GoCompositeLit getStructLiteralByReference (@ NotNull GoReferenceExpression fieldReferenceExpression ,
152185 @ NotNull GoAssignmentStatement assignment ) {
153186 GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
187+ if (previousStatement == null ) return null ;
188+
154189 if (previousStatement instanceof GoSimpleStatement ) {
155190 return getStructLiteral (fieldReferenceExpression , (GoSimpleStatement )previousStatement );
156191 }
157192 if (previousStatement instanceof GoAssignmentStatement ) {
158193 return getStructLiteral (fieldReferenceExpression , (GoAssignmentStatement )previousStatement );
159194 }
160- return null ;
195+ return getStructLiteral ( previousStatement , fieldReferenceExpression ) ;
161196 }
162197
163198 @ Nullable
@@ -172,15 +207,16 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
172207 }
173208
174209 @ 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 ;
177213 return qualifier != null ? qualifier .resolve () : null ;
178214 }
179215
180216 @ Nullable
181217 private static GoCompositeLit getStructLiteral (@ NotNull GoReferenceExpression fieldReferenceExpression ,
182218 @ NotNull GoAssignmentStatement structAssignment ) {
183- GoVarDefinition varDefinition = ObjectUtils . tryCast ( resolveQualifier ( fieldReferenceExpression ), GoVarDefinition . class );
219+ GoVarDefinition varDefinition = getDefinition ( fieldReferenceExpression );
184220 PsiElement field = fieldReferenceExpression .resolve ();
185221 if (varDefinition == null || !isFieldDefinition (field ) || !hasStructTypeWithField (varDefinition , (GoNamedElement )field )) {
186222 return null ;
@@ -193,6 +229,14 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
193229 return ObjectUtils .tryCast (compositeLit , GoCompositeLit .class );
194230 }
195231
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+
196240 private static boolean hasStructTypeWithField (@ NotNull GoVarDefinition structVarDefinition , @ NotNull GoNamedElement field ) {
197241 GoType type = structVarDefinition .getGoType (null );
198242 GoStructType structType = type != null ? ObjectUtils .tryCast (type .getUnderlyingType (), GoStructType .class ) : null ;
@@ -207,15 +251,16 @@ private static boolean isFieldInitialization(@NotNull GoElement element, @NotNul
207251
208252 @ NotNull
209253 private static List <GoReferenceExpression > getUninitializedFieldReferenceExpressions (@ NotNull GoAssignmentStatement assignment ,
210- @ NotNull GoCompositeLit structLiteral ) {
254+ @ Nullable GoCompositeLit structLiteral ) {
211255 return filter (getFieldReferenceExpressions (assignment ), expression ->
212256 isUninitializedFieldReferenceExpression (expression , structLiteral ) && !isAssignedInPreviousStatement (expression , assignment ));
213257 }
214258
215- @ Contract ("null, _-> false" )
259+ @ Contract ("null, _-> false; !null, null -> true " )
216260 private static boolean isUninitializedFieldReferenceExpression (@ Nullable GoReferenceExpression fieldReferenceExpression ,
217- @ NotNull GoCompositeLit structLiteral ) {
261+ @ Nullable GoCompositeLit structLiteral ) {
218262 if (fieldReferenceExpression == null ) return false ;
263+ if (structLiteral == null ) return true ;
219264 GoLiteralValue literalValue = structLiteral .getLiteralValue ();
220265 PsiElement resolve = fieldReferenceExpression .resolve ();
221266 return literalValue != null && isFieldDefinition (resolve ) &&
@@ -238,19 +283,31 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
238283 public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239284 Data data = getData (element );
240285 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 );
242297 }
243298
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 ();
246303 if (literalValue == null ) return ;
247304
248- for (GoReferenceExpression expression : data . getReferenceExpressions () ) {
305+ for (GoReferenceExpression expression : referenceExpressions ) {
249306 GoExpression anchor = getTopmostExpression (expression );
250- GoExpression fieldValue = GoPsiImplUtil .getRightExpression (data . getAssignment () , anchor );
307+ GoExpression fieldValue = GoPsiImplUtil .getRightExpression (parentAssignment , anchor );
251308 if (fieldValue == null ) continue ;
252309
253- GoPsiImplUtil .deleteExpressionFromAssignment (data . getAssignment () , anchor );
310+ GoPsiImplUtil .deleteExpressionFromAssignment (parentAssignment , anchor );
254311 addFieldDefinition (literalValue , expression .getIdentifier ().getText (), fieldValue .getText ());
255312 }
256313 }
@@ -272,25 +329,46 @@ private static class Data {
272329 private final GoCompositeLit myCompositeLit ;
273330 private final GoAssignmentStatement myAssignment ;
274331 private final List <GoReferenceExpression > myReferenceExpressions ;
332+ private final GoStatement myStructDeclaration ;
333+ private final GoVarDefinition myStructDefinition ;
275334
276335 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 ) {
279340 myCompositeLit = compositeLit ;
280341 myAssignment = assignment ;
281342 myReferenceExpressions = referenceExpressions ;
343+ myStructDeclaration = structDeclaration ;
344+ myStructDefinition = structDefinition ;
282345 }
283346
347+ @ Nullable
284348 public GoCompositeLit getCompositeLit () {
285349 return myCompositeLit ;
286350 }
287351
352+ @ NotNull
288353 public GoAssignmentStatement getAssignment () {
289354 return myAssignment ;
290355 }
291356
357+ @ NotNull
292358 public List <GoReferenceExpression > getReferenceExpressions () {
293359 return myReferenceExpressions ;
294360 }
361+
362+ @ Nullable
363+ public GoStatement getStructDeclaration () {
364+ return myStructDeclaration ;
365+ }
366+
367+ @ NotNull
368+ public GoVarDefinition getStructDefinition () {
369+ return myStructDefinition ;
370+ }
295371 }
296372}
373+
374+
0 commit comments