Complete only imported classes on auto-typing and first completion and set up invocation count

This commit is contained in:
Nikolay Krasko
2013-07-04 16:52:48 +04:00
parent f0a10b70c1
commit 37e4402822
15 changed files with 200 additions and 88 deletions
@@ -20,6 +20,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.JavaCompletionContributor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
@@ -43,10 +44,9 @@ import org.jetbrains.jet.plugin.references.JetSimpleNameReference;
import java.util.Collection;
class CompletionSession {
public class CompletionSession {
@Nullable
private final DeclarationDescriptor inDescriptor;
private final int customInvocationCount;
private final CompletionParameters parameters;
private final JetCompletionResultSet jetResult;
private final JetSimpleNameReference jetReference;
@@ -57,20 +57,8 @@ class CompletionSession {
@NotNull JetSimpleNameReference jetReference,
@NotNull PsiElement position
) {
this(parameters, result, jetReference, position, parameters.getInvocationCount());
}
public CompletionSession(
@NotNull CompletionParameters parameters,
@NotNull CompletionResultSet result,
@NotNull JetSimpleNameReference jetReference,
@NotNull PsiElement position,
int customInvocationCount
) {
this.parameters = parameters;
this.jetReference = jetReference;
this.customInvocationCount = customInvocationCount;
ResolveSession resolveSession = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile((JetFile) position.getContainingFile());
BindingContext expressionBindingContext = ResolveSessionUtils.resolveToExpression(resolveSession, jetReference.getExpression());
@@ -95,7 +83,7 @@ class CompletionSession {
}
if (shouldRunOnlyTypeCompletion()) {
if (customInvocationCount >= 1) {
if (parameters.getInvocationCount() >= 2) {
JetTypesCompletionHelper.addJetTypes(parameters, jetResult);
}
else {
@@ -105,6 +93,7 @@ class CompletionSession {
return isPartOfTypeDeclaration(descriptor);
}
});
JavaCompletionContributor.advertiseSecondCompletion(parameters.getPosition().getProject(), jetResult.getResult());
}
return;
@@ -116,7 +105,7 @@ class CompletionSession {
// Try to avoid computing not-imported descriptors for empty prefix
if (prefix.isEmpty()) {
if (customInvocationCount < 2) {
if (parameters.getInvocationCount() < 2) {
return;
}
@@ -210,7 +199,7 @@ class CompletionSession {
}
private boolean shouldRunTopLevelCompletion() {
if (customInvocationCount == 0) {
if (parameters.getInvocationCount() < 2) {
return false;
}
@@ -238,7 +227,7 @@ class CompletionSession {
}
private boolean shouldRunExtensionsCompletion() {
return !(customInvocationCount == 0 && jetResult.getResult().getPrefixMatcher().getPrefix().length() < 3);
return !(parameters.getInvocationCount() <= 1 && jetResult.getResult().getPrefixMatcher().getPrefix().length() < 3);
}
private void addReferenceVariants(@NotNull final Condition<DeclarationDescriptor> filterCondition) {
@@ -256,7 +245,7 @@ class CompletionSession {
}
private boolean isVisibleDescriptor(DeclarationDescriptor descriptor) {
if (customInvocationCount >= 2) {
if (parameters.getInvocationCount() >= 2) {
// Show everything if user insist on showing completion list
return true;
}
@@ -287,7 +276,7 @@ class CompletionSession {
return jetResult;
}
public int getCustomInvocationCount() {
return customInvocationCount;
public CompletionParameters getParameters() {
return parameters;
}
}
@@ -36,33 +36,36 @@ public class JetCompletionContributor extends CompletionContributor {
ProcessingContext context,
@NotNull CompletionResultSet result
) {
PsiElement position = parameters.getPosition();
if (!(position.getContainingFile() instanceof JetFile)) {
return;
}
JetSimpleNameReference jetReference = getJetReference(parameters);
if (jetReference != null) {
result.restartCompletionWhenNothingMatches();
CompletionSession session = new CompletionSession(parameters, result, jetReference, position);
session.completeForReference();
if (!session.getJetResult().isSomethingAdded() && session.getCustomInvocationCount() == 0) {
// Rerun completion if nothing was found
session = new CompletionSession(parameters, result, jetReference, position, 1);
session.completeForReference();
}
}
// Prevent from adding reference variants from standard reference contributor
result.stopHere();
doSimpleReferenceCompletion(parameters, result);
}
});
}
public static void doSimpleReferenceCompletion(CompletionParameters parameters, CompletionResultSet result) {
PsiElement position = parameters.getPosition();
if (!(position.getContainingFile() instanceof JetFile)) {
return;
}
JetSimpleNameReference jetReference = getJetReference(parameters);
if (jetReference != null) {
result.restartCompletionWhenNothingMatches();
CompletionSession session = new CompletionSession(parameters, result, jetReference, position);
session.completeForReference();
if (!session.getJetResult().isSomethingAdded() && session.getParameters().getInvocationCount() < 2) {
// Rerun completion if nothing was found
session = new CompletionSession(parameters.withInvocationCount(2), result, jetReference, position);
session.completeForReference();
}
// Prevent from adding reference variants from standard reference contributor
result.stopHere();
}
}
@Nullable
private static JetSimpleNameReference getJetReference(@NotNull CompletionParameters parameters) {
PsiElement element = parameters.getPosition();
@@ -81,4 +84,18 @@ public class JetCompletionContributor extends CompletionContributor {
return null;
}
@Override
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
if (context.getCompletionType() == CompletionType.BASIC && context.getFile() instanceof JetFile) {
PsiElement position = context.getFile().findElementAt(Math.max(0, context.getStartOffset() - 1));
if (JetPackagesContributor.ACTIVATION_PATTERN.accepts(position)) {
context.setDummyIdentifier(JetPackagesContributor.DUMMY_IDENTIFIER);
}
else if (JetExtensionReceiverTypeContributor.ACTIVATION_PATTERN.accepts(position)) {
context.setDummyIdentifier(JetExtensionReceiverTypeContributor.DUMMY_IDENTIFIER);
}
}
}
}
@@ -22,36 +22,16 @@ import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
/**
* Special contributor for getting completion of type for extensions receiver.
*/
public class JetExtensionReceiverTypeContributor extends CompletionContributor {
private static class ReceiverTypeCompletionProvider extends CompletionProvider<CompletionParameters> {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result
) {
ResolveSession resolveSession = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile(
(JetFile) parameters.getPosition().getContainingFile());
JetCompletionResultSet jetCompletionResultSet = new JetCompletionResultSet(
result, resolveSession, resolveSession.getBindingContext());
static final String DUMMY_IDENTIFIER = "KotlinExtensionDummy.fake() {}";
if (parameters.getInvocationCount() > 0) {
JetTypesCompletionHelper.addJetTypes(parameters, jetCompletionResultSet);
}
result.stopHere();
}
}
private static final ElementPattern<? extends PsiElement> ACTIVATION_PATTERN =
static final ElementPattern<? extends PsiElement> ACTIVATION_PATTERN =
// TODO: Check for fun with generic type parameters
PlatformPatterns.psiElement().afterLeaf(
JetTokens.FUN_KEYWORD.toString(),
@@ -59,7 +39,17 @@ public class JetExtensionReceiverTypeContributor extends CompletionContributor {
JetTokens.VAR_KEYWORD.toString());
public JetExtensionReceiverTypeContributor() {
extend(CompletionType.BASIC, ACTIVATION_PATTERN, new ReceiverTypeCompletionProvider());
extend(CompletionType.CLASS_NAME, ACTIVATION_PATTERN, new ReceiverTypeCompletionProvider());
extend(CompletionType.BASIC, ACTIVATION_PATTERN, new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(
@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result
) {
if (parameters.getInvocationCount() > 0) {
JetCompletionContributor.doSimpleReferenceCompletion(parameters, result);
}
result.stopHere();
}
});
}
}
@@ -18,18 +18,18 @@ package org.jetbrains.jet.plugin.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.plugin.codeInsight.TipsManager;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils;
import org.jetbrains.jet.plugin.codeInsight.TipsManager;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.plugin.references.JetSimpleNameReference;
@@ -39,10 +39,14 @@ import org.jetbrains.jet.plugin.references.JetSimpleNameReference;
*/
public class JetPackagesContributor extends CompletionContributor {
private static final String DUMMY_IDENTIFIER = "___package___";
static final String DUMMY_IDENTIFIER = "___package___";
static final ElementPattern<? extends PsiElement> ACTIVATION_PATTERN =
PlatformPatterns.psiElement().inside(JetNamespaceHeader.class);
public JetPackagesContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(),
extend(CompletionType.BASIC, ACTIVATION_PATTERN,
new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context,
@@ -53,11 +57,6 @@ public class JetPackagesContributor extends CompletionContributor {
return;
}
JetNamespaceHeader namespaceHeader = PsiTreeUtil.getParentOfType(position, JetNamespaceHeader.class);
if (namespaceHeader == null) {
return;
}
PsiReference ref = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
if (ref instanceof JetSimpleNameReference) {
@@ -88,11 +87,4 @@ public class JetPackagesContributor extends CompletionContributor {
}
});
}
@Override
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
// Will need to filter this dummy identifier to avoid showing it in completion
context.setDummyIdentifier(DUMMY_IDENTIFIER);
// context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER);
}
}
@@ -42,6 +42,8 @@ public class JetTypesCompletionHelper {
@NotNull CompletionParameters parameters,
@NotNull JetCompletionResultSet jetCompletionResult
) {
assert parameters.getInvocationCount() >= 2: "Method should be used only for force completion. In other case complete classes from scope";
jetCompletionResult.addAllElements(KotlinBuiltIns.getInstance().getNonPhysicalClasses());
Project project = parameters.getOriginalFile().getProject();
@@ -57,7 +59,7 @@ public class JetTypesCompletionHelper {
/**
* Add java elements with performing conversion to kotlin elements if necessary.
*/
static void addAdaptedJavaCompletion(
private static void addAdaptedJavaCompletion(
@NotNull CompletionParameters parameters,
@NotNull final JetCompletionResultSet jetCompletionResult
) {
@@ -1,8 +1,11 @@
class Test {
val Str<caret>
val St<caret>
}
// TIME: 1
// EXIST: String~(jet)
// EXIST: StringBuilder
// EXIST: IllegalStateException
// EXIST_JAVA_ONLY: StringBuilder
// EXIST_JAVA_ONLY: StringBuffer
// ABSENT: HTMLStyleElement
// ABSENT: Statement@Statement~(java.sql)
@@ -0,0 +1,11 @@
class Test {
val St<caret>
}
// TIME: 2
// EXIST: String~(jet)
// EXIST: IllegalStateException
// EXIST: StringBuilder
// EXIST_JAVA_ONLY: StringBuffer
// EXIST_JS_ONLY: HTMLStyleElement
// EXIST_JAVA_ONLY: Statement@Statement~(java.sql)
@@ -0,0 +1,22 @@
class StrSome {
class StrOther
fun more() {
class StrInFun
fun Str<caret>
}
}
class StrMore {
class StrAbsent
}
// TIME: 1
// EXIST: String~(jet)
// EXIST: StrSome
// EXIST: StrMore
// EXIST: StrInFun
// EXIST_JAVA_ONLY: StringBuilder
// EXIST_JAVA_ONLY: StringBuffer
// ABSENT: StrAbsent
@@ -0,0 +1,14 @@
class SomeClass {
class SomeInternal
fun some(a : S<caret>)
}
// TIME: 1
// EXIST: SomeClass, SomeInternal
// EXIST: String~(jet)
// EXIST: IllegalStateException
// EXIST_JAVA_ONLY: StringBuilder
// EXIST_JAVA_ONLY: StringBuffer
// ABSENT: HTMLStyleElement
// ABSENT: Statement@Statement~(java.sql)
@@ -0,0 +1,14 @@
class SomeClass {
class SomeInternal
fun some(a : S<caret>)
}
// TIME: 2
// EXIST: SomeClass, SomeInternal
// EXIST: String~(jet)
// EXIST: IllegalStateException
// EXIST: StringBuilder
// EXIST_JAVA_ONLY: StringBuffer
// EXIST_JS_ONLY: HTMLStyleElement
// EXIST_JAVA_ONLY: Statement@Statement~(java.sql)
@@ -0,0 +1,4 @@
fun some(a : Statement<caret>)
// TIME: 1
// EXIST: Statement@Statement~(java.sql)
@@ -8,4 +8,4 @@ fun firstFun() {
// TIME: 1
// EXIST: PropertyMetadata@PropertyMetadata~(jet)
// EXIST: PropertyMetadataImpl@PropertyMetadataImpl~(jet)
// NUMBER: 4
// NUMBER: 2
@@ -0,0 +1,4 @@
fun some(a : HTMLStyle<caret>)
// TIME: 1
// EXIST: HTMLStyleElement
@@ -129,6 +129,16 @@ public class JetBasicJSCompletionTestGenerated extends AbstractJetJSCompletionTe
doTest("idea/testData/completion/basic/common/ExtensionFunReceiver.kt");
}
@TestMetadata("ExtensionFunReceiverForce.kt")
public void testExtensionFunReceiverForce() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionFunReceiverForce.kt");
}
@TestMetadata("ExtensionInsideFunction.kt")
public void testExtensionInsideFunction() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionInsideFunction.kt");
}
@TestMetadata("ExtensionWithAdditionalTypeParameters.kt")
public void testExtensionWithAdditionalTypeParameters() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionWithAdditionalTypeParameters.kt");
@@ -254,6 +264,16 @@ public class JetBasicJSCompletionTestGenerated extends AbstractJetJSCompletionTe
doTest("idea/testData/completion/basic/common/InPackageBegin.kt");
}
@TestMetadata("InParametersTypes.kt")
public void testInParametersTypes() throws Exception {
doTest("idea/testData/completion/basic/common/InParametersTypes.kt");
}
@TestMetadata("InParametersTypesForce.kt")
public void testInParametersTypesForce() throws Exception {
doTest("idea/testData/completion/basic/common/InParametersTypesForce.kt");
}
@TestMetadata("InTypeAnnotation.kt")
public void testInTypeAnnotation() throws Exception {
doTest("idea/testData/completion/basic/common/InTypeAnnotation.kt");
@@ -426,6 +446,11 @@ public class JetBasicJSCompletionTestGenerated extends AbstractJetJSCompletionTe
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/completion/basic/js"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("AutoForceCompletion.kt")
public void testAutoForceCompletion() throws Exception {
doTest("idea/testData/completion/basic/js/AutoForceCompletion.kt");
}
@TestMetadata("InPackage.kt")
public void testInPackage() throws Exception {
doTest("idea/testData/completion/basic/js/InPackage.kt");
@@ -129,6 +129,16 @@ public class JetBasicJavaCompletionTestGenerated extends AbstractJavaCompletionT
doTest("idea/testData/completion/basic/common/ExtensionFunReceiver.kt");
}
@TestMetadata("ExtensionFunReceiverForce.kt")
public void testExtensionFunReceiverForce() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionFunReceiverForce.kt");
}
@TestMetadata("ExtensionInsideFunction.kt")
public void testExtensionInsideFunction() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionInsideFunction.kt");
}
@TestMetadata("ExtensionWithAdditionalTypeParameters.kt")
public void testExtensionWithAdditionalTypeParameters() throws Exception {
doTest("idea/testData/completion/basic/common/ExtensionWithAdditionalTypeParameters.kt");
@@ -254,6 +264,16 @@ public class JetBasicJavaCompletionTestGenerated extends AbstractJavaCompletionT
doTest("idea/testData/completion/basic/common/InPackageBegin.kt");
}
@TestMetadata("InParametersTypes.kt")
public void testInParametersTypes() throws Exception {
doTest("idea/testData/completion/basic/common/InParametersTypes.kt");
}
@TestMetadata("InParametersTypesForce.kt")
public void testInParametersTypesForce() throws Exception {
doTest("idea/testData/completion/basic/common/InParametersTypesForce.kt");
}
@TestMetadata("InTypeAnnotation.kt")
public void testInTypeAnnotation() throws Exception {
doTest("idea/testData/completion/basic/common/InTypeAnnotation.kt");
@@ -426,6 +446,11 @@ public class JetBasicJavaCompletionTestGenerated extends AbstractJavaCompletionT
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/completion/basic/java"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("AutoForceCompletion.kt")
public void testAutoForceCompletion() throws Exception {
doTest("idea/testData/completion/basic/java/AutoForceCompletion.kt");
}
@TestMetadata("ExtensionFromStandardLibrary.kt")
public void testExtensionFromStandardLibrary() throws Exception {
doTest("idea/testData/completion/basic/java/ExtensionFromStandardLibrary.kt");