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:
Yan Zhulanow
2016-06-15 21:22:25 +03:00
parent 6752df189d
commit 206e439595
10 changed files with 81 additions and 2 deletions
@@ -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}"
@@ -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
@@ -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()
}
@@ -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
}
@@ -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)
@@ -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
View File
@@ -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 {