Skip to content

Commit b0b2cae

Browse files
committed
Unresolved struct field inspection
1 parent eb669fc commit b0b2cae

File tree

11 files changed

+209
-3
lines changed

11 files changed

+209
-3
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2013-2017 Sergey Ignatov, Alexander Zolotov, Florin Patan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.goide.inspections.unresolved;
18+
19+
import com.goide.psi.GoFieldDeclaration;
20+
import com.goide.psi.GoStructType;
21+
import com.goide.psi.impl.GoElementFactory;
22+
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
23+
import com.intellij.openapi.project.Project;
24+
import com.intellij.psi.PsiElement;
25+
import com.intellij.psi.PsiFile;
26+
import com.intellij.util.ObjectUtils;
27+
import com.intellij.util.containers.ContainerUtil;
28+
import org.jetbrains.annotations.Nls;
29+
import org.jetbrains.annotations.NotNull;
30+
31+
import java.util.List;
32+
33+
public class GoAddStructFieldFix extends LocalQuickFixOnPsiElement {
34+
public static final String QUICK_FIX_NAME = "Add missing field";
35+
private final String myFieldText;
36+
private final String myTypeText;
37+
38+
protected GoAddStructFieldFix(String fieldText, String typeText, @NotNull GoStructType element) {
39+
super(element);
40+
myFieldText = fieldText;
41+
myTypeText = typeText;
42+
}
43+
44+
@NotNull
45+
@Override
46+
public String getText() {
47+
return QUICK_FIX_NAME;
48+
}
49+
50+
@Override
51+
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
52+
GoStructType structType = ObjectUtils.tryCast(startElement, GoStructType.class);
53+
if (structType == null) return;
54+
List<GoFieldDeclaration> declarations = structType.getFieldDeclarationList();
55+
PsiElement anchor = !declarations.isEmpty() ? ContainerUtil.getLastItem(declarations) : structType.getLbrace();
56+
if (anchor != null) structType.addAfter(GoElementFactory.createFieldDeclaration(project, myFieldText, myTypeText), anchor);
57+
}
58+
59+
@Nls
60+
@NotNull
61+
@Override
62+
public String getFamilyName() {
63+
return QUICK_FIX_NAME;
64+
}
65+
}

