Smart completion: auto-cast to non-null type is not recognized for field from constructor
#KT-4906 Fixed
This commit is contained in:
@@ -34,6 +34,7 @@ import com.google.common.collect.SetMultimap
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability
|
||||
import java.util.HashSet
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver
|
||||
|
||||
class TypesWithAutoCasts(val bindingContext: BindingContext) {
|
||||
public fun calculate(expression: JetExpression, receiver: JetExpression?): (DeclarationDescriptor) -> Iterable<JetType> {
|
||||
@@ -77,43 +78,43 @@ class TypesWithAutoCasts(val bindingContext: BindingContext) {
|
||||
)
|
||||
|
||||
private fun processDataFlowInfo(dataFlowInfo: DataFlowInfo?, receiver: JetExpression?): ProcessDataFlowInfoResult {
|
||||
if (dataFlowInfo != null) {
|
||||
val dataFlowValueToVariable: (DataFlowValue) -> VariableDescriptor?
|
||||
if (receiver != null) {
|
||||
val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver]
|
||||
if (receiverType != null) {
|
||||
val receiverId = DataFlowValueFactory.createDataFlowValue(receiver, receiverType, bindingContext).getId()
|
||||
dataFlowValueToVariable = {(value) ->
|
||||
val id = value.getId()
|
||||
if (id is com.intellij.openapi.util.Pair<*, *> && id.first == receiverId) id.second as? VariableDescriptor else null
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ProcessDataFlowInfoResult()
|
||||
if (dataFlowInfo == null) return ProcessDataFlowInfoResult()
|
||||
|
||||
val dataFlowValueToVariable: (DataFlowValue) -> VariableDescriptor?
|
||||
if (receiver != null) {
|
||||
val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] ?: return ProcessDataFlowInfoResult()
|
||||
val receiverId = DataFlowValueFactory.createDataFlowValue(receiver, receiverType, bindingContext).getId()
|
||||
dataFlowValueToVariable = {(value) ->
|
||||
val id = value.getId()
|
||||
if (id is com.intellij.openapi.util.Pair<*, *> && id.first == receiverId) id.second as? VariableDescriptor else null
|
||||
}
|
||||
}
|
||||
else {
|
||||
dataFlowValueToVariable = {(value) ->
|
||||
val id = value.getId()
|
||||
when {
|
||||
id is VariableDescriptor -> id
|
||||
id is com.intellij.openapi.util.Pair<*, *> && id.first is ThisReceiver -> id.second as? VariableDescriptor
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else {
|
||||
dataFlowValueToVariable = {(value) -> value.getId() as? VariableDescriptor }
|
||||
}
|
||||
|
||||
val variableToType = HashMap<VariableDescriptor, Collection<JetType>>()
|
||||
val typeInfo: SetMultimap<DataFlowValue, JetType> = dataFlowInfo.getCompleteTypeInfo()
|
||||
for ((dataFlowValue, types) in typeInfo.asMap().entrySet()) {
|
||||
val variable = dataFlowValueToVariable.invoke(dataFlowValue)
|
||||
if (variable != null) {
|
||||
variableToType[variable] = types
|
||||
}
|
||||
}
|
||||
|
||||
val nullabilityInfo: Map<DataFlowValue, Nullability> = dataFlowInfo.getCompleteNullabilityInfo()
|
||||
val notNullVariables = nullabilityInfo
|
||||
.filter { it.getValue() == Nullability.NOT_NULL }
|
||||
.map { dataFlowValueToVariable(it.getKey()) }
|
||||
.filterNotNullTo(HashSet<VariableDescriptor>())
|
||||
|
||||
return ProcessDataFlowInfoResult(variableToType, notNullVariables)
|
||||
}
|
||||
|
||||
return ProcessDataFlowInfoResult()
|
||||
val variableToType = HashMap<VariableDescriptor, Collection<JetType>>()
|
||||
val typeInfo: SetMultimap<DataFlowValue, JetType> = dataFlowInfo.getCompleteTypeInfo()
|
||||
for ((dataFlowValue, types) in typeInfo.asMap().entrySet()) {
|
||||
val variable = dataFlowValueToVariable.invoke(dataFlowValue)
|
||||
if (variable != null) {
|
||||
variableToType[variable] = types
|
||||
}
|
||||
}
|
||||
|
||||
val nullabilityInfo: Map<DataFlowValue, Nullability> = dataFlowInfo.getCompleteNullabilityInfo()
|
||||
val notNullVariables = nullabilityInfo
|
||||
.filter { it.getValue() == Nullability.NOT_NULL }
|
||||
.map { dataFlowValueToVariable(it.getKey()) }
|
||||
.filterNotNullTo(HashSet<VariableDescriptor>())
|
||||
|
||||
return ProcessDataFlowInfoResult(variableToType, notNullVariables)
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,4 @@ open class Foo{
|
||||
class Bar : Foo
|
||||
|
||||
|
||||
// EXIST: this
|
||||
// EXIST: { itemText:"this" }
|
||||
|
||||
@@ -4,4 +4,4 @@ fun f(p: Any) {
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: p
|
||||
// EXIST: { itemText:"p" }
|
||||
|
||||
@@ -6,5 +6,5 @@ class Foo(val prop1 : Any, val prop2 : Any){
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: prop1
|
||||
// ABSENT: prop2
|
||||
// EXIST: { itemText:"prop1" }
|
||||
// ABSENT: { itemText:"prop2" }
|
||||
|
||||
@@ -5,4 +5,4 @@ fun String?.foo(){
|
||||
}
|
||||
|
||||
|
||||
// EXIST: this
|
||||
// EXIST: { itemText:"this" }
|
||||
|
||||
@@ -4,4 +4,4 @@ fun f(p: String?) {
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: p
|
||||
// EXIST: { itemText:"p" }
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo(val prop : String?){
|
||||
fun f(foo: Foo) {
|
||||
if (foo.prop != null){
|
||||
var a: String = <caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ABSENT: { itemText:"prop" }
|
||||
@@ -0,0 +1,11 @@
|
||||
class Foo(val s: String?) {
|
||||
fun bar(){
|
||||
if (s != null) {
|
||||
foo(<caret>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun foo(s: String){}
|
||||
|
||||
// EXIST: { itemText:"s" }
|
||||
@@ -6,7 +6,7 @@ class Foo(val prop1 : String?, val prop2 : String?){
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: prop1
|
||||
// ABSENT: { lookupString:"prop2", itemText:"prop2" }
|
||||
// EXIST: { lookupString:"prop2", itemText:"!! prop2" }
|
||||
// EXIST: { lookupString:"prop2", itemText:"?: prop2" }
|
||||
// EXIST: { itemText:"prop1" }
|
||||
// ABSENT: { itemText:"prop2" }
|
||||
// EXIST: { itemText:"!! prop2" }
|
||||
// EXIST: { itemText:"?: prop2" }
|
||||
|
||||
@@ -71,6 +71,16 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest("idea/testData/completion/smart/AutoNotNullType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("AutoNotNullType2.kt")
|
||||
public void testAutoNotNullType2() throws Exception {
|
||||
doTest("idea/testData/completion/smart/AutoNotNullType2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("AutoNotNullTypeForConstructorParameter.kt")
|
||||
public void testAutoNotNullTypeForConstructorParameter() throws Exception {
|
||||
doTest("idea/testData/completion/smart/AutoNotNullTypeForConstructorParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("AutoNotNullTypeWithQualifier.kt")
|
||||
public void testAutoNotNullTypeWithQualifier() throws Exception {
|
||||
doTest("idea/testData/completion/smart/AutoNotNullTypeWithQualifier.kt");
|
||||
|
||||
Reference in New Issue
Block a user