[NI] Don't forget to analyze whole block for last postponed expression

This commit is contained in:
Mikhail Zarechenskiy
2017-12-18 04:43:04 +03:00
parent 8ed8e05a68
commit d818af5287
10 changed files with 108 additions and 40 deletions
@@ -106,10 +106,11 @@ class LambdaKotlinCallArgumentImpl(
dataFlowInfoBeforeThisArgument: DataFlowInfo,
argumentName: Name?,
val ktLambdaExpression: KtLambdaExpression,
val containingBlockForLambda: KtExpression,
override val parametersTypes: Array<UnwrappedType?>?
) : PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
override val ktFunction get() = ktLambdaExpression.functionLiteral
override val expression get() = ktLambdaExpression
override val expression get() = containingBlockForLambda
}
class FunctionExpressionImpl(
@@ -117,12 +118,13 @@ class FunctionExpressionImpl(
valueArgument: ValueArgument,
dataFlowInfoBeforeThisArgument: DataFlowInfo,
argumentName: Name?,
val containingBlockForFunction: KtExpression,
override val ktFunction: KtNamedFunction,
override val receiverType: UnwrappedType?,
override val parametersTypes: Array<UnwrappedType?>,
override val returnType: UnwrappedType?
) : FunctionExpression, PSIFunctionKotlinCallArgument(outerCallContext, valueArgument, dataFlowInfoBeforeThisArgument, argumentName) {
override val expression get() = ktFunction
override val expression get() = containingBlockForFunction
}
class CallableReferenceKotlinCallArgumentImpl(
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.EffectSystem
@@ -521,27 +522,14 @@ class PSICallResolver(
): PSIKotlinCallArgument {
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
val ktExpression = extractArgumentExpression(outerCallContext, valueArgument) ?: parseErrorArgument
val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument
val ktExpression = KtPsiUtil.deparenthesize(argumentExpression) ?: parseErrorArgument
val argumentName = valueArgument.getArgumentName()?.asName
val lambdaArgument: PSIKotlinCallArgument? = when (ktExpression) {
is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression,
resolveParametersTypes(outerCallContext, ktExpression.functionLiteral))
is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, ktExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, ktExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, ktExpression.typeReference) ?:
if (ktExpression.hasBlockBody()) builtIns.unitType else null
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, ktExpression, receiverType, parametersTypes, returnType)
}
else -> null
}
if (lambdaArgument != null) {
checkNoSpread(outerCallContext, valueArgument)
return lambdaArgument
processFunctionalExpression(outerCallContext, argumentExpression, startDataFlowInfo, valueArgument, argumentName, builtIns)?.let {
return it
}
if (ktExpression is KtCollectionLiteralExpression) {
@@ -596,24 +584,43 @@ class PSICallResolver(
ktExpression, argumentName, lhsNewResult, name)
}
val argumentExpression = valueArgument.getArgumentExpression() ?: return parseErrorArgument
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
val typeInfo = expressionTypingServices.getTypeInfo(argumentExpression, context)
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: parseErrorArgument
}
private fun extractArgumentExpression(outerCallContext: BasicCallResolutionContext, valueArgument: ValueArgument): KtExpression? {
val argumentExpression = valueArgument.getArgumentExpression() ?: return null
private fun processFunctionalExpression(
outerCallContext: BasicCallResolutionContext,
argumentExpression: KtExpression,
startDataFlowInfo: DataFlowInfo,
valueArgument: ValueArgument,
argumentName: Name?,
builtIns: KotlinBuiltIns
): PSIKotlinCallArgument? {
val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null
val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType<KtLambdaExpression>(true) else expression
val ktExpression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?:
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, outerCallContext) ?:
KtPsiUtil.deparenthesize(argumentExpression)
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral))
return when (ktExpression) {
is KtFunctionLiteral -> ktExpression.getParentOfType<KtLambdaExpression>(true)
else -> ktExpression
is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?:
if (postponedExpression.hasBlockBody()) builtIns.unitType else null
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName,
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType)
}
else -> return null
}
checkNoSpread(outerCallContext, valueArgument)
return lambdaArgument
}
private fun checkNoSpread(context: BasicCallResolutionContext, valueArgument: ValueArgument) {
@@ -629,6 +636,4 @@ class PSICallResolver(
parameterList.parameters[it]?.typeReference?.let { resolveType(context, it) }
}
}
}
}
@@ -0,0 +1,17 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// !CHECK_TYPE
import kotlin.reflect.KFunction0
fun test() {
val a = if (true) {
val x = 1
"".length
::foo
} else {
::foo
}
a checkType { _<KFunction0<Int>>() }
}
fun foo(): Int = 0
@@ -0,0 +1,4 @@
package
public fun foo(): kotlin.Int
public fun test(): kotlin.Unit
@@ -0,0 +1,15 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION
import java.util.HashSet
fun test123() {
val g: (Int) -> Unit = if (true) {
val set = HashSet<Int>()
fun (i: Int) {
set.add(i)
}
}
else {
{ it -> it }
}
}
@@ -0,0 +1,3 @@
package
public fun test123(): kotlin.Unit
@@ -1,11 +1,10 @@
// !WITH_NEW_INFERENCE
// !CHECK_TYPE
fun test() {
val a = if (true) {
val x = 1
({ <!NI;UNRESOLVED_REFERENCE!>x<!> })
({ x })
} else {
{ <!NI;UNUSED_EXPRESSION!>2<!> }
{ 2 }
}
<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!> <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>checkType<!> { <!NI;UNRESOLVED_REFERENCE!>_<!><() -> Int>() }
a checkType { _<() -> Int>() }
}
@@ -1,13 +1,12 @@
// !WITH_NEW_INFERENCE
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_EXPRESSION
import java.util.HashSet
fun test123() {
val g: (Int) -> Unit = if (true) {
val set = <!NI;DEBUG_INFO_MISSING_UNRESOLVED!>HashSet<!><<!NI;DEBUG_INFO_MISSING_UNRESOLVED!>Int<!>>();
val set = HashSet<Int>();
{ i ->
<!NI;UNRESOLVED_REFERENCE!>set<!>.<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>add<!>(i)
set.add(i)
}
}
else {
@@ -1858,6 +1858,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("callableReferenceAsLastExpressionInBlock.kt")
public void testCallableReferenceAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("classVsPackage.kt")
public void testClassVsPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/classVsPackage.kt");
@@ -8422,6 +8428,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("functionExpressionAsLastExpressionInBlock.kt")
public void testFunctionExpressionAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("functionLIteralInBlockInIf.kt")
public void testFunctionLIteralInBlockInIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt");
@@ -1858,6 +1858,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
doTest(fileName);
}
@TestMetadata("callableReferenceAsLastExpressionInBlock.kt")
public void testCallableReferenceAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/callableReferenceAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("classVsPackage.kt")
public void testClassVsPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/classVsPackage.kt");
@@ -8422,6 +8428,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
doTest(fileName);
}
@TestMetadata("functionExpressionAsLastExpressionInBlock.kt")
public void testFunctionExpressionAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionExpressionAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("functionLIteralInBlockInIf.kt")
public void testFunctionLIteralInBlockInIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/functionLIteralInBlockInIf.kt");