Extension callables index and its use in completion

This commit is contained in:
Valentin Kipyatkov
2015-03-30 22:45:14 +03:00
parent 546af84435
commit 5ba5618718
15 changed files with 245 additions and 75 deletions
@@ -98,7 +98,7 @@ public class JetProperty extends JetTypeParameterListOwnerStub<KotlinPropertyStu
public JetTypeReference getReceiverTypeReference() { public JetTypeReference getReceiverTypeReference() {
KotlinPropertyStub stub = getStub(); KotlinPropertyStub stub = getStub();
if (stub != null) { if (stub != null) {
if (!stub.hasReceiverTypeRef()) { if (!stub.isExtension()) {
return null; return null;
} }
else { else {
@@ -134,7 +134,7 @@ public class JetProperty extends JetTypeParameterListOwnerStub<KotlinPropertyStu
} }
else { else {
List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE); List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
int returnTypeRefPositionInPsi = stub.hasReceiverTypeRef() ? 1 : 0; int returnTypeRefPositionInPsi = stub.isExtension() ? 1 : 0;
if (typeReferences.size() <= returnTypeRefPositionInPsi) { if (typeReferences.size() <= returnTypeRefPositionInPsi) {
LOG.error("Invalid stub structure built for property:\n" + getText()); LOG.error("Invalid stub structure built for property:\n" + getText());
return null; return null;
@@ -56,13 +56,10 @@ public trait KotlinAnnotationEntryStub : StubElement<JetAnnotationEntry> {
public fun hasValueArguments(): Boolean public fun hasValueArguments(): Boolean
} }
public trait KotlinFunctionStub : KotlinStubWithFqName<JetNamedFunction> { public trait KotlinFunctionStub : KotlinCallableStubBase<JetNamedFunction> {
public fun isTopLevel(): Boolean
public fun isExtension(): Boolean
public fun hasBlockBody(): Boolean public fun hasBlockBody(): Boolean
public fun hasBody(): Boolean public fun hasBody(): Boolean
public fun hasTypeParameterListBeforeFunctionName(): Boolean public fun hasTypeParameterListBeforeFunctionName(): Boolean
public fun isProbablyNothingType(): Boolean
} }
public trait KotlinImportDirectiveStub : StubElement<JetImportDirective> { public trait KotlinImportDirectiveStub : StubElement<JetImportDirective> {
@@ -92,14 +89,17 @@ public trait KotlinPropertyAccessorStub : StubElement<JetPropertyAccessor> {
public fun hasBlockBody(): Boolean public fun hasBlockBody(): Boolean
} }
public trait KotlinPropertyStub : KotlinStubWithFqName<JetProperty> { public trait KotlinPropertyStub : KotlinCallableStubBase<JetProperty> {
public fun isVar(): Boolean public fun isVar(): Boolean
public fun isTopLevel(): Boolean
public fun hasDelegate(): Boolean public fun hasDelegate(): Boolean
public fun hasDelegateExpression(): Boolean public fun hasDelegateExpression(): Boolean
public fun hasInitializer(): Boolean public fun hasInitializer(): Boolean
public fun hasReceiverTypeRef(): Boolean
public fun hasReturnTypeRef(): Boolean public fun hasReturnTypeRef(): Boolean
}
public trait KotlinCallableStubBase<TDeclaration: JetCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
public fun isTopLevel(): Boolean
public fun isExtension(): Boolean
public fun isProbablyNothingType(): Boolean public fun isProbablyNothingType(): Boolean
} }
@@ -61,7 +61,7 @@ public class JetPropertyElementType extends JetStubElementType<KotlinPropertyStu
dataStream.writeBoolean(stub.hasDelegate()); dataStream.writeBoolean(stub.hasDelegate());
dataStream.writeBoolean(stub.hasDelegateExpression()); dataStream.writeBoolean(stub.hasDelegateExpression());
dataStream.writeBoolean(stub.hasInitializer()); dataStream.writeBoolean(stub.hasInitializer());
dataStream.writeBoolean(stub.hasReceiverTypeRef()); dataStream.writeBoolean(stub.isExtension());
dataStream.writeBoolean(stub.hasReturnTypeRef()); dataStream.writeBoolean(stub.hasReturnTypeRef());
dataStream.writeBoolean(stub.isProbablyNothingType()); dataStream.writeBoolean(stub.isProbablyNothingType());
@@ -32,7 +32,7 @@ public class KotlinPropertyStubImpl(
private val hasDelegate: Boolean, private val hasDelegate: Boolean,
private val hasDelegateExpression: Boolean, private val hasDelegateExpression: Boolean,
private val hasInitializer: Boolean, private val hasInitializer: Boolean,
private val hasReceiverTypeRef: Boolean, private val isExtension: Boolean,
private val hasReturnTypeRef: Boolean, private val hasReturnTypeRef: Boolean,
private val isProbablyNothingType: Boolean, private val isProbablyNothingType: Boolean,
private val fqName: FqName? private val fqName: FqName?
@@ -53,7 +53,7 @@ public class KotlinPropertyStubImpl(
override fun hasDelegate() = hasDelegate override fun hasDelegate() = hasDelegate
override fun hasDelegateExpression() = hasDelegateExpression override fun hasDelegateExpression() = hasDelegateExpression
override fun hasInitializer() = hasInitializer override fun hasInitializer() = hasInitializer
override fun hasReceiverTypeRef() = hasReceiverTypeRef override fun isExtension() = isExtension
override fun hasReturnTypeRef() = hasReturnTypeRef override fun hasReturnTypeRef() = hasReturnTypeRef
override fun getName() = StringRef.toString(name) override fun getName() = StringRef.toString(name)
override fun isProbablyNothingType() = isProbablyNothingType override fun isProbablyNothingType() = isProbablyNothingType
@@ -133,7 +133,7 @@ private class CallableClsStubBuilder(
hasDelegate = false, hasDelegate = false,
hasDelegateExpression = false, hasDelegateExpression = false,
hasInitializer = false, hasInitializer = false,
hasReceiverTypeRef = callableProto.hasReceiverType(), isExtension = callableProto.hasReceiverType(),
hasReturnTypeRef = true, hasReturnTypeRef = true,
fqName = c.containerFqName.child(callableName), fqName = c.containerFqName.child(callableName),
isProbablyNothingType = isProbablyNothing(callableProto) isProbablyNothingType = isProbablyNothing(callableProto)
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2015 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.kotlin.idea.stubindex
import com.intellij.psi.stubs.IndexSink
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.KotlinCallableStubBase
fun indexTopLevelExtension<TDeclaration : JetCallableDeclaration>(stub: KotlinCallableStubBase<TDeclaration>, sink: IndexSink) {
if (stub.isExtension()) {
val declaration = stub.getPsi()
declaration.getReceiverTypeReference()!!.getTypeElement()?.index(declaration, sink)
}
}
private fun <TDeclaration : JetCallableDeclaration> JetTypeElement.index(declaration: TDeclaration, sink: IndexSink) {
fun occurrence(typeName: String) {
val name = declaration.getName() ?: return
sink.occurrence(JetTopLevelExtensionsByReceiverTypeIndex.INSTANCE.getKey(),
JetTopLevelExtensionsByReceiverTypeIndex.buildKey(typeName, name))
}
when (this) {
is JetUserType -> {
//TODO: aliases
var typeName = getReferencedName() ?: return
if (declaration is JetNamedFunction) {
val typeParameter = declaration.getTypeParameters().firstOrNull { it.getName() == typeName }
if (typeParameter != null) {
val bound = typeParameter.getExtendsBound()
if (bound != null) {
bound.getTypeElement()?.index(declaration, sink)
return
}
typeName = "Any"
}
}
occurrence(typeName)
}
is JetNullableType -> getInnerType()?.index(declaration, sink)
is JetFunctionType -> {
val typeName = (if (getReceiverTypeReference() != null) "ExtensionFunction" else "Function") + getParameters().size()
occurrence(typeName)
}
else -> occurrence("Any")
}
}
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2015 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.kotlin.idea.stubindex
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StringStubIndexExtension
import com.intellij.psi.stubs.StubIndexKey
import org.jetbrains.kotlin.psi.JetCallableDeclaration
public class JetTopLevelExtensionsByReceiverTypeIndex private() : StringStubIndexExtension<JetCallableDeclaration>() {
override fun getKey() = KEY
override fun get(s: String, project: Project, scope: GlobalSearchScope)
= super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project))
companion object {
private val KEY = KotlinIndexUtil.createIndexKey<String, JetCallableDeclaration>(javaClass<JetTopLevelExtensionsByReceiverTypeIndex>())
public val INSTANCE: JetTopLevelExtensionsByReceiverTypeIndex = JetTopLevelExtensionsByReceiverTypeIndex()
public fun buildKey(receiverTypeName: String, callableName: String): String = receiverTypeName + "\n" + callableName
public fun receiverTypeNameFromKey(key: String): String = key.substringBefore('\n', "")
public fun callableNameFromKey(key: String): String = key.substringAfter('\n', "")
}
}
@@ -17,10 +17,7 @@
package org.jetbrains.kotlin.idea.stubindex; package org.jetbrains.kotlin.idea.stubindex;
import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetClassOrObject; import org.jetbrains.kotlin.psi.JetClassOrObject;
import org.jetbrains.kotlin.psi.stubs.*; import org.jetbrains.kotlin.psi.stubs.*;
import org.jetbrains.kotlin.psi.stubs.elements.StubIndexService; import org.jetbrains.kotlin.psi.stubs.elements.StubIndexService;
@@ -95,6 +92,7 @@ public class StubIndexServiceImpl implements StubIndexService {
if (fqName != null) { if (fqName != null) {
sink.occurrence(JetTopLevelFunctionFqnNameIndex.getInstance().getKey(), fqName.asString()); sink.occurrence(JetTopLevelFunctionFqnNameIndex.getInstance().getKey(), fqName.asString());
sink.occurrence(JetTopLevelFunctionByPackageIndex.getInstance().getKey(), fqName.parent().asString()); sink.occurrence(JetTopLevelFunctionByPackageIndex.getInstance().getKey(), fqName.parent().asString());
StubindexPackage.indexTopLevelExtension(stub, sink);
} }
} }
} }
@@ -116,6 +114,7 @@ public class StubIndexServiceImpl implements StubIndexService {
if (fqName != null) { if (fqName != null) {
sink.occurrence(JetTopLevelPropertyFqnNameIndex.getInstance().getKey(), fqName.asString()); sink.occurrence(JetTopLevelPropertyFqnNameIndex.getInstance().getKey(), fqName.asString());
sink.occurrence(JetTopLevelPropertyByPackageIndex.getInstance().getKey(), fqName.parent().asString()); sink.occurrence(JetTopLevelPropertyByPackageIndex.getInstance().getKey(), fqName.parent().asString());
StubindexPackage.indexTopLevelExtension(stub, sink);
} }
} }
} }
+1
View File
@@ -428,6 +428,7 @@
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetSuperClassIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetSuperClassIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetTopLevelFunctionFqnNameIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetTopLevelFunctionFqnNameIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetTopLevelPropertyFqnNameIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetTopLevelPropertyFqnNameIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetTopLevelExtensionsByReceiverTypeIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetAnnotationsIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetAnnotationsIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingFunctionShortNameIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingFunctionShortNameIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingPropertyShortNameIndex"/> <stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingPropertyShortNameIndex"/>
@@ -16,28 +16,31 @@
package org.jetbrains.kotlin.idea.caches package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StringStubIndexExtension
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.scopes.JetScope
import com.intellij.openapi.project.Project
import java.util.HashSet
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import com.intellij.psi.stubs.StringStubIndexExtension import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance import java.util.HashSet
import org.jetbrains.kotlin.idea.stubindex.* import java.util.LinkedHashSet
public class KotlinIndicesHelper( public class KotlinIndicesHelper(
private val project: Project, private val project: Project,
@@ -78,74 +81,95 @@ public class KotlinIndicesHelper(
} }
public fun getCallableTopLevelExtensions(nameFilter: (String) -> Boolean, expression: JetSimpleNameExpression): Collection<CallableDescriptor> { public fun getCallableTopLevelExtensions(nameFilter: (String) -> Boolean, expression: JetSimpleNameExpression): Collection<CallableDescriptor> {
val receiverValues = receiverValues(expression)
if (receiverValues.isEmpty()) return emptyList()
val dataFlowInfo = bindingContext.getDataFlowInfo(expression) val dataFlowInfo = bindingContext.getDataFlowInfo(expression)
val functionsIndex = JetTopLevelFunctionFqnNameIndex.getInstance() val receiverTypeNames = possibleReceiverTypeNames(receiverValues.map { it.first }, dataFlowInfo)
val propertiesIndex = JetTopLevelPropertyFqnNameIndex.getInstance()
val functionFqNames = functionsIndex.getAllKeys(project).sequence().map { FqName(it) } val index = JetTopLevelExtensionsByReceiverTypeIndex.INSTANCE
val propertyFqNames = propertiesIndex.getAllKeys(project).sequence().map { FqName(it) }
val result = HashSet<CallableDescriptor>() val declarations = index.getAllKeys(project)
result.fqNamesToSuitableExtensions(functionFqNames, nameFilter, functionsIndex, expression, bindingContext, dataFlowInfo) .sequence()
result.fqNamesToSuitableExtensions(propertyFqNames, nameFilter, propertiesIndex, expression, bindingContext, dataFlowInfo) .filter {
JetTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames
&& nameFilter(JetTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))
}
.flatMap { index.get(it, project, scope).sequence() }
return findSuitableExtensions(declarations, receiverValues, dataFlowInfo, bindingContext)
}
private fun possibleReceiverTypeNames(receiverValues: Collection<ReceiverValue>, dataFlowInfo: DataFlowInfo): Set<String> {
val result = LinkedHashSet<String>()
for (receiverValue in receiverValues) {
for (type in SmartCastUtils.getSmartCastVariants(receiverValue, bindingContext, dataFlowInfo)) {
result.addTypeNames(type)
}
}
return result return result
} }
private fun MutableCollection<CallableDescriptor>.fqNamesToSuitableExtensions( private fun receiverValues(expression: JetSimpleNameExpression): Collection<Pair<ReceiverValue, CallType>> {
fqNames: Sequence<FqName>,
nameFilter: (String) -> Boolean,
index: StringStubIndexExtension<out JetCallableDeclaration>,
expression: JetSimpleNameExpression,
bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo) {
val matchingNames = fqNames.filter { nameFilter(it.shortName().asString()) }
val receiverPair = ReferenceVariantsHelper.getExplicitReceiverData(expression) val receiverPair = ReferenceVariantsHelper.getExplicitReceiverData(expression)
if (receiverPair != null) { if (receiverPair != null) {
val (receiverExpression, callType) = receiverPair val (receiverExpression, callType) = receiverPair
val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression] val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression]
if (expressionType == null || expressionType.isError()) return if (expressionType == null || expressionType.isError()) return emptyList()
val receiverValue = ExpressionReceiver(receiverExpression, expressionType) val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
matchingNames.flatMapTo(this) { return listOf(receiverValue to callType)
findSuitableExtensions(it, index, receiverValue, dataFlowInfo, callType, bindingContext)
}
} }
else { else {
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, expression] ?: return val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, expression] ?: return emptyList()
for (receiver in resolutionScope.getImplicitReceiversWithInstance()) { return resolutionScope.getImplicitReceiversWithInstance().map { it.getValue() to CallType.NORMAL }
matchingNames.flatMapTo(this) {
findSuitableExtensions(it, index, receiver.getValue(), dataFlowInfo, CallType.NORMAL, bindingContext)
}
}
} }
} }
private fun MutableCollection<String>.addTypeNames(type: JetType) {
val constructor = type.getConstructor()
addIfNotNull(constructor.getDeclarationDescriptor()?.getName()?.asString())
constructor.getSupertypes().forEach { addTypeNames(it) }
}
/** /**
* Check that function or property with the given qualified name can be resolved in given scope and called on given receiver * Check that function or property with the given qualified name can be resolved in given scope and called on given receiver
*/ */
private fun findSuitableExtensions(callableFQN: FqName, private fun findSuitableExtensions(
index: StringStubIndexExtension<out JetCallableDeclaration>, declarations: Sequence<JetCallableDeclaration>,
receiverValue: ReceiverValue, receiverValues: Collection<Pair<ReceiverValue, CallType>>,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
callType: CallType, bindingContext: BindingContext
bindingContext: BindingContext): Sequence<CallableDescriptor> { ): Collection<CallableDescriptor> {
val extensions = index.get(callableFQN.asString(), project, scope).filter { it.getReceiverTypeReference() != null } val result = LinkedHashSet<CallableDescriptor>()
val descriptors = if (extensions.any { it.getContainingJetFile().isCompiled() } ) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations
analyzeImportReference(callableFQN) fun processDescriptor(descriptor: CallableDescriptor) {
.filterIsInstance<CallableDescriptor>() if (visibilityFilter(descriptor)) {
.filter { it.getExtensionReceiverParameter() != null } for ((receiverValue, callType) in receiverValues) {
result.addAll(descriptor.substituteExtensionIfCallable(receiverValue, callType, bindingContext, dataFlowInfo))
}
}
} }
else {
extensions.map { resolutionFacade.resolveToDescriptor(it) as CallableDescriptor } for (declaration in declarations) {
if (declaration.getContainingJetFile().isCompiled()) {
//TODO: it's temporary while resolveToDescriptor does not work for compiled declarations
for (descriptor in analyzeImportReference(declaration.getFqName()!!)) {
if (descriptor is CallableDescriptor && descriptor.getExtensionReceiverParameter() != null) {
processDescriptor(descriptor)
}
}
}
else {
processDescriptor(resolutionFacade.resolveToDescriptor(declaration) as CallableDescriptor)
}
} }
return descriptors.sequence()
.filter(visibilityFilter) return result
.flatMap { it.substituteExtensionIfCallable(receiverValue, callType, bindingContext, dataFlowInfo).sequence() }
} }
public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> { public fun getClassDescriptors(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
@@ -1,6 +1,6 @@
package second package second
fun String.helloFun() { fun String?.helloFun() {
} }
fun String.helloWithParams(i : Int) : String { fun String.helloWithParams(i : Int) : String {
@@ -10,5 +10,8 @@ fun String.helloWithParams(i : Int) : String {
fun String.helloFunPreventAutoInsert() { fun String.helloFunPreventAutoInsert() {
} }
fun <T: CharSequence> T.helloFunGeneric() {
}
fun Int.helloFake() { fun Int.helloFake() {
} }
@@ -8,5 +8,6 @@ fun firstFun() {
// EXIST: helloFun // EXIST: helloFun
// EXIST: helloFunPreventAutoInsert // EXIST: helloFunPreventAutoInsert
// EXIST: helloWithParams // EXIST: helloWithParams
// EXIST: helloFunGeneric
// ABSENT: helloFake // ABSENT: helloFake
// NUMBER: 3 // NUMBER: 4
@@ -0,0 +1,16 @@
package second
fun (() -> Unit)?.helloFun1() {
}
fun Function0<Unit>.helloFun2() {
}
fun ExtensionFunction0<String, Unit>.helloFun3() {
}
fun Function1<String, Unit>.helloFun4() {
}
fun Any.helloAny() {
}
@@ -0,0 +1,12 @@
package first
fun firstFun(p: () -> Unit) {
p.hello<caret>
}
// EXIST: helloFun1
// EXIST: helloFun2
// EXIST: helloAny
// ABSENT: helloFun3
// ABSENT: helloFun4
// NUMBER: 3
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.completion; package org.jetbrains.kotlin.completion;
import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.InnerTestClasses;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.JetTestUtils; import org.jetbrains.kotlin.test.JetTestUtils;
import org.jetbrains.kotlin.test.TestMetadata; import org.jetbrains.kotlin.test.TestMetadata;
@@ -144,6 +143,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
doTest(fileName); doTest(fileName);
} }
@TestMetadata("NotImportedExtensionFunction2")
public void testNotImportedExtensionFunction2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/multifile/NotImportedExtensionFunction2/");
doTest(fileName);
}
@TestMetadata("NotImportedExtensionProperty") @TestMetadata("NotImportedExtensionProperty")
public void testNotImportedExtensionProperty() throws Exception { public void testNotImportedExtensionProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/multifile/NotImportedExtensionProperty/"); String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/multifile/NotImportedExtensionProperty/");