src/com/goide/inspections/unresolved/GoUnresolvedReferenceInspection.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.goide.codeInsight.imports.GoImportPackageQuickFix;
2121
import com.goide.inspections.GoInspectionBase;
2222
import com.goide.psi.*;
23+
import com.goide.psi.impl.GoPsiImplUtil;
2324
import com.goide.psi.impl.GoReference;
2425
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
2526
import com.intellij.codeInspection.LocalInspectionToolSession;
@@ -33,6 +34,7 @@
3334
import com.intellij.psi.formatter.FormatterUtil;
3435
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference;
3536
import com.intellij.psi.util.PsiTreeUtil;
37+
import com.intellij.util.ObjectUtils;
3638
import com.intellij.util.containers.ContainerUtil;
3739
import org.jetbrains.annotations.NotNull;
3840
import org.jetbrains.annotations.Nullable;
@@ -74,7 +76,12 @@ public void visitReferenceExpression(@NotNull GoReferenceExpression o) {
7476
}
7577
else if (reference.resolve() == null) {
7678
LocalQuickFix[] fixes = LocalQuickFix.EMPTY_ARRAY;
77-
if (isProhibited(o, qualifier)) {
79+
GoType type = qualifier != null ? qualifier.getGoType(null) : null;
80+
GoStructType structType = type != null ? ObjectUtils.tryCast(type.getUnderlyingType(), GoStructType.class) : null;
81+
if (!"_".equals(reference.getCanonicalText()) && structType != null) {
82+
fixes = new LocalQuickFix[]{new GoAddStructFieldFix(reference.getCanonicalText(), getTypeName(o), structType)};
83+
}
84+
else if (isProhibited(o, qualifier)) {
7885
fixes = createImportPackageFixes(o, reference, holder.isOnTheFly());
7986
}
8087
else if (holder.isOnTheFly()) {
@@ -159,6 +166,14 @@ else if (holder.isOnTheFly()) {
159166
};
160167
}
161168

169+
private static String getTypeName(GoReferenceExpression referenceExpression) {
170+
GoAssignmentStatement assignment = PsiTreeUtil.getParentOfType(referenceExpression, GoAssignmentStatement.class);
171+
if (assignment == null) return "interface {}";
172+
GoExpression expression = GoPsiImplUtil.getRightExpression(assignment, referenceExpression);
173+
GoType type = expression != null ? expression.getGoType(null) : null;
174+
return type != null ? type.getText() : "interface {}";
175+
}
176+
162177
@NotNull
163178
private static LocalQuickFix[] createImportPackageFixes(@NotNull PsiElement target, @NotNull PsiReference reference, boolean onTheFly) {
164179
if (onTheFly) {

src/com/goide/psi/impl/GoElementFactory.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public static GoIfStatement createIfStatement(@NotNull Project project,
7474
public static GoImportDeclaration createEmptyImportDeclaration(@NotNull Project project) {
7575
return PsiTreeUtil.findChildOfType(createFileFromText(project, "package main\nimport (\n\n)"), GoImportDeclaration.class);
7676
}
77-
77+
7878
@NotNull
7979
public static GoImportDeclaration createImportDeclaration(@NotNull Project project, @NotNull String importString,
8080
@Nullable String alias, boolean withParens) {
@@ -191,7 +191,7 @@ public static GoGoStatement createGoStatement(@NotNull Project project, @NotNull
191191

192192
@NotNull
193193
public static GoForStatement createForStatement(@NotNull Project project, @NotNull String text) {
194-
GoFile file = createFileFromText(project, "package a; func a() {\n for {\n" + text + "\n}\n}");
194+
GoFile file = createFileFromText(project, "package a; func a() {\n for {\n" + text + "\n}\n}");
195195
return PsiTreeUtil.findChildOfType(file, GoForStatement.class);
196196
}
197197

@@ -266,4 +266,9 @@ public static GoTypeDeclaration createTypeDeclaration(@NotNull Project project,
266266
GoFile file = createFileFromText(project, "package a; type " + name + " " + type.getText());
267267
return PsiTreeUtil.findChildOfType(file, GoTypeDeclaration.class);
268268
}
269+
270+
public static GoFieldDeclaration createFieldDeclaration(@NotNull Project project, @NotNull String fieldText, @NotNull String typeText) {
271+
GoFile file = createFileFromText(project, "package a; var _ = struct { " + fieldText + " " + typeText + " }");
272+
return PsiTreeUtil.findChildOfType(file, GoFieldDeclaration.class);
273+
}
269274
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
type S struct {
4+
bb interface{}
5+
cc interface{}
6+
}
7+
8+
func main() {
9+
s := S{}
10+
s.<error descr="Unresolved reference '_'">_<caret></error> = "aa"
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
type S struct {
4+
bb interface{}
5+
cc interface{}
6+
aa string
7+
}
8+
9+
func main() {
10+
s := S{}
11+
s.aa = "aa"
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
type S struct {
4+
bb interface{}
5+
cc interface{}
6+
}
7+
8+
func main() {
9+
s := S{}
10+
s.aa<caret> = "aa"
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
type S struct {
4+
bb interface{}
5+
cc interface{}
6+
aa interface{}
7+
}
8+
9+
func main() {
10+
s := S{}
11+
s.aa<caret>
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
type S struct {
4+
bb interface{}
5+
cc interface{}
6+
}
7+
8+
func main() {
9+
s := S{}
10+
s.aa<caret>
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
type S struct {
4+
aa string
5+
}
6+
7+
func main() {
8+
s := S{}
9+
s.aa<caret> = "aa"
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
type S struct {
4+
5+
}
6+
7+
func main() {
8+
s := S{}
9+
s.aa<caret> = "aa"
10+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2013-2017 Sergey Ignatov, Alexander Zolotov, Florin Patan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.goide.quickfix;
18+
19+
import com.goide.SdkAware;
20+
import com.goide.inspections.unresolved.GoUnresolvedReferenceInspection;
21+
import org.jetbrains.annotations.NotNull;
22+
23+
@SdkAware
24+
public class GoAddStructFieldQuickFixTest extends GoQuickFixTestBase {
25+
26+
private static final String ADD_STRUCT_FIELD = "Add missing field";
27+
28+
@Override
29+
protected void setUp() throws Exception {
30+
super.setUp();
31+
myFixture.enableInspections(GoUnresolvedReferenceInspection.class);
32+
}
33+
34+
@NotNull
35+
@Override
36+
protected String getBasePath() {
37+
return "quickfixes/add-struct-field";
38+
}
39+
40+
public void testSimple() { doTest(ADD_STRUCT_FIELD); }
41+
public void testWithoutElements() { doTest(ADD_STRUCT_FIELD); }
42+
public void testWithoutAssignment() { doTest(ADD_STRUCT_FIELD); }
43+
public void testBlank() { doTestNoFix(ADD_STRUCT_FIELD, true); }
44+
}

0 commit comments

Comments
 (0)