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()) {
annotationChecker.check(multiEntry, trace, null);
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
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.VariableDescriptor
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.resolve.BindingContext
object UnderscoreChecker : SimpleDeclarationChecker {
object UnderscoreChecker : DeclarationChecker {
@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.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))
}
else if (isValidSingleUnderscore && !languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName)) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(identifier, LanguageFeature.SingleUnderscoreForParameterName))
}
}
@JvmOverloads
fun checkNamed(declaration: KtNamedDeclaration, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) {
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, allowSingleUnderscore)
fun checkNamed(
declaration: KtNamedDeclaration,
diagnosticHolder: DiagnosticSink,
languageVersionSettings: LanguageVersionSettings,
allowSingleUnderscore: Boolean = false
) {
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, languageVersionSettings, allowSingleUnderscore)
}
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings
) {
if (declaration is KtProperty && descriptor !is VariableDescriptor) return
if (declaration is KtCallableDeclaration) {
for (parameter in declaration.valueParameters) {
checkNamed(parameter, diagnosticHolder, allowSingleUnderscore = descriptor is FunctionExpressionDescriptor)
checkNamed(
parameter, diagnosticHolder, languageVersionSettings,
allowSingleUnderscore = descriptor is FunctionExpressionDescriptor
)
}
}
if (declaration is KtTypeParameterListOwner) {
for (typeParameter in declaration.typeParameters) {
checkNamed(typeParameter, diagnosticHolder)
checkNamed(typeParameter, diagnosticHolder, languageVersionSettings)
}
}
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();
if (labelExpression != null) {
PsiElement labelIdentifier = labelExpression.getIdentifier();
UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace);
UnderscoreChecker.INSTANCE.checkIdentifier(labelIdentifier, context.trace, components.languageVersionSettings);
}
KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) return TypeInfoFactoryKt.noTypeInfo(context);
@@ -146,7 +146,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
val functionDescriptor = createFunctionLiteralDescriptor(expression, context)
expression.valueParameters.forEach {
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)
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);
}
@TestMetadata("SingleUnderscoreUnsupported.kt")
public void testSingleUnderscoreUnsupported() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/SingleUnderscoreUnsupported.kt");
doTest(fileName);
}
@TestMetadata("StarsInFunctionCalls.kt")
public void testStarsInFunctionCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/StarsInFunctionCalls.kt");
@@ -29,6 +29,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) {
DataClassInheritance(KOTLIN_1_1),
InlineProperties(KOTLIN_1_1),
DestructuringLambdaParameters(KOTLIN_1_1),
SingleUnderscoreForParameterName(KOTLIN_1_1)
;
val presentableText: String