Support single-underscore variable names partially
Currently only parameters of lambdas/function expressions and destructuring entries are allowed #KT-3824 In Progress #KT-2783 In Progress
This commit is contained in:
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getDispatchReceiverWithSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasThisOrNoDispatchReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils.*
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
@@ -572,7 +573,7 @@ class ControlFlowInformationProvider private constructor(
|
||||
val element = instruction.variableDeclarationElement as? KtNamedDeclaration ?: return@traverse
|
||||
element.nameIdentifier ?: return@traverse
|
||||
if (!VariableUseState.isUsed(variableUseState)) {
|
||||
if (KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
||||
if (!element.isSingleUnderscore && KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
||||
report(Errors.UNUSED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
}
|
||||
else if (element is KtParameter) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyTypeAliasDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.scopes.*;
|
||||
@@ -304,14 +305,23 @@ public class DescriptorResolver {
|
||||
destructuringVariables = null;
|
||||
}
|
||||
|
||||
Name parameterName;
|
||||
|
||||
if (destructuringDeclaration == null) {
|
||||
parameterName = UnderscoreUtilKt.isSingleUnderscore(valueParameter)
|
||||
? Name.special("<anonymous parameter " + index + ">")
|
||||
: KtPsiUtil.safeName(valueParameter.getName());
|
||||
}
|
||||
else {
|
||||
parameterName = Name.special("<name for destructuring parameter " + index + ">");
|
||||
}
|
||||
|
||||
ValueParameterDescriptorImpl valueParameterDescriptor = ValueParameterDescriptorImpl.createWithDestructuringDeclarations(
|
||||
owner,
|
||||
null,
|
||||
index,
|
||||
valueParameterAnnotations,
|
||||
destructuringVariables == null
|
||||
? KtPsiUtil.safeName(valueParameter.getName())
|
||||
: Name.special("<name for destructuring parameter " + index + ">"),
|
||||
parameterName,
|
||||
variableType,
|
||||
valueParameter.hasDefaultValue(),
|
||||
valueParameter.hasModifier(CROSSINLINE_KEYWORD),
|
||||
|
||||
@@ -23,12 +23,14 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
@@ -186,11 +188,16 @@ class LocalVariableResolver(
|
||||
type: KotlinType?,
|
||||
trace: BindingTrace
|
||||
): LocalVariableDescriptor {
|
||||
val hasDelegate = variable is KtProperty && variable.hasDelegate();
|
||||
val hasDelegate = variable is KtProperty && variable.hasDelegate()
|
||||
val variableDescriptor = LocalVariableDescriptor(
|
||||
scope.ownerDescriptor,
|
||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
|
||||
KtPsiUtil.safeName(variable.name),
|
||||
// Note, that the same code works both for common local vars and for destructuring declarations,
|
||||
// but since the first case is illegal error must be reported somewhere else
|
||||
if (variable.isSingleUnderscore)
|
||||
Name.special("<underscore local var>")
|
||||
else
|
||||
KtPsiUtil.safeName(variable.name),
|
||||
type,
|
||||
variable.isVar,
|
||||
hasDelegate,
|
||||
@@ -199,4 +206,4 @@ class LocalVariableResolver(
|
||||
trace.record(BindingContext.VARIABLE, variable, variableDescriptor)
|
||||
return variableDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ public class ModifiersChecker {
|
||||
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
|
||||
annotationChecker.check(multiEntry, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageVersionSettings);
|
||||
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace);
|
||||
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace, /* allowSingleUnderscore = */ true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.util
|
||||
|
||||
import com.intellij.psi.StubBasedPsiElement
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
/**
|
||||
* val lambda = fun(x: Int, _: String, `_`: Double) = 1
|
||||
*
|
||||
* This property is true only for second value parameter in the example above
|
||||
*/
|
||||
val KtNamedDeclaration.isSingleUnderscore: Boolean
|
||||
get() {
|
||||
// We don't want to call 'getNameIdentifier' on stubs to prevent text building
|
||||
// But it's fine because one-underscore names are prohibited for non-local declarations (only lambda parameters, local vars are allowed)
|
||||
if (this is StubBasedPsiElement<*> && this.stub != null) return false
|
||||
return nameIdentifier?.text == "_"
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.checkers
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionExpressionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -26,15 +27,17 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
object UnderscoreChecker : SimpleDeclarationChecker {
|
||||
|
||||
fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink) {
|
||||
@JvmOverloads
|
||||
fun checkIdentifier(identifier: PsiElement?, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) {
|
||||
if (identifier == null || identifier.text.isEmpty()) return
|
||||
if (identifier.text.all { it == '_' }) {
|
||||
if (identifier.text.all { it == '_' } && (!allowSingleUnderscore || identifier.text.length != 1)) {
|
||||
diagnosticHolder.report(Errors.UNDERSCORE_IS_RESERVED.on(identifier))
|
||||
}
|
||||
}
|
||||
|
||||
fun checkNamed(declaration: KtNamedDeclaration, diagnosticHolder: DiagnosticSink) {
|
||||
checkIdentifier(declaration.nameIdentifier, diagnosticHolder)
|
||||
@JvmOverloads
|
||||
fun checkNamed(declaration: KtNamedDeclaration, diagnosticHolder: DiagnosticSink, allowSingleUnderscore: Boolean = false) {
|
||||
checkIdentifier(declaration.nameIdentifier, diagnosticHolder, allowSingleUnderscore)
|
||||
}
|
||||
|
||||
override fun check(
|
||||
@@ -46,7 +49,7 @@ object UnderscoreChecker : SimpleDeclarationChecker {
|
||||
if (declaration is KtProperty && descriptor !is VariableDescriptor) return
|
||||
if (declaration is KtCallableDeclaration) {
|
||||
for (parameter in declaration.valueParameters) {
|
||||
checkNamed(parameter, diagnosticHolder)
|
||||
checkNamed(parameter, diagnosticHolder, allowSingleUnderscore = descriptor is FunctionExpressionDescriptor)
|
||||
}
|
||||
}
|
||||
if (declaration is KtTypeParameterListOwner) {
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
|
||||
val functionDescriptor = createFunctionLiteralDescriptor(expression, context)
|
||||
expression.valueParameters.forEach {
|
||||
components.identifierChecker.checkDeclaration(it, context.trace)
|
||||
UnderscoreChecker.checkNamed(it, context.trace)
|
||||
UnderscoreChecker.checkNamed(it, context.trace, allowSingleUnderscore = true)
|
||||
}
|
||||
val safeReturnType = computeReturnType(expression, context, functionDescriptor, functionTypeExpected)
|
||||
functionDescriptor.setReturnType(safeReturnType)
|
||||
|
||||
Reference in New Issue
Block a user