Create warning for old lambda syntax.

This commit is contained in:
Stanislav Erokhin
2015-03-17 14:20:55 +03:00
parent c24c3daf54
commit 47e8b1e77c
9 changed files with 95 additions and 4 deletions
@@ -346,6 +346,9 @@ public interface Errors {
DiagnosticFactory0<JetParameter> USELESS_VARARG_ON_PARAMETER = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<JetFunctionLiteralExpression> DEPRECATED_LAMBDA_SYNTAX =
DiagnosticFactory0.create(WARNING, FUNCTION_LITERAL_EXPRESSION_DECLARATION);
// Named parameters
DiagnosticFactory0<JetParameter> DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE);
@@ -34,7 +34,7 @@ public object PositioningStrategies {
if (element is JetNamedDeclaration &&
element !is JetObjectDeclaration &&
element !is JetSecondaryConstructor &&
element !is JetNamedFunction
element !is JetFunction
) {
if (element.getNameIdentifier() == null) {
return false
@@ -115,14 +115,20 @@ public object PositioningStrategies {
public val DECLARATION_SIGNATURE: PositioningStrategy<JetDeclaration> = object : DeclarationHeader<JetDeclaration>() {
override fun mark(element: JetDeclaration): List<TextRange> {
when (element) {
is JetNamedFunction -> {
is JetFunction -> {
val endOfSignatureElement =
element.getTypeReference()
?: element.getValueParameterList()
?: element.getNameIdentifier()
?: element
return markRange(element, endOfSignatureElement)
val startElement
= if (element is JetFunctionLiteral) {
element.getReceiverTypeReference()
?: element.getValueParameterList()
?: element
}
else element
return markRange(startElement, endOfSignatureElement)
}
is JetProperty -> {
val endOfSignatureElement = element.getTypeReference() ?: element.getNameIdentifier() ?: element
@@ -168,6 +174,12 @@ public object PositioningStrategies {
}
}
public val FUNCTION_LITERAL_EXPRESSION_DECLARATION: PositioningStrategy<JetFunctionLiteralExpression>
= object : PositioningStrategy<JetFunctionLiteralExpression>() {
override fun mark(element: JetFunctionLiteralExpression) = DECLARATION_SIGNATURE_OR_DEFAULT.mark(element.getFunctionLiteral())
override fun isValid(element: JetFunctionLiteralExpression) = DECLARATION_SIGNATURE_OR_DEFAULT.isValid(element.getFunctionLiteral())
}
public val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<JetDeclaration> = object : PositioningStrategy<JetDeclaration>() {
override fun mark(element: JetDeclaration): List<TextRange> {
if (element is JetTypeParameterListOwner) {
@@ -230,6 +230,8 @@ public class DefaultErrorMessages {
MAP.put(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE, "A function expression is not allowed to specify default values for its parameters");
MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless");
MAP.put(DEPRECATED_LAMBDA_SYNTAX,
"This syntax for lambda is deprecated. Use short lambda notation {a[: Int], b[: String] -> ...} or function expression instead.");
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
@@ -17,7 +17,9 @@
package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
@@ -41,4 +43,14 @@ public class JetParameterList extends JetElementImplStub<KotlinPlaceHolderStub<J
public List<JetParameter> getParameters() {
return getStubOrPsiChildrenAsList(JetStubElementTypes.VALUE_PARAMETER);
}
// this method needed only for migrate lambda syntax
@Deprecated
public boolean isParenthesized() {
PsiElement firstChild = getFirstChild();
if (firstChild != null && firstChild.getNode() != null) {
return firstChild.getNode().getElementType() == JetTokens.LPAR;
}
return false;
}
}
@@ -911,4 +911,14 @@ public class JetPsiUtil {
}
return null;
}
public static boolean isDeprecatedLambdaSyntax(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
JetFunctionLiteral functionLiteral = functionLiteralExpression.getFunctionLiteral();
if (functionLiteral.hasDeclaredReturnType() || functionLiteral.getReceiverTypeReference() != null) return true;
JetParameterList valueParameterList = functionLiteral.getValueParameterList();
if (valueParameterList != null && valueParameterList.isParenthesized()) return true;
return false;
}
}
@@ -124,6 +124,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express
override fun visitFunctionLiteralExpression(expression: JetFunctionLiteralExpression, context: ExpressionTypingContext): JetTypeInfo? {
if (!expression.getFunctionLiteral().hasBody()) return null
if (JetPsiUtil.isDeprecatedLambdaSyntax(expression)) {
context.trace.report(DEPRECATED_LAMBDA_SYNTAX.on(expression))
}
val expectedType = context.expectedType
val functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType)
@@ -0,0 +1,24 @@
val receiver = { <!DEPRECATED_LAMBDA_SYNTAX!>Int.()<!> -> }
val receiverWithParameter = { <!DEPRECATED_LAMBDA_SYNTAX!>Int.(<!CANNOT_INFER_PARAMETER_TYPE!>a<!>)<!> -> }
val receiverAndReturnType = { <!DEPRECATED_LAMBDA_SYNTAX!>Int.(): Int<!> -> 5 }
val receiverAndReturnTypeWithParameter = { <!DEPRECATED_LAMBDA_SYNTAX!>Int.(a: Int): Int<!> -> 5 }
val returnType = { <!DEPRECATED_LAMBDA_SYNTAX!>(): Int<!> -> 5 }
val returnTypeWithParameter = { <!DEPRECATED_LAMBDA_SYNTAX!>(b: Int): Int<!> -> 5 }
val receiverWithFunctionType = { <!DEPRECATED_LAMBDA_SYNTAX!>((Int) -> Int).()<!> -> }
val parenthesizedParameters = { <!DEPRECATED_LAMBDA_SYNTAX!>(a: Int)<!> -> }
val parenthesizedParameters2 = { <!DEPRECATED_LAMBDA_SYNTAX!>(<!CANNOT_INFER_PARAMETER_TYPE!>b<!>)<!> -> }
val none = { -> }
val parameterWithFunctionType = { <!UNRESOLVED_REFERENCE!>a<!>: ((Int) -> Int) -> <!SYNTAX!><!>} // todo fix parser
val newSyntax = { a: Int -> }
val newSyntax1 = { <!CANNOT_INFER_PARAMETER_TYPE!>a<!>, <!CANNOT_INFER_PARAMETER_TYPE!>b<!> -> }
val newSyntax2 = { a: Int, b: Int -> }
val newSyntax3 = { <!CANNOT_INFER_PARAMETER_TYPE!>a<!>, b: Int -> }
val newSyntax4 = { a: Int, <!CANNOT_INFER_PARAMETER_TYPE!>b<!> -> }
@@ -0,0 +1,18 @@
package
internal val newSyntax: (kotlin.Int) -> kotlin.Unit
internal val newSyntax1: (???, ???) -> kotlin.Unit
internal val newSyntax2: (kotlin.Int, kotlin.Int) -> kotlin.Unit
internal val newSyntax3: (???, kotlin.Int) -> kotlin.Unit
internal val newSyntax4: (kotlin.Int, ???) -> kotlin.Unit
internal val none: () -> kotlin.Unit
internal val parameterWithFunctionType: () -> ((kotlin.Int) -> kotlin.Int) -> [ERROR : No type element]
internal val parenthesizedParameters: (kotlin.Int) -> kotlin.Unit
internal val parenthesizedParameters2: (???) -> kotlin.Unit
internal val receiver: kotlin.Int.() -> kotlin.Unit
internal val receiverAndReturnType: kotlin.Int.() -> kotlin.Int
internal val receiverAndReturnTypeWithParameter: kotlin.Int.(kotlin.Int) -> kotlin.Int
internal val receiverWithFunctionType: (kotlin.Int) -> kotlin.Int.() -> kotlin.Unit
internal val receiverWithParameter: kotlin.Int.(???) -> kotlin.Unit
internal val returnType: () -> kotlin.Int
internal val returnTypeWithParameter: (kotlin.Int) -> kotlin.Int
@@ -4754,6 +4754,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("DeprecatedSyntax.kt")
public void testDeprecatedSyntax() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt");
doTest(fileName);
}
@TestMetadata("ExpectedParameterTypeMismatchVariance.kt")
public void testExpectedParameterTypeMismatchVariance() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/ExpectedParameterTypeMismatchVariance.kt");