From caae6ff2ec488a8e4c8d70797e83809c776aa1c5 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 28 Mar 2017 17:15:23 +0300 Subject: [PATCH] KT-16264 Forbid usage of _ without backticks Forbid underscore-only (_, __, ___, ...) names as callees and as types. If CHECK_TYPE directive is on, filter out UNDERSCORE_USAGE_WITHOUT_BACKTICKS messages. --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../resolve/QualifiedExpressionResolver.kt | 4 +- .../kotlin/resolve/TargetPlatform.kt | 3 +- .../calls/checkers/UnderscoreUsageChecker.kt | 63 +++++++++++++++++++ .../codegen/box/multiDecl/UnderscoreNames.kt | 2 +- .../box/multiDecl/forRange/UnderscoreNames.kt | 2 +- compiler/testData/diagnostics/ReadMe.md | 2 + .../testData/diagnostics/tests/Underscore.kt | 14 ++--- .../tests/UnderscoreUsageInAnnotation.kt | 6 ++ .../tests/UnderscoreUsageInAnnotation.txt | 26 ++++++++ .../tests/UnderscoreUsageInCall.kt | 42 +++++++++++++ .../tests/UnderscoreUsageInCall.txt | 41 ++++++++++++ .../UnderscoreUsageInCallableRefTypeLHS.kt | 11 ++++ .../UnderscoreUsageInCallableRefTypeLHS.txt | 21 +++++++ .../tests/UnderscoreUsageInType.kt | 12 ++++ .../tests/UnderscoreUsageInType.txt | 15 +++++ ...UnderscoreUsageInVariableAsFunctionCall.kt | 6 ++ ...nderscoreUsageInVariableAsFunctionCall.txt | 10 +++ .../destructuringDeclarations/underscore.kt | 4 +- .../kotlin/checkers/BaseDiagnosticsTest.kt | 20 ++++-- .../checkers/DiagnosticsTestGenerated.java | 30 +++++++++ 22 files changed, 317 insertions(+), 19 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/UnderscoreUsageChecker.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.txt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInCall.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInCall.txt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.txt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInType.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInType.txt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.kt create mode 100644 compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 5a635ad616e..e68f6baf0a5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -706,6 +706,7 @@ public interface Errors { DiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 YIELD_IS_RESERVED = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 UNDERSCORE_IS_RESERVED = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 UNDERSCORE_USAGE_WITHOUT_BACKTICKS = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 INVALID_CHARACTERS = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 INAPPLICABLE_OPERATOR_MODIFIER = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index f904adbcc36..438ba692bc4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -465,6 +465,7 @@ public class DefaultErrorMessages { MAP.put(COMPARE_TO_TYPE_MISMATCH, "''compareTo()'' must return Int, but returns {0}", RENDER_TYPE); MAP.put(UNDERSCORE_IS_RESERVED, "Names _, __, ___, ..., are reserved in Kotlin"); + MAP.put(UNDERSCORE_USAGE_WITHOUT_BACKTICKS, "Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"); MAP.put(YIELD_IS_RESERVED, "{0}", STRING); MAP.put(INVALID_CHARACTERS, "Name {0}", STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index d6ba031898e..e247ca1dbd4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector import org.jetbrains.kotlin.resolve.calls.CallExpressionElement +import org.jetbrains.kotlin.resolve.calls.checkers.UnderscoreUsageChecker import org.jetbrains.kotlin.resolve.calls.unrollToLeftMostQualifiedExpression import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.ImportingScope @@ -143,7 +144,6 @@ class QualifiedExpressionResolver { val (name, simpleName) = qualifierPartList.single() val descriptor = scope.findClassifier(name, KotlinLookupLocation(simpleName)) storeResult(trace, simpleName, descriptor, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = true) - return TypeQualifierResolutionResult(qualifierPartList, descriptor) } @@ -597,6 +597,8 @@ class QualifiedExpressionResolver { trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor) + UnderscoreUsageChecker.checkSimpleNameUsage(descriptor, referenceExpression, trace) + if (descriptor is DeclarationDescriptorWithVisibility) { val fromToCheck = if (shouldBeVisibleFrom is PackageFragmentDescriptor && shouldBeVisibleFrom.source == SourceElement.NO_SOURCE && referenceExpression.containingFile !is DummyHolder) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 9c11fc7f11a..6e91a8d7a61 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -95,7 +95,8 @@ private val DEFAULT_CALL_CHECKERS = listOf( DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(), ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker, CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker, - CallableReferenceCompatibilityChecker() + CallableReferenceCompatibilityChecker(), + UnderscoreUsageChecker ) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/UnderscoreUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/UnderscoreUsageChecker.kt new file mode 100644 index 00000000000..e29f282c0ec --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/UnderscoreUsageChecker.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtSimpleNameExpression +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall + +object UnderscoreUsageChecker : CallChecker { + override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { + if (resolvedCall is VariableAsFunctionResolvedCall) return + val descriptor = resolvedCall.resultingDescriptor + val namedDescriptor = if (descriptor is ConstructorDescriptor) descriptor.containingDeclaration else descriptor + if (!namedDescriptor.name.asString().isUnderscoreOnlyName()) return + checkCallElement(resolvedCall.call.callElement, context) + } + + private fun checkCallElement(ktElement: KtElement, context: CallCheckerContext) { + when (ktElement) { + is KtSimpleNameExpression -> + checkSimpleNameUsage(ktElement, context.trace) + is KtCallExpression -> + ktElement.calleeExpression?.let { checkCallElement(it, context) } + } + } + + private fun checkSimpleNameUsage(ktName: KtSimpleNameExpression, trace: BindingTrace) { + if (ktName.text.isUnderscoreOnlyName()) { + trace.report(Errors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.on(ktName)) + } + } + + fun checkSimpleNameUsage(descriptor: DeclarationDescriptor, ktName: KtSimpleNameExpression, trace: BindingTrace) { + if (descriptor.name.asString().isUnderscoreOnlyName()) { + checkSimpleNameUsage(ktName, trace) + } + } + + fun String.isUnderscoreOnlyName() = + isNotEmpty() && all { it == '_' } + +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/multiDecl/UnderscoreNames.kt b/compiler/testData/codegen/box/multiDecl/UnderscoreNames.kt index 12dfc941fb6..3d38c505f6a 100644 --- a/compiler/testData/codegen/box/multiDecl/UnderscoreNames.kt +++ b/compiler/testData/codegen/box/multiDecl/UnderscoreNames.kt @@ -10,5 +10,5 @@ fun box() : String { val (`_`, c) = A() - return if (a == 1 && b == 2 && _ == 1 && c == 2) "OK" else "fail" + return if (a == 1 && b == 2 && `_` == 1 && c == 2) "OK" else "fail" } diff --git a/compiler/testData/codegen/box/multiDecl/forRange/UnderscoreNames.kt b/compiler/testData/codegen/box/multiDecl/forRange/UnderscoreNames.kt index ff9d07f1f46..9139c8cd549 100644 --- a/compiler/testData/codegen/box/multiDecl/forRange/UnderscoreNames.kt +++ b/compiler/testData/codegen/box/multiDecl/forRange/UnderscoreNames.kt @@ -31,7 +31,7 @@ fun doTest(): String { } for ((_, `_`) in C(2)..C(4)) { - s += "$_;" + s += "$`_`;" } return s diff --git a/compiler/testData/diagnostics/ReadMe.md b/compiler/testData/diagnostics/ReadMe.md index 8904876a1ce..7ea7569eec1 100644 --- a/compiler/testData/diagnostics/ReadMe.md +++ b/compiler/testData/diagnostics/ReadMe.md @@ -58,6 +58,8 @@ With that, an exact type of an expression can be checked in the following way: expr checkType { _() } } +`CHECK_TYPE` directive also disables `UNDERSCORE_USAGE_WITHOUT_BACKTICKS` diagnostics output. + #### Usage: // !CHECK_TYPE diff --git a/compiler/testData/diagnostics/tests/Underscore.kt b/compiler/testData/diagnostics/tests/Underscore.kt index c105b42c706..7327e54fc7a 100644 --- a/compiler/testData/diagnostics/tests/Underscore.kt +++ b/compiler/testData/diagnostics/tests/Underscore.kt @@ -5,14 +5,14 @@ @___("") data class Pair(val x: Int, val y: Int) class _<________> -val ______ = _() +val ______ = _() -fun __(___: Int, y: _?): Int { - val (_, z) = Pair(___ - 1, 42) - val (x, __________) = Pair(___ - 1, 42) +fun __(___: Int, y: _?): Int { + val (_, z) = Pair(___ - 1, 42) + val (x, __________) = Pair(___ - 1, 42) val ____ = x // in backquotes: allowed - val `_` = __________ + val `_` = __________ val q = fun(_: Int, __: Int) {} q(1, 2) @@ -21,7 +21,7 @@ fun __(___: Int, y: _< fun localFun(_: String) = 1 - __@ return if (y != null) __(____, y) else __(`_`, ______) + __@ return if (y != null) __(____, y) else __(`_`, ______) } @@ -42,5 +42,5 @@ fun oneUnderscore(_: Int) {} fun doIt(f: (Any?) -> Any?) = f(null) -val something = doIt { __ -> __ } +val something = doIt { __ -> __ } val something2 = doIt { _ -> 1 } diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.kt b/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.kt new file mode 100644 index 00000000000..6ecc749c107 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.kt @@ -0,0 +1,6 @@ +package test + +annotation class `__`(val value: String) + +@__("") class TestAnn +@`__`("") class TestAnn2 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.txt b/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.txt new file mode 100644 index 00000000000..beb1e427ad2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.txt @@ -0,0 +1,26 @@ +package + +package test { + + @test.__(value = "") public final class TestAnn { + public constructor TestAnn() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + @test.__(value = "") public final class TestAnn2 { + public constructor TestAnn2() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final annotation class __ : kotlin.Annotation { + public constructor __(/*0*/ value: kotlin.String) + public final val value: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.kt b/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.kt new file mode 100644 index 00000000000..fb91a56dbc7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.kt @@ -0,0 +1,42 @@ +// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY + +fun test(`_`: Int) { + _ + 1 + `_` + 1 +} + +fun `__`() {} + +fun testCall() { + __() + `__`() +} + +val testCallableRef = ::__ +val testCallableRef2 = ::`__` + + +object Host { + val `_` = 42 + object `__` { + val bar = 4 + } +} + +val testQualified = Host._ +val testQualified2 = Host.`_` + +object `___` { + val test = 42 +} + +val testQualifier = ___.test +val testQualifier2 = `___`.test +val testQualifier3 = Host.__.bar +val testQualifier4 = Host.`__`.bar + +fun testCallableRefLHSValue(`_`: Any) = _::toString +fun testCallableRefLHSValue2(`_`: Any) = `_`::toString + +val testCallableRefLHSObject = ___::toString +val testCallableRefLHSObject2 = `___`::toString diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.txt b/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.txt new file mode 100644 index 00000000000..9349498fdad --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInCall.txt @@ -0,0 +1,41 @@ +package + +public val testCallableRef: kotlin.reflect.KFunction0 +public val testCallableRef2: kotlin.reflect.KFunction0 +public val testCallableRefLHSObject: kotlin.reflect.KFunction0 +public val testCallableRefLHSObject2: kotlin.reflect.KFunction0 +public val testQualified: kotlin.Int = 42 +public val testQualified2: kotlin.Int = 42 +public val testQualifier: kotlin.Int = 42 +public val testQualifier2: kotlin.Int = 42 +public val testQualifier3: kotlin.Int = 4 +public val testQualifier4: kotlin.Int = 4 +public fun __(): kotlin.Unit +public fun test(/*0*/ _: kotlin.Int): kotlin.Unit +public fun testCall(): kotlin.Unit +public fun testCallableRefLHSValue(/*0*/ _: kotlin.Any): kotlin.reflect.KFunction0 +public fun testCallableRefLHSValue2(/*0*/ _: kotlin.Any): kotlin.reflect.KFunction0 + +public object Host { + private constructor Host() + public final val _: kotlin.Int = 42 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public object __ { + private constructor __() + public final val bar: kotlin.Int = 4 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public object ___ { + private constructor ___() + public final val test: kotlin.Int = 42 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.kt b/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.kt new file mode 100644 index 00000000000..17b63f0d9a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.kt @@ -0,0 +1,11 @@ +class `___` { + class `____` +} + +val testCallableRefLHSType = ___::toString +val testCallableRefLHSType2 = `___`::toString + +val testClassLiteralLHSType = ___::class +val testClassLiteralLHSType2 = `___`::class + +val tesLHSTypeFQN = `___`.____::class \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.txt b/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.txt new file mode 100644 index 00000000000..ad67ca4d779 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.txt @@ -0,0 +1,21 @@ +package + +public val tesLHSTypeFQN: kotlin.reflect.KClass<___.____> +public val testCallableRefLHSType: kotlin.reflect.KFunction1<___, kotlin.String> +public val testCallableRefLHSType2: kotlin.reflect.KFunction1<___, kotlin.String> +public val testClassLiteralLHSType: kotlin.reflect.KClass<___> +public val testClassLiteralLHSType2: kotlin.reflect.KClass<___> + +public final class ___ { + public constructor ___() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class ____ { + public constructor ____() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInType.kt b/compiler/testData/diagnostics/tests/UnderscoreUsageInType.kt new file mode 100644 index 00000000000..2c27b544f1f --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInType.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY + +class `_`<`__`> { + fun testTypeArgument(x: List<__>) = x + fun testTypeArgument2(x: List<`__`>) = x +} + +fun _.testTypeConstructor() {} +fun `_`.testTypeConstructor2() {} + +val testConstructor = _() +val testConstructor2 = `_`() diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInType.txt b/compiler/testData/diagnostics/tests/UnderscoreUsageInType.txt new file mode 100644 index 00000000000..830ff9d2f6c --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInType.txt @@ -0,0 +1,15 @@ +package + +public val testConstructor: _ +public val testConstructor2: _ +public fun _.testTypeConstructor(): kotlin.Unit +public fun _.testTypeConstructor2(): kotlin.Unit + +public final class _ { + public constructor _() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun testTypeArgument(/*0*/ x: kotlin.collections.List<__>): kotlin.collections.List<__> + public final fun testTypeArgument2(/*0*/ x: kotlin.collections.List<__>): kotlin.collections.List<__> + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.kt b/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.kt new file mode 100644 index 00000000000..36809b2a6f2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.kt @@ -0,0 +1,6 @@ +object Host { + val `____` = { -> } + fun testFunTypeVal() { + ____() + } +} diff --git a/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.txt b/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.txt new file mode 100644 index 00000000000..fa484bd6d0d --- /dev/null +++ b/compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.txt @@ -0,0 +1,10 @@ +package + +public object Host { + private constructor Host() + public final val ____: () -> kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun testFunTypeVal(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/underscore.kt b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/underscore.kt index c63a0981800..ed0d2c85b2b 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/underscore.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/underscore.kt @@ -38,11 +38,11 @@ fun test() { val (`_`, z) = A() - foo(_, z) + foo(_, z) val (_, `_`) = A() - foo(_, y) + foo(_, y) val (unused, _) = A() } diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt b/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt index 4d36a96743f..5e196059ac7 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/BaseDiagnosticsTest.kt @@ -130,10 +130,10 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava = ArrayList() init { - this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives) + this.declareCheckType = CHECK_TYPE_DIRECTIVE in directives + this.whatDiagnosticsToConsider = parseDiagnosticFilterDirective(directives, declareCheckType) this.customLanguageVersionSettings = parseLanguageVersionSettings(directives) this.checkLazyLog = CHECK_LAZY_LOG_DIRECTIVE in directives || CHECK_LAZY_LOG_DEFAULT - this.declareCheckType = CHECK_TYPE_DIRECTIVE in directives this.declareFlexibleType = EXPLICIT_FLEXIBLE_TYPES_DIRECTIVE in directives this.markDynamicCalls = MARK_DYNAMIC_CALLS_DIRECTIVE in directives if (fileName.endsWith(".java")) { @@ -358,18 +358,26 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava): Condition { + private fun parseDiagnosticFilterDirective(directiveMap: Map, allowUnderscoreUsage: Boolean): Condition { val directives = directiveMap[DIAGNOSTICS_DIRECTIVE] + val initialCondition = + if (allowUnderscoreUsage) + Condition { it.factory.name != "UNDERSCORE_USAGE_WITHOUT_BACKTICKS" } + else + Conditions.alwaysTrue() + if (directives == null) { // If "!API_VERSION" is present, disable the NEWER_VERSION_IN_SINCE_KOTLIN diagnostic. // Otherwise it would be reported in any non-trivial test on the @SinceKotlin value. if (API_VERSION_DIRECTIVE in directiveMap) { - return Condition { diagnostic -> diagnostic.factory !== Errors.NEWER_VERSION_IN_SINCE_KOTLIN } + return Conditions.and(initialCondition, Condition { + diagnostic -> diagnostic.factory !== Errors.NEWER_VERSION_IN_SINCE_KOTLIN + }) } - return Conditions.alwaysTrue() + return initialCondition } - var condition = Conditions.alwaysTrue() + var condition = initialCondition val matcher = DIAGNOSTICS_PATTERN.matcher(directives) if (!matcher.find()) { Assert.fail("Wrong syntax in the '// !$DIAGNOSTICS_DIRECTIVE: ...' directive:\n" + diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index c53c6dddecb..7b5484e91d0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -764,6 +764,36 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("UnderscoreUsageInAnnotation.kt") + public void testUnderscoreUsageInAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnderscoreUsageInAnnotation.kt"); + doTest(fileName); + } + + @TestMetadata("UnderscoreUsageInCall.kt") + public void testUnderscoreUsageInCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnderscoreUsageInCall.kt"); + doTest(fileName); + } + + @TestMetadata("UnderscoreUsageInCallableRefTypeLHS.kt") + public void testUnderscoreUsageInCallableRefTypeLHS() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnderscoreUsageInCallableRefTypeLHS.kt"); + doTest(fileName); + } + + @TestMetadata("UnderscoreUsageInType.kt") + public void testUnderscoreUsageInType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnderscoreUsageInType.kt"); + doTest(fileName); + } + + @TestMetadata("UnderscoreUsageInVariableAsFunctionCall.kt") + public void testUnderscoreUsageInVariableAsFunctionCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnderscoreUsageInVariableAsFunctionCall.kt"); + doTest(fileName); + } + @TestMetadata("UnitByDefaultForFunctionTypes.kt") public void testUnitByDefaultForFunctionTypes() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnitByDefaultForFunctionTypes.kt");