@@ -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
@@ -86,8 +104,8 @@ private static GoReferenceExpression getFieldReferenceExpression(@NotNull PsiEle
86104 List <GoReferenceExpression > fieldReferenceExpressions = getFieldReferenceExpressions (assignment );
87105 if (exists (fieldReferenceExpressions , expression -> isAssignedInPreviousStatement (expression , assignment ))) return null ;
88106
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 ;
91109 }
92110
93111 @ NotNull
@@ -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 ());
@@ -129,20 +163,19 @@ private static GoExpression getTopmostExpression(@NotNull GoExpression expressio
129163 return ObjectUtils .notNull (PsiTreeUtil .getTopmostParentOfType (expression , GoExpression .class ), expression );
130164 }
131165
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 ;
134168
135- GoReferenceExpression refExpression = unwrapParensAndCast (e );
169+ GoReferenceExpression refExpression = unwrapParensAndCast (element );
136170 return refExpression != null && refExpression .resolve () == resolve ;
137171 }
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,17 @@ 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 ;
264+
219265 GoLiteralValue literalValue = structLiteral .getLiteralValue ();
220266 PsiElement resolve = fieldReferenceExpression .resolve ();
221267 return literalValue != null && isFieldDefinition (resolve ) &&
@@ -238,19 +284,31 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
238284 public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239285 Data data = getData (element );
240286 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 );
242298 }
243299
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 ();
246304 if (literalValue == null ) return ;
247305
248- for (GoReferenceExpression expression : data . getReferenceExpressions () ) {
306+ for (GoReferenceExpression expression : referenceExpressions ) {
249307 GoExpression anchor = getTopmostExpression (expression );
250- GoExpression fieldValue = GoPsiImplUtil .getRightExpression (data . getAssignment () , anchor );
308+ GoExpression fieldValue = GoPsiImplUtil .getRightExpression (parentAssignment , anchor );
251309 if (fieldValue == null ) continue ;
252310
253- GoPsiImplUtil .deleteExpressionFromAssignment (data . getAssignment () , anchor );
311+ GoPsiImplUtil .deleteExpressionFromAssignment (parentAssignment , anchor );
254312 addFieldDefinition (literalValue , expression .getIdentifier ().getText (), fieldValue .getText ());
255313 }
256314 }
@@ -272,25 +330,46 @@ private static class Data {
272330 private final GoCompositeLit myCompositeLit ;
273331 private final GoAssignmentStatement myAssignment ;
274332 private final List <GoReferenceExpression > myReferenceExpressions ;
333+ private final GoStatement myStructDeclaration ;
334+ private final GoVarDefinition myStructDefinition ;
275335
276336 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 ) {
279341 myCompositeLit = compositeLit ;
280342 myAssignment = assignment ;
281343 myReferenceExpressions = referenceExpressions ;
344+ myStructDeclaration = structDeclaration ;
345+ myStructDefinition = structDefinition ;
282346 }
283347
348+ @ Nullable
284349 public GoCompositeLit getCompositeLit () {
285350 return myCompositeLit ;
286351 }
287352
353+ @ NotNull
288354 public GoAssignmentStatement getAssignment () {
289355 return myAssignment ;
290356 }
291357
358+ @ NotNull
292359 public List <GoReferenceExpression > getReferenceExpressions () {
293360 return myReferenceExpressions ;
294361 }
362+
363+ @ Nullable
364+ public GoStatement getStructDeclaration () {
365+ return myStructDeclaration ;
366+ }
367+
368+ @ NotNull
369+ public GoVarDefinition getStructDefinition () {
370+ return myStructDefinition ;
371+ }
295372 }
296373}
374+
375+
0 commit comments