1919import com .goide .psi .*;
2020import com .goide .psi .impl .GoElementFactory ;
2121import com .goide .psi .impl .GoPsiImplUtil ;
22+ import com .goide .psi .impl .GoStatementImpl ;
2223import com .intellij .codeInsight .intention .BaseElementAtCaretIntentionAction ;
2324import com .intellij .openapi .editor .Editor ;
2425import com .intellij .openapi .project .Project ;
@@ -53,19 +54,29 @@ public String getFamilyName() {
5354
5455 @ Override
5556 public boolean isAvailable (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) {
56- return getData (element ) != null ;
57+ return getData (element , project ) != null ;
5758 }
5859
5960 @ Nullable
60- private static Data getData (@ NotNull PsiElement element ) {
61+ private static Data getData (@ NotNull PsiElement element , @ NotNull Project project ) {
6162 if (!element .isValid () || !element .isWritable ()) return null ;
6263 GoAssignmentStatement assignment = getValidAssignmentParent (element );
6364 GoReferenceExpression selectedFieldReference = assignment != null ? getFieldReferenceExpression (element , assignment ) : null ;
64- GoCompositeLit compositeLit = selectedFieldReference != null ? getStructLiteralByReference (selectedFieldReference , assignment ) : null ;
65- if (compositeLit == null ) return null ;
65+ GoCompositeLit compositeLit =
66+ selectedFieldReference != null ? getStructLiteralByReference (selectedFieldReference , assignment , project ) : null ;
67+ GoVarDefinition structDefinition = getDefinition (selectedFieldReference );
68+ if (compositeLit == null || structDefinition == null ) return null ;
69+
70+ List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , structDefinition , compositeLit );
71+ GoStatementImpl previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatementImpl .class );
72+ return !references .isEmpty () ? new Data (assignment , compositeLit , references , previousStatement , structDefinition .getText (),
73+ isUnassigned (getSingleVarSpecByDefinition (previousStatement , structDefinition ))) : null ;
74+ }
6675
67- List <GoReferenceExpression > references = getUninitializedSingleFieldReferences (assignment , selectedFieldReference , compositeLit );
68- return !references .isEmpty () ? new Data (assignment , compositeLit , references ) : null ;
76+ @ Nullable
77+ @ Contract ("null -> null" )
78+ private static GoVarDefinition getDefinition (@ Nullable GoReferenceExpression referenceExpressions ) {
79+ return ObjectUtils .tryCast (resolveQualifier (referenceExpressions ), GoVarDefinition .class );
6980 }
7081
7182 @ Nullable
@@ -104,6 +115,22 @@ private static GoReferenceExpression unwrapParensAndCast(@Nullable PsiElement e)
104115 return ObjectUtils .tryCast (e , GoReferenceExpression .class );
105116 }
106117
118+ @ Nullable
119+ @ Contract ("_, null -> null; null, _ -> null" )
120+ private static GoVarSpec getSingleVarSpecByDefinition (@ Nullable GoStatementImpl statement ,
121+ @ Nullable GoVarDefinition definition ) {
122+ GoVarDeclaration declaration = statement != null ? statement .getVarDeclaration () : null ;
123+ List <GoVarSpec > varSpecs = declaration != null ? declaration .getVarSpecList () : emptyList ();
124+ GoVarSpec singleVarSpec = varSpecs .size () == 1 ? getFirstItem (varSpecs ) : null ;
125+ List <GoVarDefinition > varDefinitions = singleVarSpec != null ? singleVarSpec .getVarDefinitionList () : emptyList ();
126+ return varDefinitions .size () == 1 && isResolvedTo (definition , getFirstItem (varDefinitions )) ? singleVarSpec : null ;
127+ }
128+
129+ @ Contract ("null -> false" )
130+ private static boolean isUnassigned (@ Nullable GoVarSpec varSpec ) {
131+ return varSpec != null && varSpec .getExpressionList ().isEmpty ();
132+ }
133+
107134 @ Contract ("null -> false" )
108135 private static boolean isFieldReferenceExpression (@ Nullable PsiElement element ) {
109136 return element instanceof GoReferenceExpression && isFieldDefinition (((GoReferenceExpression )element ).resolve ());
@@ -138,25 +165,28 @@ private static boolean isResolvedTo(@Nullable PsiElement e, @Nullable PsiElement
138165
139166 @ NotNull
140167 private static List <GoReferenceExpression > getUninitializedSingleFieldReferences (@ NotNull GoAssignmentStatement assignment ,
141- @ NotNull GoReferenceExpression fieldReferenceExpression ,
168+ @ Nullable GoVarDefinition definition ,
142169 @ NotNull GoCompositeLit compositeLit ) {
143- PsiElement resolve = resolveQualifier (fieldReferenceExpression );
144170 List <GoReferenceExpression > uninitializedFieldReferencesByQualifier =
145- filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), resolve ));
171+ filter (getUninitializedFieldReferenceExpressions (assignment , compositeLit ), e -> isResolvedTo (e .getQualifier (), definition ));
146172 MultiMap <PsiElement , GoReferenceExpression > resolved = groupBy (uninitializedFieldReferencesByQualifier , GoReferenceExpression ::resolve );
147173 return map (filter (resolved .entrySet (), set -> set .getValue ().size () == 1 ), set -> getFirstItem (set .getValue ()));
148174 }
149175
150176 @ Nullable
151177 private static GoCompositeLit getStructLiteralByReference (@ NotNull GoReferenceExpression fieldReferenceExpression ,
152- @ NotNull GoAssignmentStatement assignment ) {
178+ @ NotNull GoAssignmentStatement assignment ,
179+ @ NotNull Project project ) {
153180 GoStatement previousStatement = PsiTreeUtil .getPrevSiblingOfType (assignment , GoStatement .class );
154181 if (previousStatement instanceof GoSimpleStatement ) {
155182 return getStructLiteral (fieldReferenceExpression , (GoSimpleStatement )previousStatement );
156183 }
157184 if (previousStatement instanceof GoAssignmentStatement ) {
158185 return getStructLiteral (fieldReferenceExpression , (GoAssignmentStatement )previousStatement );
159186 }
187+ if (previousStatement instanceof GoStatementImpl ) {
188+ return getStructLiteral ((GoStatementImpl )previousStatement , fieldReferenceExpression , project );
189+ }
160190 return null ;
161191 }
162192
@@ -172,15 +202,16 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
172202 }
173203
174204 @ Nullable
175- private static PsiElement resolveQualifier (@ NotNull GoReferenceExpression fieldReferenceExpression ) {
176- GoReferenceExpression qualifier = fieldReferenceExpression .getQualifier ();
205+ @ Contract ("null -> null" )
206+ private static PsiElement resolveQualifier (@ Nullable GoReferenceExpression fieldReferenceExpression ) {
207+ GoReferenceExpression qualifier = fieldReferenceExpression != null ? fieldReferenceExpression .getQualifier () : null ;
177208 return qualifier != null ? qualifier .resolve () : null ;
178209 }
179210
180211 @ Nullable
181212 private static GoCompositeLit getStructLiteral (@ NotNull GoReferenceExpression fieldReferenceExpression ,
182213 @ NotNull GoAssignmentStatement structAssignment ) {
183- GoVarDefinition varDefinition = ObjectUtils . tryCast ( resolveQualifier ( fieldReferenceExpression ), GoVarDefinition . class );
214+ GoVarDefinition varDefinition = getDefinition ( fieldReferenceExpression );
184215 PsiElement field = fieldReferenceExpression .resolve ();
185216 if (varDefinition == null || !isFieldDefinition (field ) || !hasStructTypeWithField (varDefinition , (GoNamedElement )field )) {
186217 return null ;
@@ -193,6 +224,19 @@ private static GoCompositeLit getStructLiteral(@NotNull GoReferenceExpression fi
193224 return ObjectUtils .tryCast (compositeLit , GoCompositeLit .class );
194225 }
195226
227+ @ Nullable
228+ private static GoCompositeLit getStructLiteral (@ NotNull GoStatementImpl statement ,
229+ @ NotNull GoReferenceExpression fieldReferenceExpression ,
230+ @ NotNull Project project ) {
231+ GoVarDefinition definition = getDefinition (fieldReferenceExpression );
232+ GoVarSpec varSpec = definition != null ? getSingleVarSpecByDefinition (statement , definition ) : null ;
233+ if (varSpec == null ) return null ;
234+ GoType structType = isUnassigned (varSpec ) ? definition .getGoType (null ) : null ;
235+ return structType != null
236+ ? GoElementFactory .createCompositeLit (project , structType )
237+ : ObjectUtils .tryCast (getFirstItem (varSpec .getRightExpressionsList ()), GoCompositeLit .class );
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 ;
@@ -236,9 +280,13 @@ private static List<? extends PsiElement> getLeftHandElements(@NotNull GoStateme
236280
237281 @ Override
238282 public void invoke (@ NotNull Project project , Editor editor , @ NotNull PsiElement element ) throws IncorrectOperationException {
239- Data data = getData (element );
283+ Data data = getData (element , project );
240284 if (data == null ) return ;
241285 moveFieldReferenceExpressions (data );
286+
287+ if (!data .needReplaceDeclarationWithShortVar ()) return ;
288+ data .getStructDeclaration ()
289+ .replace (GoElementFactory .createShortVarDeclarationStatement (project , data .getStructVarName (), data .getCompositeLit ().getText ()));
242290 }
243291
244292 private static void moveFieldReferenceExpressions (@ NotNull Data data ) {
@@ -272,13 +320,22 @@ private static class Data {
272320 private final GoCompositeLit myCompositeLit ;
273321 private final GoAssignmentStatement myAssignment ;
274322 private final List <GoReferenceExpression > myReferenceExpressions ;
323+ private final GoStatementImpl myStructDeclaration ;
324+ private final String myStructVarName ;
325+ private final boolean myNeedReplaceDeclarationWithShortVar ;
275326
276327 public Data (@ NotNull GoAssignmentStatement assignment ,
277- @ NotNull GoCompositeLit compositeLit ,
278- @ NotNull List <GoReferenceExpression > referenceExpressions ) {
328+ @ Nullable GoCompositeLit compositeLit ,
329+ @ NotNull List <GoReferenceExpression > referenceExpressions ,
330+ @ Nullable GoStatementImpl structDeclaration ,
331+ @ Nullable String structVarName ,
332+ boolean needReplaceDeclarationWithShortVar ) {
279333 myCompositeLit = compositeLit ;
280334 myAssignment = assignment ;
281335 myReferenceExpressions = referenceExpressions ;
336+ myStructDeclaration = structDeclaration ;
337+ myStructVarName = structVarName ;
338+ myNeedReplaceDeclarationWithShortVar = needReplaceDeclarationWithShortVar ;
282339 }
283340
284341 public GoCompositeLit getCompositeLit () {
@@ -292,5 +349,19 @@ public GoAssignmentStatement getAssignment() {
292349 public List <GoReferenceExpression > getReferenceExpressions () {
293350 return myReferenceExpressions ;
294351 }
352+
353+ public GoStatementImpl getStructDeclaration () {
354+ return myStructDeclaration ;
355+ }
356+
357+ public String getStructVarName () {
358+ return myStructVarName ;
359+ }
360+
361+ public boolean needReplaceDeclarationWithShortVar () {
362+ return myNeedReplaceDeclarationWithShortVar ;
363+ }
295364 }
296365}
366+
367+
0 commit comments