From 0a0bfdacb113df990e928e0c1d9312dd1c2503de Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 25 Sep 2015 14:51:00 +0300 Subject: [PATCH] Names containing only '_' are deprecated (declarations, parameters, import aliases, labels, but not backquoted names) --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 + .../rendering/DefaultErrorMessages.java | 2 + .../kotlin/resolve/ModifiersChecker.java | 1 + .../kotlin/resolve/TargetPlatform.kt | 2 +- .../kotlin/resolve/UnderscoreChecker.kt | 60 +++++++++++++++++++ .../kotlin/resolve/lazy/LazyImportScope.kt | 5 ++ .../BasicExpressionTypingVisitor.java | 5 ++ .../testData/diagnostics/tests/Underscore.kt | 16 +++++ .../testData/diagnostics/tests/Underscore.txt | 23 +++++++ .../classGenericsInParamsIndexMismatch.kt | 6 +- .../classGenericsInParamsIndexMismatch.txt | 12 ++-- .../checkers/JetDiagnosticsTestGenerated.java | 6 ++ 12 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/UnderscoreChecker.kt create mode 100644 compiler/testData/diagnostics/tests/Underscore.kt create mode 100644 compiler/testData/diagnostics/tests/Underscore.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index dbe4d46b633..8ed40c8b466 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -522,6 +522,8 @@ public interface Errors { DiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 UNDESCORE_IS_DEPRECATED = DiagnosticFactory0.create(WARNING); + // Labels DiagnosticFactory0 LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING); 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 2da965a47cb..fece0f14985 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -352,6 +352,8 @@ public class DefaultErrorMessages { MAP.put(COMPARE_TO_TYPE_MISMATCH, "''compareTo()'' must return kotlin.Int, but returns {0}", RENDER_TYPE); + MAP.put(UNDESCORE_IS_DEPRECATED, "Names _, __, ___, ..., are deprecated"); + MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY, "Returns are not allowed for functions with expression body. Use block body in '{...}'"); MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index b026cc13936..35b394a25fc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -200,6 +200,7 @@ public class ModifiersChecker { for (JetMultiDeclarationEntry multiEntry: multiDeclaration.getEntries()) { annotationChecker.check(multiEntry, trace, null); ModifierCheckerCore.INSTANCE$.check(multiEntry, trace, null); + UnderscoreChecker.INSTANCE$.checkNamed(multiEntry, trace); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 2d7d5c7af40..2f9cd3c27c8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -38,7 +38,7 @@ public abstract class TargetPlatform( } } -private val DEFAULT_DECLARATION_CHECKERS = listOf(DataClassAnnotationChecker(), ConstModifierChecker) +private val DEFAULT_DECLARATION_CHECKERS = listOf(DataClassAnnotationChecker(), ConstModifierChecker, UnderscoreChecker) private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker()) private val DEFAULT_TYPE_CHECKERS = emptyList() private val DEFAULT_VALIDATORS = listOf(DeprecatedSymbolValidator(), AccessToPrivateTopLevelSymbolValidator()) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/UnderscoreChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/UnderscoreChecker.kt new file mode 100644 index 00000000000..f619fdd1c55 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/UnderscoreChecker.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2015 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 + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.JetCallableDeclaration +import org.jetbrains.kotlin.psi.JetDeclaration +import org.jetbrains.kotlin.psi.JetNamedDeclaration +import org.jetbrains.kotlin.psi.JetTypeParameterListOwner + +object UnderscoreChecker : DeclarationChecker { + + fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink) { + if (identifier == null || identifier.text.isEmpty()) return + if (identifier.text.all { it == '_' }) { + diagnosticHolder.report(Errors.UNDESCORE_IS_DEPRECATED.on(identifier)) + } + } + + fun checkNamed(declaration: JetNamedDeclaration, diagnosticHolder: DiagnosticSink) { + checkIdentifier(declaration.nameIdentifier, diagnosticHolder) + } + + override fun check( + declaration: JetDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext + ) { + if (declaration is JetCallableDeclaration) { + for (parameter in declaration.valueParameters) { + checkNamed(parameter, diagnosticHolder) + } + } + if (declaration is JetTypeParameterListOwner) { + for (typeParameter in declaration.typeParameters) { + checkNamed(typeParameter, diagnosticHolder) + } + } + if (declaration !is JetNamedDeclaration) return + checkNamed(declaration, diagnosticHolder) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 5954d1c5cde..11a55681f37 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -100,6 +100,11 @@ class LazyImportResolver( } } } + for ((alias, import) in explicitClassImports.entries()) { + if (alias.all { it == '_' }) { + traceForImportResolve.report(Errors.UNDESCORE_IS_DEPRECATED.on(import)) + } + } for (alias in explicitClassImports.keySet()) { val imports = explicitClassImports.get(alias) if (imports.size() > 1) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index be3296ebc4c..bc4bb93cf7f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -867,6 +867,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull ExpressionTypingContext context, boolean isStatement ) { + JetSimpleNameExpression labelExpression = expression.getTargetLabel(); + if (labelExpression != null) { + PsiElement labelIdentifier = labelExpression.getIdentifier(); + UnderscoreChecker.INSTANCE$.checkIdentifier(labelIdentifier, context.trace); + } JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression == null) return TypeInfoFactoryPackage.noTypeInfo(context); diff --git a/compiler/testData/diagnostics/tests/Underscore.kt b/compiler/testData/diagnostics/tests/Underscore.kt new file mode 100644 index 00000000000..532f69758a0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/Underscore.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -DEPRECATED_SYMBOL_WITH_MESSAGE + +import kotlin.Deprecated as ___ + +@___("") data class Pair(val x: Int, val y: Int) + +class _<________> +val ______ = _() + +fun __(___: Int, y: _?): Int { + val (x, __________) = Pair(___ - 1, 42) + val ____ = x + // in backquotes: allowed + val `_` = __________ + __@ return if (y != null) __(____, y) else __(`_`, ______) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/Underscore.txt b/compiler/testData/diagnostics/tests/Underscore.txt new file mode 100644 index 00000000000..87fb6705a9b --- /dev/null +++ b/compiler/testData/diagnostics/tests/Underscore.txt @@ -0,0 +1,23 @@ +package + +public val ______: _ +public fun __(/*0*/ ___: kotlin.Int, /*1*/ y: _?): kotlin.Int + +@kotlin.Deprecated(value = "") @kotlin.data() public final class Pair { + public constructor Pair(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int) + public final val x: kotlin.Int + public final val y: kotlin.Int + public final /*synthesized*/ fun component1(): kotlin.Int + public final /*synthesized*/ fun component2(): kotlin.Int + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.Int = ...): Pair + 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/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.kt index 4616eec5f97..e07841631d6 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.kt @@ -4,7 +4,7 @@ // FILE: a.kt package p -public interface B { +public interface B { public fun foo(a: T?) } @@ -12,7 +12,7 @@ public interface B { // FILE: b.kt package p -public interface C : B { +public interface C : B { override fun foo(a: X?) } @@ -21,7 +21,7 @@ public interface C : B { // FILE: b.kt package p -public interface B<_, T> { +public interface B { public fun foo(a: T?) } diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.txt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.txt index 1e18e7a392a..b1d840e026d 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.txt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsIndexMismatch.txt @@ -3,7 +3,7 @@ package package p { - public interface B { + public interface B { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public abstract fun foo(/*0*/ a: T?): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -17,11 +17,11 @@ package package p { - public interface B { + public interface B { // -- Module: -- } - public interface C : p.B { + public interface C : p.B { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public abstract override /*1*/ fun foo(/*0*/ a: X?): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -35,7 +35,7 @@ package package p { - public interface B { + public interface B { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public abstract fun foo(/*0*/ a: T?): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -51,11 +51,11 @@ public fun test(/*0*/ b: p.B?): kotlin.Unit package p { - public interface B { + public interface B { // -- Module: -- } - public interface C : p.B { + public interface C : p.B { // -- Module: -- } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 28330f132eb..03dcf8817c3 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -541,6 +541,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("Underscore.kt") + public void testUnderscore() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/Underscore.kt"); + doTest(fileName); + } + @TestMetadata("UnitByDefaultForFunctionTypes.kt") public void testUnitByDefaultForFunctionTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/UnitByDefaultForFunctionTypes.kt");