IterableVariableMacro to honor smart casts

This commit is contained in:
Valentin Kipyatkov
2015-11-17 16:33:18 +03:00
parent 51647853f3
commit 0e740dc0a6
8 changed files with 29 additions and 20 deletions
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider
import org.jetbrains.kotlin.idea.completion.ArgumentPositionData
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
import org.jetbrains.kotlin.idea.completion.SmartCastCalculator
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
import org.jetbrains.kotlin.idea.completion.Tail
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.getResolutionScope
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.completion.*
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.FuzzyType
@@ -81,7 +82,7 @@ class SmartCompletion(
private val callableTypeExpectedInfo = expectedInfos.filterCallableExpected()
public val smartCastCalculator: SmartCastCalculator by lazy(LazyThreadSafetyMode.NONE) {
SmartCastCalculator(bindingContext, resolutionFacade.moduleDescriptor, expression, resolutionFacade)
SmartCastCalculator(bindingContext, resolutionFacade.moduleDescriptor, expression, callTypeAndReceiver.receiver as? KtExpression, resolutionFacade)
}
public val descriptorFilter: ((DeclarationDescriptor, AbstractLookupElementFactory) -> Collection<LookupElement>)? =
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.idea.completion.*
import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.resolve.callableReferences.getReflectionTypeForCandidateDescriptor
@@ -14,19 +14,18 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.completion
package org.jetbrains.kotlin.idea.core
import com.intellij.openapi.util.Pair
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
@@ -43,15 +42,14 @@ import java.util.*
class SmartCastCalculator(
val bindingContext: BindingContext,
val containingDeclarationOrModule: DeclarationDescriptor,
expression: KtExpression,
contextElement: PsiElement,
receiver: KtExpression?,
resolutionFacade: ResolutionFacade
) {
private val receiver = if (expression is KtSimpleNameExpression) expression.getReceiverExpression() else null
// keys are VariableDescriptor's and ThisReceiver's
private val entityToSmartCastInfo: Map<Any, SmartCastInfo> = processDataFlowInfo(
bindingContext.getDataFlowInfo(expression),
expression.getResolutionScope(bindingContext, resolutionFacade),
bindingContext.getDataFlowInfo(contextElement),
contextElement.getResolutionScope(bindingContext, resolutionFacade),
receiver)
fun types(descriptor: VariableDescriptor): Collection<KotlinType> {
@@ -114,7 +112,7 @@ class SmartCastCalculator(
val entityToInfo = HashMap<Any, SmartCastInfo>()
for ((dataFlowValue, types) in dataFlowInfo.completeTypeInfo.asMap().entrySet()) {
for ((dataFlowValue, types) in dataFlowInfo.completeTypeInfo.asMap().entries) {
val entity = dataFlowValueToEntity.invoke(dataFlowValue)
if (entity != null) {
entityToInfo[entity] = SmartCastInfo(types, false)
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.IterableTypesDetection
import org.jetbrains.kotlin.idea.core.IterableTypesDetector
import org.jetbrains.kotlin.idea.core.SmartCastCalculator
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingContext
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
class IterableVariableMacro : BaseKotlinVariableMacro() {
private companion object {
val ITERABLE_TYPES_DETECTOR_KEY = Key<IterableTypesDetector>("ITERABLE_TYPES_DETECTOR_KEY")
val SMART_CAST_CALCULATOR_KEY = Key<SmartCastCalculator>("SMART_CAST_CALCULATOR_KEY")
}
override fun getName() = "kotlinIterableVariable"
@@ -39,12 +41,15 @@ class IterableVariableMacro : BaseKotlinVariableMacro() {
val resolutionFacade = contextElement.getResolutionFacade()
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val detector = resolutionFacade.getIdeService(IterableTypesDetection::class.java).createDetector(scope)
val smartCastCalculator = SmartCastCalculator(bindingContext, scope.ownerDescriptor, contextElement, null, resolutionFacade)
userData.putUserData(ITERABLE_TYPES_DETECTOR_KEY, detector)
userData.putUserData(SMART_CAST_CALCULATOR_KEY, smartCastCalculator)
}
override fun isSuitable(variableDescriptor: VariableDescriptor, project: Project, userData: UserDataHolder): Boolean {
val detector = userData.getUserData(ITERABLE_TYPES_DETECTOR_KEY)!!
//TODO: smart-casts
return detector.isIterable(variableDescriptor.type, null)
val smartCastCalculator = userData.getUserData(SMART_CAST_CALCULATOR_KEY)!!
val types = smartCastCalculator.types(variableDescriptor)
return types.any { detector.isIterable(it, null) }
}
}
+5 -3
View File
@@ -7,12 +7,14 @@ class MyClass {
public var collection : HashSet<Int>? = null
private var isAlive : Boolean = false
fun main(args : Array<String>, v : Int) {
fun main(args : Array<String>, v : Int, o: Any) {
var str = ""
val myList = ArrayList<String>()
val stream = FileInputStream(".")
for (collection in args) {
<caret>
if (o is String) {
for (collection in args) {
<caret>
}
}
}
}
+4 -2
View File
@@ -7,10 +7,12 @@ class MyClass {
public var collection : HashSet<Int>? = null
private var isAlive : Boolean = false
fun main(args : Array<String>, v : Int) {
fun main(args : Array<String>, v : Int, o: Any) {
var str = ""
val myList = ArrayList<String>()
val stream = FileInputStream(".")
<caret>
if (o is String) {
<caret>
}
}
}
@@ -198,7 +198,7 @@ public class LiveTemplatesTest extends KotlinLightCodeInsightFixtureTestCase {
public void testIter() {
start();
assertStringItems("args", "myList", "str", "stream");
assertStringItems("args", "myList", "o", "str", "stream");
type("args");
nextTab(2);