KT-4822 Wrong scope is used for local variable name completion
#KT-4822 Fixed
This commit is contained in:
@@ -17,18 +17,19 @@
|
|||||||
package org.jetbrains.kotlin.resolve.bindingContextUtil
|
package org.jetbrains.kotlin.resolve.bindingContextUtil
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.FUNCTION
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.FUNCTION
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.WritableScope
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||||
|
|
||||||
public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingContext): FunctionDescriptor? {
|
public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingContext): FunctionDescriptor? {
|
||||||
@@ -55,7 +56,9 @@ public fun JetExpression.isUsedAsStatement(context: BindingContext): Boolean = !
|
|||||||
public fun <C : ResolutionContext<C>> ResolutionContext<C>.recordScopeAndDataFlowInfo(expression: JetExpression?) {
|
public fun <C : ResolutionContext<C>> ResolutionContext<C>.recordScopeAndDataFlowInfo(expression: JetExpression?) {
|
||||||
if (expression == null) return
|
if (expression == null) return
|
||||||
|
|
||||||
trace.record(BindingContext.RESOLUTION_SCOPE, expression, scope)
|
val scopeToRecord = if (scope is WritableScope) scope.takeSnapshot() else scope
|
||||||
|
trace.record(BindingContext.RESOLUTION_SCOPE, expression, scopeToRecord)
|
||||||
|
|
||||||
val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)
|
val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)
|
||||||
if (typeInfo != null) {
|
if (typeInfo != null) {
|
||||||
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo))
|
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo))
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public trait WritableScope : JetScope {
|
|||||||
READING
|
READING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun takeSnapshot(): JetScope
|
||||||
|
|
||||||
public fun changeLockLevel(lockLevel: LockLevel): WritableScope
|
public fun changeLockLevel(lockLevel: LockLevel): WritableScope
|
||||||
|
|
||||||
public fun addLabeledDeclaration(descriptor: DeclarationDescriptor)
|
public fun addLabeledDeclaration(descriptor: DeclarationDescriptor)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.util.collectionUtils.concatInOrder
|
|||||||
|
|
||||||
// Writes to: maps
|
// Writes to: maps
|
||||||
|
|
||||||
public class WritableScopeImpl(override val workerScope: JetScope,
|
public class WritableScopeImpl(outerScope: JetScope,
|
||||||
private val ownerDeclarationDescriptor: DeclarationDescriptor,
|
private val ownerDeclarationDescriptor: DeclarationDescriptor,
|
||||||
protected val redeclarationHandler: RedeclarationHandler,
|
protected val redeclarationHandler: RedeclarationHandler,
|
||||||
private val debugName: String)
|
private val debugName: String)
|
||||||
@@ -40,9 +40,9 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
|
|
||||||
private val explicitlyAddedDescriptors = SmartList<DeclarationDescriptor>()
|
private val explicitlyAddedDescriptors = SmartList<DeclarationDescriptor>()
|
||||||
|
|
||||||
private var functionGroups: MutableMap<Name, SmartList<FunctionDescriptor>>? = null
|
private var functionGroups: MutableMap<Name, SmartList<Int>>? = null
|
||||||
|
|
||||||
private var variableOrClassDescriptors: MutableMap<Name, DeclarationDescriptor>? = null
|
private var variableOrClassDescriptors: MutableMap<Name, SmartList<Int>>? = null //TODO: implement SmartIntList
|
||||||
|
|
||||||
private var labelsToDescriptors: MutableMap<Name, SmartList<DeclarationDescriptor>>? = null
|
private var labelsToDescriptors: MutableMap<Name, SmartList<DeclarationDescriptor>>? = null
|
||||||
|
|
||||||
@@ -52,8 +52,12 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
|
|
||||||
override fun getContainingDeclaration(): DeclarationDescriptor = ownerDeclarationDescriptor
|
override fun getContainingDeclaration(): DeclarationDescriptor = ownerDeclarationDescriptor
|
||||||
|
|
||||||
|
private var lastSnapshot: Snapshot? = null
|
||||||
|
|
||||||
private var lockLevel: WritableScope.LockLevel = WritableScope.LockLevel.WRITING
|
private var lockLevel: WritableScope.LockLevel = WritableScope.LockLevel.WRITING
|
||||||
|
|
||||||
|
override val workerScope: JetScope = if (outerScope is WritableScope) outerScope.takeSnapshot() else outerScope
|
||||||
|
|
||||||
override fun changeLockLevel(lockLevel: WritableScope.LockLevel): WritableScope {
|
override fun changeLockLevel(lockLevel: WritableScope.LockLevel): WritableScope {
|
||||||
if (lockLevel.ordinal() < this.lockLevel.ordinal()) {
|
if (lockLevel.ordinal() < this.lockLevel.ordinal()) {
|
||||||
throw IllegalStateException("cannot lower lock level from " + this.lockLevel + " to " + lockLevel + " at " + toString())
|
throw IllegalStateException("cannot lower lock level from " + this.lockLevel + " to " + lockLevel + " at " + toString())
|
||||||
@@ -74,6 +78,14 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun takeSnapshot(): JetScope {
|
||||||
|
checkMayRead()
|
||||||
|
if (lastSnapshot == null || lastSnapshot!!.descriptorLimit != explicitlyAddedDescriptors.size()) {
|
||||||
|
lastSnapshot = Snapshot(explicitlyAddedDescriptors.size())
|
||||||
|
}
|
||||||
|
return lastSnapshot!!
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDescriptors(kindFilter: DescriptorKindFilter,
|
override fun getDescriptors(kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||||
checkMayRead()
|
checkMayRead()
|
||||||
@@ -108,17 +120,18 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
|
|
||||||
val name = descriptor.getName()
|
val name = descriptor.getName()
|
||||||
|
|
||||||
val originalDescriptor = variableOrClassDescriptors?.get(name)
|
val originalDescriptor = variableOrClassDescriptorByName(name)
|
||||||
if (originalDescriptor != null) {
|
if (originalDescriptor != null) {
|
||||||
redeclarationHandler.handleRedeclaration(originalDescriptor, descriptor)
|
redeclarationHandler.handleRedeclaration(originalDescriptor, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val descriptorIndex = addDescriptor(descriptor)
|
||||||
|
|
||||||
if (variableOrClassDescriptors == null) {
|
if (variableOrClassDescriptors == null) {
|
||||||
variableOrClassDescriptors = HashMap()
|
variableOrClassDescriptors = HashMap()
|
||||||
}
|
}
|
||||||
variableOrClassDescriptors!!.put(name, descriptor)
|
variableOrClassDescriptors!!.getOrPut(descriptor.getName()) { SmartList() }.add(descriptorIndex)
|
||||||
|
|
||||||
explicitlyAddedDescriptors.add(descriptor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addVariableDescriptor(variableDescriptor: VariableDescriptor) {
|
override fun addVariableDescriptor(variableDescriptor: VariableDescriptor) {
|
||||||
@@ -128,7 +141,7 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
override fun getLocalVariable(name: Name): VariableDescriptor? {
|
override fun getLocalVariable(name: Name): VariableDescriptor? {
|
||||||
checkMayRead()
|
checkMayRead()
|
||||||
|
|
||||||
val descriptor = variableOrClassDescriptors?.get(name)
|
val descriptor = variableOrClassDescriptorByName(name)
|
||||||
if (descriptor is VariableDescriptor) {
|
if (descriptor is VariableDescriptor) {
|
||||||
return descriptor
|
return descriptor
|
||||||
}
|
}
|
||||||
@@ -139,18 +152,18 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
override fun addFunctionDescriptor(functionDescriptor: FunctionDescriptor) {
|
override fun addFunctionDescriptor(functionDescriptor: FunctionDescriptor) {
|
||||||
checkMayWrite()
|
checkMayWrite()
|
||||||
|
|
||||||
|
val descriptorIndex = addDescriptor(functionDescriptor)
|
||||||
|
|
||||||
if (functionGroups == null) {
|
if (functionGroups == null) {
|
||||||
functionGroups = HashMap(1)
|
functionGroups = HashMap(1)
|
||||||
}
|
}
|
||||||
functionGroups!!.getOrPut(functionDescriptor.getName()) { SmartList() }.add(functionDescriptor)
|
functionGroups!!.getOrPut(functionDescriptor.getName()) { SmartList() }.add(descriptorIndex)
|
||||||
explicitlyAddedDescriptors.add(functionDescriptor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
|
override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
|
||||||
checkMayRead()
|
checkMayRead()
|
||||||
|
|
||||||
val functionGroupByName = functionGroups?.get(name)
|
return concatInOrder(functionsByName(name), workerScope.getFunctions(name))
|
||||||
return concatInOrder(functionGroupByName, workerScope.getFunctions(name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addClassifierDescriptor(classifierDescriptor: ClassifierDescriptor) {
|
override fun addClassifierDescriptor(classifierDescriptor: ClassifierDescriptor) {
|
||||||
@@ -160,7 +173,7 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
override fun getClassifier(name: Name): ClassifierDescriptor? {
|
override fun getClassifier(name: Name): ClassifierDescriptor? {
|
||||||
checkMayRead()
|
checkMayRead()
|
||||||
|
|
||||||
return variableOrClassDescriptors?.get(name) as? ClassifierDescriptor
|
return variableOrClassDescriptorByName(name) as? ClassifierDescriptor
|
||||||
?: workerScope.getClassifier(name)
|
?: workerScope.getClassifier(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +204,35 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
|
|
||||||
override fun getOwnDeclaredDescriptors(): Collection<DeclarationDescriptor> = explicitlyAddedDescriptors
|
override fun getOwnDeclaredDescriptors(): Collection<DeclarationDescriptor> = explicitlyAddedDescriptors
|
||||||
|
|
||||||
|
private fun variableOrClassDescriptorByName(name: Name, descriptorLimit: Int = explicitlyAddedDescriptors.size()): DeclarationDescriptor? {
|
||||||
|
val descriptorIndices = variableOrClassDescriptors?.get(name) ?: return null
|
||||||
|
for (i in descriptorIndices.indices.reversed()) {
|
||||||
|
val descriptorIndex = descriptorIndices[i]
|
||||||
|
if (descriptorIndex < descriptorLimit) {
|
||||||
|
return descriptorIndex.descriptorByIndex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun functionsByName(name: Name, descriptorLimit: Int = explicitlyAddedDescriptors.size()): List<FunctionDescriptor>? {
|
||||||
|
val descriptorIndices = functionGroups?.get(name) ?: return null
|
||||||
|
for (i in descriptorIndices.indices.reversed()) {
|
||||||
|
val descriptorIndex = descriptorIndices[i]
|
||||||
|
if (descriptorIndex < descriptorLimit) {
|
||||||
|
return descriptorIndices.truncated(descriptorIndex + 1).map { it.descriptorByIndex() as FunctionDescriptor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDescriptor(descriptor: DeclarationDescriptor): Int {
|
||||||
|
explicitlyAddedDescriptors.add(descriptor)
|
||||||
|
return explicitlyAddedDescriptors.size() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Int.descriptorByIndex() = explicitlyAddedDescriptors[this]
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return javaClass.getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " " + debugName + " for " + getContainingDeclaration()
|
return javaClass.getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " " + debugName + " for " + getContainingDeclaration()
|
||||||
}
|
}
|
||||||
@@ -207,4 +249,65 @@ public class WritableScopeImpl(override val workerScope: JetScope,
|
|||||||
p.popIndent()
|
p.popIndent()
|
||||||
p.println("}")
|
p.println("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun <T> List<T>.truncated(newSize: Int) = if (newSize == size()) this else subList(0, newSize)
|
||||||
|
|
||||||
|
private inner class Snapshot(val descriptorLimit: Int) : JetScope by this@WritableScopeImpl {
|
||||||
|
override fun getDescriptors(kindFilter: DescriptorKindFilter,
|
||||||
|
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||||
|
checkMayRead()
|
||||||
|
changeLockLevel(WritableScope.LockLevel.READING)
|
||||||
|
|
||||||
|
val workerResult = workerScope.getDescriptors(kindFilter, nameFilter)
|
||||||
|
|
||||||
|
if (descriptorLimit == 0) return workerResult
|
||||||
|
|
||||||
|
val result = ArrayList<DeclarationDescriptor>(workerResult.size() + descriptorLimit)
|
||||||
|
for (i in 0..descriptorLimit-1) {
|
||||||
|
result.add(explicitlyAddedDescriptors[i])
|
||||||
|
}
|
||||||
|
result.addAll(workerResult)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLocalVariable(name: Name): VariableDescriptor? {
|
||||||
|
checkMayRead()
|
||||||
|
|
||||||
|
val descriptor = variableOrClassDescriptorByName(name, descriptorLimit)
|
||||||
|
if (descriptor is VariableDescriptor) {
|
||||||
|
return descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
return workerScope.getLocalVariable(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFunctions(name: Name): Collection<FunctionDescriptor> {
|
||||||
|
checkMayRead()
|
||||||
|
|
||||||
|
return concatInOrder(functionsByName(name, descriptorLimit), workerScope.getFunctions(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getClassifier(name: Name): ClassifierDescriptor? {
|
||||||
|
checkMayRead()
|
||||||
|
|
||||||
|
return variableOrClassDescriptorByName(name, descriptorLimit) as? ClassifierDescriptor
|
||||||
|
?: workerScope.getClassifier(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOwnDeclaredDescriptors(): Collection<DeclarationDescriptor> = explicitlyAddedDescriptors.truncated(descriptorLimit)
|
||||||
|
|
||||||
|
override fun printScopeStructure(p: Printer) {
|
||||||
|
p.println(javaClass.getSimpleName(), " {")
|
||||||
|
p.pushIndent()
|
||||||
|
|
||||||
|
p.println("descriptorLimit = ", descriptorLimit)
|
||||||
|
|
||||||
|
p.print("WritableScope = ")
|
||||||
|
this@WritableScopeImpl.printScopeStructure(p.withholdIndentOnce())
|
||||||
|
|
||||||
|
p.popIndent()
|
||||||
|
p.println("}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ public class ReferenceVariantsHelper(
|
|||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean
|
||||||
): Collection<DeclarationDescriptor> {
|
): Collection<DeclarationDescriptor> {
|
||||||
val parent = expression.getParent()
|
val parent = expression.getParent()
|
||||||
val resolutionScope = context.correctedResolutionScope(expression) ?: return listOf()
|
val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf()
|
||||||
val containingDeclaration = resolutionScope.getContainingDeclaration()
|
val containingDeclaration = resolutionScope.getContainingDeclaration()
|
||||||
|
|
||||||
if (parent is JetImportDirective || parent is JetPackageDirective) {
|
if (parent is JetImportDirective || parent is JetPackageDirective) {
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ public class ShadowedDeclarationsFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val calleeExpression = call.getCalleeExpression() ?: return descriptors
|
val calleeExpression = call.getCalleeExpression() ?: return descriptors
|
||||||
var resolutionScope = bindingContext.correctedResolutionScope(calleeExpression) ?: return descriptors
|
var resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return descriptors
|
||||||
|
|
||||||
if (descriptorsToImport.isNotEmpty()) {
|
if (descriptorsToImport.isNotEmpty()) {
|
||||||
resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors",
|
resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors",
|
||||||
|
|||||||
@@ -16,15 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.util
|
package org.jetbrains.kotlin.idea.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
|
|
||||||
public fun JetFunctionLiteral.findLabelAndCall(): Pair<Name?, JetCallExpression?> {
|
public fun JetFunctionLiteral.findLabelAndCall(): Pair<Name?, JetCallExpression?> {
|
||||||
val literalParent = (this.getParent() as JetFunctionLiteralExpression).getParent()
|
val literalParent = (this.getParent() as JetFunctionLiteralExpression).getParent()
|
||||||
@@ -51,34 +44,3 @@ public fun JetFunctionLiteral.findLabelAndCall(): Pair<Name?, JetCallExpression?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns corrected resolution scope excluding variable inside its own initializer
|
|
||||||
// will not be needed after correcting JetScope stored BindingContext (see KT-4822 Wrong scope is used for local variable name completion)
|
|
||||||
public fun BindingContext.correctedResolutionScope(expression: JetExpression): JetScope? {
|
|
||||||
val scope = get(BindingContext.RESOLUTION_SCOPE, expression) ?: return null
|
|
||||||
|
|
||||||
val variablesToExclude = hashSetOf<VariableDescriptor>()
|
|
||||||
for (element in expression.parentsWithSelf) {
|
|
||||||
if (element is JetExpression) {
|
|
||||||
val declaration = element.getParent() as? JetVariableDeclaration ?: continue
|
|
||||||
if (element == declaration.getInitializer()) {
|
|
||||||
variablesToExclude.addIfNotNull(get(BindingContext.VARIABLE, declaration))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variablesToExclude.isEmpty()) return scope
|
|
||||||
|
|
||||||
return object : JetScope by scope {
|
|
||||||
override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean)
|
|
||||||
= scope.getDescriptors(kindFilter, nameFilter).filter { it !in variablesToExclude }
|
|
||||||
|
|
||||||
//TODO: it's not correct!
|
|
||||||
override fun getLocalVariable(name: Name): VariableDescriptor? {
|
|
||||||
val variable = scope.getLocalVariable(name) ?: return null
|
|
||||||
return if (variable in variablesToExclude) null else variable
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getProperties(name: Name) = scope.getProperties(name).filter { it !in variablesToExclude }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -198,13 +198,28 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
|||||||
// set is used only for completion in code fragments
|
// set is used only for completion in code fragments
|
||||||
protected val referenceVariants: Collection<DeclarationDescriptor> by Delegates.lazy {
|
protected val referenceVariants: Collection<DeclarationDescriptor> by Delegates.lazy {
|
||||||
if (descriptorKindFilter != null) {
|
if (descriptorKindFilter != null) {
|
||||||
referenceVariantsHelper.getReferenceVariants(reference!!.expression, descriptorKindFilter!!, false, prefixMatcher.asNameFilter())
|
val expression = reference!!.expression
|
||||||
|
referenceVariantsHelper.getReferenceVariants(expression, descriptorKindFilter!!, false, prefixMatcher.asNameFilter())
|
||||||
|
.excludeNonInitializedVariable(expression)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filters out variable inside its initializer
|
||||||
|
private fun Collection<DeclarationDescriptor>.excludeNonInitializedVariable(expression: JetExpression): Collection<DeclarationDescriptor> {
|
||||||
|
for (element in expression.parentsWithSelf) {
|
||||||
|
val parent = element.getParent()
|
||||||
|
if (parent is JetVariableDeclaration && element == parent.getInitializer()) {
|
||||||
|
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, parent]
|
||||||
|
return this.filter { it != descriptor }
|
||||||
|
}
|
||||||
|
if (element is JetDeclaration) break // we can use variable inside lambda or anonymous object located in its initializer
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
||||||
val descriptors = referenceVariantsHelper.getReferenceVariants(reference!!.expression, descriptorKindFilter!!, true, prefixMatcher.asNameFilter())
|
val descriptors = referenceVariantsHelper.getReferenceVariants(reference!!.expression, descriptorKindFilter!!, true, prefixMatcher.asNameFilter())
|
||||||
return descriptors.filter { descriptor ->
|
return descriptors.filter { descriptor ->
|
||||||
|
|||||||
+1
-2
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
||||||
import org.jetbrains.kotlin.idea.completion.*
|
import org.jetbrains.kotlin.idea.completion.*
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.correctedResolutionScope
|
|
||||||
import org.jetbrains.kotlin.psi.JetExpression
|
import org.jetbrains.kotlin.psi.JetExpression
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -41,7 +40,7 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
|||||||
public fun addToCollection(collection: MutableCollection<LookupElement>,
|
public fun addToCollection(collection: MutableCollection<LookupElement>,
|
||||||
expectedInfos: Collection<ExpectedInfo>,
|
expectedInfos: Collection<ExpectedInfo>,
|
||||||
context: JetExpression) {
|
context: JetExpression) {
|
||||||
val resolutionScope = bindingContext.correctedResolutionScope(context) ?: return
|
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return
|
||||||
|
|
||||||
val added = HashSet<String>()
|
val added = HashSet<String>()
|
||||||
for (expectedInfo in expectedInfos) {
|
for (expectedInfo in expectedInfos) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo() {
|
||||||
|
val v = {
|
||||||
|
<caret>
|
||||||
|
val hello = 1
|
||||||
|
hello
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ABSENT: hello
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
val xxx = 3
|
||||||
|
|
||||||
|
fun foo(xxx: Int) {
|
||||||
|
val xxx = 1.0
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
val xxx = 'c'
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
val xxx: Any = run {
|
||||||
|
val xxx: String = xx<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: { lookupString: "xxx", itemText: "xxx", typeText: "Char" }
|
||||||
|
// NOTHING_ELSE
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
val xxx: String = <caret>
|
||||||
|
|
||||||
|
// ABSENT: xxx
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(p: () -> Unit): String = ""
|
||||||
|
|
||||||
|
val xxx: String = foo { <caret> }
|
||||||
|
|
||||||
|
// EXIST: xxx
|
||||||
+24
@@ -823,6 +823,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoLocalsDeclaredAhead.kt")
|
||||||
|
public void testNoLocalsDeclaredAhead() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoLocalsDeclaredAhead.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NoNestedClassAfterReceiver.kt")
|
@TestMetadata("NoNestedClassAfterReceiver.kt")
|
||||||
public void testNoNestedClassAfterReceiver() throws Exception {
|
public void testNoNestedClassAfterReceiver() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoNestedClassAfterReceiver.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoNestedClassAfterReceiver.kt");
|
||||||
@@ -1422,6 +1428,24 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer4.kt")
|
||||||
|
public void testInInitializer4() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer4.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer5.kt")
|
||||||
|
public void testInInitializer5() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer5.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer6.kt")
|
||||||
|
public void testInInitializer6() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer6.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Locals1.kt")
|
@TestMetadata("Locals1.kt")
|
||||||
public void testLocals1() throws Exception {
|
public void testLocals1() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");
|
||||||
|
|||||||
+24
@@ -823,6 +823,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoLocalsDeclaredAhead.kt")
|
||||||
|
public void testNoLocalsDeclaredAhead() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoLocalsDeclaredAhead.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("NoNestedClassAfterReceiver.kt")
|
@TestMetadata("NoNestedClassAfterReceiver.kt")
|
||||||
public void testNoNestedClassAfterReceiver() throws Exception {
|
public void testNoNestedClassAfterReceiver() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoNestedClassAfterReceiver.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/NoNestedClassAfterReceiver.kt");
|
||||||
@@ -1422,6 +1428,24 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer4.kt")
|
||||||
|
public void testInInitializer4() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer4.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer5.kt")
|
||||||
|
public void testInInitializer5() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer5.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InInitializer6.kt")
|
||||||
|
public void testInInitializer6() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer6.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Locals1.kt")
|
@TestMetadata("Locals1.kt")
|
||||||
public void testLocals1() throws Exception {
|
public void testLocals1() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user