From d05a7224c7e7cbc87fe0efb6515afe3f035abcab Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Thu, 8 Oct 2015 20:57:48 +0300 Subject: [PATCH] add check for escaped identifiers --- .../checkers/JvmSimpleNameBacktickChecker.kt | 67 ++++++++++ .../jvm/platform/JvmPlatformConfigurator.kt | 6 +- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/DeclarationChecker.kt | 4 +- .../kotlin/resolve/DeclarationsChecker.java | 8 ++ .../kotlin/resolve/IdentifierChecker.kt | 31 +++++ .../kotlin/resolve/LazyTopDownAnalyzer.kt | 5 +- .../kotlin/resolve/TargetPlatform.kt | 6 +- .../jetbrains/kotlin/resolve/TypeResolver.kt | 4 +- .../ControlStructureTypingVisitor.java | 3 + .../ExpressionTypingComponents.java | 7 +- .../ExpressionTypingVisitorForStatements.java | 2 + .../expressions/FunctionsTypingVisitor.kt | 2 + .../diagnostics/tests/BacktickNames.kt | 98 +++++++++++++++ .../diagnostics/tests/BacktickNames.txt | 114 ++++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 6 + .../js/resolve/JsPlatformConfigurator.kt | 4 +- 18 files changed, 359 insertions(+), 10 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSimpleNameBacktickChecker.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/IdentifierChecker.kt create mode 100644 compiler/testData/diagnostics/tests/BacktickNames.kt create mode 100644 compiler/testData/diagnostics/tests/BacktickNames.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSimpleNameBacktickChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSimpleNameBacktickChecker.kt new file mode 100644 index 00000000000..3d9e9fb2f4c --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSimpleNameBacktickChecker.kt @@ -0,0 +1,67 @@ +/* + * 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.jvm.checkers + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.IdentifierChecker + +object JvmSimpleNameBacktickChecker : IdentifierChecker { + // See The Java Virtual Machine Specification, section 4.7.9.1 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9.1 + private val CHARS = setOf('.', ';', '[', ']', '/', '<', '>', ':', '\\') + + override fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink) { + if (identifier == null) return + + reportIfNeeded(identifier.text, identifier, diagnosticHolder) + } + + override fun checkDeclaration(declaration: JetDeclaration, diagnosticHolder: DiagnosticSink) { + if (declaration is JetMultiDeclaration) { + declaration.entries.forEach { checkNamed(it, diagnosticHolder) } + } + if (declaration is JetCallableDeclaration) { + declaration.valueParameters.forEach { checkNamed(it, diagnosticHolder) } + } + if (declaration is JetTypeParameterListOwner) { + declaration.typeParameters.forEach { checkNamed(it, diagnosticHolder) } + } + if (declaration is JetNamedDeclaration) { + checkNamed(declaration, diagnosticHolder) + } + } + + fun checkNamed(declaration: JetNamedDeclaration, diagnosticHolder: DiagnosticSink) { + val name = declaration.name ?: return + + val element = declaration.nameIdentifier ?: declaration + reportIfNeeded(name, element, diagnosticHolder) + } + + private fun reportIfNeeded(name: String, element: PsiElement, diagnosticHolder: DiagnosticSink) { + val text = JetPsiUtil.unquoteIdentifier(name) + if (text.isEmpty()) { + diagnosticHolder.report(Errors.INVALID_CHARACTERS.on(element, "should not be empty")) + } + else if (text.any { it in CHARS }) { + diagnosticHolder.report(Errors.INVALID_CHARACTERS.on(element, "contains illegal characters: ${CHARS.intersect(text.toSet()).joinToString("")}")) + } + } +} + diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index d4d70c702a5..e4b0ac521ff 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.jvm.checkers.* import org.jetbrains.kotlin.types.DynamicTypesSettings + public object JvmPlatformConfigurator : PlatformConfigurator( DynamicTypesSettings(), additionalDeclarationCheckers = listOf( @@ -60,7 +61,9 @@ public object JvmPlatformConfigurator : PlatformConfigurator( additionalAnnotationCheckers = listOf( RepeatableAnnotationChecker, FileClassAnnotationsChecker - ) + ), + + identifierChecker = JvmSimpleNameBacktickChecker ) { override fun configure(container: StorageComponentContainer) { @@ -69,4 +72,3 @@ public object JvmPlatformConfigurator : PlatformConfigurator( container.useImpl() } } - diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 1faceae84d9..97bc11a261c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -565,6 +565,7 @@ public interface Errors { DiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 UNDERSCORE_IS_DEPRECATED = DiagnosticFactory0.create(WARNING); + DiagnosticFactory1 INVALID_CHARACTERS = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 INAPPLICABLE_OPERATOR_MODIFIER = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 INAPPLICABLE_INFIX_MODIFIER = 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 ee202e54fbd..011d4c82272 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -377,6 +377,7 @@ public class DefaultErrorMessages { MAP.put(COMPARE_TO_TYPE_MISMATCH, "''compareTo()'' must return kotlin.Int, but returns {0}", RENDER_TYPE); MAP.put(UNDERSCORE_IS_DEPRECATED, "Names _, __, ___, ..., are deprecated"); + MAP.put(INVALID_CHARACTERS, "Name {0}", STRING); MAP.put(INAPPLICABLE_OPERATOR_MODIFIER, "'operator' modifier is inapplicable on this function"); MAP.put(INAPPLICABLE_INFIX_MODIFIER, "'infix' modifier is inapplicable on this function"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationChecker.kt index 897ea5c6126..fcd3793703e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationChecker.kt @@ -16,9 +16,9 @@ package org.jetbrains.kotlin.resolve -import org.jetbrains.kotlin.psi.JetDeclaration -import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.JetDeclaration public interface DeclarationChecker { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java index 3726c7e8f36..76a13b015eb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.java @@ -48,16 +48,19 @@ public class DeclarationsChecker { @NotNull private final ModifiersChecker.ModifiersCheckingProcedure modifiersChecker; @NotNull private final DescriptorResolver descriptorResolver; @NotNull private final AnnotationChecker annotationChecker; + @NotNull private final IdentifierChecker identifierChecker; public DeclarationsChecker( @NotNull DescriptorResolver descriptorResolver, @NotNull ModifiersChecker modifiersChecker, @NotNull AnnotationChecker annotationChecker, + @NotNull IdentifierChecker identifierChecker, @NotNull BindingTrace trace ) { this.descriptorResolver = descriptorResolver; this.modifiersChecker = modifiersChecker.withTrace(trace); this.annotationChecker = annotationChecker; + this.identifierChecker = identifierChecker; this.trace = trace; } @@ -88,6 +91,7 @@ public class DeclarationsChecker { checkPrimaryConstructor(classOrObject, classDescriptor); modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor); + identifierChecker.checkDeclaration(classOrObject, trace); checkClassExposedType(classOrObject, classDescriptor); } @@ -98,6 +102,7 @@ public class DeclarationsChecker { checkFunction(function, functionDescriptor); modifiersChecker.checkModifiersForDeclaration(function, functionDescriptor); + identifierChecker.checkDeclaration(function, trace); } Map properties = bodiesResolveContext.getProperties(); @@ -107,6 +112,7 @@ public class DeclarationsChecker { checkProperty(property, propertyDescriptor); modifiersChecker.checkModifiersForDeclaration(property, propertyDescriptor); + identifierChecker.checkDeclaration(property, trace); } for (Map.Entry entry : bodiesResolveContext.getSecondaryConstructors().entrySet()) { @@ -119,6 +125,7 @@ public class DeclarationsChecker { private void checkConstructorDeclaration(ConstructorDescriptor constructorDescriptor, JetDeclaration declaration) { modifiersChecker.checkModifiersForDeclaration(declaration, constructorDescriptor); + identifierChecker.checkDeclaration(declaration, trace); } private void checkModifiersAndAnnotationsInPackageDirective(JetFile file) { @@ -819,6 +826,7 @@ public class DeclarationsChecker { PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText(); modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor); + identifierChecker.checkDeclaration(accessor, trace); } checkAccessor(propertyDescriptor, property.getGetter(), propertyDescriptor.getGetter()); checkAccessor(propertyDescriptor, property.getSetter(), propertyDescriptor.getSetter()); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/IdentifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/IdentifierChecker.kt new file mode 100644 index 00000000000..af3800f58e1 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/IdentifierChecker.kt @@ -0,0 +1,31 @@ +/* + * 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.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.JetDeclaration + +public interface IdentifierChecker { + fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink) + fun checkDeclaration(declaration: JetDeclaration, diagnosticHolder: DiagnosticSink) + + object DEFAULT : IdentifierChecker { + override fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink) {} + override fun checkDeclaration(declaration: JetDeclaration, diagnosticHolder: DiagnosticSink) {} + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index 9e424d3fdea..195b905e49d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -47,9 +47,11 @@ public class LazyTopDownAnalyzer( private val topLevelDescriptorProvider: TopLevelDescriptorProvider, private val fileScopeProvider: FileScopeProvider, private val declarationScopeProvider: DeclarationScopeProvider, - private val qualifiedExpressionResolver: QualifiedExpressionResolver + private val qualifiedExpressionResolver: QualifiedExpressionResolver, + private val identifierChecker: IdentifierChecker ) { public fun analyzeDeclarations(topDownAnalysisMode: TopDownAnalysisMode, declarations: Collection, outerDataFlowInfo: DataFlowInfo): TopDownAnalysisContext { + val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider) val topLevelFqNames = HashMultimap.create() @@ -93,6 +95,7 @@ public class LazyTopDownAnalyzer( } override fun visitPackageDirective(directive: JetPackageDirective) { + directive.packageNames.forEach { identifierChecker.checkIdentifier(it.getIdentifier(), trace) } qualifiedExpressionResolver.resolvePackageHeader(directive, moduleDescriptor, trace) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 93416aad909..13cb5bf822b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -43,7 +43,7 @@ abstract class TargetPlatform( override val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance override val defaultModuleParameters = ModuleParameters.Empty - override val platformConfigurator = PlatformConfigurator(DynamicTypesSettings(), listOf(), listOf(), listOf(), listOf(), listOf()) + override val platformConfigurator = PlatformConfigurator(DynamicTypesSettings(), listOf(), listOf(), listOf(), listOf(), listOf(), IdentifierChecker.DEFAULT) } } @@ -65,7 +65,8 @@ open class PlatformConfigurator( additionalCallCheckers: List, additionalTypeCheckers: List, additionalSymbolUsageValidators: List, - private val additionalAnnotationCheckers: List + private val additionalAnnotationCheckers: List, + private val identifierChecker: IdentifierChecker ) { private val declarationCheckers: List = DEFAULT_DECLARATION_CHECKERS + additionalDeclarationCheckers @@ -81,6 +82,7 @@ open class PlatformConfigurator( typeCheckers.forEach { useInstance(it) } useInstance(symbolUsageValidator) additionalAnnotationCheckers.forEach { useInstance(it) } + useInstance(identifierChecker) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index ae9ab6987e3..41abc8f32d8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -52,7 +52,8 @@ public class TypeResolver( private val storageManager: StorageManager, private val lazinessToken: TypeLazinessToken, private val dynamicTypesSettings: DynamicTypesSettings, - private val dynamicCallableDescriptors: DynamicCallableDescriptors + private val dynamicCallableDescriptors: DynamicCallableDescriptors, + private val identifierChecker: IdentifierChecker ) { public open class FlexibleTypeCapabilitiesProvider { @@ -238,6 +239,7 @@ public class TypeResolver( override fun visitFunctionType(type: JetFunctionType) { val receiverTypeRef = type.getReceiverTypeReference() + type.parameters.forEach { identifierChecker.checkDeclaration(it, c.trace) } val receiverType = if (receiverTypeRef == null) null else resolveType(c.noBareTypes(), receiverTypeRef) type.parameters.forEach { checkParameterInFunctionType(it) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index 8d9e3edeb5f..a85cdc92306 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -393,6 +393,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (loopParameter != null) { VariableDescriptor variableDescriptor = createLoopParameterDescriptor(loopParameter, expectedParameterType, context); components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(loopParameter, variableDescriptor); + components.identifierChecker.checkDeclaration(loopParameter, context.trace); loopScope.addVariableDescriptor(variableDescriptor); } @@ -406,6 +407,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { loopScope, multiParameter, iteratorNextAsReceiver, loopRange, context ); components.modifiersChecker.withTrace(context.trace).checkModifiersForMultiDeclaration(multiParameter); + components.identifierChecker.checkDeclaration(multiParameter, context.trace); } } @@ -473,6 +475,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetParameter catchParameter = catchClause.getCatchParameter(); JetExpression catchBody = catchClause.getCatchBody(); if (catchParameter != null) { + components.identifierChecker.checkDeclaration(catchParameter, context.trace); ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace); modifiersChecking.checkParameterHasNoValOrVar(catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER); ModifierCheckerCore.INSTANCE$.check(catchParameter, context.trace, null); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index d2c20806f13..268f3f8f0cb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; import org.jetbrains.kotlin.types.DynamicTypesSettings; -import org.jetbrains.kotlin.types.TypeIntersector; import javax.inject.Inject; @@ -55,6 +54,7 @@ public class ExpressionTypingComponents { /*package*/ ModifiersChecker modifiersChecker; /*package*/ DataFlowAnalyzer dataFlowAnalyzer; /*package*/ Iterable callCheckers; + /*package*/ IdentifierChecker identifierChecker; @Inject public void setGlobalContext(@NotNull GlobalContext globalContext) { @@ -161,6 +161,11 @@ public class ExpressionTypingComponents { this.modifiersChecker = modifiersChecker; } + @Inject + public void setIdentifierChecker(@NotNull IdentifierChecker identifierChecker) { + this.identifierChecker = identifierChecker; + } + @Inject public void setDataFlowAnalyzer(@NotNull DataFlowAnalyzer dataFlowAnalyzer) { this.dataFlowAnalyzer = dataFlowAnalyzer; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index c80ae6507b3..c46bba80e4f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -165,6 +165,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito scope.addVariableDescriptor(propertyDescriptor); components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor); + components.identifierChecker.checkDeclaration(property, context.trace); return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(property, context)); } @@ -185,6 +186,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito } components.multiDeclarationResolver.defineLocalVariablesFromMultiDeclaration(scope, multiDeclaration, expressionReceiver, initializer, context); components.modifiersChecker.withTrace(context.trace).checkModifiersForMultiDeclaration(multiDeclaration); + components.identifierChecker.checkDeclaration(multiDeclaration, context.trace); return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(multiDeclaration, context)); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index bbd73c2de17..acc49e22213 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -106,6 +106,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express ) components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(function, functionDescriptor) + components.identifierChecker.checkDeclaration(function, context.trace) if (!function.hasBody()) { context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)) } @@ -140,6 +141,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express val functionTypeExpected = !noExpectedType(expectedType) && KotlinBuiltIns.isFunctionOrExtensionFunctionType(expectedType) val functionDescriptor = createFunctionLiteralDescriptor(expression, context) + expression.valueParameters.forEach { components.identifierChecker.checkDeclaration(it, context.trace) } val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected) functionDescriptor.setReturnType(safeReturnType) diff --git a/compiler/testData/diagnostics/tests/BacktickNames.kt b/compiler/testData/diagnostics/tests/BacktickNames.kt new file mode 100644 index 00000000000..78c377a028d --- /dev/null +++ b/compiler/testData/diagnostics/tests/BacktickNames.kt @@ -0,0 +1,98 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER +// TODO Uncomment all the examples when there will be no problems with light classes +//package `foo.bar` + +// TODO: Uncomment after fixing KT-9416 +//import kotlin.Deprecated as `deprecate\entity` + +//@`deprecate\entity`("") data class Pair(val x: Int, val y: Int) + +// Names should not contains characters: '.', ';', '[', ']', '/', '<', '>', ':', '\\' +//class `class.name` +class `class;name` +class `class[name` +class `class]name` +//class `class/name` +class `class +class `class>name` +class `class:name` +class `class\name` + +class ` ` {} +class ` ` + +//val `val.X` = 10 +val `val;X` = 10 +val `val[X` = 10 +val `val]X` = 10 +//val `val/X` = 10 +val `val = 10 +val `val>X` = 10 +val `val:X` = 10 +val `val\X` = 10 + +val `;` = 1 +val `[` = 2 +val `]` = 3 +// org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException: Descriptor wasn't found for declaration PROPERTY +// Names which start with '<' are treated as "special": see Name.java +//val `<` = 4 + +val `>` = 5 +val `:` = 6 +val `\` = 7 +// org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException: Descriptor wasn't found for declaration PROPERTY +// Names which start with '<' are treated as "special": see Name.java +//val `<>` = 8 + +val `[]` = 9 +val `[;]` = 10 + +// TODO Uncomment when there will be no problems with light classes (Error: Invalid formal type parameter (must be a valid Java identifier)) +//class AWithTypeParameter<`T:K`> {} +//fun <`T/K`> genericFun(x: `T/K`) {} + +class B(val `a:b`: Int, val `c:d`: Int) + +val ff: (`x:X`: Int) -> Unit = {} +val fg: ((`x:X`: Int) -> Unit) -> Unit = {} +val fh: ((Int) -> ((`x:X`: Int) -> Unit) -> Unit) = {{}} + +fun f(x: Int, g: (Int) -> Unit) = g(x) + +data class Data(val x: Int, val y: Int) + +class A() { + init { + val `a:b` = 10 + } + + fun g(`x:y`: Int) { + val `s:` = 30 + } +} + +fun `foo:bar`(`\arg`: Int): Int { + val (`a:b`, c) = Data(10, 20) + val `a\b` = 10 + + fun localFun() {} + + for (`x/y` in 0..10) { + } + + f(10) { + `x:z`: Int -> localFun() + } + + f(20, fun(`x:z`: Int): Unit {}) + + try { + val `a:` = 10 + } + catch (`e:a`: Exception) { + val `b:` = 20 + } + + return `\arg` +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/BacktickNames.txt b/compiler/testData/diagnostics/tests/BacktickNames.txt new file mode 100644 index 00000000000..ecb5390a0ef --- /dev/null +++ b/compiler/testData/diagnostics/tests/BacktickNames.txt @@ -0,0 +1,114 @@ +package + +public val `:`: kotlin.Int = 6 +public val `;`: kotlin.Int = 1 +public val `>`: kotlin.Int = 5 +public val `[`: kotlin.Int = 2 +public val `[;]`: kotlin.Int = 10 +public val `[]`: kotlin.Int = 9 +public val `\`: kotlin.Int = 7 +public val `]`: kotlin.Int = 3 +public val ff: (kotlin.Int) -> kotlin.Unit +public val fg: ((kotlin.Int) -> kotlin.Unit) -> kotlin.Unit +public val fh: (kotlin.Int) -> ((kotlin.Int) -> kotlin.Unit) -> kotlin.Unit +public val `val:X`: kotlin.Int = 10 +public val `val;X`: kotlin.Int = 10 +public val `valX`: kotlin.Int = 10 +public val `val[X`: kotlin.Int = 10 +public val `val\X`: kotlin.Int = 10 +public val `val]X`: kotlin.Int = 10 +public fun f(/*0*/ x: kotlin.Int, /*1*/ g: (kotlin.Int) -> kotlin.Unit): kotlin.Unit +public fun `foo:bar`(/*0*/ `\arg`: kotlin.Int): kotlin.Int + +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 +} + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun g(/*0*/ `x:y`: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B { + public constructor B(/*0*/ `a:b`: kotlin.Int, /*1*/ `c:d`: kotlin.Int) + public final val `a:b`: kotlin.Int + public final val `c:d`: kotlin.Int + 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 +} + +@kotlin.data() public final class Data { + public constructor Data(/*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 = ...): Data + 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 `class:name` { + public constructor `class:name`() + 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 `class;name` { + public constructor `class;name`() + 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 `classname` { + public constructor `class>name`() + 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 `class[name` { + public constructor `class[name`() + 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 `class\name` { + public constructor `class\name`() + 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 `class]name` { + public constructor `class]name`() + 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/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index f6442e881e5..67e228f6230 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -91,6 +91,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("BacktickNames.kt") + public void testBacktickNames() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/BacktickNames.kt"); + doTest(fileName); + } + @TestMetadata("Basic.kt") public void testBasic() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/Basic.kt"); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt index ecd0812d64c..86f0d0b6771 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/JsPlatformConfigurator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.resolve import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker +import org.jetbrains.kotlin.resolve.IdentifierChecker import org.jetbrains.kotlin.resolve.PlatformConfigurator import org.jetbrains.kotlin.types.DynamicTypesAllowed @@ -28,7 +29,8 @@ public object JsPlatformConfigurator : PlatformConfigurator( additionalCallCheckers = listOf(), additionalTypeCheckers = listOf(), additionalSymbolUsageValidators = listOf(), - additionalAnnotationCheckers = listOf() + additionalAnnotationCheckers = listOf(), + identifierChecker = IdentifierChecker.DEFAULT ) { override fun configure(container: StorageComponentContainer) { super.configure(container)