Fixed KT-5020 Smart completion should work at the initializer of a val with no explicit type

#KT-5020 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-07-22 23:07:55 +04:00
parent ca25a3feaa
commit 91c983706a
5 changed files with 45 additions and 3 deletions
@@ -144,7 +144,7 @@ class CompletionSession {
return isVisibleDescriptor(descriptor);
}
};
SmartCompletion completion = new SmartCompletion(jetReference.getExpression(), getResolveSession(), visibilityFilter);
SmartCompletion completion = new SmartCompletion(jetReference.getExpression(), getResolveSession(), visibilityFilter, (JetFile)parameters.getOriginalFile());
Collection<LookupElement> elements = completion.buildLookupElements(descriptors);
if (elements != null) {
for (LookupElement element : elements) {
@@ -29,10 +29,13 @@ import org.jetbrains.jet.plugin.completion.*
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.plugin.util.makeNotNullable
import org.jetbrains.jet.plugin.util.makeNullable
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.plugin.caches.resolve.getLazyResolveSession
class SmartCompletion(val expression: JetSimpleNameExpression,
val resolveSession: ResolveSessionForBodies,
val visibilityFilter: (DeclarationDescriptor) -> Boolean) {
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
val originalFile: JetFile) {
private val bindingContext = resolveSession.resolveToElement(expression)
private val moduleDescriptor = resolveSession.getModuleDescriptor()
@@ -73,7 +76,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
receiver = null
}
val allExpectedInfos = ExpectedInfos(bindingContext, moduleDescriptor).calculate(expressionWithType) ?: return null
val allExpectedInfos = calcExpectedInfos(expressionWithType) ?: return null
val filteredExpectedInfos = allExpectedInfos.filter { !it.`type`.isError() }
if (filteredExpectedInfos.isEmpty()) return null
@@ -125,6 +128,23 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
return result
}
private fun calcExpectedInfos(expression: JetExpression): Collection<ExpectedInfo>? {
// if our expression is initializer of implicitly typed variable - take type of variable from original file
val varDeclaration = expression.getParent() as? JetVariableDeclaration
if (varDeclaration != null && expression == varDeclaration.getInitializer() && varDeclaration.getTypeRef() == null) {
val offset = varDeclaration.getTextRange()!!.getStartOffset()
val originalDeclaration = PsiTreeUtil.findElementOfClassAtOffset(originalFile, offset, javaClass<JetVariableDeclaration>(), true)
if (originalDeclaration != null) {
val variableDescriptor = originalDeclaration.getLazyResolveSession().resolveToDescriptor(originalDeclaration) as? VariableDescriptor
if (variableDescriptor != null) {
return listOf(ExpectedInfo(variableDescriptor.getType(), null))
}
}
}
return ExpectedInfos(bindingContext, moduleDescriptor).calculate(expression)
}
private fun calcItemsToSkip(expression: JetExpression): Set<DeclarationDescriptor> {
val parent = expression.getParent()
when(parent) {
@@ -0,0 +1,6 @@
fun foo(p1: String, p2: Int) {
val v = <caret>"a"
}
// EXIST: p1
// ABSENT: p2
@@ -0,0 +1,6 @@
class A(s: String) {
val v = s.<caret>length()
}
// EXIST: size
// ABSENT: substring
@@ -231,6 +231,16 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest("idea/testData/completion/smart/IfValueInBlock2.kt");
}
@TestMetadata("ImplicitlyTypedValInitializer1.kt")
public void testImplicitlyTypedValInitializer1() throws Exception {
doTest("idea/testData/completion/smart/ImplicitlyTypedValInitializer1.kt");
}
@TestMetadata("ImplicitlyTypedValInitializer2.kt")
public void testImplicitlyTypedValInitializer2() throws Exception {
doTest("idea/testData/completion/smart/ImplicitlyTypedValInitializer2.kt");
}
@TestMetadata("InElvisOperator1.kt")
public void testInElvisOperator1() throws Exception {
doTest("idea/testData/completion/smart/InElvisOperator1.kt");