Skip to content

Commit

Permalink
Add templates
Browse files Browse the repository at this point in the history
  • Loading branch information
wbars committed May 24, 2017
1 parent 9f63fbf commit a2737bd
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 37 deletions.
79 changes: 59 additions & 20 deletions src/com/goide/inspections/unresolved/GoAddStructFieldFix.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@

package com.goide.inspections.unresolved;

import com.goide.psi.GoFieldDeclaration;
import com.goide.psi.GoReferenceExpression;
import com.goide.psi.GoStructType;
import com.goide.psi.GoType;
import com.goide.psi.impl.GoElementFactory;
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.goide.GoConstants;
import com.goide.psi.*;
import com.goide.psi.impl.GoPsiImplUtil;
import com.goide.util.GoUtil;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.codeInsight.template.impl.ConstantNode;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
Expand All @@ -33,15 +37,11 @@

import java.util.List;

public class GoAddStructFieldFix extends LocalQuickFixOnPsiElement {
public class GoAddStructFieldFix extends LocalQuickFixAndIntentionActionOnPsiElement {
public static final String QUICK_FIX_NAME = "Add missing field";
private final String myFieldText;
private final String myTypeText;

protected GoAddStructFieldFix(String fieldText, String typeText, @NotNull PsiElement element) {
protected GoAddStructFieldFix(@NotNull PsiElement element) {
super(element);
myFieldText = fieldText;
myTypeText = typeText;
}

@NotNull
Expand All @@ -51,20 +51,59 @@ public String getText() {
}

@Override
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
GoStructType structType = resolveStructType(startElement);
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
if (editor == null) return;
GoReferenceExpression referenceExpression = ObjectUtils.tryCast(startElement, GoReferenceExpression.class);
GoStructType structType = referenceExpression != null ? resolveStructType(referenceExpression) : null;
if (structType == null) return;

List<GoFieldDeclaration> declarations = structType.getFieldDeclarationList();
PsiElement anchor = !declarations.isEmpty() ? ContainerUtil.getLastItem(declarations) : structType.getLbrace();
structType.addAfter(GoElementFactory.createFieldDeclaration(project, myFieldText, myTypeText), anchor);
if (anchor == null) return;

startTemplate(project, editor, file, referenceExpression, anchor);
}

private static void startTemplate(@NotNull Project project,
@NotNull Editor editor,
@NotNull PsiFile file,
GoReferenceExpression referenceExpression,
PsiElement anchor) {
Template template = TemplateManager.getInstance(project).createTemplate("", "");
template.addTextSegment(referenceExpression.getReference().getCanonicalText() + " ");
template.addVariable(new ConstantNode(getTypeName(referenceExpression, file)), true);
template.addTextSegment("\n");
editor.getCaretModel().moveToOffset(anchor.getTextRange().getEndOffset() + 1);
template.setToReformat(true);
TemplateManager.getInstance(project).startTemplate(editor, template);
}


private static String getTypeName(GoReferenceExpression referenceExpression, PsiFile file) {
GoAssignmentStatement assignment = PsiTreeUtil.getParentOfType(referenceExpression, GoAssignmentStatement.class);
if (assignment == null) return GoConstants.INTERFACE_TYPE;
GoExpression expression = GoPsiImplUtil.getRightExpression(assignment, referenceExpression);
GoType type = expression != null ? expression.getGoType(null) : null;

if (type instanceof GoSpecType) {
GoSpecType spec = (GoSpecType)type;
GoFile typeFile = ObjectUtils.tryCast(spec.getContainingFile(), GoFile.class);
if (typeFile != null && (file.isEquivalentTo(typeFile) || GoUtil.inSamePackage(typeFile, file))) {
return spec.getIdentifier().getText();
}
}
return type != null ? GoPsiImplUtil.getText(type) : GoConstants.INTERFACE_TYPE;
}

@Nullable
private static GoStructType resolveStructType(@NotNull PsiElement startElement) {
GoReferenceExpression referenceExpression = ObjectUtils.tryCast(startElement, GoReferenceExpression.class);
GoReferenceExpression qualifier = referenceExpression != null ? referenceExpression.getQualifier() : null;
GoType type = qualifier != null ? qualifier.getGoType(null) : null;
return type != null ? ObjectUtils.tryCast(type.getUnderlyingType(), GoStructType.class) : null;
private static GoStructType resolveStructType(@NotNull GoReferenceExpression referenceExpression) {
GoReferenceExpression qualifier = referenceExpression.getQualifier();
GoSpecType type = qualifier != null ? ObjectUtils.tryCast(qualifier.getGoType(null), GoSpecType.class) : null;
return type != null ? ObjectUtils.tryCast(type.getType(), GoStructType.class) : null;
}

@Nls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.goide.codeInsight.imports.GoImportPackageQuickFix;
import com.goide.inspections.GoInspectionBase;
import com.goide.psi.*;
import com.goide.psi.impl.GoPsiImplUtil;
import com.goide.psi.impl.GoReference;
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
import com.intellij.codeInspection.LocalInspectionToolSession;
Expand Down Expand Up @@ -79,7 +78,7 @@ else if (reference.resolve() == null) {
GoType type = qualifier != null ? qualifier.getGoType(null) : null;
GoStructType structType = type != null ? ObjectUtils.tryCast(type.getUnderlyingType(), GoStructType.class) : null;
if (!"_".equals(reference.getCanonicalText()) && structType != null) {
fixes = new LocalQuickFix[]{new GoAddStructFieldFix(reference.getCanonicalText(), getTypeName(o), o)};
fixes = new LocalQuickFix[]{new GoAddStructFieldFix(o)};
}
else if (isProhibited(o, qualifier)) {
fixes = createImportPackageFixes(o, reference, holder.isOnTheFly());
Expand Down Expand Up @@ -166,14 +165,6 @@ else if (holder.isOnTheFly()) {
};
}

private static String getTypeName(GoReferenceExpression referenceExpression) {
GoAssignmentStatement assignment = PsiTreeUtil.getParentOfType(referenceExpression, GoAssignmentStatement.class);
if (assignment == null) return "interface {}";
GoExpression expression = GoPsiImplUtil.getRightExpression(assignment, referenceExpression);
GoType type = expression != null ? expression.getGoType(null) : null;
return type != null ? type.getText() : "interface {}";
}

@NotNull
private static LocalQuickFix[] createImportPackageFixes(@NotNull PsiElement target, @NotNull PsiReference reference, boolean onTheFly) {
if (onTheFly) {
Expand Down
5 changes: 0 additions & 5 deletions src/com/goide/psi/impl/GoElementFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,4 @@ public static GoTypeDeclaration createTypeDeclaration(@NotNull Project project,
GoFile file = createFileFromText(project, "package a; type " + name + " " + type.getText());
return PsiTreeUtil.findChildOfType(file, GoTypeDeclaration.class);
}

public static GoFieldDeclaration createFieldDeclaration(@NotNull Project project, @NotNull String fieldText, @NotNull String typeText) {
GoFile file = createFileFromText(project, "package a; var _ = struct { " + fieldText + " " + typeText + " }");
return PsiTreeUtil.findChildOfType(file, GoFieldDeclaration.class);
}
}
12 changes: 12 additions & 0 deletions testData/quickfixes/add-struct-field/complexType-after.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

type S struct {
bb interface{}
cc interface{}
aa S
}

func main() {
s := S{}
s.aa = S{}
}
11 changes: 11 additions & 0 deletions testData/quickfixes/add-struct-field/complexType.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

type S struct {
bb interface{}
cc interface{}
}

func main() {
s := S{}
s.aa<caret> = S{}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ type S struct {

func main() {
s := S{}
s.aa<caret>
s.aa
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ type S struct {

func main() {
s := S{}
s.aa<caret> = "aa"
s.aa = "aa"
}
1 change: 1 addition & 0 deletions tests/com/goide/quickfix/GoAddStructFieldQuickFixTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ protected String getBasePath() {

public void testSimple() { doTest(ADD_STRUCT_FIELD); }
public void testWithoutElements() { doTest(ADD_STRUCT_FIELD); }
public void testComplexType() { doTest(ADD_STRUCT_FIELD); }
public void testWithoutAssignment() { doTest(ADD_STRUCT_FIELD); }
public void testBlank() { doTestNoFix(ADD_STRUCT_FIELD, true); }
}

0 comments on commit a2737bd

Please sign in to comment.