diff --git a/annotations/com/intellij/codeInsight/completion/annotations.xml b/annotations/com/intellij/codeInsight/completion/annotations.xml index 935b49e4d51..4ace98ca782 100644 --- a/annotations/com/intellij/codeInsight/completion/annotations.xml +++ b/annotations/com/intellij/codeInsight/completion/annotations.xml @@ -27,6 +27,18 @@ name='com.intellij.codeInsight.completion.CompletionSorter com.intellij.codeInsight.completion.CompletionSorter weighBefore(java.lang.String, com.intellij.codeInsight.lookup.LookupElementWeigher...)'> + + + + + + + + + @@ -41,6 +53,10 @@ + + + diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java index ad20346a2b6..c33e1cacaf9 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java @@ -63,6 +63,7 @@ import static org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper.getTop */ public class JetShortNamesCache extends PsiShortNamesCache { + @NotNull public static JetShortNamesCache getKotlinInstance(@NotNull Project project) { PsiShortNamesCache[] extensions = Extensions.getArea(project).getExtensionPoint(PsiShortNamesCache.EP_NAME).getExtensions(); for (PsiShortNamesCache extension : extensions) { @@ -354,6 +355,7 @@ public class JetShortNamesCache extends PsiShortNamesCache { return functionFQNs; } + @NotNull public Collection getJetClassesDescriptors( @NotNull Condition acceptedShortNameCondition, @NotNull KotlinCodeAnalyzer analyzer, diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.java b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.java deleted file mode 100644 index a824c36a4a4..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.completion; - -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Conditions; -import com.intellij.psi.PsiElement; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.PsiTreeUtil; -import kotlin.Function1; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.plugin.caches.JetShortNamesCache; -import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; -import org.jetbrains.jet.plugin.codeInsight.TipsManager; -import org.jetbrains.jet.plugin.completion.smart.SmartCompletion; -import org.jetbrains.jet.plugin.project.ResolveSessionForBodies; -import org.jetbrains.jet.plugin.references.JetSimpleNameReference; - -import java.util.Collection; - -class CompletionSession { - @Nullable - private final DeclarationDescriptor inDescriptor; - private final CompletionParameters parameters; - private final JetCompletionResultSet jetResult; - private final JetSimpleNameReference jetReference; - - public CompletionSession( - @NotNull CompletionParameters parameters, - @NotNull CompletionResultSet result, - @NotNull JetSimpleNameReference jetReference, - @NotNull PsiElement position - ) { - this.parameters = parameters; - this.jetReference = jetReference; - - ResolveSessionForBodies resolveSession = - ResolvePackage.getLazyResolveSession((JetFile) position.getContainingFile()); - BindingContext expressionBindingContext = resolveSession.resolveToElement(jetReference.getExpression()); - JetScope scope = expressionBindingContext.get(BindingContext.RESOLUTION_SCOPE, jetReference.getExpression()); - - inDescriptor = scope != null ? scope.getContainingDeclaration() : null; - Condition descriptorFilter = new Condition() { - @Override - public boolean value(DeclarationDescriptor descriptor) { - return isVisibleDescriptor(descriptor); - } - }; - - // set prefix matcher here to override default one which relies on CompletionUtil.findReferencePrefix() - // which sometimes works incorrectly for Kotlin - result = result.withPrefixMatcher(CompletionUtil.findJavaIdentifierPrefix(parameters)); - - result = CompletionPackage.addKotlinSorting(result, parameters); - - this.jetResult = new JetCompletionResultSet(result, resolveSession, expressionBindingContext, descriptorFilter); - } - - public void completeForReference() { - assert parameters.getCompletionType() == CompletionType.BASIC; - - if (isOnlyKeywordCompletion(getPosition())) { - return; - } - - if (shouldRunOnlyTypeCompletion()) { - if (parameters.getInvocationCount() >= 2) { - JetTypesCompletionHelper.addJetTypes(parameters, jetResult); - } - else { - addReferenceVariants(new Condition() { - @Override - public boolean value(DeclarationDescriptor descriptor) { - return isPartOfTypeDeclaration(descriptor); - } - }); - JavaCompletionContributor.advertiseSecondCompletion(parameters.getPosition().getProject(), jetResult.getResult()); - } - - return; - } - - addReferenceVariants(Conditions.alwaysTrue()); - - String prefix = jetResult.getResult().getPrefixMatcher().getPrefix(); - - // Try to avoid computing not-imported descriptors for empty prefix - if (prefix.isEmpty()) { - if (parameters.getInvocationCount() < 2) { - return; - } - - if (PsiTreeUtil.getParentOfType(jetReference.getExpression(), JetDotQualifiedExpression.class) == null) { - return; - } - } - - if (shouldRunTopLevelCompletion()) { - JetTypesCompletionHelper.addJetTypes(parameters, jetResult); - addJetTopLevelFunctions(); - addJetTopLevelObjects(); - } - - if (shouldRunExtensionsCompletion()) { - addJetExtensions(); - } - } - - public void completeSmart() { - assert parameters.getCompletionType() == CompletionType.SMART; - - Collection descriptors = TipsManager.getReferenceVariants( - jetReference.getExpression(), getExpressionBindingContext()); - Function1 visibilityFilter = new Function1() { - @Override - public Boolean invoke(DeclarationDescriptor descriptor) { - return isVisibleDescriptor(descriptor); - } - }; - SmartCompletion completion = new SmartCompletion(jetReference.getExpression(), getResolveSession(), visibilityFilter, (JetFile)parameters.getOriginalFile()); - Collection elements = completion.buildLookupElements(descriptors); - if (elements != null) { - for (LookupElement element : elements) { - jetResult.addElement(element); - } - } - } - - private static boolean isOnlyKeywordCompletion(PsiElement position) { - return PsiTreeUtil.getParentOfType(position, JetModifierList.class) != null; - } - - private void addJetExtensions() { - Project project = getPosition().getProject(); - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); - - Collection jetCallableExtensions = namesCache.getJetCallableExtensions( - jetResult.getShortNameFilter(), - jetReference.getExpression(), - getResolveSession(), - GlobalSearchScope.allScope(project)); - - jetResult.addAllElements(jetCallableExtensions); - } - - private static boolean isPartOfTypeDeclaration(@NotNull DeclarationDescriptor descriptor) { - if (descriptor instanceof PackageViewDescriptor || descriptor instanceof TypeParameterDescriptor) { - return true; - } - - if (descriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) descriptor; - - if (KotlinBuiltIns.getInstance().isUnit(classDescriptor.getDefaultType())) return true; - - ClassKind kind = classDescriptor.getKind(); - return !(kind == ClassKind.OBJECT || kind == ClassKind.CLASS_OBJECT); - } - - return false; - } - - private void addJetTopLevelFunctions() { - String actualPrefix = jetResult.getResult().getPrefixMatcher().getPrefix(); - Project project = getPosition().getProject(); - - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); - GlobalSearchScope scope = GlobalSearchScope.allScope(project); - Collection functionNames = namesCache.getAllTopLevelFunctionNames(); - - // TODO: Fix complete extension not only on contains - for (String name : functionNames) { - if (name.contains(actualPrefix)) { - jetResult.addAllElements(namesCache.getTopLevelFunctionDescriptorsByName( - name, jetReference.getExpression(), getResolveSession(), scope)); - } - } - } - - private void addJetTopLevelObjects() { - Project project = getPosition().getProject(); - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); - GlobalSearchScope scope = GlobalSearchScope.allScope(project); - Collection objectNames = namesCache.getAllTopLevelObjectNames(); - - for (String name : objectNames) { - if (jetResult.getResult().getPrefixMatcher().prefixMatches(name)) { - jetResult.addAllElements(namesCache.getTopLevelObjectsByName(name, jetReference.getExpression(), getResolveSession(), scope)); - } - } - } - - private boolean shouldRunOnlyTypeCompletion() { - // Check that completion in the type annotation context and if there's a qualified - // expression we are at first of it - JetTypeReference typeReference = PsiTreeUtil.getParentOfType(getPosition(), JetTypeReference.class); - if (typeReference != null) { - JetSimpleNameExpression firstPartReference = PsiTreeUtil.findChildOfType(typeReference, JetSimpleNameExpression.class); - return firstPartReference == jetReference.getExpression(); - } - - return false; - } - - private boolean shouldRunTopLevelCompletion() { - if (parameters.getInvocationCount() < 2) { - return false; - } - - PsiElement element = getPosition(); - if (getPosition().getNode().getElementType() == JetTokens.IDENTIFIER) { - if (element.getParent() instanceof JetSimpleNameExpression) { - if (!JetPsiUtil.isSelectorInQualified((JetSimpleNameExpression) element.getParent())) { - return true; - } - } - } - - return false; - } - - private boolean shouldRunExtensionsCompletion() { - return parameters.getInvocationCount() > 1 || jetResult.getResult().getPrefixMatcher().getPrefix().length() >= 3; - } - - private void addReferenceVariants(@NotNull final Condition filterCondition) { - Collection descriptors = TipsManager.getReferenceVariants( - jetReference.getExpression(), getExpressionBindingContext()); - - Collection filterDescriptors = Collections2.filter(descriptors, new Predicate() { - @Override - public boolean apply(@Nullable DeclarationDescriptor descriptor) { - return descriptor != null && filterCondition.value(descriptor); - } - }); - - jetResult.addAllElements(filterDescriptors); - } - - private boolean isVisibleDescriptor(DeclarationDescriptor descriptor) { - if (parameters.getInvocationCount() >= 2) { - // Show everything if user insist on showing completion list - return true; - } - - if (descriptor instanceof DeclarationDescriptorWithVisibility) { - if (inDescriptor != null) { - //noinspection ConstantConditions - return Visibilities.isVisible((DeclarationDescriptorWithVisibility) descriptor, inDescriptor); - } - } - - return true; - } - - private BindingContext getExpressionBindingContext() { - return jetResult.getBindingContext(); - } - - private ResolveSessionForBodies getResolveSession() { - return jetResult.getResolveSession(); - } - - private PsiElement getPosition() { - return parameters.getPosition(); - } - - @NotNull - public JetCompletionResultSet getJetResult() { - return jetResult; - } - - @NotNull - public CompletionParameters getParameters() { - return parameters; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt new file mode 100644 index 00000000000..e58f05f407a --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt @@ -0,0 +1,200 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.completion + +import com.intellij.codeInsight.completion.* +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.caches.JetShortNamesCache +import org.jetbrains.jet.plugin.caches.resolve.* +import org.jetbrains.jet.plugin.codeInsight.TipsManager +import org.jetbrains.jet.plugin.completion.smart.SmartCompletion +import org.jetbrains.jet.plugin.references.JetSimpleNameReference + +class CompletionSession(public val parameters: CompletionParameters, + resultSet: CompletionResultSet, + private val jetReference: JetSimpleNameReference, + position: PsiElement) { + private val inDescriptor: DeclarationDescriptor? + public val jetResult: JetCompletionResultSet + + private val resolveSession = (position.getContainingFile() as JetFile).getLazyResolveSession() + private val bindingContext = resolveSession.resolveToElement(jetReference.expression) + private val position = parameters.getPosition() + + ;{ + inDescriptor = bindingContext.get(BindingContext.RESOLUTION_SCOPE, jetReference.expression)?.getContainingDeclaration() + + // set prefix matcher here to override default one which relies on CompletionUtil.findReferencePrefix() + // which sometimes works incorrectly for Kotlin + var result = resultSet.withPrefixMatcher(CompletionUtil.findJavaIdentifierPrefix(parameters)) + + result = result.addKotlinSorting(parameters) + + this.jetResult = JetCompletionResultSet(result, resolveSession, bindingContext, { isVisibleDescriptor(it) }) + } + + public fun completeForReference() { + assert(parameters.getCompletionType() == CompletionType.BASIC) + + if (isOnlyKeywordCompletion(position)) return + + if (shouldRunOnlyTypeCompletion()) { + if (parameters.getInvocationCount() >= 2) { + JetTypesCompletionHelper.addJetTypes(parameters, jetResult) + } + else { + addReferenceVariants { isPartOfTypeDeclaration(it) } + JavaCompletionContributor.advertiseSecondCompletion(parameters.getPosition().getProject(), jetResult.result) + } + + return + } + + addReferenceVariants { true } + + val prefix = jetResult.result.getPrefixMatcher().getPrefix() + + // Try to avoid computing not-imported descriptors for empty prefix + if (prefix.isEmpty()) { + if (parameters.getInvocationCount() < 2) return + + if (PsiTreeUtil.getParentOfType(jetReference.expression, javaClass()) == null) return + } + + if (shouldRunTopLevelCompletion()) { + JetTypesCompletionHelper.addJetTypes(parameters, jetResult) + addJetTopLevelFunctions() + addJetTopLevelObjects() + } + + if (shouldRunExtensionsCompletion()) { + addJetExtensions() + } + } + + public fun completeSmart() { + assert(parameters.getCompletionType() == CompletionType.SMART) + + val descriptors = TipsManager.getReferenceVariants(jetReference.expression, jetResult.bindingContext) + val completion = SmartCompletion(jetReference.expression, resolveSession, { isVisibleDescriptor(it) }, parameters.getOriginalFile() as JetFile) + completion.buildLookupElements(descriptors)?.forEach { jetResult.addElement(it) } + } + + private fun isOnlyKeywordCompletion(position: PsiElement) + = PsiTreeUtil.getParentOfType(position, javaClass()) != null + + private fun addJetExtensions() { + val project = position.getProject() + val namesCache = JetShortNamesCache.getKotlinInstance(project) + jetResult.addAllElements(namesCache.getJetCallableExtensions({ jetResult.shortNameFilter(it!!) }, jetReference.expression, resolveSession, GlobalSearchScope.allScope(project))) + } + + private fun isPartOfTypeDeclaration(descriptor: DeclarationDescriptor): Boolean { + return when (descriptor) { + is PackageViewDescriptor, is TypeParameterDescriptor -> true + + is ClassDescriptor -> { + val kind = descriptor.getKind() + KotlinBuiltIns.getInstance().isUnit(descriptor.getDefaultType()) || + kind != ClassKind.OBJECT && kind != ClassKind.CLASS_OBJECT + } + + else -> false + } + } + + private fun addJetTopLevelFunctions() { + val actualPrefix = jetResult.result.getPrefixMatcher().getPrefix() + val project = position.getProject() + val namesCache = JetShortNamesCache.getKotlinInstance(project) + val scope = GlobalSearchScope.allScope(project) + val functionNames = namesCache.getAllTopLevelFunctionNames() + + // TODO: Fix complete extension not only on contains + for (name in functionNames) { + if (name.contains(actualPrefix)) { + jetResult.addAllElements(namesCache.getTopLevelFunctionDescriptorsByName(name, jetReference.expression, resolveSession, scope)) + } + } + } + + private fun addJetTopLevelObjects() { + val project = position.getProject() + val namesCache = JetShortNamesCache.getKotlinInstance(project) + val scope = GlobalSearchScope.allScope(project) + val objectNames = namesCache.getAllTopLevelObjectNames() + + for (name in objectNames) { + if (jetResult.result.getPrefixMatcher().prefixMatches(name)) { + jetResult.addAllElements(namesCache.getTopLevelObjectsByName(name, jetReference.expression, resolveSession, scope)) + } + } + } + + private fun shouldRunOnlyTypeCompletion(): Boolean { + // Check that completion in the type annotation context and if there's a qualified + // expression we are at first of it + val typeReference = PsiTreeUtil.getParentOfType(position, javaClass()) + if (typeReference != null) { + val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass()) + return firstPartReference == jetReference.expression + } + + return false + } + + private fun shouldRunTopLevelCompletion(): Boolean { + if (parameters.getInvocationCount() < 2) { + return false + } + + if (position.getNode()!!.getElementType() == JetTokens.IDENTIFIER) { + val parent = position.getParent() + if (parent is JetSimpleNameExpression && !JetPsiUtil.isSelectorInQualified(parent)) return true + } + + return false + } + + private fun shouldRunExtensionsCompletion(): Boolean { + return parameters.getInvocationCount() > 1 || jetResult.result.getPrefixMatcher().getPrefix().length >= 3 + } + + private fun addReferenceVariants(filterCondition: (DeclarationDescriptor) -> Boolean) { + val descriptors = TipsManager.getReferenceVariants(jetReference.expression, jetResult.bindingContext) + jetResult.addAllElements(descriptors.filter { filterCondition(it) }) + } + + private fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean { + // Show everything if user insist on showing completion list + if (parameters.getInvocationCount() >= 2) return true + + if (descriptor is DeclarationDescriptorWithVisibility && inDescriptor != null) { + return Visibilities.isVisible(descriptor as DeclarationDescriptorWithVisibility, inDescriptor) + } + + return true + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt index b2dd2bbe2fd..88cb66cd18b 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.kt @@ -83,13 +83,12 @@ public class JetCompletionContributor : CompletionContributor() { } val expressionEnd = expression.getTextRange()!!.getEndOffset() - val suggestedReplacementOffset: Int - if (expression is JetCallExpression) { + val suggestedReplacementOffset = if (expression is JetCallExpression) { val calleeExpression = (expression as JetCallExpression).getCalleeExpression() - suggestedReplacementOffset = if (calleeExpression != null) calleeExpression.getTextRange()!!.getEndOffset() else expressionEnd + if (calleeExpression != null) calleeExpression.getTextRange()!!.getEndOffset() else expressionEnd } else { - suggestedReplacementOffset = expressionEnd + expressionEnd } if (suggestedReplacementOffset > context.getReplacementOffset()) { context.setReplacementOffset(suggestedReplacementOffset) @@ -123,7 +122,7 @@ public class JetCompletionContributor : CompletionContributor() { if (parameters.getCompletionType() == CompletionType.BASIC) { session.completeForReference() - if (!session.getJetResult().isSomethingAdded() && session.getParameters().getInvocationCount() < 2) { + if (!session.jetResult.isSomethingAdded && session.parameters.getInvocationCount() < 2) { // Rerun completion if nothing was found session = CompletionSession(parameters.withInvocationCount(2), result, jetReference, position) session.completeForReference() @@ -139,22 +138,8 @@ public class JetCompletionContributor : CompletionContributor() { } } - private fun getJetReference(parameters: CompletionParameters): JetSimpleNameReference? { - val element = parameters.getPosition() - val parent = element.getParent() - if (parent != null) { - val references = parent.getReferences() - if (references.size != 0) { - for (reference in references) { - if (reference is JetSimpleNameReference) { - return reference as JetSimpleNameReference - } - } - } - } - - return null - } + private fun getJetReference(parameters: CompletionParameters): JetSimpleNameReference? + = parameters.getPosition().getParent()?.getReferences()?.filterIsInstance(javaClass())?.firstOrNull() private fun isAtEndOfLine(offset: Int, document: Document): Boolean { var i = offset diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.java deleted file mode 100644 index 84d62ba92d3..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.completion; - -import com.intellij.codeInsight.completion.CompletionResultSet; -import com.intellij.codeInsight.completion.InsertionContext; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementDecorator; -import com.intellij.codeInsight.lookup.LookupElementPresentation; -import com.intellij.openapi.util.Condition; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.plugin.completion.handlers.CaretPosition; -import org.jetbrains.jet.plugin.completion.handlers.GenerateLambdaInfo; -import org.jetbrains.jet.plugin.completion.handlers.HandlersPackage; -import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler; -import org.jetbrains.jet.plugin.project.ResolveSessionForBodies; - -import java.util.List; - -public class JetCompletionResultSet { - private final ResolveSessionForBodies resolveSession; - private final BindingContext bindingContext; - private final Condition descriptorFilter; - private final CompletionResultSet result; - private boolean isSomethingAdded; - - public JetCompletionResultSet( - @NotNull CompletionResultSet result, - @NotNull ResolveSessionForBodies resolveSession, - @NotNull BindingContext bindingContext, - @NotNull Condition descriptorFilter) { - this.result = result; - this.resolveSession = resolveSession; - this.bindingContext = bindingContext; - this.descriptorFilter = descriptorFilter; - } - - public ResolveSessionForBodies getResolveSession() { - return resolveSession; - } - - public BindingContext getBindingContext() { - return bindingContext; - } - - public CompletionResultSet getResult() { - return result; - } - - public void addAllElements(@NotNull Iterable descriptors) { - for (DeclarationDescriptor descriptor : descriptors) { - addElement(descriptor); - } - } - - public void addElement(DeclarationDescriptor descriptor) { - if (!descriptorFilter.value(descriptor)) { - return; - } - - addElement(DescriptorLookupConverter.createLookupElement(resolveSession, descriptor)); - - // add special item for function with one argument of function type with more than one parameter - if (descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - List parameters = functionDescriptor.getValueParameters(); - if (parameters.size() == 1) { - final JetType parameterType = parameters.get(0).getType(); - if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) { - int parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size(); - if (parameterCount > 1) { - LookupElement lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, descriptor); - addElement(new LookupElementDecorator(lookupElement) { - @Override - public void renderElement(@NotNull LookupElementPresentation presentation) { - super.renderElement(presentation); - presentation.setItemText(getLookupString() + " " + HandlersPackage.buildLambdaPresentation(parameterType)); - } - - @Override - public void handleInsert(InsertionContext context) { - new JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, new GenerateLambdaInfo(parameterType, true)) - .handleInsert(context, this); - } - }); - } - } - } - } - } - - public void addElement(@NotNull LookupElement element) { - if (!result.getPrefixMatcher().prefixMatches(element)) return; - - result.addElement(element); - isSomethingAdded = true; - } - - public boolean isSomethingAdded() { - return isSomethingAdded; - } - - @NotNull - public Condition getShortNameFilter() { - return new Condition() { - @Override - public boolean value(String s) { - return result.getPrefixMatcher().prefixMatches(s); - } - }; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.kt b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.kt new file mode 100644 index 00000000000..4d435468a37 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionResultSet.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.completion + +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementDecorator +import com.intellij.codeInsight.lookup.LookupElementPresentation +import com.intellij.openapi.util.Condition +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.plugin.completion.handlers.* +import org.jetbrains.jet.plugin.project.ResolveSessionForBodies + +public class JetCompletionResultSet(public val result: CompletionResultSet, + public val resolveSession: ResolveSessionForBodies, + public val bindingContext: BindingContext, + private val descriptorFilter: (DeclarationDescriptor) -> Boolean) { + public var isSomethingAdded: Boolean = false + private set + + public fun addAllElements(descriptors: Iterable) { + for (descriptor in descriptors) { + addElement(descriptor) + } + } + + public fun addElement(descriptor: DeclarationDescriptor) { + if (!descriptorFilter(descriptor)) return + + addElement(DescriptorLookupConverter.createLookupElement(resolveSession, descriptor)) + + // add special item for function with one argument of function type with more than one parameter + if (descriptor is FunctionDescriptor) { + val parameters = descriptor.getValueParameters() + if (parameters.size() == 1) { + val parameterType = parameters.get(0).getType() + if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) { + val parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size() + if (parameterCount > 1) { + val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, descriptor) + addElement(object : LookupElementDecorator(lookupElement) { + override fun renderElement(presentation: LookupElementPresentation) { + super.renderElement(presentation) + presentation.setItemText(getLookupString() + " " + buildLambdaPresentation(parameterType)) + } + + override fun handleInsert(context: InsertionContext) { + JetFunctionInsertHandler(CaretPosition.IN_BRACKETS, GenerateLambdaInfo(parameterType, true)).handleInsert(context, this) + } + }) + } + } + } + } + } + + public fun addElement(element: LookupElement) { + if (!result.getPrefixMatcher().prefixMatches(element)) return + + result.addElement(element) + isSomethingAdded = true + } + + public val shortNameFilter: (String) -> Boolean = { result.getPrefixMatcher().prefixMatches(it) } +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java b/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java deleted file mode 100644 index e4ccd3e11df..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.completion; - -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementDecorator; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiClass; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.Consumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.asJava.KotlinLightClass; -import org.jetbrains.jet.lang.descriptors.ClassKind; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils; -import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils; -import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper; -import org.jetbrains.jet.plugin.caches.JetShortNamesCache; -import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler; -import org.jetbrains.jet.plugin.project.ProjectStructureUtil; - -public class JetTypesCompletionHelper { - private JetTypesCompletionHelper() { - } - - static void addJetTypes( - @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(); - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); - jetCompletionResult.addAllElements(namesCache.getJetClassesDescriptors( - jetCompletionResult.getShortNameFilter(), jetCompletionResult.getResolveSession(), GlobalSearchScope.allScope(project))); - - if (!ProjectStructureUtil.isJsKotlinModule((JetFile) parameters.getOriginalFile())) { - addAdaptedJavaCompletion(parameters, jetCompletionResult); - } - } - - /** - * Add java elements with performing conversion to kotlin elements if necessary. - */ - private static void addAdaptedJavaCompletion( - @NotNull CompletionParameters parameters, - @NotNull final JetCompletionResultSet jetCompletionResult - ) { - JavaClassNameCompletionContributor.addAllClasses( - parameters, - false, - JavaCompletionSorting.addJavaSorting(parameters, jetCompletionResult.getResult()).getPrefixMatcher(), - new Consumer() { - @Override - public void consume(LookupElement lookupElement) { - if (lookupElement instanceof JavaPsiClassReferenceElement) { - final JavaPsiClassReferenceElement javaPsiReferenceElement = (JavaPsiClassReferenceElement) lookupElement; - - PsiClass psiClass = javaPsiReferenceElement.getObject(); - if (addJavaClassAsJetLookupElement(psiClass, jetCompletionResult)) { - return; - } - - jetCompletionResult.addElement(new LookupElementDecorator(javaPsiReferenceElement) { - @Override - public void handleInsert(InsertionContext context) { - JetJavaClassInsertHandler.INSTANCE.handleInsert(context, javaPsiReferenceElement); - } - }); - } - } - }); - } - - private static boolean addJavaClassAsJetLookupElement(PsiClass aClass, JetCompletionResultSet jetCompletionResult) { - if (aClass instanceof KotlinLightClass) { - // Do nothing. Kotlin not-compiled class should have already been added as kotlin element before. - return true; - } - - if (JavaResolverPsiUtils.isCompiledKotlinClass(aClass)) { - if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) { - String qualifiedName = aClass.getQualifiedName(); - if (qualifiedName != null) { - FqName fqName = new FqName(qualifiedName); - jetCompletionResult.addAllElements( - ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.getResolveSession(), fqName)); - } - } - - return true; - } - - return false; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.kt b/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.kt new file mode 100644 index 00000000000..9426a69a518 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetTypesCompletionHelper.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.completion + +import com.intellij.codeInsight.completion.* +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementDecorator +import com.intellij.psi.PsiClass +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.Consumer +import org.jetbrains.jet.asJava.KotlinLightClass +import org.jetbrains.jet.lang.descriptors.ClassKind +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils +import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils +import org.jetbrains.jet.lang.resolve.name.FqName +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper +import org.jetbrains.jet.plugin.caches.JetShortNamesCache +import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler +import org.jetbrains.jet.plugin.project.ProjectStructureUtil + +object JetTypesCompletionHelper { + fun addJetTypes(parameters: CompletionParameters, jetCompletionResult: JetCompletionResultSet) { + assert(parameters.getInvocationCount() >= 2, "Method should be used only for force completion. In other case complete classes from scope") + + jetCompletionResult.addAllElements(KotlinBuiltIns.getInstance().getNonPhysicalClasses()) + + val project = parameters.getOriginalFile().getProject() + val namesCache = JetShortNamesCache.getKotlinInstance(project) + jetCompletionResult.addAllElements(namesCache.getJetClassesDescriptors({ jetCompletionResult.shortNameFilter(it!!) }, jetCompletionResult.resolveSession, GlobalSearchScope.allScope(project))) + + if (!ProjectStructureUtil.isJsKotlinModule(parameters.getOriginalFile() as JetFile)) { + addAdaptedJavaCompletion(parameters, jetCompletionResult) + } + } + + /** + * Add java elements with performing conversion to kotlin elements if necessary. + */ + private fun addAdaptedJavaCompletion(parameters: CompletionParameters, jetCompletionResult: JetCompletionResultSet) { + JavaClassNameCompletionContributor.addAllClasses(parameters, false, JavaCompletionSorting.addJavaSorting(parameters, jetCompletionResult.result).getPrefixMatcher(), object : Consumer { + override fun consume(lookupElement: LookupElement?) { + if (lookupElement is JavaPsiClassReferenceElement) { + val psiClass = lookupElement.getObject() + + if (addJavaClassAsJetLookupElement(psiClass, jetCompletionResult)) return + + jetCompletionResult.addElement(object : LookupElementDecorator(lookupElement) { + override fun handleInsert(context: InsertionContext) { + JetJavaClassInsertHandler.INSTANCE.handleInsert(context, lookupElement) + } + }) + } + } + }) + } + + private fun addJavaClassAsJetLookupElement(aClass: PsiClass, jetCompletionResult: JetCompletionResultSet): Boolean { + if (aClass is KotlinLightClass) { + // Do nothing. Kotlin not-compiled class should have already been added as kotlin element before. + return true + } + + if (JavaResolverPsiUtils.isCompiledKotlinClass(aClass)) { + if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) { + val qualifiedName = aClass.getQualifiedName() + if (qualifiedName != null) { + jetCompletionResult.addAllElements(ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.resolveSession, FqName(qualifiedName))) + } + } + + return true + } + + return false + } +}