Replace getJetTypeFqName with fqNameOrNull extension (#3613)

* Replace getJetTypeFqName with fqNameOrNull extension

* Remove usage of nameIfStandardType

This is from the org.jetbrains.kotlin.js package which should be avoided
while detekt is limited to Kotlin/JVM analysis only.

* Use KotlinType.fqNameOrNull extension to simplify rule
This commit is contained in:
Matthew Haughton
2021-03-30 05:42:56 +11:00
committed by GitHub
parent 14f655eb62
commit 31bf79e73b
11 changed files with 49 additions and 47 deletions

View File

@@ -8,7 +8,7 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.valueOrDefaultCommaSeparated
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtLambdaExpression
@@ -98,13 +98,14 @@ class SpekTestDiscovery(config: Config = Config.empty) : Rule(config) {
if (!property.hasDelegate()) {
val initExpr = property.initializer
val fqType = initExpr?.getType(bindingContext)
?.getJetTypeFqName(false)
?.fqNameOrNull()
?.asString()
if (fqType != null && fqType !in allowedTypes) {
report(
CodeSmell(
issue,
Entity.atName(property),
"Variable declarations which do not met the allowed types should be memoized."
"Variable declarations which do not meet the allowed types should be memoized."
)
)
}

View File

@@ -126,3 +126,7 @@ public final class io/gitlab/arturbosch/detekt/rules/TraversingKt {
public static final fun isPublicInherited (Lorg/jetbrains/kotlin/psi/KtNamedDeclaration;)Z
}
public final class io/gitlab/arturbosch/detekt/rules/TypeUtilsKt {
public static final fun fqNameOrNull (Lorg/jetbrains/kotlin/types/KotlinType;)Lorg/jetbrains/kotlin/name/FqName;
}

View File

@@ -0,0 +1,10 @@
package io.gitlab.arturbosch.detekt.rules
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
fun KotlinType.fqNameOrNull(): FqName? {
return TypeUtils.getClassDescriptor(this)?.fqNameOrNull()
}

View File

@@ -8,7 +8,7 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.BindingContext
@@ -92,7 +92,7 @@ class SuspendFunWithFlowReturnType(config: Config) : Rule(config) {
yield(this@isCoroutinesFlow)
yieldAll(this@isCoroutinesFlow.supertypes())
}
.map { it.getJetTypeFqName(printTypeArguments = false) }
.mapNotNull { it.fqNameOrNull()?.asString() }
.contains("kotlinx.coroutines.flow.Flow")
}
}

View File

@@ -8,8 +8,8 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import io.gitlab.arturbosch.detekt.rules.safeAs
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtIsExpression
@@ -66,8 +66,9 @@ class DontDowncastCollectionTypes(config: Config) : Rule(config) {
private fun checkForDowncast(parent: KtExpression, left: KtExpression, right: KtTypeReference?) {
val lhsType = left
.getType(bindingContext)
?.nameIfStandardType
?.identifier
?.fqNameOrNull()
?.shortName()
?.asString()
val rhsType = right
?.typeElement

View File

@@ -8,8 +8,8 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import io.gitlab.arturbosch.detekt.rules.identifierName
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
@@ -88,6 +88,7 @@ class NonBooleanPropertyPrefixedWithIs(config: Config = Config.empty) : Rule(con
private fun getTypeName(parameter: KtCallableDeclaration): String? {
return parameter.createTypeBindingForReturnType(bindingContext)
?.type
?.getJetTypeFqName(false)
?.fqNameOrNull()
?.asString()
}
}

View File

@@ -7,7 +7,7 @@ import io.gitlab.arturbosch.detekt.api.Entity
import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import org.jetbrains.kotlin.js.descriptorUtils.nameIfStandardType
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtElement
@@ -34,7 +34,12 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
*/
class ExplicitCollectionElementAccessMethod(config: Config = Config.empty) : Rule(config) {
private val ktCollections = setOf("Map", "MutableMap", "List", "MutableList")
private val ktCollections = setOf(
"kotlin.collections.Map",
"kotlin.collections.MutableMap",
"kotlin.collections.List",
"kotlin.collections.MutableList"
)
private val mapAccessMethods = setOf("get", "put")
@@ -72,23 +77,7 @@ class ExplicitCollectionElementAccessMethod(config: Config = Config.empty) : Rul
}
private fun KotlinType?.isEligibleCollection(): Boolean {
this?.nameIfStandardType?.let {
return it.toString() in ktCollections
}
return this?.collectTypes()?.any { it.constructor.toString() in ktAndJavaCollections } == true
}
private fun KotlinType.collectTypes(): Set<KotlinType> {
val result = mutableSetOf<KotlinType>()
this
.constructor
.supertypes
.forEach { type ->
result.add(type)
type.supertypes().forEach {
result.addAll(it.collectTypes())
}
}
return result
if (this?.fqNameOrNull()?.asString() in ktCollections) return true
return this?.supertypes()?.any { it.constructor.toString() in ktAndJavaCollections } == true
}
}

View File

@@ -10,7 +10,7 @@ import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.api.internal.valueOrDefaultCommaSeparated
import io.gitlab.arturbosch.detekt.rules.extractMethodNameAndParams
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
@@ -79,7 +79,7 @@ class ForbiddenMethodCall(config: Config = Config.empty) : Rule(config) {
val resolvedCall = expression.getResolvedCall(bindingContext) ?: return
val methodName = resolvedCall.resultingDescriptor.fqNameOrNull()?.asString()
val encounteredParamTypes = resolvedCall.resultingDescriptor.valueParameters
.map { it.type.getJetTypeFqName(false) }
.map { it.type.fqNameOrNull()?.asString() }
if (methodName != null) {
forbiddenMethods

View File

@@ -8,7 +8,9 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import io.gitlab.arturbosch.detekt.rules.isOverride
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtTypeArgumentList
@@ -17,7 +19,6 @@ import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
/**
* This rule detects usages of `Void` and reports them as forbidden.
@@ -53,7 +54,7 @@ class ForbiddenVoid(config: Config = Config.empty) : Rule(config) {
if (bindingContext == BindingContext.EMPTY) return
val kotlinType = typeReference.getAbbreviatedTypeOrType(bindingContext) ?: return
if (kotlinType.constructor.declarationDescriptor?.fqNameOrNull()?.asString() == VOID_CLASS_NAME) {
if (kotlinType.fqNameOrNull() == VOID_FQ_NAME) {
if (ruleSetConfig.valueOrDefault(IGNORE_OVERRIDDEN, false) && typeReference.isPartOfOverriddenSignature()) {
return
}
@@ -84,6 +85,6 @@ class ForbiddenVoid(config: Config = Config.empty) : Rule(config) {
companion object {
const val IGNORE_OVERRIDDEN = "ignoreOverridden"
const val IGNORE_USAGE_IN_GENERICS = "ignoreUsageInGenerics"
const val VOID_CLASS_NAME = "java.lang.Void"
val VOID_FQ_NAME = FqName("java.lang.Void")
}
}

View File

@@ -8,6 +8,7 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCallExpression
@@ -22,8 +23,8 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
/**
* Redundant maps add complexity to the code and accomplish nothing. They should be removed or replaced with the proper
@@ -74,7 +75,7 @@ import org.jetbrains.kotlin.types.KotlinType
@Suppress("ReturnCount")
class RedundantHigherOrderMapUsage(config: Config = Config.empty) : Rule(config) {
override val issue: Issue = Issue(
"RedundantHigherOrderMapUsage",
javaClass.simpleName,
Severity.Style,
"Checks for Redundant 'map' calls.",
Debt.FIVE_MINS
@@ -115,13 +116,8 @@ class RedundantHigherOrderMapUsage(config: Config = Config.empty) : Rule(config)
return lambda
}
private fun KotlinType.isInheritorOf(fqName: FqName): Boolean {
return isTypeOf(fqName) || constructor.supertypes.any { it.isTypeOf(fqName) }
}
private fun KotlinType.isTypeOf(fqName: FqName): Boolean {
return constructor.declarationDescriptor?.fqNameSafe == fqName
}
private fun KotlinType.isInheritorOf(fqName: FqName): Boolean =
fqNameOrNull() == fqName || immediateSupertypes().any { it.fqNameOrNull() == fqName }
private fun KtFunctionLiteral.isRedundant(lambdaStatements: List<KtExpression>): Boolean {
val lambdaDescriptor = bindingContext[BindingContext.FUNCTION, this] ?: return false

View File

@@ -8,8 +8,8 @@ import io.gitlab.arturbosch.detekt.api.Issue
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.RequiresTypeResolution
import io.gitlab.arturbosch.detekt.rules.fqNameOrNull
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtBinaryExpression
@@ -138,8 +138,7 @@ class UseIsNullOrEmpty(config: Config = Config.empty) : Rule(config) {
callExpression.getResolvedCall(bindingContext)?.resultingDescriptor?.fqNameOrNull() in fqNames
}
private fun KtSimpleNameExpression.classFqName() =
getType(bindingContext)?.constructor?.declarationDescriptor.safeAs<ClassDescriptor>()?.fqNameOrNull()
private fun KtSimpleNameExpression.classFqName() = getType(bindingContext)?.fqNameOrNull()
private fun KtSimpleNameExpression.isCollectionOrArrayOrString(): Boolean {
val classFqName = classFqName() ?: return false