Merge branch 'statimp'

This commit is contained in:
peter
2010-08-26 20:33:55 +01:00
13 changed files with 302 additions and 37 deletions
@@ -16,15 +16,17 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.daemon.impl.actions.AddImportAction;
import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupActionProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementAction;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiMethod;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
@@ -32,20 +34,20 @@ import com.intellij.util.Consumer;
public class ExcludeFromCompletionLookupActionProvider implements LookupActionProvider {
public void fillActions(LookupElement element, Lookup lookup, Consumer<LookupElementAction> consumer) {
final Object o = element.getObject();
PsiClass clazz = null;
if (o instanceof PsiType) {
clazz = PsiUtil.resolveClassInType((PsiType)o);
} else if (o instanceof PsiClass) {
clazz = (PsiClass)o;
if (o instanceof PsiClass) {
PsiClass clazz = (PsiClass)o;
addExcludes(consumer, clazz, clazz.getQualifiedName());
} else if (o instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)o;
addExcludes(consumer, method, StaticImportMethodFix.getMethodQualifiedName(method));
}
if (clazz != null && clazz.isValid()) {
final String qname = clazz.getQualifiedName();
if (qname != null) {
final Project project = clazz.getProject();
for (final String s : AddImportAction.getAllExcludableStrings(qname)) {
consumer.consume(new ExcludeFromCompletionAction(project, s));
}
}
}
private static void addExcludes(Consumer<LookupElementAction> consumer, PsiMember element, @Nullable String qname) {
if (qname == null) return;
final Project project = element.getProject();
for (final String s : AddImportAction.getAllExcludableStrings(qname)) {
consumer.consume(new ExcludeFromCompletionAction(project, s));
}
}
@@ -0,0 +1,123 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.completion.simple.PsiMethodInsertHandler;
import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMethodFix;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiTreeUtil;
/**
* @author peter
*/
public class JavaGlobalMemberNameCompletionContributor extends CompletionContributor {
private static final LookupElementRenderer<LookupElement> STATIC_METHOD_RENDERER = new LookupElementRenderer<LookupElement>() {
@Override
public void renderElement(LookupElement element, LookupElementPresentation presentation) {
PsiMethod method = (PsiMethod)element.getObject();
final PsiClass containingClass = method.getContainingClass();
presentation.setIcon(DefaultLookupItemRenderer.getRawIcon(element, presentation.isReal()));
presentation.setItemText(method.getName());
final String params = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY,
PsiFormatUtil.SHOW_PARAMETERS,
PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE);
if (containingClass != null) {
presentation.setTailText(params + " in " + containingClass.getName());
} else {
presentation.setTailText(params);
}
final PsiType type = method.getReturnType();
if (type != null) {
presentation.setTypeText(type.getPresentableText());
}
}
};
private static final InsertHandler<LookupElement> STATIC_METHOD_INSERT_HANDLER = new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
PsiMethodInsertHandler.INSTANCE.handleInsert(context, item);
final PsiClass containingClass = ((PsiMethod)item.getObject()).getContainingClass();
if (containingClass != null) {
PsiDocumentManager.getInstance(containingClass.getProject()).commitDocument(context.getDocument());
final PsiReferenceExpression ref = PsiTreeUtil
.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false);
if (ref != null) {
ref.bindToElementViaStaticImport(containingClass);
}
}
}
};
@Override
public void fillCompletionVariants(CompletionParameters parameters, final CompletionResultSet result) {
if (parameters.getCompletionType() != CompletionType.CLASS_NAME) {
return;
}
final PrefixMatcher matcher = result.getPrefixMatcher();
final String prefix = matcher.getPrefix();
if (prefix.length() == 0 || !Character.isLowerCase(prefix.charAt(0))) {
return;
}
final PsiElement position = parameters.getPosition();
final PsiElement parent = position.getParent();
if (!(parent instanceof PsiReferenceExpression)) {
return;
}
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)parent;
if (referenceExpression.isQualified()) {
return;
}
processStaticMethods(result, position, STATIC_METHOD_INSERT_HANDLER);
}
public static void processStaticMethods(final CompletionResultSet result,
final PsiElement position,
final InsertHandler<LookupElement> insertHandler) {
PrefixMatcher matcher = result.getPrefixMatcher();
final Project project = position.getProject();
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
final PsiShortNamesCache namesCache = JavaPsiFacade.getInstance(project).getShortNamesCache();
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();
final String[] methodNames = ApplicationManager.getApplication().runReadAction(new Computable<String[]>() {
public String[] compute() {
return namesCache.getAllMethodNames();
}
});
for (final String methodName : methodNames) {
if (matcher.prefixMatches(methodName)) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return namesCache.getMethodsByName(methodName, scope);
}
});
for (final PsiMethod method : methods) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (method.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(method, position, null)) {
final PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
if (!JavaCompletionUtil.isInExcludedPackage(containingClass) && !StaticImportMethodFix.isExcluded(method)) {
result.addElement(LookupElementDecorator.withInsertHandler(
LookupElementDecorator.withRenderer(LookupElementBuilder.create(method), STATIC_METHOD_RENDERER),
insertHandler));
}
}
}
}
});
}
}
}
}
}
@@ -39,11 +39,11 @@ import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public class PsiMethodInsertHandler implements InsertHandler<LookupItem<PsiMethod>> {
public class PsiMethodInsertHandler implements InsertHandler<LookupElement> {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.simple.PsiMethodInsertHandler");
public static final PsiMethodInsertHandler INSTANCE = new PsiMethodInsertHandler();
public static void insertParentheses(final InsertionContext context, final LookupItem item, boolean overloadsMatter, boolean hasParams) {
public static void insertParentheses(final InsertionContext context, final LookupElement item, boolean overloadsMatter, boolean hasParams) {
final Editor editor = context.getEditor();
final TailType tailType = getTailType(item, context);
final PsiFile file = context.getFile();
@@ -73,12 +73,12 @@ public class PsiMethodInsertHandler implements InsertHandler<LookupItem<PsiMetho
}
}
public void handleInsert(final InsertionContext context, final LookupItem<PsiMethod> item) {
public void handleInsert(final InsertionContext context, final LookupElement item) {
final Editor editor = context.getEditor();
final Document document = editor.getDocument();
final PsiFile file = context.getFile();
final int offset = editor.getCaretModel().getOffset();
final PsiMethod method = item.getObject();
final PsiMethod method = (PsiMethod)item.getObject();
final LookupElement[] allItems = context.getElements();
final boolean overloadsMatter = allItems.length == 1 && item.getUserData(LookupItem.FORCE_SHOW_SIGNATURE_ATTR) == null;
@@ -115,9 +115,9 @@ public class PsiMethodInsertHandler implements InsertHandler<LookupItem<PsiMetho
}
@NotNull
private static TailType getTailType(final LookupItem item, InsertionContext context) {
private static TailType getTailType(final LookupElement item, InsertionContext context) {
final char completionChar = context.getCompletionChar();
if (completionChar == '!') return item.getTailType();
if (completionChar == '!') return item instanceof LookupItem ? ((LookupItem)item).getTailType() : TailType.NONE;
if (completionChar == '(') {
final Object o = item.getObject();
if (o instanceof PsiMethod) {
@@ -141,8 +141,8 @@ public class PsiMethodInsertHandler implements InsertHandler<LookupItem<PsiMetho
return !(place.getParent() instanceof PsiImportStaticReferenceElement);
}
private static void insertExplicitTypeParams(final LookupItem<PsiMethod> item, final Document document, final int offset, PsiFile file) {
final PsiMethod method = item.getObject();
private static void insertExplicitTypeParams(final LookupElement item, final Document document, final int offset, PsiFile file) {
final PsiMethod method = (PsiMethod)item.getObject();
if (!SmartCompletionDecorator.hasUnboundTypeParams(method)) {
return;
}
@@ -42,6 +42,7 @@ import com.intellij.ui.popup.list.PopupListElementRenderer;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -138,8 +139,9 @@ public class StaticImportMethodFix implements IntentionAction {
return result;
}
private static boolean isExcluded(PsiMethod method) {
String name = getQName(method);
public static boolean isExcluded(PsiMethod method) {
String name = getMethodQualifiedName(method);
if (name == null) return false;
CodeInsightSettings cis = CodeInsightSettings.getInstance();
for (String excluded : cis.EXCLUDED_PACKAGES) {
if (name.equals(excluded) || name.startsWith(excluded + ".")) {
@@ -199,7 +201,7 @@ public class StaticImportMethodFix implements IntentionAction {
return FINAL_CHOICE;
}
String qname = getQName(selectedValue);
String qname = getMethodQualifiedName(selectedValue);
if (qname == null) return FINAL_CHOICE;
List<String> excludableStrings = AddImportAction.getAllExcludableStrings(qname);
return new BaseListPopupStep<String>(null, excludableStrings) {
@@ -264,12 +266,13 @@ public class StaticImportMethodFix implements IntentionAction {
popup.showInBestPositionFor(editor);
}
private static String getQName(PsiMethod selectedValue) {
PsiClass containingClass = selectedValue.getContainingClass();
@Nullable
public static String getMethodQualifiedName(PsiMethod method) {
PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return null;
String className = containingClass.getQualifiedName();
if (className == null) return null;
return className + "." + selectedValue.getName();
return className + "." + method.getName();
}
public boolean startInWriteAction() {
+1
View File
@@ -18,6 +18,7 @@
<orderEntry type="module" module-name="compiler-impl" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="module" module-name="notNull" />
<orderEntry type="library" name="Groovy" level="project" />
</component>
</module>
@@ -0,0 +1,74 @@
package com.intellij.codeInsight.completion;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.util.ArrayUtil;
/**
* @author peter
*/
public class GlobalMemberNameCompletionTest extends LightCodeInsightFixtureTestCase {
public void testMethodName() throws Exception {
myFixture.addClass("""
package foo;
public class Foo {
public static int abcmethod() {}
static void methodThatsNotVisible() {}
}
""")
doTest "class Bar {{ abcm<caret> }}", """import static foo.Foo.abcmethod;
class Bar {{ abcmethod()<caret> }}"""
}
@Override protected void tearDown() {
CodeInsightSettings.instance.EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY
super.tearDown()
}
public void testExcludeClassFromCompletion() throws Exception {
myFixture.addClass("""package foo;
public class Foo {
public static int abcmethod() {}
}
""")
myFixture.addClass("""package foo;
public class Excl {
public static int abcmethod2() {}
}
""")
CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Excl"] as String[]
doTest "class Bar {{ abcm<caret> }}", """import static foo.Foo.abcmethod;
class Bar {{ abcmethod()<caret> }}"""
}
public void testExcludeMethodFromCompletion() throws Exception {
myFixture.addClass("""package foo;
public class Foo {
public static int abcmethod1() {}
public static int abcmethodExcluded() {}
}
""")
CodeInsightSettings.instance.EXCLUDED_PACKAGES = ["foo.Foo.abcmethodExcluded"] as String[]
doTest "class Bar {{ abcm<caret> }}", """import static foo.Foo.abcmethod1;
class Bar {{ abcmethod1()<caret> }}"""
}
private void doTest(String input, String output) {
myFixture.configureByText("a.java", input)
assertOneElement myFixture.complete(CompletionType.CLASS_NAME)
myFixture.type('\n')
myFixture.checkResult output
}
}
@@ -16,11 +16,12 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
@@ -65,6 +66,11 @@ public class InsertionContext {
return myEditor;
}
@NotNull
public Document getDocument() {
return getEditor().getDocument();
}
public OffsetMap getOffsetMap() {
return myOffsetMap;
}
@@ -44,7 +44,7 @@ public class DefaultLookupItemRenderer extends LookupElementRenderer<LookupItem>
}
@Nullable
public static Icon getRawIcon(final LookupItem item, boolean real) {
public static Icon getRawIcon(final LookupElement item, boolean real) {
final Icon icon = _getRawIcon(item, real);
if (icon != null && icon.getIconHeight() > SAMPLE_ICON.getIconHeight()) {
return new SizedIcon(icon, icon.getIconWidth(), SAMPLE_ICON.getIconHeight());
@@ -53,9 +53,11 @@ public class DefaultLookupItemRenderer extends LookupElementRenderer<LookupItem>
}
@Nullable
private static Icon _getRawIcon(LookupItem item, boolean real) {
Icon icon = (Icon)item.getAttribute(LookupItem.ICON_ATTR);
if (icon != null) return icon;
private static Icon _getRawIcon(LookupElement item, boolean real) {
if (item instanceof LookupItem) {
Icon icon = (Icon)((LookupItem)item).getAttribute(LookupItem.ICON_ATTR);
if (icon != null) return icon;
}
Object o = item.getObject();
@@ -305,6 +305,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
void type(final char c);
void type(final String s);
void performEditorAction(String actionId);
/**
@@ -602,6 +602,13 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
}.execute();
}
@Override
public void type(String s) {
for (int i = 0; i < s.length(); i++) {
type(s.charAt(i));
}
}
public void performEditorAction(final String actionId) {
assertInitialized();
final DataContext dataContext = DataManager.getInstance().getDataContext();
@@ -45,7 +45,6 @@ import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
@@ -98,6 +97,22 @@ public class GroovyCompletionContributor extends CompletionContributor {
psiElement().withParent(psiElement(GrReferenceExpression.class).withParent(psiElement(GrArgumentList.class).withParent(GrCall.class)));
private static final String[] THIS_SUPER = {"this", "super"};
private static final InsertHandler<LookupElement> STATIC_IMPORT_INSERT_HANDLER = new InsertHandler<LookupElement>() {
@Override
public void handleInsert(InsertionContext context, LookupElement item) {
new GroovyInsertHandler().handleInsert(context, item);
final PsiClass containingClass = ((PsiMethod)item.getObject()).getContainingClass();
if (containingClass != null) {
PsiDocumentManager.getInstance(containingClass.getProject()).commitDocument(context.getDocument());
final GrReferenceExpression ref = PsiTreeUtil
.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), GrReferenceExpression.class, false);
if (ref != null) {
ref.bindToElementViaStaticImport(containingClass);
}
}
}
};
public static boolean isReferenceInNewExpression(PsiElement reference) {
if (!(reference instanceof GrCodeReferenceElement)) return false;
@@ -303,7 +318,7 @@ public class GroovyCompletionContributor extends CompletionContributor {
}
});
extend(CompletionType.BASIC, psiElement().withParent(GrReferenceElement.class), new CompletionProvider<CompletionParameters>() {
extend(CompletionType.BASIC, psiElement().withParent(GrReferenceElement.class), new CompletionProvider<CompletionParameters>(false) {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@@ -323,6 +338,20 @@ public class GroovyCompletionContributor extends CompletionContributor {
}
});
extend(CompletionType.CLASS_NAME, psiElement().withParent(GrReferenceElement.class), new CompletionProvider<CompletionParameters>(false) {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull final CompletionResultSet result) {
final PsiElement position = parameters.getPosition();
if (((GrReferenceElement)position.getParent()).getQualifier() != null) return;
final String s = result.getPrefixMatcher().getPrefix();
if (StringUtil.isEmpty(s) || !Character.isLowerCase(s.charAt(0))) return;
JavaGlobalMemberNameCompletionContributor.processStaticMethods(result, position, STATIC_IMPORT_INSERT_HANDLER);
}
});
}
private static void addPropertiesForClass(CompletionResultSet result,
@@ -107,4 +107,17 @@ public class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCa
myFixture.checkResult "a.FooBarGooDoo<caret>"
}
public void testStaticMethod() throws Exception {
myFixture.addFileToProject("b.groovy", """
class Foo {
static def abcmethod(int a) {}
}""")
myFixture.configureByText("a.groovy", "abcme<caret>")
myFixture.complete(CompletionType.CLASS_NAME)
myFixture.checkResult """import static Foo.abcmethod
abcmethod(<caret>)"""
}
}
+4 -1
View File
@@ -229,7 +229,8 @@
order="first, before javaMemberName, after xml"/>
<completion.contributor language="JAVA" implementationClass="com.intellij.codeInsight.completion.JavaCompletionContributor" id="javaLegacy"
order="last, before legacy, before default, before javaClassName"/>
<completion.contributor language="any" implementationClass="com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor" id="javaClassReference"/>
<completion.contributor language="any" implementationClass="com.intellij.codeInsight.completion.JavaClassReferenceCompletionContributor"
id="javaClassReference"/>
<completion.contributor language="any" implementationClass="com.intellij.codeInsight.completion.JavaMethodMergingContributor" id="methodMerger"
order="before javaLegacy, before default"/>
@@ -237,6 +238,8 @@
order="before javaLegacy"/>
<completion.contributor language="any" implementationClass="com.intellij.codeInsight.completion.JavaClassNameCompletionContributor" id="javaClassName"
order="last, before default"/>
<completion.contributor language="JAVA" implementationClass="com.intellij.codeInsight.completion.JavaGlobalMemberNameCompletionContributor"
id="javaGlobalMemberName" order="last, after javaClassName"/>
<completion.contributor language="JAVA" implementationClass="com.intellij.codeInsight.completion.JavaDocCompletionContributor" id="javadoc"
order="last, before javaLegacy"/>