From 33f9a0c7984f3ac725b1779cdd9ec59c1bf28f9e Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 21 Apr 2016 20:00:15 +0300 Subject: [PATCH] Lint: Review changes --- .../tools/klint/checks/CleanupDetector.java | 8 +- .../tools/klint/checks/ParcelDetector.java | 2 +- .../src/org/jetbrains/uast/UastUtils.kt | 115 ++++++++++++++---- .../org/jetbrains/uast/kinds/UastModifier.kt | 3 +- .../uast/kinds/UastVariableInitialierKind.kt | 8 +- .../uast/java/declarations/JavaUClass.kt | 2 +- .../uast/java/declarations/JavaUVariable.kt | 4 +- .../java/internal/javaInternalUastUtils.kt | 2 +- .../kotlin/uast/declarations/KotlinUClass.kt | 13 +- .../uast/declarations/KotlinUVariable.kt | 15 ++- .../uast/declarations/kotlinUFunctions.kt | 25 +++- .../uast/internal/kotlinInternalUastUtils.kt | 38 +++--- .../kinds/KotlinVariableInitializerKinds.kt | 24 ++++ 13 files changed, 190 insertions(+), 69 deletions(-) create mode 100644 plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/kinds/KotlinVariableInitializerKinds.kt diff --git a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/CleanupDetector.java b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/CleanupDetector.java index ebf60e28e55..f471730fea3 100644 --- a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/CleanupDetector.java +++ b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/CleanupDetector.java @@ -365,9 +365,9 @@ public class CleanupDetector extends Detector implements UastScanner { // getFragmentManager().beginTransaction().addToBackStack("test") // .disallowAddToBackStack().hide(mFragment2).setBreadCrumbShortTitle("test") // .show(mFragment2).setCustomAnimations(0, 0).commit(); - List chains = UastUtils.getQualifiedChains(node); - if (chains.size() > 0) { - UExpression lastExpression = chains.get(chains.size() - 1); + List chain = UastUtils.getQualifiedChain(node); + if (chain.size() > 0) { + UExpression lastExpression = chain.get(chain.size() - 1); if (lastExpression instanceof UCallExpression) { UCallExpression methodInvocation = (UCallExpression) lastExpression; if (isTransactionCommitMethodCall(context, methodInvocation) @@ -418,7 +418,7 @@ public class CleanupDetector extends Detector implements UastScanner { return null; } - UQualifiedExpression topMostQualified = UastUtils.findTopMostQualifiedExpression(((UExpression) expression)); + UQualifiedExpression topMostQualified = UastUtils.findOutermostQualifiedExpression(((UExpression) expression)); if (topMostQualified == null) { return null; } diff --git a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/ParcelDetector.java b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/ParcelDetector.java index 7682a66774b..3e4826bd951 100644 --- a/plugins/lint/lint-checks/src/com/android/tools/klint/checks/ParcelDetector.java +++ b/plugins/lint/lint-checks/src/com/android/tools/klint/checks/ParcelDetector.java @@ -90,7 +90,7 @@ public class ParcelDetector extends Detector implements UastScanner { String name = reference.getName(); if (name.equals("Parcelable")) { 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; if (!hasField) { for (UClass companion : node.getCompanions()) { diff --git a/plugins/uast-common/src/org/jetbrains/uast/UastUtils.kt b/plugins/uast-common/src/org/jetbrains/uast/UastUtils.kt index a86c6187c99..e47e4162025 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/UastUtils.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/UastUtils.kt @@ -140,6 +140,12 @@ fun UClass.getAllDeclarations(context: UastContext): List = 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() 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) { - is UQualifiedExpression -> { - if (parent.selector == current) - findParent(parent.parent as? UExpression, parent) ?: parent - else - current - } - else -> null - } - - return findParent(parent as? UExpression, this) ?: this -} - +/** + * Get the nearest parent of the type [T]. + * + * @return the nearest parent of type [T], or null if the parent with such type was not found. + */ inline fun 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 fun UElement.getParentOfType(clazz: Class, strict: Boolean = true): T? { tailrec fun findParent(element: UElement?): UElement? { @@ -181,6 +184,35 @@ fun UElement.getParentOfType(clazz: Class, strict: Boolean = tr 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 UClass.findStaticMemberOfType(name: String, type: Class): T? { for (companion in companions) { val member = companion.declarations.firstOrNull { @@ -198,6 +230,12 @@ fun UClass.findStaticMemberOfType(name: String, type: Class): T? { } fun UExpression.asQualifiedIdentifiers(): List? { + if (this is USimpleReferenceExpression) { + return listOf(this.identifier) + } else if (this !is UQualifiedExpression) { + return null + } + var error = false val list = mutableListOf() fun addIdentifiers(expr: UQualifiedExpression) { @@ -213,20 +251,29 @@ fun UExpression.asQualifiedIdentifiers(): List? { } list += selector.identifier } - when (this) { - is UQualifiedExpression -> addIdentifiers(this) - is USimpleReferenceExpression -> list += identifier - else -> return null - } + + addIdentifiers(this) 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 { val identifiers = this.asQualifiedIdentifiers() ?: return false val passedIdentifiers = fqName.split('.') 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 { val identifiers = this.asQualifiedIdentifiers() ?: return false val passedIdentifiers = fqName.trim('.').split('.') @@ -237,6 +284,12 @@ fun UExpression.startsWithQualified(fqName: String): Boolean { 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 { val identifiers = this.asQualifiedIdentifiers()?.asReversed() ?: return false val passedIdentifiers = fqName.trim('.').split('.').asReversed() @@ -247,15 +300,31 @@ fun UExpression.endsWithQualified(fqName: String): Boolean { 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 return when (parent) { - is UQualifiedExpression -> parent.findTopMostQualifiedExpression() + is UQualifiedExpression -> parent.findOutermostQualifiedExpression() else -> if (this is UQualifiedExpression) this else null } } -fun UExpression.getQualifiedChains(): List { +/** + * 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 { fun collect(expr: UQualifiedExpression, chains: MutableList) { val receiver = expr.receiver if (receiver is UQualifiedExpression) { @@ -272,7 +341,7 @@ fun UExpression.getQualifiedChains(): List { } } - val qualifiedExpression = this.findTopMostQualifiedExpression() ?: return emptyList() + val qualifiedExpression = this.findOutermostQualifiedExpression() ?: return emptyList() val chains = mutableListOf() collect(qualifiedExpression, chains) return chains diff --git a/plugins/uast-common/src/org/jetbrains/uast/kinds/UastModifier.kt b/plugins/uast-common/src/org/jetbrains/uast/kinds/UastModifier.kt index 3d43747bf8f..8d01f533e52 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/kinds/UastModifier.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/kinds/UastModifier.kt @@ -35,8 +35,9 @@ open class UastModifier(val name: String) { @JvmField val OVERRIDE = UastModifier("override") @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) } diff --git a/plugins/uast-common/src/org/jetbrains/uast/kinds/UastVariableInitialierKind.kt b/plugins/uast-common/src/org/jetbrains/uast/kinds/UastVariableInitialierKind.kt index 78a390b0e6e..8e6617df33e 100644 --- a/plugins/uast-common/src/org/jetbrains/uast/kinds/UastVariableInitialierKind.kt +++ b/plugins/uast-common/src/org/jetbrains/uast/kinds/UastVariableInitialierKind.kt @@ -17,15 +17,11 @@ package org.jetbrains.uast.kinds open class UastVariableInitialierKind(val name: String) { - class Simple(name: String) : UastVariableInitialierKind(name) - class Delegation(name: String) : UastVariableInitialierKind(name) + class Expression(name: String) : UastVariableInitialierKind(name) companion object { @JvmField - val SIMPLE = Simple("simple") - - @JvmField - val DELEGATION = Simple("delegation") + val EXPRESSION = Expression("expression") @JvmField val NO_INITIALIZER = UastVariableInitialierKind("no_initializer") diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt index c29f6ec694e..2b7531ea67d 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUClass.kt @@ -193,7 +193,7 @@ private class JavaUAnonymousClassConstructorParameter( override val initializer by lz { JavaConverter.convert(psi.expressions[index], this) } override val initializerKind: UastVariableInitialierKind - get() = UastVariableInitialierKind.SIMPLE + get() = UastVariableInitialierKind.EXPRESSION override val kind: UastVariableKind get() = UastVariableKind.VALUE_PARAMETER diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt index d111b4aeb8e..3a667a2cb57 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/declarations/JavaUVariable.kt @@ -21,7 +21,7 @@ import com.intellij.psi.PsiVariable import org.jetbrains.uast.* import org.jetbrains.uast.kinds.UastVariableInitialierKind 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 class JavaUVariable( @@ -37,7 +37,7 @@ class JavaUVariable( override val initializer by lz { JavaConverter.convertOrEmpty(psi.initializer, this) } 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) { is PsiField -> UastVariableKind.MEMBER diff --git a/plugins/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt b/plugins/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt index 3f8cd9def20..1a1a654d8b5 100644 --- a/plugins/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt +++ b/plugins/uast-java/src/org/jetbrains/uast/java/internal/javaInternalUastUtils.kt @@ -27,7 +27,7 @@ private val MODIFIER_MAP = mapOf( ) internal fun PsiModifierListOwner.hasModifier(modifier: UastModifier): Boolean { - if (modifier == UastModifier.FIELD && this is PsiField) { + if (modifier == UastModifier.JVM_FIELD && this is PsiField) { return true; } if (modifier == UastModifier.OVERRIDE && this is PsiAnnotationOwner) { diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUClass.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUClass.kt index e3c67ee04a8..884f4b1c5b8 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUClass.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUClass.kt @@ -17,9 +17,14 @@ package org.jetbrains.kotlin.uast 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.fileClasses.NoResolveFileClassesProvider import org.jetbrains.kotlin.idea.caches.resolve.analyze 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.KtClassOrObject import org.jetbrains.kotlin.psi.KtObjectDeclaration @@ -69,10 +74,10 @@ class KotlinUClass( } override val internalName by lz { - val generationState = psi.getGenerationState() - val descriptor = generationState.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi] - as? ClassDescriptor ?: return@lz null - generationState.typeMapper.mapClass(descriptor).internalName + val descriptor = resolveToDescriptor() ?: return@lz null + val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider, null, + IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME) + typeMapper.mapClass(descriptor).internalName } override fun getSuperClass(context: UastContext): UClass? { diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUVariable.kt index dae3dee0785..ab98e0e0d60 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/KotlinUVariable.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.uast.kinds.KotlinVariableInitializerKinds import org.jetbrains.uast.* import org.jetbrains.uast.kinds.UastVariableInitialierKind import org.jetbrains.uast.psi.PsiElementBacked @@ -42,9 +43,9 @@ open class KotlinUVariable( override val initializerKind by lz { if ((psi as? KtProperty)?.delegateExpression != null) - UastVariableInitialierKind.DELEGATION + KotlinVariableInitializerKinds.DELEGATION else if (psi.initializer != null) - UastVariableInitialierKind.SIMPLE + UastVariableInitialierKind.EXPRESSION else UastVariableInitialierKind.NO_INITIALIZER } @@ -148,7 +149,10 @@ class KotlinDestructuringUVariable( override val initializer by lz { KotlinConverter.convertOrEmpty(psi.initializer, this) } 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 type: UType @@ -174,7 +178,10 @@ class KotlinParameterUVariable( override val initializer by lz { KotlinConverter.convert(psi.defaultValue, this) as? UExpression } override val initializerKind: UastVariableInitialierKind - get() = UastVariableInitialierKind.NO_INITIALIZER + get() = if (initializer != null) + UastVariableInitialierKind.EXPRESSION + else + UastVariableInitialierKind.NO_INITIALIZER override val kind = UastVariableKind.VALUE_PARAMETER diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt index a869bea3e7f..867687d5498 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/declarations/kotlinUFunctions.kt @@ -16,14 +16,20 @@ 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.FunctionDescriptor +import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.uast.* import org.jetbrains.uast.kinds.UastVariableInitialierKind import org.jetbrains.uast.psi.PsiElementBacked @@ -48,10 +54,21 @@ abstract class KotlinAbstractUFunction : KotlinAbstractUElement(), UFunction, Ps } override val bytecodeDescriptor by lz { - val generationState = psi.getGenerationState() - val descriptor = generationState.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi] - as? FunctionDescriptor ?: return@lz null - generationState.typeMapper.mapAsmMethod(descriptor).descriptor + val bindingContext = psi.analyze(BodyResolveMode.PARTIAL) + val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, psi] as? FunctionDescriptor ?: return@lz null + + 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) diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/internal/kotlinInternalUastUtils.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/internal/kotlinInternalUastUtils.kt index 408824e7936..44c0d5893e3 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/internal/kotlinInternalUastUtils.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/internal/kotlinInternalUastUtils.kt @@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.state.GenerationState 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.analyzeAndGetResult 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 || 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 } - 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.IMMUTABLE && this is KtVariableDeclaration && !this.isVar) return true @@ -74,12 +89,12 @@ internal fun KtModifierListOwner.hasModifier(modifier: UastModifier): Boolean { 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 + val bindingContext = analyze(BodyResolveMode.PARTIAL) for (annotationFqName in annotationFqNames) { val annotationEntry = findAnnotation(FqName(annotationFqName)) ?: continue - val bindingContext = this.analyze(BodyResolveMode.PARTIAL) val annotationDescriptor = bindingContext[BindingContext.ANNOTATION, annotationEntry] ?: continue val classifierDescriptor = annotationDescriptor.type.constructor.declarationDescriptor ?: continue val fqName = DescriptorUtils.getFqName(classifierDescriptor).asString() @@ -110,17 +125,4 @@ internal fun DeclarationDescriptor.toSource() = try { null } -internal fun 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 -} \ No newline at end of file +internal fun lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer) \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/kinds/KotlinVariableInitializerKinds.kt b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/kinds/KotlinVariableInitializerKinds.kt new file mode 100644 index 00000000000..1822d432aaf --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/kotlin/uast/kinds/KotlinVariableInitializerKinds.kt @@ -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") +} \ No newline at end of file