Introduce KotlinBuiltIns.isUnderKotlinPackage

Semantics is the same as in the former
FunctionDescriptor.hasSubpackageOfKotlin, but it doesn't compute the FQ
name of the descriptor
This commit is contained in:
Alexander Udalov
2017-06-20 19:48:46 +03:00
parent 7bc42f89d3
commit aed5b934f8
6 changed files with 27 additions and 20 deletions
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.isSubpackageOf
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -105,22 +103,17 @@ fun FunctionDescriptor.isOperatorMod(): Boolean {
return this.isOperator && name in OperatorConventions.REM_TO_MOD_OPERATION_NAMES.values
}
// This is an alternate function to KotlinBuiltIns.isBuiltIn
// It is safer as it produces stable results independent of target platform (Java/JS/Native)
fun FunctionDescriptor.hasSubpackageOfKotlin(): Boolean {
val descriptorFqName = fqNameOrNull() ?: return false
return descriptorFqName.isSubpackageOf(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
}
fun shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings: LanguageVersionSettings): Boolean {
return languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) && languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_1
}
private fun checkModConvention(descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
diagnosticHolder: DiagnosticSink, modifier: PsiElement) {
private fun checkModConvention(
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
diagnosticHolder: DiagnosticSink, modifier: PsiElement
) {
if (!descriptor.isOperatorMod()) return
if (descriptor.hasSubpackageOfKotlin()) {
if (KotlinBuiltIns.isUnderKotlinPackage(descriptor)) {
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
}
@@ -136,4 +129,3 @@ private fun addWarningAboutDeprecatedMod(descriptor: FunctionDescriptor, diagnos
val newNameConvention = OperatorConventions.REM_TO_MOD_OPERATION_NAMES.inverse()[descriptor.name]
diagnosticHolder.report(Errors.DEPRECATED_BINARY_MOD_AS_REM.on(reportOn, descriptor, newNameConvention!!.asString()))
}
@@ -473,9 +473,7 @@ private class ConstantExpressionEvaluatorVisitor(
private fun evaluateCall(callExpression: KtExpression, receiverExpression: KtExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
val resolvedCall = callExpression.getResolvedCall(trace.bindingContext) ?: return null
val descriptorFqName = resolvedCall.resultingDescriptor.fqNameOrNull() ?: return null
if (!descriptorFqName.isSubpackageOf(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)) return null
if (!KotlinBuiltIns.isUnderKotlinPackage(resolvedCall.resultingDescriptor)) return null
val resultingDescriptorName = resolvedCall.resultingDescriptor.name
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.calls.checkers.hasSubpackageOfKotlin
import org.jetbrains.kotlin.resolve.calls.checkers.isOperatorMod
import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -190,7 +189,7 @@ private fun deprecationByOverridden(root: CallableMemberDescriptor, languageVers
private fun DeclarationDescriptor.getOwnDeprecations(languageVersionSettings: LanguageVersionSettings): List<Deprecation> {
// The problem is that declaration `mod` in built-ins has @Deprecated annotation but actually it was deprecated only in version 1.1
if (this is FunctionDescriptor && this.isOperatorMod() && this.hasSubpackageOfKotlin()) {
if (this is FunctionDescriptor && this.isOperatorMod() && KotlinBuiltIns.isUnderKotlinPackage(this)) {
if (!shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
return emptyList()
}
@@ -210,8 +210,8 @@ class LazyJavaClassDescriptor(
}
private fun getPurelyImplementedSupertype(): KotlinType? {
val annotatedPurelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation()?.takeIf {
!it.isRoot && it.toUnsafe().startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)
val annotatedPurelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation()?.takeIf { fqName ->
!fqName.isRoot && fqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)
}
val purelyImplementedFqName =
@@ -381,6 +381,20 @@ public abstract class KotlinBuiltIns {
return DescriptorUtils.getParentOfType(descriptor, BuiltInsPackageFragment.class, false) != null;
}
/**
* @return true if the containing package of the descriptor is "kotlin" or any subpackage of "kotlin"
*/
public static boolean isUnderKotlinPackage(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor current = descriptor;
while (current != null) {
if (current instanceof PackageFragmentDescriptor) {
return ((PackageFragmentDescriptor) current).getFqName().startsWith(BUILT_INS_PACKAGE_NAME);
}
current = current.getContainingDeclaration();
}
return false;
}
@NotNull
public MemberScope getBuiltInsPackageScope() {
return packageFragments.invoke().builtInsPackageFragment.getMemberScope();
@@ -98,6 +98,10 @@ public final class FqName {
return fqName.pathSegments();
}
public boolean startsWith(@NotNull Name segment) {
return fqName.startsWith(segment);
}
@NotNull
public static FqName topLevel(@NotNull Name shortName) {
return new FqName(FqNameUnsafe.topLevel(shortName));