KT-12023 Kotlin Lint: Cast doesn't trigger minSdk error
Check Kotlin as/is types. (cherry picked from commit c0db8e0)
This commit is contained in:
@@ -68,6 +68,15 @@ open class ApiDetector : Detector(), UastScanner {
|
||||
return super.visitCallExpression(node)
|
||||
}
|
||||
|
||||
override fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType): Boolean {
|
||||
val typeRef = node.typeReference
|
||||
if (typeRef != null) {
|
||||
checkVersion(context, typeRef, node.type.resolve(context))
|
||||
}
|
||||
|
||||
return super.visitBinaryExpressionWithType(node)
|
||||
}
|
||||
|
||||
override fun visitSimpleReferenceExpression(node: USimpleReferenceExpression): Boolean {
|
||||
checkVersion(context, node, node.resolve(context) as? UVariable)
|
||||
return super.visitSimpleReferenceExpression(node)
|
||||
|
||||
@@ -36,6 +36,11 @@ interface UBinaryExpressionWithType : UExpression {
|
||||
*/
|
||||
val type: UType
|
||||
|
||||
/**
|
||||
* Returns the type reference.
|
||||
*/
|
||||
val typeReference: UTypeReference?
|
||||
|
||||
override fun logString() = log("UBinaryExpressionWithType (${getExpressionType()?.name}, ${operationKind.name})", operand)
|
||||
override fun renderString() = "${operand.renderString()} ${operationKind.name} ${type.name}"
|
||||
|
||||
|
||||
+4
@@ -18,6 +18,7 @@ package org.jetbrains.uast.java
|
||||
import com.intellij.psi.PsiInstanceOfExpression
|
||||
import org.jetbrains.uast.UBinaryExpressionWithType
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UTypeReference
|
||||
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
||||
import org.jetbrains.uast.psi.PsiElementBacked
|
||||
|
||||
@@ -27,6 +28,9 @@ class JavaUInstanceCheckExpression(
|
||||
) : JavaAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, JavaUElementWithType, JavaEvaluatableUElement {
|
||||
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
||||
override val type by lz { JavaConverter.convert(psi.checkType?.type, this) }
|
||||
|
||||
override val typeReference: UTypeReference?
|
||||
get() = null
|
||||
|
||||
override val operationKind: UastBinaryExpressionWithTypeKind.InstanceCheck
|
||||
get() = UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.uast.java
|
||||
import com.intellij.psi.PsiTypeCastExpression
|
||||
import org.jetbrains.uast.UBinaryExpressionWithType
|
||||
import org.jetbrains.uast.UElement
|
||||
import org.jetbrains.uast.UTypeReference
|
||||
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
||||
import org.jetbrains.uast.psi.PsiElementBacked
|
||||
|
||||
@@ -28,6 +29,9 @@ class JavaUTypeCastExpression(
|
||||
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
||||
override val type by lz { JavaConverter.convert(psi.castType?.type, this) }
|
||||
|
||||
override val typeReference: UTypeReference?
|
||||
get() = null
|
||||
|
||||
override val operationKind: UastBinaryExpressionWithTypeKind.TypeCast
|
||||
get() = UastBinaryExpressionWithTypeKind.TYPE_CAST
|
||||
}
|
||||
@@ -188,6 +188,10 @@ internal object KotlinConverter : UastConverter {
|
||||
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return UastErrorType
|
||||
return KotlinUType(type, typeReference.project, parent, typeReference.typeElement)
|
||||
}
|
||||
|
||||
internal fun convertTypeReference(typeReference: KtTypeReference, parent: UElement): UTypeReference {
|
||||
return KotlinUTypeReference(typeReference, parent)
|
||||
}
|
||||
|
||||
internal fun asSimpleReference(element: PsiElement?, parent: UElement): USimpleReferenceExpression? {
|
||||
if (element == null) return null
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.uast
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.psi.PsiElementBacked
|
||||
|
||||
class KotlinUTypeReference(
|
||||
override val psi: KtTypeReference,
|
||||
override val parent: UElement
|
||||
) : KotlinAbstractUElement(), UTypeReference, PsiElementBacked {
|
||||
override fun resolve(context: UastContext): UClass? {
|
||||
val descriptor = psi.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, psi]
|
||||
?.constructor?.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
return context.convert(descriptor.toSource()) as? UClass
|
||||
}
|
||||
|
||||
override val nameElement: UElement?
|
||||
get() = KotlinDumbUElement(psi, this)
|
||||
|
||||
override val name: String
|
||||
get() = psi.name.orAnonymous()
|
||||
}
|
||||
+4
@@ -28,6 +28,7 @@ class KotlinUBinaryExpressionWithType(
|
||||
) : KotlinAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||
override val operand by lz { KotlinConverter.convert(psi.left, this) }
|
||||
override val type by lz { KotlinConverter.convert(psi.right, this) }
|
||||
override val typeReference by lz { psi.right?.let { KotlinConverter.convertTypeReference(it, this) } }
|
||||
override val operationKind = when (psi.operationReference.getReferencedNameElementType()) {
|
||||
KtTokens.AS_KEYWORD -> UastBinaryExpressionWithTypeKind.TYPE_CAST
|
||||
KtTokens.AS_SAFE -> KotlinBinaryExpressionWithTypeKinds.SAFE_TYPE_CAST
|
||||
@@ -47,4 +48,7 @@ class KotlinCustomUBinaryExpressionWithType(
|
||||
|
||||
lateinit override var type: UType
|
||||
internal set
|
||||
|
||||
override var typeReference: UTypeReference? = null
|
||||
internal set
|
||||
}
|
||||
+3
-1
@@ -64,7 +64,9 @@ class KotlinUSwitchEntry(
|
||||
it.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||
}
|
||||
type = KotlinConverter.convert(it.typeReference, this)
|
||||
val typeRef = it.typeReference
|
||||
type = KotlinConverter.convert(typeRef, this)
|
||||
typeReference = typeRef?.let { KotlinConverter.convertTypeReference(it, this) }
|
||||
}
|
||||
is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(it.expression, this)
|
||||
else -> EmptyUExpression(this)
|
||||
|
||||
+1
@@ -27,5 +27,6 @@ class KotlinUTypeCheckExpression(
|
||||
) : KotlinAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||
override val operand by lz { KotlinConverter.convert(psi.leftHandSide, this) }
|
||||
override val type by lz { KotlinConverter.convert(psi.typeReference, this) }
|
||||
override val typeReference by lz { psi.typeReference?.let { KotlinConverter.convertTypeReference(it, this) } }
|
||||
override val operationKind = KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||
}
|
||||
+5
-1
@@ -8,6 +8,7 @@ import org.w3c.dom.DOMError
|
||||
import org.w3c.dom.DOMErrorHandler
|
||||
import org.w3c.dom.DOMLocator
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import android.app.Activity
|
||||
import android.app.ApplicationErrorReport
|
||||
@@ -108,7 +109,10 @@ class ApiCallTest: Activity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun test(priority: Boolean) {
|
||||
fun test(priority: Boolean, layout: ViewGroup) {
|
||||
if (layout is <error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout</error>) {}
|
||||
layout as? <error descr="Class requires API level 14 (current min is 1): `GridLayout`">GridLayout</error>
|
||||
|
||||
if (android.os.Build.VERSION.<error descr="Field requires API level 4 (current min is 1): `SDK_INT`">SDK_INT</error> >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
GridLayout(null).getOrientation(); // Not flagged
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user