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)
|
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 {
|
override fun visitSimpleReferenceExpression(node: USimpleReferenceExpression): Boolean {
|
||||||
checkVersion(context, node, node.resolve(context) as? UVariable)
|
checkVersion(context, node, node.resolve(context) as? UVariable)
|
||||||
return super.visitSimpleReferenceExpression(node)
|
return super.visitSimpleReferenceExpression(node)
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ interface UBinaryExpressionWithType : UExpression {
|
|||||||
*/
|
*/
|
||||||
val type: UType
|
val type: UType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type reference.
|
||||||
|
*/
|
||||||
|
val typeReference: UTypeReference?
|
||||||
|
|
||||||
override fun logString() = log("UBinaryExpressionWithType (${getExpressionType()?.name}, ${operationKind.name})", operand)
|
override fun logString() = log("UBinaryExpressionWithType (${getExpressionType()?.name}, ${operationKind.name})", operand)
|
||||||
override fun renderString() = "${operand.renderString()} ${operationKind.name} ${type.name}"
|
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 com.intellij.psi.PsiInstanceOfExpression
|
||||||
import org.jetbrains.uast.UBinaryExpressionWithType
|
import org.jetbrains.uast.UBinaryExpressionWithType
|
||||||
import org.jetbrains.uast.UElement
|
import org.jetbrains.uast.UElement
|
||||||
|
import org.jetbrains.uast.UTypeReference
|
||||||
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
|
|
||||||
@@ -27,6 +28,9 @@ class JavaUInstanceCheckExpression(
|
|||||||
) : JavaAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, JavaUElementWithType, JavaEvaluatableUElement {
|
) : JavaAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, JavaUElementWithType, JavaEvaluatableUElement {
|
||||||
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
||||||
override val type by lz { JavaConverter.convert(psi.checkType?.type, this) }
|
override val type by lz { JavaConverter.convert(psi.checkType?.type, this) }
|
||||||
|
|
||||||
|
override val typeReference: UTypeReference?
|
||||||
|
get() = null
|
||||||
|
|
||||||
override val operationKind: UastBinaryExpressionWithTypeKind.InstanceCheck
|
override val operationKind: UastBinaryExpressionWithTypeKind.InstanceCheck
|
||||||
get() = UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
get() = UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.uast.java
|
|||||||
import com.intellij.psi.PsiTypeCastExpression
|
import com.intellij.psi.PsiTypeCastExpression
|
||||||
import org.jetbrains.uast.UBinaryExpressionWithType
|
import org.jetbrains.uast.UBinaryExpressionWithType
|
||||||
import org.jetbrains.uast.UElement
|
import org.jetbrains.uast.UElement
|
||||||
|
import org.jetbrains.uast.UTypeReference
|
||||||
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
import org.jetbrains.uast.UastBinaryExpressionWithTypeKind
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
|
|
||||||
@@ -28,6 +29,9 @@ class JavaUTypeCastExpression(
|
|||||||
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
override val operand by lz { JavaConverter.convertOrEmpty(psi.operand, this) }
|
||||||
override val type by lz { JavaConverter.convert(psi.castType?.type, this) }
|
override val type by lz { JavaConverter.convert(psi.castType?.type, this) }
|
||||||
|
|
||||||
|
override val typeReference: UTypeReference?
|
||||||
|
get() = null
|
||||||
|
|
||||||
override val operationKind: UastBinaryExpressionWithTypeKind.TypeCast
|
override val operationKind: UastBinaryExpressionWithTypeKind.TypeCast
|
||||||
get() = UastBinaryExpressionWithTypeKind.TYPE_CAST
|
get() = UastBinaryExpressionWithTypeKind.TYPE_CAST
|
||||||
}
|
}
|
||||||
@@ -188,6 +188,10 @@ internal object KotlinConverter : UastConverter {
|
|||||||
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return UastErrorType
|
val type = bindingContext[BindingContext.TYPE, typeReference] ?: return UastErrorType
|
||||||
return KotlinUType(type, typeReference.project, parent, typeReference.typeElement)
|
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? {
|
internal fun asSimpleReference(element: PsiElement?, parent: UElement): USimpleReferenceExpression? {
|
||||||
if (element == null) return null
|
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 {
|
) : KotlinAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||||
override val operand by lz { KotlinConverter.convert(psi.left, this) }
|
override val operand by lz { KotlinConverter.convert(psi.left, this) }
|
||||||
override val type by lz { KotlinConverter.convert(psi.right, 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()) {
|
override val operationKind = when (psi.operationReference.getReferencedNameElementType()) {
|
||||||
KtTokens.AS_KEYWORD -> UastBinaryExpressionWithTypeKind.TYPE_CAST
|
KtTokens.AS_KEYWORD -> UastBinaryExpressionWithTypeKind.TYPE_CAST
|
||||||
KtTokens.AS_SAFE -> KotlinBinaryExpressionWithTypeKinds.SAFE_TYPE_CAST
|
KtTokens.AS_SAFE -> KotlinBinaryExpressionWithTypeKinds.SAFE_TYPE_CAST
|
||||||
@@ -47,4 +48,7 @@ class KotlinCustomUBinaryExpressionWithType(
|
|||||||
|
|
||||||
lateinit override var type: UType
|
lateinit override var type: UType
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
|
override var typeReference: UTypeReference? = null
|
||||||
|
internal set
|
||||||
}
|
}
|
||||||
+3
-1
@@ -64,7 +64,9 @@ class KotlinUSwitchEntry(
|
|||||||
it.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
it.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
||||||
else -> UastBinaryExpressionWithTypeKind.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)
|
is KtWhenConditionWithExpression -> KotlinConverter.convertOrEmpty(it.expression, this)
|
||||||
else -> EmptyUExpression(this)
|
else -> EmptyUExpression(this)
|
||||||
|
|||||||
+1
@@ -27,5 +27,6 @@ class KotlinUTypeCheckExpression(
|
|||||||
) : KotlinAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
|
) : KotlinAbstractUElement(), UBinaryExpressionWithType, PsiElementBacked, KotlinUElementWithType, KotlinEvaluatableUElement {
|
||||||
override val operand by lz { KotlinConverter.convert(psi.leftHandSide, this) }
|
override val operand by lz { KotlinConverter.convert(psi.leftHandSide, this) }
|
||||||
override val type by lz { KotlinConverter.convert(psi.typeReference, 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
|
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.DOMErrorHandler
|
||||||
import org.w3c.dom.DOMLocator
|
import org.w3c.dom.DOMLocator
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.ViewGroup.LayoutParams
|
import android.view.ViewGroup.LayoutParams
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.ApplicationErrorReport
|
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) {
|
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
|
GridLayout(null).getOrientation(); // Not flagged
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user