IDEA-50677 Groovy 1.7: Smart Code Completion for anonymous interface implementation expression could be added

This commit is contained in:
Maxim.Medvedev
2012-03-26 18:11:01 +04:00
parent ccf014f060
commit be108dce90
10 changed files with 71 additions and 47 deletions
@@ -27,6 +27,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -35,7 +36,7 @@ import java.util.List;
/**
* @author peter
*/
class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<LookupItem>> {
public class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<LookupItem>> {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ConstructorInsertHandler");
public static final ConstructorInsertHandler SMART_INSTANCE = new ConstructorInsertHandler(true);
public static final ConstructorInsertHandler BASIC_INSTANCE = new ConstructorInsertHandler(false);
@@ -169,6 +170,7 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
return hasParams;
}
@Nullable
private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) {
final Project project = file.getProject();
PsiDocumentManager.getInstance(project).commitAllDocuments();
@@ -180,13 +182,20 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
PsiElement parent = element.getParent();
if (!(parent instanceof PsiAnonymousClass)) return null;
try{
return genAnonymousBodyFor((PsiAnonymousClass)parent, editor, file, project);
}
public static Runnable genAnonymousBodyFor(PsiAnonymousClass parent,
final Editor editor,
final PsiFile file,
final Project project) {
try {
CodeStyleManager.getInstance(project).reformat(parent);
}
catch(IncorrectOperationException e){
catch (IncorrectOperationException e) {
LOG.error(e);
}
offset = parent.getTextRange().getEndOffset() - 1;
int offset = parent.getTextRange().getEndOffset() - 1;
editor.getCaretModel().moveToOffset(offset);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
editor.getSelectionModel().removeSelection();
@@ -17,7 +17,7 @@ package com.intellij.codeInsight.generation;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
import com.intellij.lang.ASTNode;
import com.intellij.lang.StdLanguages;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
@@ -109,7 +109,7 @@ public class GenerateMembersUtil {
}
@NotNull
public static <T extends GenerationInfo> List<T> insertMembersBeforeAnchor(PsiClass aClass, PsiElement anchor, @NotNull List<T> memberPrototypes) throws IncorrectOperationException {
public static <T extends GenerationInfo> List<T> insertMembersBeforeAnchor(PsiClass aClass, @Nullable PsiElement anchor, @NotNull List<T> memberPrototypes) throws IncorrectOperationException {
boolean before = true;
for (T memberPrototype : memberPrototypes) {
memberPrototype.insert(aClass, anchor, before);
@@ -280,7 +280,7 @@ public class GenerateMembersUtil {
if (paramName == null) paramName = "p" + i;
PsiParameter newParameter = factory.createParameter(paramName, substituted);
if (parameter.getLanguage() == StdLanguages.JAVA) {
if (parameter.getLanguage() == JavaLanguage.INSTANCE) {
PsiModifierList modifierList = newParameter.getModifierList();
modifierList = (PsiModifierList)modifierList.replace(parameter.getModifierList());
processAnnotations(project, modifierList);
@@ -280,7 +280,7 @@ public class GroovySmartCompletionContributor extends CompletionContributor {
final PsiClass psiClass = com.intellij.psi.util.PsiUtil.resolveClassInType(type);
if (psiClass == null) return null;
if (psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) return null;
//if (psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) return null;
if (!checkForInnerClass(psiClass, place)) return null;
final LookupItem item = PsiTypeLookupItem.createLookupItem(JavaCompletionUtil.eliminateWildcards(type), place);
@@ -17,15 +17,19 @@
package org.jetbrains.plugins.groovy.lang.completion.handlers;
import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.ConstructorInsertHandler;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.JavaCompletionFeatures;
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
@@ -33,6 +37,8 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
* @author Maxim.Medvedev
*/
public class AfterNewClassInsertHandler implements InsertHandler<LookupItem<PsiClassType>> {
private static final Logger LOG = Logger.getInstance(AfterNewClassInsertHandler.class);
private final PsiClassType myClassType;
private final boolean myTriggerFeature;
@@ -41,14 +47,15 @@ public class AfterNewClassInsertHandler implements InsertHandler<LookupItem<PsiC
myTriggerFeature = triggerFeature;
}
public void handleInsert(InsertionContext context, LookupItem<PsiClassType> item) {
public void handleInsert(final InsertionContext context, LookupItem<PsiClassType> item) {
final PsiClassType.ClassResolveResult resolveResult = myClassType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
if (psiClass == null || !psiClass.isValid()) {
return;
}
GroovyPsiElement place = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), GroovyPsiElement.class, false);
GroovyPsiElement place =
PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), GroovyPsiElement.class, false);
boolean hasParams = place != null && GroovyCompletionUtil.hasConstructorParameters(psiClass, place);
if (myTriggerFeature) {
FeatureUsageTracker.getInstance().triggerFeatureUsed(JavaCompletionFeatures.AFTER_NEW);
@@ -60,9 +67,36 @@ public class AfterNewClassInsertHandler implements InsertHandler<LookupItem<PsiC
else {
ParenthesesInsertHandler.NO_PARAMETERS.handleInsert(context, item);
}
GroovyCompletionUtil.addImportForItem(context.getFile(), context.getStartOffset(), item);
if (hasParams) {
AutoPopupController.getInstance(context.getProject()).autoPopupParameterInfo(context.getEditor(), null);
}
if (psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
final Editor editor = context.getEditor();
final int offset = context.getTailOffset();
editor.getDocument().insertString(offset, " {}");
editor.getCaretModel().moveToOffset(offset + 2);
context.setLaterRunnable(generateAnonymousBody(editor, context.getFile()));
}
}
@Nullable
private static Runnable generateAnonymousBody(final Editor editor, final PsiFile file) {
final Project project = file.getProject();
PsiDocumentManager.getInstance(project).commitAllDocuments();
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
if (element == null) return null;
PsiElement parent = element.getParent().getParent();
if (!(parent instanceof PsiAnonymousClass)) return null;
return ConstructorInsertHandler.genAnonymousBodyFor((PsiAnonymousClass)parent, editor, file, project);
}
}
@@ -36,12 +36,8 @@ public class GroovySmartCompletionTest extends GroovyCompletionTestBase {
assertOrderedEquals(myFixture.lookupElementStrings, "Bar", "Foo");
}
public void testSmartCompletionAfterNewInDeclarationWithInterface() throws Throwable { doSmartTest(); }
public void testCaretAfterSmartCompletionAfterNewInDeclaration() throws Throwable { doSmartTest(); }
public void testSmartCompletionAfterNewInDeclarationWithAbstractClass() throws Throwable { doSmartTest(); }
public void testSmartCompletionAfterNewInDeclarationWithArray() throws Throwable { doSmartTest(); }
public void testSmartCompletionAfterNewInDeclarationWithIntArray() throws Throwable { doSmartTest(); }
@@ -128,4 +124,19 @@ throw new RuntimeException()
void testInnerClassReferenceWithoutQualifier() {
doSmartTest()
}
void testAnonymousClassCompletion() {
myFixture.configureByText('_a.groovy', '''\
Runnable r = new Run<caret>
''')
myFixture.complete(CompletionType.SMART)
myFixture.checkResult('''\
Runnable r = new Runnable() {
@Override
void run() {
<caret><selection>//To change body of implemented methods use File | Settings | File Templates.</selection>
}
}
''')
}
}
@@ -1,6 +1,6 @@
class Foo {
static class Bar {}
{
List<Bar> l = new AL<caret>
List<Bar> l = new ArrL<caret>
}
}
@@ -1,9 +0,0 @@
abstract class Foo {
}
class Bar extends Foo {
}
abstract class Foo2 extends Foo {
}
Foo f = new <caret>
@@ -1,9 +0,0 @@
abstract class Foo {
}
class Bar extends Foo {
}
abstract class Foo2 extends Foo {
}
Foo f = new Bar()<caret>
@@ -1,6 +0,0 @@
interface Foo {
}
class Bar implements Foo {
}
Foo f = new <caret>
@@ -1,6 +0,0 @@
interface Foo {
}
class Bar implements Foo {
}
Foo f = new Bar()<caret>