More efficient code completion + fixed a few bugs

This commit is contained in:
Valentin Kipyatkov
2014-11-02 14:32:10 +03:00
parent f31832dea9
commit fe5dbbf9b3
21 changed files with 166 additions and 74 deletions
@@ -58,7 +58,6 @@ import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor;
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
@@ -30,6 +30,7 @@ import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor
import org.jetbrains.jet.lang.types.TypeUtils
import java.util.ArrayList
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
import org.jetbrains.jet.lang.descriptors.SamConstructorDescriptor
public object SamConversionResolverImpl : SamConversionResolver {
override fun resolveSamConstructor(name: Name, scope: JetScope): SamConstructorDescriptor? {
@@ -147,7 +147,7 @@ public class SingleAbstractMethodUtils {
) {
assert isSamInterface(samInterface) : samInterface;
SamConstructorDescriptor result = new SamConstructorDescriptor(owner, samInterface);
SamConstructorDescriptorImpl result = new SamConstructorDescriptorImpl(owner, samInterface);
TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result);
@@ -18,10 +18,11 @@ package org.jetbrains.jet.lang.resolve.java.descriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.SamConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
public class SamConstructorDescriptor extends SimpleFunctionDescriptorImpl {
public SamConstructorDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JavaClassDescriptor samInterface) {
public class SamConstructorDescriptorImpl extends SimpleFunctionDescriptorImpl implements SamConstructorDescriptor {
public SamConstructorDescriptorImpl(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JavaClassDescriptor samInterface) {
super(containingDeclaration, null, samInterface.getAnnotations(), samInterface.getName(),
Kind.SYNTHESIZED, samInterface.getSource());
}
@@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.java.lazy.LazyJavaResolverContext
import org.jetbrains.jet.lang.resolve.java.lazy.withTypes
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptorImpl
public abstract class LazyJavaStaticScope(
c: LazyJavaResolverContext,
@@ -18,11 +18,11 @@ package org.jetbrains.jet.lang.resolve.java.resolver
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor
import org.jetbrains.jet.lang.descriptors.SamConstructorDescriptor
public trait SamConversionResolver {
public fun resolveSamConstructor(name: Name, scope: JetScope): SamConstructorDescriptor?
@@ -0,0 +1,20 @@
/*
* 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.lang.descriptors;
public interface SamConstructorDescriptor extends SimpleFunctionDescriptor {
}
@@ -51,7 +51,7 @@ public trait JetScope {
* (that means that the implementation is not obliged to use the filters but may do so when it gives any performance advantage).
*/
public fun getDescriptors(kindFilterMask: Int = ALL_KINDS_MASK,
nameFilter: (Name) -> Boolean = { true }): Collection<DeclarationDescriptor>
nameFilter: (Name) -> Boolean = ALL_NAME_FILTER): Collection<DeclarationDescriptor>
/**
* Adds receivers to the list in order of locality, so that the closest (the most local) receiver goes first
@@ -100,6 +100,40 @@ public trait JetScope {
public val VARIABLES_AND_PROPERTIES_MASK: Int = LOCAL_VARIABLE or NON_EXTENSION_PROPERTY or EXTENSION_PROPERTY
public val ALL_NAME_FILTER: (Name) -> Boolean = { true }
public fun descriptorKind(descriptor: DeclarationDescriptor): Int {
return when (descriptor) {
is ClassDescriptor -> when (descriptor.getKind()) {
ClassKind.OBJECT, ClassKind.CLASS_OBJECT -> OBJECT
ClassKind.ENUM_ENTRY -> ENUM_ENTRY
else -> TYPE
}
is PackageFragmentDescriptor, is PackageViewDescriptor -> PACKAGE
is SamConstructorDescriptor -> SAM_CONSTRUCTOR
is FunctionDescriptor -> if (descriptor.getExtensionReceiverParameter() != null) EXTENSION_FUNCTION else ORDINARY_FUNCTION
is PropertyDescriptor -> if (descriptor.getExtensionReceiverParameter() != null) EXTENSION_PROPERTY else NON_EXTENSION_PROPERTY
is VariableDescriptor -> LOCAL_VARIABLE
else -> 0 /* unknown */
}
}
}
}
/**
* The same as getDescriptors(kindFilterMask, nameFilter) but the result is guaranteed to be filtered by kind and name.
*/
public fun JetScope.getDescriptorsFiltered(kindFilterMask: Int,
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
return getDescriptors(kindFilterMask, nameFilter).filter {
(JetScope.descriptorKind(it) and kindFilterMask) != 0 && nameFilter(it.getName())
}
}
@@ -28,9 +28,9 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils
import java.util.*
import org.jetbrains.jet.lang.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.jet.lang.resolve.descriptorUtil.isExtension
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.jet.lang.resolve.scopes.getDescriptorsFiltered
public object TipsManager{
@@ -64,9 +64,8 @@ public object TipsManager{
val qualifier = context[BindingContext.QUALIFIER, receiverExpression]
if (qualifier != null) {
//TODO: filter out extensions!
// It's impossible to add extension function for package or class (if it's class object, expression type is not null)
qualifier.scope.getDescriptors(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter).filterTo(descriptors, ::filterIfInfix)
qualifier.scope.getDescriptorsFiltered(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter).filterTo(descriptors, ::filterIfInfix)
}
val expressionType = context[BindingContext.EXPRESSION_TYPE, receiverExpression]
@@ -74,12 +73,12 @@ public object TipsManager{
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
val dataFlowInfo = context.getDataFlowInfo(expression)
val mask = kindFilterMask and JetScope.NON_EXTENSIONS_MASK and JetScope.TYPE.inv()
for (variant in SmartCastUtils.getSmartCastVariants(receiverValue, context, dataFlowInfo)) {
//TODO: filter out nested classes!
variant.getMemberScope().getDescriptors(kindFilterMask, nameFilter).filterTo(descriptors) { filterIfInfix(it) && !it.isExtension }
variant.getMemberScope().getDescriptorsFiltered(mask, nameFilter).filterTo(descriptors, ::filterIfInfix)
}
descriptors.addAll(getCallableExtensions(resolutionScope, listOf(receiverValue), context, dataFlowInfo, isInfixCall, kindFilterMask, nameFilter))
descriptors.addCallableExtensions(resolutionScope, receiverValue, context, dataFlowInfo, isInfixCall, kindFilterMask, nameFilter)
}
return descriptors
@@ -87,21 +86,21 @@ public object TipsManager{
}
if (parent is JetImportDirective || parent is JetPackageDirective) {
return excludeNonPackageDescriptors(resolutionScope.getDescriptors(kindFilterMask and JetScope.PACKAGE, nameFilter))
if (kindFilterMask and JetScope.PACKAGE == 0) return listOf()
return resolutionScope.getDescriptorsFiltered(JetScope.PACKAGE, nameFilter)
}
else {
val descriptorsSet = HashSet<DeclarationDescriptor>()
val receivers = resolutionScope.getImplicitReceiversHierarchy()
for (receiver in receivers) {
receiver.getType().getMemberScope().getDescriptors(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter)
.filterTo(descriptorsSet) { !it.isExtension }
receivers.flatMapTo(descriptorsSet) {
it.getType().getMemberScope().getDescriptorsFiltered(kindFilterMask and JetScope.NON_EXTENSIONS_MASK, nameFilter)
}
val dataFlowInfo = context.getDataFlowInfo(expression)
val receiverValues = receivers.map { it.getValue() }
resolutionScope.getDescriptors(kindFilterMask, nameFilter).filterTo(descriptorsSet) {
resolutionScope.getDescriptorsFiltered(kindFilterMask, nameFilter).filterTo(descriptorsSet) {
if (it is CallableDescriptor && it.getExtensionReceiverParameter() != null) {
it.isExtensionCallable(receiverValues, context, dataFlowInfo, false)
}
@@ -113,23 +112,21 @@ public object TipsManager{
}
}
public fun getCallableExtensions(
private fun MutableCollection<DeclarationDescriptor>.addCallableExtensions(
resolutionScope: JetScope,
receivers: Collection<ReceiverValue>,
receiver: ReceiverValue,
context: BindingContext,
dataFlowInfo: DataFlowInfo,
isInfixCall: Boolean,
kindFilterMask: Int,
nameFilter: (Name) -> Boolean): Collection<CallableDescriptor> {
nameFilter: (Name) -> Boolean) {
val mask = kindFilterMask and JetScope.EXTENSIONS_MASK
if (mask == 0) return listOf()
return resolutionScope.getDescriptors(mask, nameFilter)
.stream()
.filterIsInstance(javaClass<CallableDescriptor>())
.filter {
it.getExtensionReceiverParameter() != null && it.isExtensionCallable(receivers, context, dataFlowInfo, isInfixCall)
}
.toList()
if (mask != 0) {
resolutionScope.getDescriptorsFiltered(mask, nameFilter)
.stream()
.filterIsInstance(javaClass<CallableDescriptor>())
.filterTo(this) { ExpressionTypingUtils.checkIsExtensionCallable(receiver, it, isInfixCall, context, dataFlowInfo) }
}
}
public fun CallableDescriptor.isExtensionCallable(receivers: Collection<ReceiverValue>,
@@ -145,20 +142,6 @@ public object TipsManager{
context: BindingContext,
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
return excludeNonPackageDescriptors(resolutionScope.getDescriptors(JetScope.PACKAGE, nameFilter))
}
private fun excludeNonPackageDescriptors(descriptors: Collection<DeclarationDescriptor>): Collection<DeclarationDescriptor> {
return descriptors.filter{
if (it is PackageViewDescriptor) {
// Heuristic: we don't want to complete "System" in "package java.lang.Sys",
// so we find class of the same name as package, we exclude this package
val parent = it.getContainingDeclaration()
parent == null || parent.getMemberScope().getClassifier(it.getName()) == null
}
else {
false
}
}
return resolutionScope.getDescriptorsFiltered(JetScope.PACKAGE, nameFilter)
}
}
@@ -141,7 +141,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
addAllTypes()
}
else {
addReferenceVariants(JetScope.TYPE or JetScope.PACKAGE) { isPartOfTypeDeclaration(it) }
addReferenceVariants(JetScope.TYPE or JetScope.PACKAGE)
collector.addDescriptorElements(listOf(KotlinBuiltIns.getInstance().getUnit()), false)
JavaCompletionContributor.advertiseSecondCompletion(project, resultSet)
}
}
@@ -175,20 +176,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
private fun isOnlyKeywordCompletion()
= PsiTreeUtil.getParentOfType(position, javaClass<JetModifierList>()) != null
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 shouldRunOnlyTypeCompletion(): Boolean {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
@@ -201,8 +188,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
return false
}
private fun addReferenceVariants(kindFilterMask: Int, filterCondition: (DeclarationDescriptor) -> Boolean = { true }) {
collector.addDescriptorElements(getReferenceVariants(kindFilterMask).filter { filterCondition(it) }, suppressAutoInsertion = false)
private fun addReferenceVariants(kindFilterMask: Int) {
collector.addDescriptorElements(getReferenceVariants(kindFilterMask), suppressAutoInsertion = false)
}
}
@@ -34,7 +34,7 @@ import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.lang.psi.psiUtil.getReceiverExpression
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptorImpl
class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
@@ -38,7 +38,7 @@ import org.jetbrains.jet.plugin.util.makeNotNullable
import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.descriptors.PackageFragmentDescriptor
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor
import org.jetbrains.jet.lang.descriptors.SamConstructorDescriptor
class TypeInstantiationItems(val resolveSession: ResolveSessionForBodies, val bindingContext: BindingContext, val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>) {
@@ -0,0 +1,10 @@
enum class E {
AAA
BBB
fun foo(): <caret>
}
// ABSENT: AAA
// ABSENT: BBB
@@ -0,0 +1,9 @@
package pack
fun String.extFoo(){}
fun foo() {
pack.<caret>
}
// ABSENT: extFoo
@@ -0,0 +1,11 @@
class C {
class Nested
inner class Inner
}
fun foo(c: C) {
c.<caret>
}
// ABSENT: Nested
// ABSENT: Inner
@@ -0,0 +1,6 @@
package java.lang.<caret>
// EXIST: annotation
// EXIST: reflect
// ABSENT: System
// ABSENT: Thread
@@ -598,6 +598,24 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName);
}
@TestMetadata("NoEnumEntryType.kt")
public void testNoEnumEntryType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoEnumEntryType.kt");
doTest(fileName);
}
@TestMetadata("NoExtensionsAfterQualifier.kt")
public void testNoExtensionsAfterQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoExtensionsAfterQualifier.kt");
doTest(fileName);
}
@TestMetadata("NoNestedClassAfterReceiver.kt")
public void testNoNestedClassAfterReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoNestedClassAfterReceiver.kt");
doTest(fileName);
}
@TestMetadata("NoObjectInTypePosition.kt")
public void testNoObjectInTypePosition() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoObjectInTypePosition.kt");
@@ -598,6 +598,24 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("NoEnumEntryType.kt")
public void testNoEnumEntryType() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoEnumEntryType.kt");
doTest(fileName);
}
@TestMetadata("NoExtensionsAfterQualifier.kt")
public void testNoExtensionsAfterQualifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoExtensionsAfterQualifier.kt");
doTest(fileName);
}
@TestMetadata("NoNestedClassAfterReceiver.kt")
public void testNoNestedClassAfterReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoNestedClassAfterReceiver.kt");
doTest(fileName);
}
@TestMetadata("NoObjectInTypePosition.kt")
public void testNoObjectInTypePosition() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/NoObjectInTypePosition.kt");
@@ -937,6 +955,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("PackageDirective.kt")
public void testPackageDirective() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/PackageDirective.kt");
doTest(fileName);
}
@TestMetadata("PropertyMetadata.kt")
public void testPropertyMetadata() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/PropertyMetadata.kt");
@@ -204,12 +204,6 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("FunctionReference11.kt")
public void testFunctionReference11() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/FunctionReference11.kt");
doTest(fileName);
}
@TestMetadata("FunctionReference12.kt")
public void testFunctionReference12() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/FunctionReference12.kt");
@@ -228,12 +222,6 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("FunctionReference5.kt")
public void testFunctionReference5() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/FunctionReference5.kt");
doTest(fileName);
}
@TestMetadata("FunctionReference7.kt")
public void testFunctionReference7() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/FunctionReference7.kt");