Lint: Review changes
This commit is contained in:
@@ -365,9 +365,9 @@ public class CleanupDetector extends Detector implements UastScanner {
|
|||||||
// getFragmentManager().beginTransaction().addToBackStack("test")
|
// getFragmentManager().beginTransaction().addToBackStack("test")
|
||||||
// .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test")
|
// .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test")
|
||||||
// .show(mFragment2).setCustomAnimations(0, 0).commit();
|
// .show(mFragment2).setCustomAnimations(0, 0).commit();
|
||||||
List<UExpression> chains = UastUtils.getQualifiedChains(node);
|
List<UExpression> chain = UastUtils.getQualifiedChain(node);
|
||||||
if (chains.size() > 0) {
|
if (chain.size() > 0) {
|
||||||
UExpression lastExpression = chains.get(chains.size() - 1);
|
UExpression lastExpression = chain.get(chain.size() - 1);
|
||||||
if (lastExpression instanceof UCallExpression) {
|
if (lastExpression instanceof UCallExpression) {
|
||||||
UCallExpression methodInvocation = (UCallExpression) lastExpression;
|
UCallExpression methodInvocation = (UCallExpression) lastExpression;
|
||||||
if (isTransactionCommitMethodCall(context, methodInvocation)
|
if (isTransactionCommitMethodCall(context, methodInvocation)
|
||||||
@@ -418,7 +418,7 @@ public class CleanupDetector extends Detector implements UastScanner {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
UQualifiedExpression topMostQualified = UastUtils.findTopMostQualifiedExpression(((UExpression) expression));
|
UQualifiedExpression topMostQualified = UastUtils.findOutermostQualifiedExpression(((UExpression) expression));
|
||||||
if (topMostQualified == null) {
|
if (topMostQualified == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public class ParcelDetector extends Detector implements UastScanner {
|
|||||||
String name = reference.getName();
|
String name = reference.getName();
|
||||||
if (name.equals("Parcelable")) {
|
if (name.equals("Parcelable")) {
|
||||||
UVariable field = UastUtils.findStaticMemberOfType(node, "CREATOR", UVariable.class);
|
UVariable field = UastUtils.findStaticMemberOfType(node, "CREATOR", UVariable.class);
|
||||||
boolean hasField = field != null && field.hasModifier(UastModifier.FIELD);
|
boolean hasField = field != null && field.hasModifier(UastModifier.JVM_FIELD) && field.hasModifier(UastModifier.STATIC);
|
||||||
boolean hasNamedCompanionObject = false;
|
boolean hasNamedCompanionObject = false;
|
||||||
if (!hasField) {
|
if (!hasField) {
|
||||||
for (UClass companion : node.getCompanions()) {
|
for (UClass companion : node.getCompanions()) {
|
||||||
|
|||||||
@@ -140,6 +140,12 @@ fun UClass.getAllDeclarations(context: UastContext): List<UDeclaration> = mutabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all functions in class (including supertypes).
|
||||||
|
*
|
||||||
|
* @param context the Uast context
|
||||||
|
* @return the list of functions for the receiver class and its supertypes
|
||||||
|
*/
|
||||||
fun UClass.getAllFunctions(context: UastContext) = getAllDeclarations(context).filterIsInstance<UFunction>()
|
fun UClass.getAllFunctions(context: UastContext) = getAllDeclarations(context).filterIsInstance<UFunction>()
|
||||||
|
|
||||||
tailrec fun UQualifiedExpression.getCallElementFromQualified(): UCallExpression? {
|
tailrec fun UQualifiedExpression.getCallElementFromQualified(): UCallExpression? {
|
||||||
@@ -151,22 +157,19 @@ tailrec fun UQualifiedExpression.getCallElementFromQualified(): UCallExpression?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun UCallExpression.getQualifiedCallElement(): UExpression {
|
/**
|
||||||
fun findParent(parent: UExpression?, current: UExpression): UExpression? = when (parent) {
|
* Get the nearest parent of the type [T].
|
||||||
is UQualifiedExpression -> {
|
*
|
||||||
if (parent.selector == current)
|
* @return the nearest parent of type [T], or null if the parent with such type was not found.
|
||||||
findParent(parent.parent as? UExpression, parent) ?: parent
|
*/
|
||||||
else
|
|
||||||
current
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
return findParent(parent as? UExpression, this) ?: this
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T: UElement> UElement.getParentOfType(): T? = getParentOfType(T::class.java)
|
inline fun <reified T: UElement> UElement.getParentOfType(): T? = getParentOfType(T::class.java)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the nearest parent of the type [T].
|
||||||
|
*
|
||||||
|
* @param strict if false, return the received element if it's type is [T], do not check the received element overwise.
|
||||||
|
* @return the nearest parent of type [T], or null if the parent with such type was not found.
|
||||||
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun <T: UElement> UElement.getParentOfType(clazz: Class<T>, strict: Boolean = true): T? {
|
fun <T: UElement> UElement.getParentOfType(clazz: Class<T>, strict: Boolean = true): T? {
|
||||||
tailrec fun findParent(element: UElement?): UElement? {
|
tailrec fun findParent(element: UElement?): UElement? {
|
||||||
@@ -181,6 +184,35 @@ fun <T: UElement> UElement.getParentOfType(clazz: Class<T>, strict: Boolean = tr
|
|||||||
return findParent(if (!strict) this else parent) as? T
|
return findParent(if (!strict) this else parent) as? T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the topmost parent qualified expression for the call expression.
|
||||||
|
*
|
||||||
|
* Example 1:
|
||||||
|
* Code: variable.call(args)
|
||||||
|
* Call element: E = call(args)
|
||||||
|
* Qualified call element: Q = [getQualifiedCallElement](E) = variable.call(args)
|
||||||
|
*
|
||||||
|
* Example 2:
|
||||||
|
* Code: call(args)
|
||||||
|
* Call element: E = call(args)
|
||||||
|
* Qualified call element: Q = [getQualifiedCallElement](E) = call(args) (no qualifier)
|
||||||
|
*
|
||||||
|
* @return containing qualified expression if the call is a child of the qualified expression, call element otherwise.
|
||||||
|
*/
|
||||||
|
fun UCallExpression.getQualifiedCallElement(): UExpression {
|
||||||
|
fun findParent(current: UExpression?, previous: UExpression): UExpression? = when (current) {
|
||||||
|
is UQualifiedExpression -> {
|
||||||
|
if (current.selector == previous)
|
||||||
|
findParent(current.parent as? UExpression, current) ?: current
|
||||||
|
else
|
||||||
|
previous
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
return findParent(parent as? UExpression, this) ?: this
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> UClass.findStaticMemberOfType(name: String, type: Class<out T>): T? {
|
fun <T> UClass.findStaticMemberOfType(name: String, type: Class<out T>): T? {
|
||||||
for (companion in companions) {
|
for (companion in companions) {
|
||||||
val member = companion.declarations.firstOrNull {
|
val member = companion.declarations.firstOrNull {
|
||||||
@@ -198,6 +230,12 @@ fun <T> UClass.findStaticMemberOfType(name: String, type: Class<out T>): T? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun UExpression.asQualifiedIdentifiers(): List<String>? {
|
fun UExpression.asQualifiedIdentifiers(): List<String>? {
|
||||||
|
if (this is USimpleReferenceExpression) {
|
||||||
|
return listOf(this.identifier)
|
||||||
|
} else if (this !is UQualifiedExpression) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
var error = false
|
var error = false
|
||||||
val list = mutableListOf<String>()
|
val list = mutableListOf<String>()
|
||||||
fun addIdentifiers(expr: UQualifiedExpression) {
|
fun addIdentifiers(expr: UQualifiedExpression) {
|
||||||
@@ -213,20 +251,29 @@ fun UExpression.asQualifiedIdentifiers(): List<String>? {
|
|||||||
}
|
}
|
||||||
list += selector.identifier
|
list += selector.identifier
|
||||||
}
|
}
|
||||||
when (this) {
|
|
||||||
is UQualifiedExpression -> addIdentifiers(this)
|
addIdentifiers(this)
|
||||||
is USimpleReferenceExpression -> list += identifier
|
|
||||||
else -> return null
|
|
||||||
}
|
|
||||||
return if (error) null else list
|
return if (error) null else list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the received expression is a qualified chain of identifiers, and the chain is [fqName].
|
||||||
|
*
|
||||||
|
* @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example".
|
||||||
|
* @return true, if the received expression is a qualified chain of identifiers, and the chain is [fqName].
|
||||||
|
*/
|
||||||
fun UExpression.matchesQualified(fqName: String): Boolean {
|
fun UExpression.matchesQualified(fqName: String): Boolean {
|
||||||
val identifiers = this.asQualifiedIdentifiers() ?: return false
|
val identifiers = this.asQualifiedIdentifiers() ?: return false
|
||||||
val passedIdentifiers = fqName.split('.')
|
val passedIdentifiers = fqName.split('.')
|
||||||
return identifiers == passedIdentifiers
|
return identifiers == passedIdentifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the received expression is a qualified chain of identifiers, and the leading part of such chain is [fqName].
|
||||||
|
*
|
||||||
|
* @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example".
|
||||||
|
* @return true, if the received expression is a qualified chain of identifiers, and the leading part of such chain is [fqName].
|
||||||
|
*/
|
||||||
fun UExpression.startsWithQualified(fqName: String): Boolean {
|
fun UExpression.startsWithQualified(fqName: String): Boolean {
|
||||||
val identifiers = this.asQualifiedIdentifiers() ?: return false
|
val identifiers = this.asQualifiedIdentifiers() ?: return false
|
||||||
val passedIdentifiers = fqName.trim('.').split('.')
|
val passedIdentifiers = fqName.trim('.').split('.')
|
||||||
@@ -237,6 +284,12 @@ fun UExpression.startsWithQualified(fqName: String): Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName].
|
||||||
|
*
|
||||||
|
* @param fqName the chain part to check against. Sequence of identifiers, separated by dot ('.'). Example: "com.example".
|
||||||
|
* @return true, if the received expression is a qualified chain of identifiers, and the trailing part of such chain is [fqName].
|
||||||
|
*/
|
||||||
fun UExpression.endsWithQualified(fqName: String): Boolean {
|
fun UExpression.endsWithQualified(fqName: String): Boolean {
|
||||||
val identifiers = this.asQualifiedIdentifiers()?.asReversed() ?: return false
|
val identifiers = this.asQualifiedIdentifiers()?.asReversed() ?: return false
|
||||||
val passedIdentifiers = fqName.trim('.').split('.').asReversed()
|
val passedIdentifiers = fqName.trim('.').split('.').asReversed()
|
||||||
@@ -247,15 +300,31 @@ fun UExpression.endsWithQualified(fqName: String): Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun UExpression.findTopMostQualifiedExpression(): UQualifiedExpression? {
|
/**
|
||||||
|
* Return the outermost qualified expression.
|
||||||
|
*
|
||||||
|
* @return the outermost qualified expression,
|
||||||
|
* this element if the parent expression is not a qualified expression,
|
||||||
|
* or null if the element is not a qualified expression.
|
||||||
|
*/
|
||||||
|
fun UExpression.findOutermostQualifiedExpression(): UQualifiedExpression? {
|
||||||
val parent = this.parent
|
val parent = this.parent
|
||||||
return when (parent) {
|
return when (parent) {
|
||||||
is UQualifiedExpression -> parent.findTopMostQualifiedExpression()
|
is UQualifiedExpression -> parent.findOutermostQualifiedExpression()
|
||||||
else -> if (this is UQualifiedExpression) this else null
|
else -> if (this is UQualifiedExpression) this else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun UExpression.getQualifiedChains(): List<UExpression> {
|
/**
|
||||||
|
* Return the list of qualified expressions.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* Code: obj.call(param).anotherCall(param2).getter
|
||||||
|
* Qualified chain: [obj, call(param), anotherCall(param2), getter]
|
||||||
|
*
|
||||||
|
* @return list of qualified expressions, or the empty list if the received expression is not a qualified expression.
|
||||||
|
*/
|
||||||
|
fun UExpression.getQualifiedChain(): List<UExpression> {
|
||||||
fun collect(expr: UQualifiedExpression, chains: MutableList<UExpression>) {
|
fun collect(expr: UQualifiedExpression, chains: MutableList<UExpression>) {
|
||||||
val receiver = expr.receiver
|
val receiver = expr.receiver
|
||||||
if (receiver is UQualifiedExpression) {
|
if (receiver is UQualifiedExpression) {
|
||||||
@@ -272,7 +341,7 @@ fun UExpression.getQualifiedChains(): List<UExpression> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val qualifiedExpression = this.findTopMostQualifiedExpression() ?: return emptyList()
|
val qualifiedExpression = this.findOutermostQualifiedExpression() ?: return emptyList()
|
||||||
val chains = mutableListOf<UExpression>()
|
val chains = mutableListOf<UExpression>()
|
||||||
collect(qualifiedExpression, chains)
|
collect(qualifiedExpression, chains)
|
||||||
return chains
|
return chains
|
||||||
|
|||||||
@@ -35,8 +35,9 @@ open class UastModifier(val name: String) {
|
|||||||
@JvmField
|
@JvmField
|
||||||
val OVERRIDE = UastModifier("override")
|
val OVERRIDE = UastModifier("override")
|
||||||
@JvmField
|
@JvmField
|
||||||
val FIELD = UastModifier("field")
|
val JVM_FIELD = UastModifier("field")
|
||||||
|
|
||||||
|
// JVM-related modifiers are not listed here
|
||||||
val VALUES = listOf(ABSTRACT, STATIC, FINAL, IMMUTABLE, VARARG, OVERRIDE)
|
val VALUES = listOf(ABSTRACT, STATIC, FINAL, IMMUTABLE, VARARG, OVERRIDE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,11 @@
|
|||||||
package org.jetbrains.uast.kinds
|
package org.jetbrains.uast.kinds
|
||||||
|
|
||||||
open class UastVariableInitialierKind(val name: String) {
|
open class UastVariableInitialierKind(val name: String) {
|
||||||
class Simple(name: String) : UastVariableInitialierKind(name)
|
class Expression(name: String) : UastVariableInitialierKind(name)
|
||||||
class Delegation(name: String) : UastVariableInitialierKind(name)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
val SIMPLE = Simple("simple")
|
val EXPRESSION = Expression("expression")
|
||||||
|
|
||||||
@JvmField
|
|
||||||
val DELEGATION = Simple("delegation")
|
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val NO_INITIALIZER = UastVariableInitialierKind("no_initializer")
|
val NO_INITIALIZER = UastVariableInitialierKind("no_initializer")
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ private class JavaUAnonymousClassConstructorParameter(
|
|||||||
override val initializer by lz { JavaConverter.convert(psi.expressions[index], this) }
|
override val initializer by lz { JavaConverter.convert(psi.expressions[index], this) }
|
||||||
|
|
||||||
override val initializerKind: UastVariableInitialierKind
|
override val initializerKind: UastVariableInitialierKind
|
||||||
get() = UastVariableInitialierKind.SIMPLE
|
get() = UastVariableInitialierKind.EXPRESSION
|
||||||
|
|
||||||
override val kind: UastVariableKind
|
override val kind: UastVariableKind
|
||||||
get() = UastVariableKind.VALUE_PARAMETER
|
get() = UastVariableKind.VALUE_PARAMETER
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import com.intellij.psi.PsiVariable
|
|||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
||||||
import org.jetbrains.uast.kinds.UastVariableInitialierKind.Companion.NO_INITIALIZER
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind.Companion.NO_INITIALIZER
|
||||||
import org.jetbrains.uast.kinds.UastVariableInitialierKind.Companion.SIMPLE
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind.Companion.EXPRESSION
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
|
|
||||||
class JavaUVariable(
|
class JavaUVariable(
|
||||||
@@ -37,7 +37,7 @@ class JavaUVariable(
|
|||||||
override val initializer by lz { JavaConverter.convertOrEmpty(psi.initializer, this) }
|
override val initializer by lz { JavaConverter.convertOrEmpty(psi.initializer, this) }
|
||||||
|
|
||||||
override val initializerKind: UastVariableInitialierKind
|
override val initializerKind: UastVariableInitialierKind
|
||||||
get() = if (psi.initializer != null) SIMPLE else NO_INITIALIZER
|
get() = if (psi.initializer != null) EXPRESSION else NO_INITIALIZER
|
||||||
|
|
||||||
override val kind = when (psi) {
|
override val kind = when (psi) {
|
||||||
is PsiField -> UastVariableKind.MEMBER
|
is PsiField -> UastVariableKind.MEMBER
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ private val MODIFIER_MAP = mapOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
internal fun PsiModifierListOwner.hasModifier(modifier: UastModifier): Boolean {
|
internal fun PsiModifierListOwner.hasModifier(modifier: UastModifier): Boolean {
|
||||||
if (modifier == UastModifier.FIELD && this is PsiField) {
|
if (modifier == UastModifier.JVM_FIELD && this is PsiField) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (modifier == UastModifier.OVERRIDE && this is PsiAnnotationOwner) {
|
if (modifier == UastModifier.OVERRIDE && this is PsiAnnotationOwner) {
|
||||||
|
|||||||
@@ -17,9 +17,14 @@
|
|||||||
package org.jetbrains.kotlin.uast
|
package org.jetbrains.kotlin.uast
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||||
|
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
|
||||||
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||||
@@ -69,10 +74,10 @@ class KotlinUClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val internalName by lz {
|
override val internalName by lz {
|
||||||
val generationState = psi.getGenerationState()
|
val descriptor = resolveToDescriptor() ?: return@lz null
|
||||||
val descriptor = generationState.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi]
|
val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null,
|
||||||
as? ClassDescriptor ?: return@lz null
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME)
|
||||||
generationState.typeMapper.mapClass(descriptor).internalName
|
typeMapper.mapClass(descriptor).internalName
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSuperClass(context: UastContext): UClass? {
|
override fun getSuperClass(context: UastContext): UClass? {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.uast.kinds.KotlinVariableInitializerKinds
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
@@ -42,9 +43,9 @@ open class KotlinUVariable(
|
|||||||
|
|
||||||
override val initializerKind by lz {
|
override val initializerKind by lz {
|
||||||
if ((psi as? KtProperty)?.delegateExpression != null)
|
if ((psi as? KtProperty)?.delegateExpression != null)
|
||||||
UastVariableInitialierKind.DELEGATION
|
KotlinVariableInitializerKinds.DELEGATION
|
||||||
else if (psi.initializer != null)
|
else if (psi.initializer != null)
|
||||||
UastVariableInitialierKind.SIMPLE
|
UastVariableInitialierKind.EXPRESSION
|
||||||
else
|
else
|
||||||
UastVariableInitialierKind.NO_INITIALIZER
|
UastVariableInitialierKind.NO_INITIALIZER
|
||||||
}
|
}
|
||||||
@@ -148,7 +149,10 @@ class KotlinDestructuringUVariable(
|
|||||||
override val initializer by lz { KotlinConverter.convertOrEmpty(psi.initializer, this) }
|
override val initializer by lz { KotlinConverter.convertOrEmpty(psi.initializer, this) }
|
||||||
|
|
||||||
override val initializerKind: UastVariableInitialierKind
|
override val initializerKind: UastVariableInitialierKind
|
||||||
get() = UastVariableInitialierKind.NO_INITIALIZER
|
get() = if (initializer != null)
|
||||||
|
UastVariableInitialierKind.EXPRESSION
|
||||||
|
else
|
||||||
|
UastVariableInitialierKind.NO_INITIALIZER
|
||||||
|
|
||||||
override val kind = UastVariableKind.LOCAL_VARIABLE
|
override val kind = UastVariableKind.LOCAL_VARIABLE
|
||||||
override val type: UType
|
override val type: UType
|
||||||
@@ -174,7 +178,10 @@ class KotlinParameterUVariable(
|
|||||||
override val initializer by lz { KotlinConverter.convert(psi.defaultValue, this) as? UExpression }
|
override val initializer by lz { KotlinConverter.convert(psi.defaultValue, this) as? UExpression }
|
||||||
|
|
||||||
override val initializerKind: UastVariableInitialierKind
|
override val initializerKind: UastVariableInitialierKind
|
||||||
get() = UastVariableInitialierKind.NO_INITIALIZER
|
get() = if (initializer != null)
|
||||||
|
UastVariableInitialierKind.EXPRESSION
|
||||||
|
else
|
||||||
|
UastVariableInitialierKind.NO_INITIALIZER
|
||||||
|
|
||||||
override val kind = UastVariableKind.VALUE_PARAMETER
|
override val kind = UastVariableKind.VALUE_PARAMETER
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.uast
|
package org.jetbrains.kotlin.uast
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||||
|
import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
|
||||||
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.uast.*
|
import org.jetbrains.uast.*
|
||||||
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
||||||
import org.jetbrains.uast.psi.PsiElementBacked
|
import org.jetbrains.uast.psi.PsiElementBacked
|
||||||
@@ -48,10 +54,21 @@ abstract class KotlinAbstractUFunction : KotlinAbstractUElement(), UFunction, Ps
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val bytecodeDescriptor by lz {
|
override val bytecodeDescriptor by lz {
|
||||||
val generationState = psi.getGenerationState()
|
val bindingContext = psi.analyze(BodyResolveMode.PARTIAL)
|
||||||
val descriptor = generationState.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi]
|
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi] as? FunctionDescriptor ?: return@lz null
|
||||||
as? FunctionDescriptor ?: return@lz null
|
|
||||||
generationState.typeMapper.mapAsmMethod(descriptor).descriptor
|
fun KotlinType?.isAnonymous(): Boolean {
|
||||||
|
if (this == null) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor.valueParameters.any { it.type.isAnonymous() } || descriptor.returnType.isAnonymous()) {
|
||||||
|
return@lz null
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null,
|
||||||
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME)
|
||||||
|
typeMapper.mapAsmMethod(descriptor).descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
|
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
|
||||||
|
|||||||
+19
-17
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.util.findAnnotation
|
import org.jetbrains.kotlin.idea.util.findAnnotation
|
||||||
@@ -61,12 +62,26 @@ internal fun KtModifierListOwner.hasModifier(modifier: UastModifier): Boolean {
|
|||||||
}
|
}
|
||||||
if (this is KtDeclaration && (parent is KtObjectDeclaration ||
|
if (this is KtDeclaration && (parent is KtObjectDeclaration ||
|
||||||
parent is KtClassBody && parent?.parent is KtObjectDeclaration)) {
|
parent is KtClassBody && parent?.parent is KtObjectDeclaration)) {
|
||||||
return hasAnnotations(JVM_STATIC_FQNAME, JVM_FIELD_FQNAME)
|
return hasAnyAnnotation(JVM_STATIC_FQNAME, JVM_FIELD_FQNAME)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifier == UastModifier.FIELD) return hasAnnotations(JVM_FIELD_FQNAME)
|
if (modifier == UastModifier.JVM_FIELD) {
|
||||||
|
var bindingContext: BindingContext? = null
|
||||||
|
fun getOrCreateBindingContext(): BindingContext {
|
||||||
|
if (bindingContext == null) {
|
||||||
|
bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||||
|
}
|
||||||
|
return bindingContext!!
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this is KtProperty) {
|
||||||
|
val context = getOrCreateBindingContext()
|
||||||
|
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? PropertyDescriptor ?: return false
|
||||||
|
return context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
if (modifier == UastModifier.FINAL) return hasModifier(KtTokens.FINAL_KEYWORD)
|
if (modifier == UastModifier.FINAL) return hasModifier(KtTokens.FINAL_KEYWORD)
|
||||||
if (modifier == UastModifier.IMMUTABLE && this is KtVariableDeclaration && !this.isVar) return true
|
if (modifier == UastModifier.IMMUTABLE && this is KtVariableDeclaration && !this.isVar) return true
|
||||||
|
|
||||||
@@ -74,12 +89,12 @@ internal fun KtModifierListOwner.hasModifier(modifier: UastModifier): Boolean {
|
|||||||
return hasModifier(javaModifier)
|
return hasModifier(javaModifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtElement.hasAnnotations(vararg annotationFqNames: String): Boolean {
|
private fun KtElement.hasAnyAnnotation(vararg annotationFqNames: String): Boolean {
|
||||||
if (this !is KtAnnotated) return false
|
if (this !is KtAnnotated) return false
|
||||||
|
|
||||||
|
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||||
for (annotationFqName in annotationFqNames) {
|
for (annotationFqName in annotationFqNames) {
|
||||||
val annotationEntry = findAnnotation(FqName(annotationFqName)) ?: continue
|
val annotationEntry = findAnnotation(FqName(annotationFqName)) ?: continue
|
||||||
val bindingContext = this.analyze(BodyResolveMode.PARTIAL)
|
|
||||||
val annotationDescriptor = bindingContext[BindingContext.ANNOTATION, annotationEntry] ?: continue
|
val annotationDescriptor = bindingContext[BindingContext.ANNOTATION, annotationEntry] ?: continue
|
||||||
val classifierDescriptor = annotationDescriptor.type.constructor.declarationDescriptor ?: continue
|
val classifierDescriptor = annotationDescriptor.type.constructor.declarationDescriptor ?: continue
|
||||||
val fqName = DescriptorUtils.getFqName(classifierDescriptor).asString()
|
val fqName = DescriptorUtils.getFqName(classifierDescriptor).asString()
|
||||||
@@ -111,16 +126,3 @@ internal fun DeclarationDescriptor.toSource() = try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer)
|
internal fun <T> lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer)
|
||||||
|
|
||||||
internal fun KtElement.getGenerationState(): GenerationState {
|
|
||||||
val analysisResult = this.analyzeAndGetResult()
|
|
||||||
val file = getContainingKtFile()
|
|
||||||
val state = GenerationState(
|
|
||||||
file.project,
|
|
||||||
ClassBuilderFactories.THROW_EXCEPTION,
|
|
||||||
analysisResult.moduleDescriptor,
|
|
||||||
analysisResult.bindingContext,
|
|
||||||
listOf(file))
|
|
||||||
state.beforeCompile()
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.kinds
|
||||||
|
|
||||||
|
import org.jetbrains.uast.kinds.UastVariableInitialierKind
|
||||||
|
|
||||||
|
object KotlinVariableInitializerKinds {
|
||||||
|
@JvmField
|
||||||
|
val DELEGATION = UastVariableInitialierKind("delegation")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user