@@ -61,11 +61,32 @@ 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 = needReplaceDeclarationWithShortVar
71+ ? createStructLiteral (structDefinition , previousStatement .getProject ())
72+ : getStructLiteralByReference (selectedFieldReference , assignment );
73+ if (compositeLit == null || structDefinition == null ) return null ;
74+
75+ List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , structDefinition , compositeLit );
76+ return !references .isEmpty () ? new Data (assignment , compositeLit , references , previousStatement , structDefinition .getText (),
77+ needReplaceDeclarationWithShortVar ) : null ;
78+ }
79+
80+ @ Nullable
81+ private static GoCompositeLit createStructLiteral (@ NotNull GoVarDefinition definition , @ NotNull Project project ) {
82+ GoType type = definition .getGoType (null );
83+ return type != null ? GoElementFactory .createCompositeLit (project , type ) : null ;
84+ }
85+
86+ @ Nullable
87+ @ Contract ("null -> null" )
88+ private static GoVarDefinition getDefinition (@ Nullable GoReferenceExpression referenceExpressions ) {
89+ return ObjectUtils .tryCast (resolveQualifier (referenceExpressions ), GoVarDefinition .class );
6990 }
7091
7192 @ Nullable
@@ -104,6 +125,22 @@ private static GoReferenceExpression unwrapParensAndCast(@Nullable PsiElement e)
104125 return ObjectUtils .tryCast (e , GoReferenceExpression .class );
105126 }
106127
128+ @ Nullable
129+ @ Contract ("_, null -> null; null, _ -> null" )
130+ private static GoVarSpec getSingleVarSpecByDefinition (@ Nullable GoStatement statement ,
131+ @ Nullable GoVarDefinition definition ) {
132+ GoVarDeclaration declaration = statement != null ? statement .getVarDeclaration () : null ;
133+ List <GoVarSpec > varSpecs = declaration != null ? declaration .getVarSpecList () : emptyList ();
134+ GoVarSpec singleVarSpec = varSpecs .size () == 1 ? getFirstItem (varSpecs ) : null ;
135+ List <GoVarDefinition > varDefinitions = singleVarSpec != null ? singleVarSpec .getVarDefinitionList () : emptyList ();
136+ return varDefinitions .size () == 1 && definition == getFirstItem (varDefinitions ) ? singleVarSpec : null ;
137+ }
138+
139+ @ Contract ("null -> false" )
140+ private static boolean isUnassigned (@ Nullable GoVarSpec varSpec ) {
141+ return varSpec != null && varSpec .getExpressionList ().isEmpty ();
142+ }
143+
107144 @ Contract ("null -> false" )
108145 private static boolean isFieldReferenceExpression (@ Nullable PsiElement element ) {
109146 return element instanceof GoReferenceExpression && isFieldDefinition (((GoReferenceExpression )element ).resolve ());
@@ -138,11 +175,10 @@ private static boolean isResolvedTo(@Nullable PsiElement e, @Nullable PsiElement
138175
139176 @ NotNull
140177 private static List <GoReferenceExpression > getUninitializedSingleFieldReferences (@ NotNull GoAssignmentStatement assignment ,
141- @ NotNull GoReferenceExpression fieldReferenceExpression ,
178+ @ Nullable GoVarDefinition definition ,
142179 @ NotNull GoCompositeLit compositeLit ) {
143- PsiElement resolve = resolveQualifier (fieldReferenceExpression );
144180 List <GoReferenceExpression > uninitializedFieldReferencesByQualifier =
145- filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), resolve ));
181+ filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), definition ));
146182 MultiMap <PsiElement , GoReferenceExpression > resolved = groupBy (uninitializedFieldReferencesByQualifier , GoReferenceExpression ::resolve );
147183 return map (filter (resolved .entrySet (), set -> set .getValue ().size () == 1 ), set -> getFirstItem (set .getValue ()));
148184 }
@@ -151,13 +187,15 @@ private static List<GoReferenceExpression> getUninitializedSingleFieldReferences
151187 private static GoCompositeLit getStructLiteralByReference (@ NotNull GoReferenceExpression fieldReferenceExpression ,
152188 @ NotNull GoAssignmentStatement assignment ) {
153189 GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
190+ if (previousStatement == null ) return null ;
191+
154192 if (previousStatement instanceof GoSimpleStatement ) {
155193 return getStructLiteral (fieldReferenceExpression , (GoSimpleStatement )previousStatement );
156194 }
157195 if (previousStatement instanceof GoAssignmentStatement ) {
158196 return getStructLiteral (fieldReferenceExpression , (GoAssignmentStatement )previousStatement );
159197 }
160- return null ;
198+ return getStructLiteral ( previousStatement , fieldReferenceExpression ) ;
161199 }
162200
163201 @ Nullable
@@ -172,15 +210,16 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
172210 }
173211
174212 @ Nullable
175- private static PsiElement resolveQualifier (@ NotNull GoReferenceExpression fieldReferenceExpression ) {
176- GoReferenceExpression qualifier = fieldReferenceExpression .getQualifier ();
213+ @ Contract ("null -> null" )
214+ private static PsiElement resolveQualifier (@ Nullable GoReferenceExpression fieldReferenceExpression ) {
215+ GoReferenceExpression qualifier = fieldReferenceExpression != null ? fieldReferenceExpression .getQualifier () : null ;
177216 return qualifier != null ? qualifier .resolve () : null ;
178217 }
179218
180219 @ Nullable
181220 private static GoCompositeLit getStructLiteral (@ NotNull GoReferenceExpression fieldReferenceExpression ,
182221 @ NotNull GoAssignmentStatement structAssignment ) {
183- GoVarDefinition varDefinition = ObjectUtils . tryCast ( resolveQualifier ( fieldReferenceExpression ), GoVarDefinition . class );
222+ GoVarDefinition varDefinition = getDefinition ( fieldReferenceExpression );
184223 PsiElement field = fieldReferenceExpression .resolve ();
185224 if (varDefinition == null || !isFieldDefinition (field ) || !hasStructTypeWithField (varDefinition , (GoNamedElement )field )) {
186225 return null ;
@@ -193,6 +232,14 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
193232 return ObjectUtils .tryCast (compositeLit , GoCompositeLit .class );
194233 }
195234
235+ @ Nullable
236+ private static GoCompositeLit getStructLiteral (@ NotNull GoStatement statement ,
237+ @ NotNull GoReferenceExpression fieldReferenceExpression ) {
238+ GoVarDefinition definition = getDefinition (fieldReferenceExpression );
239+ GoVarSpec varSpec = definition != null ? getSingleVarSpecByDefinition (statement , definition ) : null ;
240+ return varSpec != null ? ObjectUtils .tryCast (getFirstItem (varSpec .getRightExpressionsList ()), GoCompositeLit .class ) : null ;
241+ }
242+
196243 private static boolean hasStructTypeWithField (@ NotNull GoVarDefinition structVarDefinition , @ NotNull GoNamedElement field ) {
197244 GoType type = structVarDefinition .getGoType (null );
198245 GoStructType structType = type != null ? ObjectUtils .tryCast (type .getUnderlyingType (), GoStructType .class ) : null ;
@@ -239,6 +286,10 @@ public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement
239286 Data data = getData (element );
240287 if (data == null ) return ;
241288 moveFieldReferenceExpressions (data );
289+
290+ if (!data .needReplaceDeclarationWithShortVar ()) return ;
291+ data .getStructDeclaration ()
292+ .replace (GoElementFactory .createShortVarDeclarationStatement (project , data .getStructVarName (), data .getCompositeLit ().getText ()));
242293 }
243294
244295 private static void moveFieldReferenceExpressions (@ NotNull Data data ) {
@@ -272,13 +323,22 @@ private static class Data {
272323 private final GoCompositeLit myCompositeLit ;
273324 private final GoAssignmentStatement myAssignment ;
274325 private final List <GoReferenceExpression > myReferenceExpressions ;
326+ private final GoStatement myStructDeclaration ;
327+ private final String myStructVarName ;
328+ private final boolean myNeedReplaceDeclarationWithShortVar ;
275329
276330 public Data (@ NotNull GoAssignmentStatement assignment ,
277- @ NotNull GoCompositeLit compositeLit ,
278- @ NotNull List <GoReferenceExpression > referenceExpressions ) {
331+ @ Nullable GoCompositeLit compositeLit ,
332+ @ NotNull List <GoReferenceExpression > referenceExpressions ,
333+ @ Nullable GoStatement structDeclaration ,
334+ @ Nullable String structVarName ,
335+ boolean needReplaceDeclarationWithShortVar ) {
279336 myCompositeLit = compositeLit ;
280337 myAssignment = assignment ;
281338 myReferenceExpressions = referenceExpressions ;
339+ myStructDeclaration = structDeclaration ;
340+ myStructVarName = structVarName ;
341+ myNeedReplaceDeclarationWithShortVar = needReplaceDeclarationWithShortVar ;
282342 }
283343
284344 public GoCompositeLit getCompositeLit () {
@@ -292,5 +352,19 @@ public GoAssignmentStatement getAssignment() {
292352 public List <GoReferenceExpression > getReferenceExpressions () {
293353 return myReferenceExpressions ;
294354 }
355+
356+ public GoStatement getStructDeclaration () {
357+ return myStructDeclaration ;
358+ }
359+
360+ public String getStructVarName () {
361+ return myStructVarName ;
362+ }
363+
364+ public boolean needReplaceDeclarationWithShortVar () {
365+ return myNeedReplaceDeclarationWithShortVar ;
366+ }
295367 }
296368}
369+
370+
0 commit comments