Extension callables index and its use in completion
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
@@ -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', "")
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
+4
-1
@@ -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() {
|
||||||
}
|
}
|
||||||
+2
-1
@@ -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
|
||||||
+16
@@ -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() {
|
||||||
|
}
|
||||||
+12
@@ -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
|
||||||
+6
-1
@@ -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/");
|
||||||
|
|||||||
Reference in New Issue
Block a user