Add SingleUnderscoreForParameterName language feature

This commit is contained in:
Denis Zharkov
2016-10-24 11:40:01 +03:00
parent 1f0293eb42
commit 09dc207052
8 changed files with 81 additions and 12 deletions
@@ -206,7 +206,7 @@ public class ModifiersChecker {
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) { for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
annotationChecker.check(multiEntry, trace, null); annotationChecker.check(multiEntry, trace, null);
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageVersionSettings); ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageVersionSettings);
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace, /* allowSingleUnderscore = */ true); UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace, languageVersionSettings, /* allowSingleUnderscore = */ true);
} }
} }
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.resolve.checkers package org.jetbrains.kotlin.resolve.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor
@@ -25,39 +27,57 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
object UnderscoreChecker : SimpleDeclarationChecker { object UnderscoreChecker : DeclarationChecker {
@JvmOverloads @JvmOverloads
fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) { fun checkIdentifier(
identifier: PsiElement?,
diagnosticHolder: DiagnosticSink,
languageVersionSettings: LanguageVersionSettings,
allowSingleUnderscore: Boolean = false
) {
if (identifier == null || identifier.text.isEmpty()) return if (identifier == null || identifier.text.isEmpty()) return
if (identifier.text.all { it == '_' } && (!allowSingleUnderscore || identifier.text.length != 1)) { val isValidSingleUnderscore = allowSingleUnderscore && identifier.text == "_"
if (!isValidSingleUnderscore && identifier.text.all { it == '_' }) {
diagnosticHolder.report(Errors.UNDERSCORE_IS_RESERVED.on(identifier)) diagnosticHolder.report(Errors.UNDERSCORE_IS_RESERVED.on(identifier))
} }
else if (isValidSingleUnderscore && !languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName)) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(identifier, LanguageFeature.SingleUnderscoreForParameterName))
}
} }
@JvmOverloads @JvmOverloads
fun checkNamed(declaration: KtNamedDeclaration, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) { fun checkNamed(
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, allowSingleUnderscore) declaration: KtNamedDeclaration,
diagnosticHolder: DiagnosticSink,
languageVersionSettings: LanguageVersionSettings,
allowSingleUnderscore: Boolean = false
) {
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, languageVersionSettings, allowSingleUnderscore)
} }
override fun check( override fun check(
declaration: KtDeclaration, declaration: KtDeclaration,
descriptor: DeclarationDescriptor, descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink, diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings
) { ) {
if (declaration is KtProperty && descriptor !is VariableDescriptor) return if (declaration is KtProperty && descriptor !is VariableDescriptor) return
if (declaration is KtCallableDeclaration) { if (declaration is KtCallableDeclaration) {
for (parameter in declaration.valueParameters) { for (parameter in declaration.valueParameters) {
checkNamed(parameter, diagnosticHolder, allowSingleUnderscore = descriptor is FunctionExpressionDescriptor) checkNamed(
parameter, diagnosticHolder, languageVersionSettings,
allowSingleUnderscore = descriptor is FunctionExpressionDescriptor
)
} }
} }
if (declaration is KtTypeParameterListOwner) { if (declaration is KtTypeParameterListOwner) {
for (typeParameter in declaration.typeParameters) { for (typeParameter in declaration.typeParameters) {
checkNamed(typeParameter, diagnosticHolder) checkNamed(typeParameter, diagnosticHolder, languageVersionSettings)
} }
} }
if (declaration !is KtNamedDeclaration) return if (declaration !is KtNamedDeclaration) return
checkNamed(declaration, diagnosticHolder) checkNamed(declaration, diagnosticHolder, languageVersionSettings)
} }
} }
@@ -870,7 +870,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
KtSimpleNameExpression labelExpression = expression.getTargetLabel(); KtSimpleNameExpression labelExpression = expression.getTargetLabel();
if (labelExpression != null) { if (labelExpression != null) {
PsiElement labelIdentifier = labelExpression.getIdentifier(); PsiElement labelIdentifier = labelExpression.getIdentifier();
UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace); UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace, components.languageVersionSettings);
} }
KtExpression baseExpression = expression.getBaseExpression(); KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return TypeInfoFactoryKt.noTypeInfo(context); if (baseExpression == null) return TypeInfoFactoryKt.noTypeInfo(context);
@@ -146,7 +146,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val functionDescriptor = createFunctionLiteralDescriptor(expression, context) val functionDescriptor = createFunctionLiteralDescriptor(expression, context)
expression.valueParameters.forEach { expression.valueParameters.forEach {
components.identifierChecker.checkDeclaration(it, context.trace) components.identifierChecker.checkDeclaration(it, context.trace)
UnderscoreChecker.checkNamed(it, context.trace, allowSingleUnderscore = true) UnderscoreChecker.checkNamed(it, context.trace, components.languageVersionSettings, allowSingleUnderscore = true)
} }
val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected) val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected)
functionDescriptor.setReturnType(safeReturnType) functionDescriptor.setReturnType(safeReturnType)
@@ -0,0 +1,27 @@
// !LANGUAGE: -SingleUnderscoreForParameterName
data class A(val x: Int, val y: Int)
fun foo(a: Array<A>) {
val (<!UNSUPPORTED_FEATURE!>_<!>, y) = A(1, 2)
y.hashCode()
val q1: (Int, String) -> Unit = {
<!UNSUPPORTED_FEATURE!>_<!>, s -> s.hashCode()
}
q1(1, "")
val q2: (Int, String) -> Unit = fun(<!UNSUPPORTED_FEATURE!>_<!>: Int, s: String) {
s.hashCode()
}
q2(1, "")
val q3: (A) -> Unit = {
(<!UNSUPPORTED_FEATURE!>_<!>, y) -> y.hashCode()
}
q3(A(2, 3))
for ((<!UNSUPPORTED_FEATURE!>_<!>, z) in a) {
z.hashCode()
}
}
@@ -0,0 +1,15 @@
package
public fun foo(/*0*/ a: kotlin.Array<A>): kotlin.Unit
public final data class A {
public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int)
public final val x: kotlin.Int
public final val y: kotlin.Int
public final operator /*synthesized*/ fun component1(): kotlin.Int
public final operator /*synthesized*/ fun component2(): kotlin.Int
public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int = ...): A
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
@@ -655,6 +655,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("SingleUnderscoreUnsupported.kt")
public void testSingleUnderscoreUnsupported() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt");
doTest(fileName);
}
@TestMetadata("StarsInFunctionCalls.kt") @TestMetadata("StarsInFunctionCalls.kt")
public void testStarsInFunctionCalls() throws Exception { public void testStarsInFunctionCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/StarsInFunctionCalls.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/StarsInFunctionCalls.kt");
@@ -29,6 +29,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) {
DataClassInheritance(KOTLIN_1_1), DataClassInheritance(KOTLIN_1_1),
InlineProperties(KOTLIN_1_1), InlineProperties(KOTLIN_1_1),
DestructuringLambdaParameters(KOTLIN_1_1), DestructuringLambdaParameters(KOTLIN_1_1),
SingleUnderscoreForParameterName(KOTLIN_1_1)
; ;
val presentableText: String val presentableText: String