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.
This commit is contained in:
@@ -706,6 +706,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtSimpleNameExpression, KotlinType> COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> YIELD_IS_RESERVED = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> UNDERSCORE_IS_RESERVED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> UNDERSCORE_USAGE_WITHOUT_BACKTICKS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> INVALID_CHARACTERS = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> INAPPLICABLE_OPERATOR_MODIFIER = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<AdditionalTypeChecker>()
|
||||
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
|
||||
+63
@@ -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 == '_' }
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ fun doTest(): String {
|
||||
}
|
||||
|
||||
for ((_, `_`) in C(2)..C(4)) {
|
||||
s += "$_;"
|
||||
s += "$`_`;"
|
||||
}
|
||||
|
||||
return s
|
||||
|
||||
+2
@@ -58,6 +58,8 @@ With that, an exact type of an expression can be checked in the following way:
|
||||
expr checkType { _<A>() }
|
||||
}
|
||||
|
||||
`CHECK_TYPE` directive also disables `UNDERSCORE_USAGE_WITHOUT_BACKTICKS` diagnostics output.
|
||||
|
||||
#### Usage:
|
||||
|
||||
// !CHECK_TYPE
|
||||
|
||||
+7
-7
@@ -5,14 +5,14 @@
|
||||
@___("") data class Pair(val x: Int, val y: Int)
|
||||
|
||||
class <!UNDERSCORE_IS_RESERVED!>_<!><<!UNDERSCORE_IS_RESERVED!>________<!>>
|
||||
val <!UNDERSCORE_IS_RESERVED!>______<!> = _<Int>()
|
||||
val <!UNDERSCORE_IS_RESERVED!>______<!> = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>()
|
||||
|
||||
fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: _<Int>?): Int {
|
||||
val (_, <!UNUSED_VARIABLE!>z<!>) = Pair(___ - 1, 42)
|
||||
val (x, <!UNDERSCORE_IS_RESERVED!>__________<!>) = Pair(___ - 1, 42)
|
||||
fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>?): Int {
|
||||
val (_, <!UNUSED_VARIABLE!>z<!>) = Pair(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!> - 1, 42)
|
||||
val (x, <!UNDERSCORE_IS_RESERVED!>__________<!>) = Pair(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!> - 1, 42)
|
||||
val <!UNDERSCORE_IS_RESERVED!>____<!> = x
|
||||
// in backquotes: allowed
|
||||
val `_` = __________
|
||||
val `_` = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__________<!>
|
||||
|
||||
val q = fun(_: Int, <!UNDERSCORE_IS_RESERVED, UNUSED_PARAMETER!>__<!>: Int) {}
|
||||
q(1, 2)
|
||||
@@ -21,7 +21,7 @@ fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: _<
|
||||
|
||||
fun localFun(<!UNDERSCORE_IS_RESERVED!>_<!>: String) = 1
|
||||
|
||||
<!UNDERSCORE_IS_RESERVED!>__<!>@ return if (y != null) __(____, y) else __(`_`, ______)
|
||||
<!UNDERSCORE_IS_RESERVED!>__<!>@ return if (y != null) <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>, y) else <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(`_`, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>______<!>)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,5 +42,5 @@ fun oneUnderscore(<!UNDERSCORE_IS_RESERVED!>_<!>: Int) {}
|
||||
|
||||
fun doIt(f: (Any?) -> Any?) = f(null)
|
||||
|
||||
val something = doIt { <!UNDERSCORE_IS_RESERVED!>__<!> -> __ }
|
||||
val something = doIt { <!UNDERSCORE_IS_RESERVED!>__<!> -> <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!> }
|
||||
val something2 = doIt { _ -> 1 }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
annotation class `__`(val value: String)
|
||||
|
||||
@<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>("") class TestAnn
|
||||
@`__`("") class TestAnn2
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
fun test(`_`: Int) {
|
||||
<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!> + 1
|
||||
`_` + 1
|
||||
}
|
||||
|
||||
fun `__`() {}
|
||||
|
||||
fun testCall() {
|
||||
<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>()
|
||||
`__`()
|
||||
}
|
||||
|
||||
val testCallableRef = ::<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>
|
||||
val testCallableRef2 = ::`__`
|
||||
|
||||
|
||||
object Host {
|
||||
val `_` = 42
|
||||
object `__` {
|
||||
val bar = 4
|
||||
}
|
||||
}
|
||||
|
||||
val testQualified = Host.<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>
|
||||
val testQualified2 = Host.`_`
|
||||
|
||||
object `___` {
|
||||
val test = 42
|
||||
}
|
||||
|
||||
val testQualifier = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!>.test
|
||||
val testQualifier2 = `___`.test
|
||||
val testQualifier3 = Host.<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>.bar
|
||||
val testQualifier4 = Host.`__`.bar
|
||||
|
||||
fun testCallableRefLHSValue(`_`: Any) = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>::toString
|
||||
fun testCallableRefLHSValue2(`_`: Any) = `_`::toString
|
||||
|
||||
val testCallableRefLHSObject = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!>::toString
|
||||
val testCallableRefLHSObject2 = `___`::toString
|
||||
@@ -0,0 +1,41 @@
|
||||
package
|
||||
|
||||
public val testCallableRef: kotlin.reflect.KFunction0<kotlin.Unit>
|
||||
public val testCallableRef2: kotlin.reflect.KFunction0<kotlin.Unit>
|
||||
public val testCallableRefLHSObject: kotlin.reflect.KFunction0<kotlin.String>
|
||||
public val testCallableRefLHSObject2: kotlin.reflect.KFunction0<kotlin.String>
|
||||
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<kotlin.String>
|
||||
public fun testCallableRefLHSValue2(/*0*/ _: kotlin.Any): kotlin.reflect.KFunction0<kotlin.String>
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class `___` {
|
||||
class `____`
|
||||
}
|
||||
|
||||
val testCallableRefLHSType = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!>::toString
|
||||
val testCallableRefLHSType2 = `___`::toString
|
||||
|
||||
val testClassLiteralLHSType = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!>::class
|
||||
val testClassLiteralLHSType2 = `___`::class
|
||||
|
||||
val tesLHSTypeFQN = `___`.<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>::class
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
class `_`<`__`> {
|
||||
fun testTypeArgument(x: List<<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>>) = x
|
||||
fun testTypeArgument2(x: List<`__`>) = x
|
||||
}
|
||||
|
||||
fun <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Any>.testTypeConstructor() {}
|
||||
fun `_`<Any>.testTypeConstructor2() {}
|
||||
|
||||
val testConstructor = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Any>()
|
||||
val testConstructor2 = `_`<Any>()
|
||||
@@ -0,0 +1,15 @@
|
||||
package
|
||||
|
||||
public val testConstructor: _<kotlin.Any>
|
||||
public val testConstructor2: _<kotlin.Any>
|
||||
public fun _<kotlin.Any>.testTypeConstructor(): kotlin.Unit
|
||||
public fun _<kotlin.Any>.testTypeConstructor2(): kotlin.Unit
|
||||
|
||||
public final class _</*0*/ __> {
|
||||
public constructor _</*0*/ __>()
|
||||
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
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
object Host {
|
||||
val `____` = { -> }
|
||||
fun testFunTypeVal() {
|
||||
<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>()
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
}
|
||||
Vendored
+2
-2
@@ -38,11 +38,11 @@ fun test() {
|
||||
|
||||
val (<!REDECLARATION!>`_`<!>, z) = A()
|
||||
|
||||
foo(_, z)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>, z)
|
||||
|
||||
val (_, <!NAME_SHADOWING, REDECLARATION!>`_`<!>) = A()
|
||||
|
||||
foo(<!TYPE_MISMATCH!>_<!>, y)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, TYPE_MISMATCH!>_<!>, y)
|
||||
|
||||
val (<!UNUSED_VARIABLE!>unused<!>, _) = A()
|
||||
}
|
||||
|
||||
@@ -130,10 +130,10 @@ abstract class BaseDiagnosticsTest : KotlinMultiFileTestWithJava<TestModule, Tes
|
||||
val dynamicCallDescriptors: List<DeclarationDescriptor> = 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<TestModule, Tes
|
||||
return values
|
||||
}
|
||||
|
||||
private fun parseDiagnosticFilterDirective(directiveMap: Map<String, String>): Condition<Diagnostic> {
|
||||
private fun parseDiagnosticFilterDirective(directiveMap: Map<String, String>, allowUnderscoreUsage: Boolean): Condition<Diagnostic> {
|
||||
val directives = directiveMap[DIAGNOSTICS_DIRECTIVE]
|
||||
val initialCondition =
|
||||
if (allowUnderscoreUsage)
|
||||
Condition<Diagnostic> { 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<Diagnostic>()
|
||||
var condition = initialCondition
|
||||
val matcher = DIAGNOSTICS_PATTERN.matcher(directives)
|
||||
if (!matcher.find()) {
|
||||
Assert.fail("Wrong syntax in the '// !$DIAGNOSTICS_DIRECTIVE: ...' directive:\n" +
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user