Lint: Update Uast implementation (the new version is without declaration level)

This commit is contained in:
Yan Zhulanow
2016-10-13 20:26:55 +03:00
committed by Yan Zhulanow
parent 6491d3fbac
commit d5d491e6b2
222 changed files with 4606 additions and 5405 deletions
@@ -1,50 +1,73 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
/** import com.intellij.lang.Language
* Interface for the Uast context. import com.intellij.openapi.project.Project
* import com.intellij.psi.PsiClass
* Context is needed for resolution, cause the reference can point to the element of the different language. import com.intellij.psi.PsiElement
*/ import com.intellij.psi.PsiMethod
interface UastContext { import com.intellij.psi.PsiVariable
/** import org.jetbrains.uast.psi.PsiElementBacked
* Returns all active language plugins.
*/
val languagePlugins: List<UastLanguagePlugin>
/** class UastContext(override val project: Project) : UastLanguagePlugin {
* Convert an element of some language-specific AST to Uast element. private companion object {
* If two or more language plugins can convert the given [element] type, private val CONTEXT_LANGUAGE = object : Language("UastContextLanguage") {}
* the first converter in the [languagePlugins] list will be chosen. }
*
* @param element the language-specific AST element
* @return [UElement] instance, or null if [element] type is not supported by any of the provided language plugins.
*/
fun convert(element: Any?): UElement? {
if (element == null) {
return null
}
for (plugin in languagePlugins) { override val language: Language
val uelement = plugin.converter.convertWithParent(element) get() = CONTEXT_LANGUAGE
if (uelement != null) {
return uelement override val priority: Int
} get() = 0
val languagePlugins: Collection<UastLanguagePlugin>
get() = UastLanguagePlugin.getInstances(project)
fun findPlugin(element: PsiElement): UastLanguagePlugin? {
val language = element.language
return languagePlugins.firstOrNull { it.language == language }
}
override fun isFileSupported(fileName: String) = languagePlugins.any { it.isFileSupported(fileName) }
fun getMethod(method: PsiMethod): UMethod = convertWithParent<UMethod>(method)!!
fun getVariable(variable: PsiVariable): UVariable = convertWithParent<UVariable>(variable)!!
fun getClass(clazz: PsiClass): UClass = convertWithParent<UClass>(clazz)!!
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
return findPlugin(element)?.convertElement(element, parent, requiredType)
}
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
return findPlugin(element)?.convertElementWithParent(element, requiredType)
}
override fun getMethodCallExpression(
element: PsiElement,
containingClassFqName: String?,
methodName: String
): UastLanguagePlugin.ResolvedMethod? {
return findPlugin(element)?.getMethodCallExpression(element, containingClassFqName, methodName)
}
override fun getConstructorCallExpression(
element: PsiElement,
fqName: String
): UastLanguagePlugin.ResolvedConstructor? {
return findPlugin(element)?.getConstructorCallExpression(element, fqName)
}
override fun isExpressionValueUsed(element: UExpression): Boolean {
val language = element.getLanguage()
return (languagePlugins.firstOrNull { it.language == language })?.isExpressionValueUsed(element) ?: false
}
private tailrec fun UElement.getLanguage(): Language {
if (this is PsiElementBacked) {
psi?.language?.let { return it }
} }
return null val containingElement = this.containingElement ?: throw IllegalStateException("At least UFile should have a language")
return containingElement.getLanguage()
} }
} }
@@ -1,93 +1,98 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
import org.jetbrains.uast.visitor.UastVisitor import com.intellij.lang.Language
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import com.intellij.psi.*
interface UastLanguagePlugin {
companion object {
val extensionPointName = ExtensionPointName.create<UastLanguagePlugin>("org.jetbrains.uast.uastLanguagePlugin")
fun getInstances(project: Project): Collection<UastLanguagePlugin> {
val projectArea = Extensions.getArea(project)
if (!projectArea.hasExtensionPoint(extensionPointName.name)) return listOf()
return projectArea.getExtensionPoint(extensionPointName).extensions.toList()
}
}
data class ResolvedMethod(val call: UCallExpression, val method: PsiMethod)
data class ResolvedConstructor(val call: UCallExpression, val constructor: PsiMethod, val clazz: PsiClass)
val language: Language
val project: Project
/**
* Interface for the Uast element converter.
* Each [UastLanguagePlugin] should implement a proper [UastContext],
* which translates language-specific AST elements to Uast elements.
*/
interface UastConverter {
/** /**
* Convert a language-specific AST element to the [UElement] implementation with the given parent. * Checks if the file with the given [fileName] is supported.
* *
* @param element the element of the supported language-specific AST. * @param fileName the source file name.
* @param parent the parent of the newly created [UElement]. * @return true, if the file is supported by this converter, false otherwise.
* @return a [UElement], or null if the given [element] is not supported by this converter.
*
* No exceptions should be thrown during conversion, return `null` instead.
*/ */
fun convert(element: Any?, parent: UElement): UElement? fun isFileSupported(fileName: String): Boolean
/**
* Returns the converter priority. Might be positive, negative or 0 (Java's is 0).
* UastConverter with the higher priority will be queried earlier.
*
* Priority is useful when a language N wraps its own elements (NElement) to, for example, Java's PsiElements,
* and Java resolves the reference to such wrapped PsiElements, not the original NElement.
* In this case N implementation can handle such wrappers in UastConverter earlier than Java's converter,
* so N language converter will have a higher priority.
*/
val priority: Int
fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>? = null): UElement?
/** /**
* Convert [element] to the [UElement] with the given parent. * Convert [element] to the [UElement] with the given parent.
*/ */
fun convertWithParent(element: Any?): UElement? fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement?
/** fun getMethodCallExpression(
* Checks if the file with the given [name] is supported. element: PsiElement,
* containingClassFqName: String?,
* @param name the source file name. methodName: String
* @return true, if the file is supported by this converter, false otherwise. ): ResolvedMethod?
*/
fun isFileSupported(name: String): Boolean
}
/** fun getConstructorCallExpression(
* Interface for the Uast language plugin. element: PsiElement,
* fqName: String
* [UElement] implementations are loaded using language plugins provided in [UastContext]. ) : ResolvedConstructor?
* Each plugin must have a language-specific AST -> Uast (e.g. PsiElement -> UElement) converter.
*/
interface UastLanguagePlugin {
/**
* Returns converter for the specific language AST.
*/
val converter: UastConverter
/** fun getMethodBody(element: PsiMethod): UExpression? {
* Returns list of visitor extensions for the specific language AST. if (element is UMethod) return element.uastBody
*/ return (convertElementWithParent(element, null) as? UMethod)?.uastBody
val visitorExtensions: List<UastVisitorExtension>
}
/**
* Interface for the Uast visitor extension.
*
* A language plugin could provide a number of visitor extensions, which transforms some [UElement] into another.
* For example, Java accessors (getters/setters) are expressed in Kotlin as properties,
* but it can be useful to see them as functions in diagnostics, so the visitor extension
* can convert such property accessor calls to the ordinary function calls.
*/
interface UastVisitorExtension {
/**
* Invoke extension on an element.
*
* @param element a [UElement] to process.
* @param visitor current visitor.
* @param context current context.
*/
operator fun invoke(element: UElement, visitor: UastVisitor, context: UastContext)
}
object UastConverterUtils {
@JvmStatic
fun isFileSupported(converters: List<UastLanguagePlugin>, name: String): Boolean {
return converters.any { it.converter.isFileSupported(name) }
} }
fun getInitializerBody(element: PsiClassInitializer): UExpression {
if (element is UClassInitializer) return element.uastBody
return (convertElementWithParent(element, null) as? UClassInitializer)?.uastBody ?: UastEmptyExpression
}
fun getInitializerBody(element: PsiVariable): UExpression? {
if (element is UVariable) return element.uastInitializer
return (convertElementWithParent(element, null) as? UVariable)?.uastInitializer
}
/**
* Returns true if the expression value is used.
* Do not rely on this property too much, its value can be approximate in some cases.
*/
fun isExpressionValueUsed(element: UExpression): Boolean
}
inline fun <reified T : UElement> UastLanguagePlugin.convertOpt(element: PsiElement?, parent: UElement?): T? {
if (element == null) return null
return convertElement(element, parent) as? T
}
inline fun <reified T : UElement> UastLanguagePlugin.convert(element: PsiElement, parent: UElement?): T {
return convertElement(element, parent, T::class.java) as T
}
inline fun <reified T : UElement> UastLanguagePlugin.convertWithParent(element: PsiElement?): T? {
if (element == null) return null
return convertElementWithParent(element, T::class.java) as? T
} }
@@ -1,348 +1,135 @@
/* @file:JvmMultifileClass
* Copyright 2000-2015 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.
*/
@file:JvmName("UastUtils") @file:JvmName("UastUtils")
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.visitor.UastVisitor import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.psi.PsiElementBacked
import java.io.File
internal val ERROR_NAME = "<error>" inline fun <reified T : UElement> UElement.getParentOfType(strict: Boolean = true): T? = getParentOfType(T::class.java, strict)
/** @JvmOverloads
* Returns the containing class of an element. fun <T : UElement> UElement.getParentOfType(parentClass: Class<out UElement>, strict: Boolean = true): T? {
* var element = (if (strict) containingElement else this) ?: return null
* @return the containing [UClass] element, while (true) {
* or null if the receiver is null, or it is a top-level declaration. if (parentClass.isInstance(element)) {
*/ @Suppress("UNCHECKED_CAST")
tailrec fun UElement?.getContainingClass(): UClass? { return element as T
val parent = this?.parent ?: return null }
if (parent is UClass) return parent element = element.containingElement ?: return null
return parent.getContainingClass() }
} }
/** fun <T : UElement> UElement.getParentOfType(
* Returns the containing file of an element. parentClass: Class<out UElement>,
* strict: Boolean = true,
* @return the containing [UFile] element, vararg terminators: Class<out UElement>
* or null if the receiver is null, or the element is not inside a [UFile] (it is abmormal). ): T? {
*/ var element = (if (strict) containingElement else this) ?: return null
tailrec fun UElement?.getContainingFile(): UFile? { while (true) {
val parent = this?.parent ?: return null if (parentClass.isInstance(element)) {
if (parent is UFile) return parent @Suppress("UNCHECKED_CAST")
return parent.getContainingFile() return element as T
}
if (terminators.any { it.isInstance(element) }) {
return null
}
element = element.containingElement ?: return null
}
} }
fun UElement?.getContainingClassOrEmpty() = getContainingClass() ?: UClassNotResolved fun <T : UElement> UElement.getParentOfType(
strict: Boolean = true,
/** firstParentClass: Class<out T>,
* Returns the containing function of an element. vararg parentClasses: Class<out T>
* ): T? {
* @return the containing [UFunction] element, var element = (if (strict) containingElement else this) ?: return null
* or null if the receiver is null, or the element is not inside a [UFunction]. while (true) {
*/ if (firstParentClass.isInstance(element)) {
tailrec fun UElement?.getContainingFunction(): UFunction? { @Suppress("UNCHECKED_CAST")
val parent = this?.parent ?: return null return element as T
if (parent is UFunction) return parent }
return parent.getContainingFunction() if (parentClasses.any { it.isInstance(element) }) {
@Suppress("UNCHECKED_CAST")
return element as T
}
element = element.containingElement ?: return null
}
} }
/** fun UElement.getContainingFile() = getParentOfType<UFile>(UFile::class.java)
* Returns the containing declaration of an element.
*
* @return the containing [UDeclaration] element,
* or null if the receiver is null, or the element is a top-level declaration.
*/
tailrec fun UElement?.getContainingDeclaration(): UDeclaration? {
val parent = this?.parent ?: return null
if (parent is UDeclaration) return parent
return parent.getContainingDeclaration()
}
/** fun UElement.getContainingUMethod() = getParentOfType<UMethod>(UMethod::class.java)
* Checks if the element is a top-level declaration. fun UElement.getContainingUVariable() = getParentOfType<UVariable>(UVariable::class.java)
*
* @return true if the element is a top-level declaration, false otherwise.
*/
fun UDeclaration.isTopLevel() = parent is UFile
/** fun UElement.getContainingMethod() = getContainingUMethod()?.psi
* Builds the log message for the [UElement.logString] function. fun UElement.getContainingVariable() = getContainingUVariable()?.psi
*
* @param firstLine the message line (the interface name, some optional information). fun PsiElement?.getContainingClass() = this?.let { PsiTreeUtil.getParentOfType(it, PsiClass::class.java) }
* @param nested nested UElements. Could be `List<UElement>`, [UElement] or `null`.
* @throws IllegalStateException if the [nested] argument is invalid. fun UElement.isChildOf(probablyParent: UElement?, strict: Boolean = false): Boolean {
* @return the rendered log string. tailrec fun isChildOf(current: UElement?, probablyParent: UElement): Boolean {
*/ return when (current) {
fun UElement.log(firstLine: String, vararg nested: Any?): String { null -> false
return (if (firstLine.isBlank()) "" else firstLine + "\n") + nested.joinToString("\n") { probablyParent -> true
when (it) { else -> isChildOf(current.containingElement, probablyParent)
null -> "<no element>".withMargin
is List<*> ->
@Suppress("UNCHECKED_CAST")
(it as List<UElement>).logString()
is UElement -> it.logString().withMargin
else -> error("Invalid element type: $it")
} }
} }
if (probablyParent == null) return false
return isChildOf(if (strict) this else containingElement, probablyParent)
} }
val String.withMargin: String
get() = lines().joinToString("\n") { " " + it }
fun List<UElement>.acceptList(visitor: UastVisitor) {
for (element in this) {
element.accept(visitor)
}
}
@Suppress("UNCHECKED_CAST")
fun UClass.findFunctions(name: String) = declarations.filter { it is UFunction && it.matchesName(name) } as List<UFunction>
fun UCallExpression.getReceiver(): UExpression? = (this.parent as? UQualifiedExpression)?.receiver
/** /**
* Resolves the receiver element if it implements [UResolvable]. * Resolves the receiver element if it implements [UResolvable].
* *
* @return the resolved element, or null if the element was not resolved, or if the receiver element is not an [UResolvable]. * @return the resolved element, or null if the element was not resolved, or if the receiver element is not an [UResolvable].
*/ */
fun UElement.resolveIfCan(context: UastContext): UDeclaration? = (this as? UResolvable)?.resolve(context) fun UElement.tryResolve(): PsiElement? = (this as? UResolvable)?.resolve()
/** fun UElement.tryResolveNamed(): PsiNamedElement? = (this as? UResolvable)?.resolve() as? PsiNamedElement
* Find an annotation with the required qualified name.
*
* @param fqName the qualified name to search
* @return [UAnnotation] element if the annotation with the specified [fqName] was found, null otherwise.
*/
fun UAnnotated.findAnnotation(fqName: String) = annotations.firstOrNull { it.fqName == fqName }
/** fun UElement.tryResolveUDeclaration(context: UastContext): UDeclaration? {
* Get all class declarations (including supertypes). return (this as? UResolvable)?.resolve()?.let { context.convertElementWithParent(it, null) as? UDeclaration }
*
* @param context the Uast context
* @return the list of declarations for the receiver class
*/
fun UClass.getAllDeclarations(context: UastContext): List<UDeclaration> = mutableListOf<UDeclaration>().apply {
this += declarations
for (superType in superTypes) {
superType.resolveClass(context)?.declarations?.let { this += it }
}
} }
/** fun UReferenceExpression?.getQualifiedName() = (this?.resolve() as? PsiClass)?.qualifiedName
* 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>()
tailrec fun UQualifiedExpression.getCallElementFromQualified(): UCallExpression? {
val selector = this.selector
return when (selector) {
is UQualifiedExpression -> selector.getCallElementFromQualified()
is UCallExpression -> selector
else -> null
}
}
/** /**
* Get the nearest parent of the type [T]. * Returns the String expression value, or null if the value can't be calculated or if the calculated value is not a String.
*
* @return the nearest parent of type [T], or null if the parent with such type was not found.
*/ */
inline fun <reified T: UElement> UElement.getParentOfType(): T? = getParentOfType(T::class.java) fun UExpression.evaluateString(): String? = evaluate() as? String
/** /**
* Get the nearest parent of the type [T]. * Get a physical [File] for this file, or null if there is no such file on disk.
*
* @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 UFile.getIoFile(): File? = psi.virtualFile?.let { VfsUtilCore.virtualToIoFile(it) }
fun <T: UElement> UElement.getParentOfType(clazz: Class<T>, strict: Boolean = true): T? {
tailrec fun findParent(element: UElement?): UElement? { tailrec fun UElement.getUastContext(): UastContext {
return when { if (this is PsiElementBacked) {
element == null -> null val psi = this.psi
clazz.isInstance(element) -> element if (psi != null) {
else -> findParent(element.parent) return ServiceManager.getService(psi.project, UastContext::class.java) ?: error("UastContext not found")
} }
} }
@Suppress("UNCHECKED_CAST") return (containingElement ?: error("PsiElement should exist at least for UFile")).getUastContext()
return findParent(if (!strict) this else parent) as? T
} }
/** tailrec fun UElement.getLanguagePlugin(): UastLanguagePlugin {
* Get the topmost parent qualified expression for the call expression. if (this is PsiElementBacked) {
* val psi = this.psi
* Example 1: if (psi != null) {
* Code: variable.call(args) val uastContext = ServiceManager.getService(psi.project, UastContext::class.java) ?: error("UastContext not found")
* Call element: E = call(args) return uastContext.findPlugin(psi) ?: error("Language plugin was not found for $this (${this.javaClass.name})")
* 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? {
for (companion in companions) {
val member = companion.declarations.firstOrNull {
it.name == name && type.isInstance(it) && it is UModifierOwner && it.hasModifier(UastModifier.STATIC)
}
@Suppress("UNCHECKED_CAST")
if (member != null) return member as T
}
@Suppress("UNCHECKED_CAST")
return declarations.firstOrNull {
it.name == name && it is UModifierOwner
&& it.hasModifier(UastModifier.STATIC) && type.isInstance(it)
} as T
}
fun UExpression.asQualifiedIdentifiers(): List<String>? {
if (this is USimpleReferenceExpression) {
return listOf(this.identifier)
} else if (this !is UQualifiedExpression) {
return null
}
var error = false
val list = mutableListOf<String>()
fun addIdentifiers(expr: UQualifiedExpression) {
val receiver = expr.receiver
val selector = expr.selector as? USimpleReferenceExpression ?: run { error = true; return }
when (receiver) {
is UQualifiedExpression -> addIdentifiers(receiver)
is USimpleReferenceExpression -> list += receiver.identifier
else -> {
error = true
return
}
}
list += selector.identifier
}
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('.')
if (identifiers.size < passedIdentifiers.size) return false
passedIdentifiers.forEachIndexed { i, passedIdentifier ->
if (passedIdentifier != identifiers[i]) return false
}
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()
if (identifiers.size < passedIdentifiers.size) return false
passedIdentifiers.forEachIndexed { i, passedIdentifier ->
if (passedIdentifier != identifiers[i]) return false
}
return true
}
/**
* 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.findOutermostQualifiedExpression()
else -> if (this is UQualifiedExpression) this else null
}
}
/**
* 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>) {
val receiver = expr.receiver
if (receiver is UQualifiedExpression) {
collect(receiver, chains)
} else {
chains += receiver
}
val selector = expr.selector
if (selector is UQualifiedExpression) {
collect(selector, chains)
} else {
chains += selector
} }
} }
val qualifiedExpression = this.findOutermostQualifiedExpression() ?: return emptyList() return (containingElement ?: error("PsiElement should exist at least for UFile")).getLanguagePlugin()
val chains = mutableListOf<UExpression>()
collect(qualifiedExpression, chains)
return chains
} }
@@ -1,75 +0,0 @@
/*
* Copyright 2000-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.uast
import org.jetbrains.uast.visitor.UastVisitor
/**
Represents an applied JVM annotation.
*/
interface UAnnotation : UElement, UNamed, UFqNamed {
/**
* Returns the list of named value arguments.
*/
val valueArguments: List<UNamedExpression>
/**
* Returns the class of this annotation.
*
* @return annotation class or null if the class was not resolved
*/
fun resolve(context: UastContext): UClass?
/**
* Returns the evaluated value of the argument with the specified name.
*
* @param name name of the annotation value parameter
* @return the argument value
*/
fun getValue(name: String) = valueArguments.firstOrNull { it.name == name }?.expression?.evaluate()
/**
* Returns the list of Pair(name, evaluatedValue) for all applied annotation arguments.
*
* @return the list of name-value pairs.
*/
fun getValues() = valueArguments.map { Pair(it.name, it.expression.evaluate()) }
override fun logString() = log("UAnnotation ($name)")
override fun renderString(): String {
return if (valueArguments.isEmpty())
"@$name"
else
"@$name(" + valueArguments.joinToString { it.renderString() } + ")"
}
override fun accept(visitor: UastVisitor) {
if (visitor.visitAnnotation(this)) return
valueArguments.acceptList(visitor)
visitor.afterVisitAnnotation(this)
}
}
/**
* Represents an annotated element.
*/
interface UAnnotated : UElement {
/**
* Returns the list of annotations applied to the current element.
*/
val annotations: List<UAnnotation>
}
@@ -0,0 +1,13 @@
package org.jetbrains.uast
import com.intellij.psi.PsiElement
import org.jetbrains.uast.psi.PsiElementBacked
class UComment(override val psi: PsiElement, override val containingElement: UElement) : UElement, PsiElementBacked {
val text: String
get() = asSourceString()
override fun asLogString() = "UComment"
override fun asRenderString(): String = asSourceString()
override fun asSourceString(): String = psi.text
}
@@ -24,14 +24,20 @@ interface UElement {
/** /**
* Returns the element parent. * Returns the element parent.
*/ */
val parent: UElement? val containingElement: UElement?
/** /**
* Returns true if this element is valid, false otherwise. * Returns true if this element is valid, false otherwise.
*/ */
open val isValid: Boolean val isPsiValid: Boolean
get() = true get() = true
/**
* Returns the list of comments for this element.
*/
val comments: List<UComment>
get() = emptyList()
/** /**
* Returns the log string. * Returns the log string.
* *
@@ -49,7 +55,7 @@ interface UElement {
* @return the expression tree for this element. * @return the expression tree for this element.
* @see [UIfExpression] for example. * @see [UIfExpression] for example.
*/ */
fun logString(): String fun asLogString(): String
/** /**
* Returns the string in pseudo-code. * Returns the string in pseudo-code.
@@ -63,7 +69,15 @@ interface UElement {
* @return the rendered text. * @return the rendered text.
* @see [UIfExpression] for example. * @see [UIfExpression] for example.
*/ */
fun renderString(): String = logString() fun asRenderString(): String = asLogString()
/**
* Returns the string as written in the source file.
* Use this String only for logging and diagnostic text messages.
*
* @return the original text.
*/
fun asSourceString(): String = asRenderString()
/** /**
* Passes the element to the specified visitor. * Passes the element to the specified visitor.
@@ -72,104 +86,6 @@ interface UElement {
*/ */
fun accept(visitor: UastVisitor) { fun accept(visitor: UastVisitor) {
visitor.visitElement(this) visitor.visitElement(this)
visitor.afterVisitElement(this)
} }
} }
/**
* An interface for the [UElement] which was synthesized by an [UastExtendableVisitor].
* A synthesized element is not processed by an [UastExtendableVisitor].
*/
interface SynthesizedUElement : UElement
/**
* An interface for the [UElement] which has a name.
*/
interface UNamed {
/**
* Returns the name of this element.
*/
val name: String
/**
* Checks if the element name is equal to the passed name.
*
* @param name the name to check against
* @return true if the element name is equal to [name], false otherwise.
*/
fun matchesName(name: String) = this.name == name
}
/**
* An interface for the [UElement] which has a qualified name.
*/
interface UFqNamed : UNamed {
/**
* Returns the qualified name of this element, or null if the qualified name was not resolved.
*/
val fqName: String?
/**
* Checks if the element qualified name is equal to the passed name.
*
* @param fqName qualified name to check against
* @return true if the element name is not null and is equal to [name], false otherwise.
*/
fun matchesFqName(fqName: String) = this.fqName == fqName
}
/**
* An interface for the [UElement] which has Uast modifiers.
*/
interface UModifierOwner {
/**
* Checks if the element has the passed modifier.
*
* @param modifier modifier to check
* @return true if the element has [modifier], false otherwise.
*/
fun hasModifier(modifier: UastModifier): Boolean
}
/**
* An interface for the [UElement] which has a visibility (class, function, variable).
*/
interface UVisibilityOwner {
/**
* Returns the element visibility.
*/
val visibility: UastVisibility
}
/**
* An inteface for the [UElement] which can be resolved to the its declaration.
*/
interface UResolvable {
/**
* Returns the declaration element.
*
* @param context the Uast context
* @return the resolved declaration, or null if the declaration was not resolved.
*/
fun resolve(context: UastContext): UDeclaration?
/**
* Returns the declaration element or an empty Uast declaration element if the declaration was not resolved.
* An empty declaration element should be a singleton.
* [resolveOrEmpty] should not create new elements each time the declaration was not resolved.
*
* @param context the Uast context
* @return the resolved declaration, of an empty error Uast declaration element if the declaration was not resolved.
*
* @see [UDeclarationNotResolved]
*/
fun resolveOrEmpty(context: UastContext): UDeclaration = resolve(context) ?: UDeclarationNotResolved
/**
* Returns the declaration [UClass] element of null if the declaration was not resolved.
*
* @param context the Uast context
* @return the resolved [UClass] element, or null if the class was not resolved,
* or if the resolved [UElement] is not an instance of [UClass].
*/
fun resolveClass(context: UastContext): UClass? = resolve(context) as? UClass
}
@@ -15,12 +15,23 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiType
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/**
* Represents an expression or statement (which is considered as an expression in Uast).
*/
interface UExpression : UElement { interface UExpression : UElement {
open fun evaluate(): Any? = null /**
fun evaluateString(): String? = evaluate() as? String * Returns the expression value or null if the value can't be calculated.
fun getExpressionType(): UType? = null */
fun evaluate(): Any? = null
/**
* Returns expression type, or null if type can not be inferred, or if this expression is a statement.
*/
fun getExpressionType(): PsiType? = null
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitElement(this) visitor.visitElement(this)
@@ -28,15 +39,35 @@ interface UExpression : UElement {
} }
} }
interface NoAnnotations : UAnnotated { /**
override val annotations: List<UAnnotation> * Represents an annotated element.
get() = emptyList() */
interface UAnnotated : UElement {
/**
* Returns the list of annotations applied to the current element.
*/
val annotations: List<PsiAnnotation>
/**
* Looks up for annotation element using the annotation qualified name.
*
* @param fqName the qualified name to search
* @return the first annotation element with the specified qualified name, or null if there is no annotation with such name.
*/
fun findAnnotation(fqName: String): PsiAnnotation? = annotations.firstOrNull { it.qualifiedName == fqName }
} }
interface NoModifiers : UModifierOwner { /**
override fun hasModifier(modifier: UastModifier) = false * In some cases (user typing, syntax error) elements, which are supposed to exist, are missing.
} * The obvious example — the lack of the condition expression in [UIfExpression], e.g. `if () return`.
* [UIfExpression.condition] is required to return not-null values,
* and Uast implementation should return something instead of `null` in this case.
*
* Use [UastEmptyExpression] in this case.
*/
object UastEmptyExpression : UExpression {
override val containingElement: UElement?
get() = null
class EmptyUExpression(override val parent: UElement) : UExpression { override fun asLogString() = "EmptyExpression"
override fun logString() = "EmptyExpression"
} }
@@ -1,68 +0,0 @@
/*
* Copyright 2000-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.uast
import org.jetbrains.uast.visitor.UastVisitor
/**
* Represents a source file.
* File is the topmost element of the UElement hierarchy.
* Files should not be nested, thus the [parent] property should always return null.
*/
interface UFile: UElement {
/**
* Returns the qualified package name of this file.
* Could be an empty string if the package is "default", or null if the package directive is not present in this file.
*/
val packageFqName: String?
/**
* Returns the list of import statements.
*/
val importStatements: List<UImportStatement>
/**
* Returns the list of declarations in this file (classes, properties, functions, etc).
*/
val declarations: List<UDeclaration>
/**
* Returns list of classes containing in this file.
*/
val classes: List<UClass>
get() = declarations.filterIsInstance<UClass>()
override val parent: UElement?
get() = null
override fun accept(visitor: UastVisitor) {
if (visitor.visitFile(this)) return
declarations.acceptList(visitor)
importStatements.acceptList(visitor)
visitor.afterVisitFile(this)
}
override fun logString() = "UFile (package = $packageFqName)\n" + declarations.joinToString("\n") { it.logString().withMargin }
override fun renderString() = buildString {
if (!packageFqName.isNullOrBlank()) {
appendln("package $packageFqName")
appendln()
}
declarations.forEach { appendln(it.renderString()) }
}
}
@@ -14,16 +14,20 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.uast package org.jetbrains.uast
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.uast.UElement
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class KotlinDumbUElement( class UIdentifier(
override val psi: PsiElement?, override val psi: PsiElement?,
override val parent: UElement override val containingElement: UElement?
) : KotlinAbstractUElement(), UElement, PsiElementBacked { ) : UElement, PsiElementBacked {
override fun logString() = "KotlinDumbUElement" /**
override fun renderString() = "<stub@$psi>" * Returns the identifier name.
*/
val name: String
get() = psi?.text ?: "<error>"
override fun asLogString() = "Identifier ($name)"
} }
@@ -0,0 +1,19 @@
package org.jetbrains.uast
/**
* An interface for the [UElement] which has a name.
*/
interface UNamed {
/**
* Returns the element name.
*/
val name: String?
/**
* Checks if the element name is equal to the passed name.
*
* @param name the name to check against
* @return true if the element name is equal to [name], false otherwise.
*/
fun matchesName(name: String) = this.name == name
}
@@ -0,0 +1,13 @@
package org.jetbrains.uast
import com.intellij.psi.PsiElement
interface UResolvable {
/**
* Resolve the reference.
* Note that the reference is *always* resolved to an unwrapped [PsiElement], never to a [UElement].
*
* @return the resolved element, or null if the reference couldn't be resolved.
*/
fun resolve(): PsiElement?
}
@@ -0,0 +1,16 @@
package org.jetbrains.uast
import com.intellij.psi.PsiType
import com.intellij.psi.PsiTypeVisitor
object UastErrorType : PsiType(emptyArray()) {
override fun getInternalCanonicalText() = "<ErrorType>"
override fun equalsToText(text: String) = false
override fun getCanonicalText() = internalCanonicalText
override fun getPresentableText() = canonicalText
override fun isValid() = false
override fun getResolveScope() = null
override fun getSuperTypes() = emptyArray<PsiType>()
override fun <A : Any?> accept(visitor: PsiTypeVisitor<A>) = visitor.visitType(this)
}
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -32,6 +33,16 @@ interface UDoWhileExpression : ULoopExpression {
*/ */
val condition: UExpression val condition: UExpression
/**
* Returns an identifier for the 'do' keyword.
*/
val doIdentifier: UIdentifier
/**
* Returns an identifier for the 'while' keyword.
*/
val whileIdentifier: UIdentifier
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitDoWhileExpression(this)) return if (visitor.visitDoWhileExpression(this)) return
condition.accept(visitor) condition.accept(visitor)
@@ -39,11 +50,11 @@ interface UDoWhileExpression : ULoopExpression {
visitor.afterVisitDoWhileExpression(this) visitor.afterVisitDoWhileExpression(this)
} }
override fun renderString() = buildString { override fun asRenderString() = buildString {
append("do ") append("do ")
append(body.renderString()) append(body.asRenderString())
appendln("while (${condition.renderString()})") appendln("while (${condition.asRenderString()})")
} }
override fun logString() = log("UDoWhileExpression", condition, body) override fun asLogString() = log("UDoWhileExpression", condition, body)
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -30,29 +31,33 @@ interface UForEachExpression : ULoopExpression {
/** /**
* Returns the loop variable. * Returns the loop variable.
*/ */
val variable: UVariable val variable: UParameter
/** /**
* Returns the iterated value (collection, sequence, iterable etc.) * Returns the iterated value (collection, sequence, iterable etc.)
*/ */
val iteratedValue: UExpression val iteratedValue: UExpression
/**
* Returns the identifier for the 'for' ('foreach') keyword.
*/
val forIdentifier: UIdentifier
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitForEachExpression(this)) return if (visitor.visitForEachExpression(this)) return
variable.accept(visitor)
iteratedValue.accept(visitor) iteratedValue.accept(visitor)
body.accept(visitor) body.accept(visitor)
visitor.afterVisitForEachExpression(this) visitor.afterVisitForEachExpression(this)
} }
override fun renderString() = buildString { override fun asRenderString() = buildString {
append("for (") append("for (")
append(variable.name) append(variable.name)
append(" : ") append(" : ")
append(iteratedValue.renderString()) append(iteratedValue.asRenderString())
append(") ") append(") ")
append(body.renderString()) append(body.asRenderString())
} }
override fun logString() = log("UForEachExpression", variable, iteratedValue, body) override fun asLogString() = log("UForEachExpression", variable, iteratedValue, body)
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -42,6 +43,11 @@ interface UForExpression : ULoopExpression {
*/ */
val update: UExpression? val update: UExpression?
/**
* Returns the identifier for the 'for' keyword.
*/
val forIdentifier: UIdentifier
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitForExpression(this)) return if (visitor.visitForExpression(this)) return
declaration?.accept(visitor) declaration?.accept(visitor)
@@ -51,16 +57,16 @@ interface UForExpression : ULoopExpression {
visitor.afterVisitForExpression(this) visitor.afterVisitForExpression(this)
} }
override fun renderString() = buildString { override fun asRenderString() = buildString {
append("for (") append("for (")
declaration?.let { append(it.renderString()) } declaration?.let { append(it.asRenderString()) }
append("; ") append("; ")
condition?.let { append(it.renderString()) } condition?.let { append(it.asRenderString()) }
append("; ") append("; ")
update?.let { append(it.renderString()) } update?.let { append(it.asRenderString()) }
append(") ") append(") ")
append(body.renderString()) append(body.asRenderString())
} }
override fun logString() = log("UForExpression", declaration, condition, update, body) override fun asLogString() = log("UForExpression", declaration, condition, update, body)
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -41,43 +42,53 @@ interface UIfExpression : UExpression {
/** /**
* Returns the expression which is executed if the condition is true, or null if the expression is empty. * Returns the expression which is executed if the condition is true, or null if the expression is empty.
*/ */
val thenBranch: UExpression? val thenExpression: UExpression?
/** /**
* Returns the expression which is executed if the condition is false, or null if the expression is empty. * Returns the expression which is executed if the condition is false, or null if the expression is empty.
*/ */
val elseBranch: UExpression? val elseExpression: UExpression?
/** /**
* Returns true if the expression is ternary (condition ? trueExpression : falseExpression). * Returns true if the expression is ternary (condition ? trueExpression : falseExpression).
*/ */
val isTernary: Boolean val isTernary: Boolean
/**
* Returns an identifier for the 'if' keyword.
*/
val ifIdentifier: UIdentifier
/**
* Returns an identifier for the 'else' keyword, or null if the conditional expression has not the 'else' part.
*/
val elseIdentifier: UIdentifier?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitIfExpression(this)) return if (visitor.visitIfExpression(this)) return
condition.accept(visitor) condition.accept(visitor)
thenBranch?.accept(visitor) thenExpression?.accept(visitor)
elseBranch?.accept(visitor) elseExpression?.accept(visitor)
visitor.afterVisitIfExpression(this) visitor.afterVisitIfExpression(this)
} }
override fun logString() = log("UIfExpression", condition, thenBranch, elseBranch) override fun asLogString() = log("UIfExpression", condition, thenExpression, elseExpression)
override fun renderString() = buildString { override fun asRenderString() = buildString {
if (isTernary) { if (isTernary) {
append("(" + condition.renderString() + ")") append("(" + condition.asRenderString() + ")")
append(" ? ") append(" ? ")
append("(" + (thenBranch?.renderString() ?: "<noexpr>") + ")") append("(" + (thenExpression?.asRenderString() ?: "<noexpr>") + ")")
append(" : ") append(" : ")
append("(" + (elseBranch?.renderString() ?: "<noexpr>") + ")") append("(" + (elseExpression?.asRenderString() ?: "<noexpr>") + ")")
} else { } else {
append("if (${condition.renderString()}) ") append("if (${condition.asRenderString()}) ")
thenBranch?.let { append(it.renderString()) } thenExpression?.let { append(it.asRenderString()) }
val elseBranch = elseBranch val elseBranch = elseExpression
if (elseBranch != null && elseBranch !is EmptyUExpression) { if (elseBranch != null && elseBranch !is UastEmptyExpression) {
if (thenBranch !is UBlockExpression) append(" ") if (thenExpression !is UBlockExpression) append(" ")
append("else ") append("else ")
append(elseBranch.renderString()) append(elseBranch.asRenderString())
} }
} }
} }
@@ -16,7 +16,7 @@
package org.jetbrains.uast package org.jetbrains.uast
/** /**
* Represents the loop expression. * Represents a loop expression.
*/ */
interface ULoopExpression : UExpression { interface ULoopExpression : UExpression {
/** /**
@@ -15,6 +15,8 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -30,17 +32,22 @@ import org.jetbrains.uast.visitor.UastVisitor
* conditional expression. * conditional expression.
*/ */
interface USwitchExpression : UExpression { interface USwitchExpression : UExpression {
/* /**
Returns the expression on which the `switch` expression is performed. Returns the expression on which the `switch` expression is performed.
*/ */
val expression: UExpression? val expression: UExpression?
/* /**
Returns the switch body. Returns the switch body.
Body should contain [USwitchClauseExpression] expressions. The body should contain [USwitchClauseExpression] expressions.
*/ */
val body: UExpression val body: UExpression
/**
* Returns an identifier for the 'switch' ('case', 'when', ...) keyword.
*/
val switchIdentifier: UIdentifier
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitSwitchExpression(this)) return if (visitor.visitSwitchExpression(this)) return
expression?.accept(visitor) expression?.accept(visitor)
@@ -48,11 +55,12 @@ interface USwitchExpression : UExpression {
visitor.afterVisitSwitchExpression(this) visitor.afterVisitSwitchExpression(this)
} }
override fun logString() = log("USwitchExpression", expression, body) override fun asLogString() = log("USwitchExpression", expression, body)
override fun renderString() = buildString {
val expr = expression?.let { "(" + it.renderString() + ") " } ?: "" override fun asRenderString() = buildString {
val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: ""
appendln("switch $expr") appendln("switch $expr")
appendln(body.renderString()) appendln(body.asRenderString())
} }
} }
@@ -74,8 +82,8 @@ interface USwitchClauseExpression : UExpression {
visitor.afterVisitSwitchClauseExpression(this) visitor.afterVisitSwitchClauseExpression(this)
} }
override fun renderString() = (caseValues?.joinToString { it.renderString() } ?: "else") + " -> " override fun asRenderString() = (caseValues?.joinToString { it.asRenderString() } ?: "else") + " -> "
override fun logString() = log("USwitchClauseExpression", caseValues) override fun asLogString() = log("USwitchClauseExpression", caseValues)
} }
/** /**
@@ -97,6 +105,6 @@ interface USwitchClauseExpressionWithBody : USwitchClauseExpression {
visitor.afterVisitSwitchClauseExpression(this) visitor.afterVisitSwitchClauseExpression(this)
} }
override fun renderString() = (caseValues?.joinToString { it.renderString() } ?: "else") + " -> " + body.renderString() override fun asRenderString() = (caseValues?.joinToString { it.asRenderString() } ?: "else") + " -> " + body.asRenderString()
override fun logString() = log("USwitchClauseExpressionWithBody", caseValues, body) override fun asLogString() = log("USwitchClauseExpressionWithBody", caseValues, body)
} }
@@ -15,6 +15,11 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiResourceListElement
import com.intellij.psi.PsiType
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -38,10 +43,15 @@ import org.jetbrains.uast.visitor.UastVisitor
* expressions. * expressions.
*/ */
interface UTryExpression : UExpression { interface UTryExpression : UExpression {
/**
* Returns `true` if the try expression is a try-with-resources expression.
*/
val isResources: Boolean
/** /**
* Returns the list of try resources, or null if this expression is not a `try-with-resources` expression. * Returns the list of try resources, or null if this expression is not a `try-with-resources` expression.
*/ */
val resources: List<UElement>? val resources: List<PsiResourceListElement>?
/** /**
* Returns the `try` clause expression. * Returns the `try` clause expression.
@@ -58,26 +68,32 @@ interface UTryExpression : UExpression {
*/ */
val finallyClause: UExpression? val finallyClause: UExpression?
/**
* Returns an identifier for the 'try' keyword.
*/
val tryIdentifier: UIdentifier
/**
* Returns an identifier for the 'finally' keyword, or null if the 'try' expression has not a 'finally' clause.
*/
val finallyIdentifier: UIdentifier?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitTryExpression(this)) return if (visitor.visitTryExpression(this)) return
resources?.acceptList(visitor)
tryClause.accept(visitor) tryClause.accept(visitor)
catchClauses.acceptList(visitor) catchClauses.acceptList(visitor)
finallyClause?.accept(visitor) finallyClause?.accept(visitor)
visitor.afterVisitTryExpression(this) visitor.afterVisitTryExpression(this)
} }
override fun renderString() = buildString { override fun asRenderString() = buildString {
append("try ") append("try ")
appendln(tryClause.renderString().trim('\n')) appendln(tryClause.asRenderString().trim('\n', '\r'))
catchClauses.forEach { appendln(it.renderString().trim('\n')) } catchClauses.forEach { appendln(it.asRenderString().trim('\n', '\r')) }
finallyClause?.let { append("finally ").append(it.renderString().trim('\n')) } finallyClause?.let { append("finally ").append(it.asRenderString().trim('\n', '\r')) }
} }
override fun logString() = "UTryExpression\n" + override fun asLogString() = log("UTryExpression", tryClause, catchClauses, finallyClause)
tryClause.logString().withMargin +
catchClauses.joinToString("\n") { it.logString().withMargin } +
(finallyClause?.let { it.logString().withMargin } ?: "<no finally clause>" )
} }
/** /**
@@ -92,21 +108,25 @@ interface UCatchClause : UElement {
/** /**
* Returns the exception parameter variables for this `catch` clause. * Returns the exception parameter variables for this `catch` clause.
*/ */
val parameters: List<UVariable> val parameters: List<UParameter>
/** /**
* Returns the exception types for this `catch` clause. * Returns the exception type references for this `catch` clause.
*/ */
val types: List<UType> val typeReferences: List<UTypeReferenceExpression>
/**
* Returns the expression types for this `catch` clause.
*/
val types: List<PsiType>
get() = typeReferences.map { it.type }
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitCatchClause(this)) return if (visitor.visitCatchClause(this)) return
body.accept(visitor) body.accept(visitor)
parameters.acceptList(visitor)
types.acceptList(visitor)
visitor.afterVisitCatchClause(this) visitor.afterVisitCatchClause(this)
} }
override fun logString() = log("UCatchClause", body) override fun asLogString() = log("UCatchClause", body)
override fun renderString() = "catch (e) " + body.renderString() override fun asRenderString() = "catch (e) " + body.asRenderString()
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -32,6 +33,11 @@ interface UWhileExpression : ULoopExpression {
*/ */
val condition: UExpression val condition: UExpression
/**
* Returns an identifier for the 'while' keyword.
*/
val whileIdentifier: UIdentifier
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitWhileExpression(this)) return if (visitor.visitWhileExpression(this)) return
condition.accept(visitor) condition.accept(visitor)
@@ -39,10 +45,10 @@ interface UWhileExpression : ULoopExpression {
visitor.afterVisitWhileExpression(this) visitor.afterVisitWhileExpression(this)
} }
override fun renderString() = buildString { override fun asRenderString() = buildString {
append("while (${condition.renderString()}) ") append("while (${condition.asRenderString()}) ")
append(body.renderString()) append(body.asRenderString())
} }
override fun logString() = log("UWhileExpression", condition, body) override fun asLogString() = log("UWhileExpression", condition, body)
} }
@@ -0,0 +1,18 @@
package org.jetbrains.uast
import com.intellij.psi.PsiAnnotation
class SimpleUAnnotation(
psi: PsiAnnotation,
override val containingElement: UElement?
) : UAnnotation, PsiAnnotation by psi {
override val psi: PsiAnnotation = unwrap(psi)
private companion object {
fun unwrap(psi: PsiAnnotation): PsiAnnotation {
val unwrapped = if (psi is UAnnotation) psi.psi else psi
assert(unwrapped !is UElement)
return unwrapped
}
}
}
@@ -0,0 +1,24 @@
package org.jetbrains.uast
import com.intellij.psi.PsiAnnotation
import org.jetbrains.uast.psi.PsiElementBacked
import org.jetbrains.uast.visitor.UastVisitor
/**
* An annotation wrapper to be used in [UastVisitor].
*/
interface UAnnotation : UElement, PsiAnnotation, PsiElementBacked {
/**
* Returns the original annotation (which is *always* unwrapped [PsiAnnotation], never a [UAnnotation]).
*/
override val psi: PsiAnnotation
override fun getOriginalElement() = psi.originalElement
override fun asLogString() = "UAnnotation"
override fun accept(visitor: UastVisitor) {
if (visitor.visitAnnotation(this)) return
visitor.afterVisitAnnotation(this)
}
}
@@ -1,152 +1,45 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
import com.intellij.psi.PsiAnonymousClass
import com.intellij.psi.PsiClass
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents a JVM class (ordinary class, interface, annotation, singleton, etc.). * A class wrapper to be used in [UastVisitor].
*/ */
interface UClass : UDeclaration, UFqNamed, UModifierOwner, UVisibilityOwner, UAnnotated { interface UClass : UDeclaration, PsiClass {
/** override val psi: PsiClass
* Returns the class simple (non-qualified) name.
* The simple class name is only for the debug purposes. Do not check against it in the production code.
*/
override val name: String
/** /**
* Returns true if the class is anonymous ([name] in this case should return a placeholder like "<anonymous>"). * Returns a [UClass] wrapper of the superclass of this class, or null if this class is [java.lang.Object].
*/ */
val isAnonymous: Boolean val uastSuperClass: UClass?
get() {
val superClass = superClass ?: return null
return getUastContext().convertWithParent(superClass)
}
/** /**
* Returns the class kind (ordinary class, interface, annotation, etc.). * Returns [UDeclaration] wrappers for the class declarations.
*/ */
val kind: UastClassKind val uastDeclarations: List<UDeclaration>
/** val uastFields: List<UVariable>
* Returns the default type for this class. val uastInitializers: List<UClassInitializer>
*/ val uastMethods: List<UMethod>
val defaultType: UType val uastNestedClasses: List<UClass>
/** override fun asLogString() = "UClass (name = $name)"
* Returns the class companions.
*/
val companions: List<UClass>
/**
* Returns the class JVM name, or null if the JVM name is unknown.
*/
open val internalName: String?
get() = null
/**
* Returns the all supertypes of this class.
*/
val superTypes: List<UType>
/**
* Returns class declarations (nested classes, constructors, functions, variables, etc.).
* An empty (default) constructor also should be present.
*/
val declarations: List<UDeclaration>
/**
* Returns nested classes declared in this class.
*/
val nestedClasses: List<UClass>
get() = declarations.filterIsInstance<UClass>()
/**
* Returns functions declared in this class.
*/
val functions: List<UFunction>
get() = declarations.filterIsInstance<UFunction>()
/**
* Returns properties declared in this class.
*/
val properties: List<UVariable>
get() = declarations.filterIsInstance<UVariable>()
/**
* Returns constructors declared in this class.
*/
@Suppress("UNCHECKED_CAST")
val constructors: List<UFunction>
get() = declarations.filter { it is UFunction && it.kind == UastFunctionKind.CONSTRUCTOR } as List<UFunction>
/**
* Checks if the class is subclass of another.
*
* @param fqName qualified name of the class to check against
* @return true if the class is the *subclass* of the class with the specified [fqName],
* false if the class qualified name is [fqName] or if the class is not a subclass of the class with the specified [fqName]
*/
fun isSubclassOf(fqName: String) : Boolean
/**
* Get the direct superclass of this class.
*
* @return null if the class has not a superclass (java.lang.Object).
*/
fun getSuperClass(context: UastContext): UClass?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitClass(this)) return if (visitor.visitClass(this)) return
nameElement?.accept(visitor) uastAnnotations.acceptList(visitor)
declarations.acceptList(visitor) uastDeclarations.acceptList(visitor)
annotations.acceptList(visitor)
visitor.afterVisitClass(this) visitor.afterVisitClass(this)
} }
override fun renderString() = buildString {
appendWithSpace(visibility.name)
appendWithSpace(renderModifiers())
appendWithSpace(kind.text)
appendWithSpace(name)
val declarations = if (declarations.isEmpty()) "" else buildString {
appendln("{")
append(declarations.joinToString("\n\n") { it.renderString().trim('\n') }.withMargin)
append("\n}")
}
append(declarations)
}
override fun logString() = log("UClass ($name, kind = ${kind.text})", declarations)
} }
object UClassNotResolved : UClass { interface UAnonymousClass : UClass, PsiAnonymousClass {
override val isAnonymous = true override val psi: PsiAnonymousClass
override val kind = UastClassKind.CLASS
override val visibility = UastVisibility.PRIVATE
override val superTypes = emptyList<UType>()
override val declarations = emptyList<UDeclaration>()
override fun isSubclassOf(fqName: String) = false
override val companions = emptyList<UClass>()
override val defaultType = UastErrorType
override val nameElement = null
override val parent = null
override val name = ERROR_NAME
override val fqName = null
override val internalName = null
override fun hasModifier(modifier: UastModifier) = false
override val annotations = emptyList<UAnnotation>()
override fun getSuperClass(context: UastContext) = null
} }
@@ -0,0 +1,29 @@
package org.jetbrains.uast
import com.intellij.psi.PsiClassInitializer
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.visitor.UastVisitor
/**
* A class initializer wrapper to be used in [UastVisitor].
*/
interface UClassInitializer : UDeclaration, PsiClassInitializer {
override val psi: PsiClassInitializer
/**
* Returns the body of this class initializer.
*/
val uastBody: UExpression
@Deprecated("Use uastBody instead.", ReplaceWith("uastBody"))
override fun getBody() = psi.body
override fun accept(visitor: UastVisitor) {
if (visitor.visitInitializer(this)) return
uastAnnotations.acceptList(visitor)
uastBody.accept(visitor)
visitor.afterVisitInitializer(this)
}
override fun asLogString() = "UMethod (name = ${psi.name}"
}
@@ -1,57 +1,43 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
import org.jetbrains.uast.visitor.UastVisitor import com.intellij.psi.PsiElement
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierListOwner
import org.jetbrains.uast.psi.PsiElementBacked
/** /**
* Represents a declaration. * A [PsiElement] declaration wrapper.
*/ */
interface UDeclaration : UElement, UNamed { interface UDeclaration : UElement, PsiElementBacked, PsiModifierListOwner {
/** /**
* Returns an element for the name node, or null if the node does not exist in the underlying AST (Psi). * Returns the original declaration (which is *always* unwrapped, never a [UDeclaration]).
*/ */
val nameElement: UElement? override val psi: PsiModifierListOwner
override fun getOriginalElement(): PsiElement? = psi.originalElement
/** /**
* Checks if the function name is [name], and the function containing class qualified name is [containingClassFqName]. * Returns the declaration name identifier, or null if the declaration is anonymous.
*
* @param containingClassFqName the required containing class qualified name.
* @param name the function name to check against.
* @return true if the call is a function call, the function name is [name],
* and the qualified name of the function direct containing class is [containingClassFqName],
* false otherwise.
*/ */
open fun matchesNameWithContaining(containingClassFqName: String, name: String): Boolean { val uastAnchor: UElement?
if (!matchesName(name)) return false
val containingClass = this.getContainingClass() ?: return false
return containingClass.matchesFqName(containingClassFqName)
}
override fun accept(visitor: UastVisitor) { val uastAnnotations: List<UAnnotation>
visitor.visitElement(this)
visitor.afterVisitElement(this) /**
} * Returns `true` if this declaration has a [PsiModifier.STATIC] modifier.
} */
val isStatic: Boolean
object UDeclarationNotResolved : UDeclaration { get() = hasModifierProperty(PsiModifier.STATIC)
override val name = ERROR_NAME
override val nameElement = null /**
override val parent = null * Returns `true` if this declaration has a [PsiModifier.FINAL] modifier.
*/
override fun logString() = "[!] $name" val isFinal: Boolean
override fun renderString() = name get() = hasModifierProperty(PsiModifier.FINAL)
/**
* Returns a declaration visibility.
*/
val visibility: UastVisibility
get() = UastVisibility[this]
} }
@@ -0,0 +1,57 @@
package org.jetbrains.uast
import com.intellij.psi.PsiFile
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.visitor.UastVisitor
/**
* Represents a Uast file.
*/
interface UFile : UElement {
/**
* Returns the original [PsiFile].
*/
val psi: PsiFile
/**
* Returns the Java package name of this file.
* Returns an empty [String] for the default package.
*/
val packageName: String
/**
* Returns the import statements for this file.
*/
val imports: List<UImportStatement>
/**
* Returns the list of top-level classes declared in this file.
*/
val classes: List<UClass>
/**
* Returns the plugin for a language used in this file.
*/
val languagePlugin: UastLanguagePlugin
/**
* Returns all comments in file.
*/
val allCommentsInFile: List<UComment>
override fun asLogString() = "UFile"
/**
* [UFile] is a top-level element of the Uast hierarchy, thus the [containingElement] always returns null for it.
*/
override val containingElement: UElement?
get() = null
override fun accept(visitor: UastVisitor) {
if (visitor.visitFile(this)) return
imports.acceptList(visitor)
classes.acceptList(visitor)
visitor.afterVisitFile(this)
}
}
@@ -1,127 +0,0 @@
/*
* Copyright 2000-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.uast
import org.jetbrains.uast.visitor.UastVisitor
/**
* Represents a function.
* Function could be a JVM method, a property accessor, a constructor, etc.
*/
interface UFunction : UDeclaration, UModifierOwner, UVisibilityOwner, UAnnotated {
/**
* Returns the function kind.
*/
val kind: UastFunctionKind
/**
* Returns the function value parameters.
*/
val valueParameters: List<UVariable>
/**
* Returns the function value parameters count.
* Retrieving the parameter count could be faster than getting the [valueParameters.size],
* because there is no need to create actual [UVariable] instances.
*/
val valueParameterCount: Int
/**
* Returns the function type parameters.
*/
val typeParameters: List<UTypeReference>
/**
* Returns the function type parameter count.
*/
val typeParameterCount: Int
/**
* Returns the function return type, or null if the function does not have a return type
* (e.g. it is a constructor).
*/
val returnType: UType?
/**
* Returns the function body expression.
*/
val body: UExpression?
/**
* Returns the function JVM descriptor (for example, "(ILjava/lang/String;)[I"), or null if the descriptor is unknown.
*/
open val bytecodeDescriptor: String?
get() = null
/**
* Get the list of all super functions for this function.
*/
fun getSuperFunctions(context: UastContext): List<UFunction>
override fun accept(visitor: UastVisitor) {
if (visitor.visitFunction(this)) return
nameElement?.accept(visitor)
valueParameters.acceptList(visitor)
body?.accept(visitor)
annotations.acceptList(visitor)
typeParameters.acceptList(visitor)
returnType?.accept(visitor)
visitor.afterVisitFunction(this)
}
override fun renderString(): String = buildString {
appendWithSpace(visibility.name)
appendWithSpace(renderModifiers())
append("fun ")
if (typeParameterCount > 0) {
append('<').append(typeParameters.joinToString { it.renderString() }).append("> ")
}
append(name)
append('(')
append(valueParameters.joinToString() { it.renderString() })
append(')')
returnType?.let { append(": " + it.renderString()) }
val body = body
val bodyRendered = when (body) {
null -> ""
is UBlockExpression -> " " + body.renderString()
else -> " = " + body.renderString()
}
append(bodyRendered)
}
override fun logString() = log("UFunction ($name, kind = ${kind.text}, paramCount = $valueParameterCount)", body)
}
object UFunctionNotResolved : UFunction {
override val kind = UastFunctionKind(ERROR_NAME)
override val valueParameters = emptyList<UVariable>()
override val valueParameterCount = 0
override val typeParameters = emptyList<UTypeReference>()
override val typeParameterCount = 0
override val returnType = null
override val body = null
override val visibility = UastVisibility.PRIVATE
override val nameElement = null
override val parent = null
override val name = ERROR_NAME
override fun hasModifier(modifier: UastModifier) = false
override fun getSuperFunctions(context: UastContext) = emptyList<UFunction>()
override val annotations = emptyList<UAnnotation>()
}
@@ -1,49 +1,26 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
import org.jetbrains.uast.psi.PsiElementBacked
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents an import statement. * Represents an import statement.
*/ */
interface UImportStatement : UElement { interface UImportStatement : UResolvable, UElement, PsiElementBacked {
/** /**
* Returns the qualified name to import. * Returns true if the statement is an import-on-demand (star-import) statement.
*/ */
val fqNameToImport: String? val isOnDemand: Boolean
/** /**
* Returns true is the import is a "star" import (on-demand, all-under). * Returns the reference to the imported element.
*/ */
val isStarImport: Boolean val importReference: UElement?
/** override fun asLogString() = "UImportStatement (onDemand = $isOnDemand)"
* Resolve the import statement to the declaration.
*
* @param context the Uast context
* @return the declaration element, or null if the declaration was not resolved.
*/
fun resolve(context: UastContext): UDeclaration?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitImportStatement(this) if (visitor.visitImportStatement(this)) return
visitor.afterVisitImportStatement(this) visitor.afterVisitImportStatement(this)
} }
override fun logString() = "UImport ($fqNameToImport)"
override fun renderString() = "import ${fqNameToImport ?: ""}"
} }
@@ -0,0 +1,58 @@
package org.jetbrains.uast
import com.intellij.psi.PsiAnnotationMethod
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.visitor.UastVisitor
/**
* A method visitor to be used in [UastVisitor].
*/
interface UMethod : UDeclaration, PsiMethod {
override val psi: PsiMethod
/**
* Returns the body expression (which can be also a [UBlockExpression]).
*/
val uastBody: UExpression?
/**
* Returns the method parameters.
*/
val uastParameters: List<UParameter>
@Deprecated("Use uastBody instead.", ReplaceWith("uastBody"))
override fun getBody() = psi.body
override fun accept(visitor: UastVisitor) {
if (visitor.visitMethod(this)) return
uastAnnotations.acceptList(visitor)
uastParameters.acceptList(visitor)
uastBody?.accept(visitor)
visitor.afterVisitMethod(this)
}
override fun asLogString() = "UMethod (name = $name)"
}
interface UAnnotationMethod : UMethod, PsiAnnotationMethod {
override val psi: PsiAnnotationMethod
/**
* Returns the default value of this annotation method.
*/
val uastDefaultValue: UExpression?
override fun getDefaultValue() = psi.defaultValue
override fun accept(visitor: UastVisitor) {
if (visitor.visitMethod(this)) return
uastAnnotations.acceptList(visitor)
uastParameters.acceptList(visitor)
uastBody?.accept(visitor)
uastDefaultValue?.accept(visitor)
visitor.afterVisitMethod(this)
}
override fun asLogString() = "UAnnotationMethod (name = $name)"
}
@@ -1,122 +0,0 @@
/*
* Copyright 2000-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.uast
import org.jetbrains.uast.visitor.UastVisitor
/**
* Represents the type.
* The abstraction is quite simple. Intersection types, union types, platform types are yet to be supported.
*/
interface UType : UElement, UNamed, UFqNamed, UAnnotated, UResolvable {
/**
* Returns the simple (non-qualified) type name.
* The simple type name is only for the debug purposes. Do not check against it in the production code.
*/
override val name: String
/**
* Returns true if the type is either a boxed or an unboxed [Integer], false otherwise.
*/
val isInt: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Short], false otherwise.
*/
val isShort: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Long], false otherwise.
*/
val isLong: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Float], false otherwise.
*/
val isFloat: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Double], false otherwise.
*/
val isDouble: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Character], false otherwise.
*/
val isChar: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Boolean], false otherwise.
*/
val isBoolean: Boolean
/**
* Returns true if the type is either a boxed or an unboxed [Byte], false otherwise.
*/
val isByte: Boolean
override fun logString() = "UType ($name)"
override fun renderString() = name
/**
* Returns the [UClass] declaration element for this type.
*
* @param context the Uast context
* @return the [UClass] declaration element, or null if the class was not resolved.
*/
override fun resolve(context: UastContext): UClass?
override fun resolveOrEmpty(context: UastContext) = resolve(context) ?: UClassNotResolved
override fun accept(visitor: UastVisitor) {
if (visitor.visitType(this)) return
annotations.acceptList(visitor)
visitor.afterVisitType(this)
}
}
/**
* Represents a type reference.
*/
interface UTypeReference : UDeclaration, UResolvable {
override fun renderString() = ""
override fun logString() = log("UTypeReference")
/**
* Returns the [UClass] declaration for this type reference.
*
* @param context the Uast context
* @return the [UClass] declaration element, or null if the class was not resolved.
*/
override fun resolve(context: UastContext): UClass?
override fun resolveOrEmpty(context: UastContext) = resolve(context) ?: UClassNotResolved
}
object UastErrorType : UType, NoAnnotations {
override val isInt = false
override val isLong = false
override val isShort = false
override val isFloat = false
override val isDouble = false
override val isChar = false
override val isByte = false
override val parent = null
override val name = ERROR_NAME
override val fqName = null
override val isBoolean = false
override fun resolve(context: UastContext) = null
}
@@ -1,95 +1,70 @@
/*
* Copyright 2000-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.uast package org.jetbrains.uast
import org.jetbrains.uast.kinds.UastVariableInitialierKind import com.intellij.psi.*
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
interface UVariable : UDeclaration, UModifierOwner, UVisibilityOwner, UAnnotated { /**
/** * A variable wrapper to be used in [UastVisitor].
* Return the variable initializer (or the default value for value parameter), or null if the variable is not initialized. */
*/ interface UVariable : UDeclaration, PsiVariable {
val initializer: UExpression? override val psi: PsiVariable
/** /**
* Return the variable initializer kind (simple initializer, property delegation, etc.). * Returns the variable initializer or the parameter default value, or null if the variable has not an initializer.
*/ */
val initializerKind: UastVariableInitialierKind val uastInitializer: UExpression?
/** /**
* Return the variable kind. * Returns variable type reference.
*/ */
val kind: UastVariableKind val typeReference: UTypeReferenceExpression?
/**
* Return the variable type.
*/
val type: UType
/**
* Return the list of accessors if the variable is a property, or null otherwise.
*/
open val accessors: List<UFunction>?
get() = null
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitVariable(this)) return if (visitor.visitVariable(this)) return
nameElement?.accept(visitor) uastAnnotations.acceptList(visitor)
initializer?.accept(visitor) uastInitializer?.accept(visitor)
annotations.acceptList(visitor)
type.accept(visitor)
visitor.afterVisitVariable(this) visitor.afterVisitVariable(this)
} }
override fun renderString(): String = buildString { @Deprecated("Use uastInitializer instead.", ReplaceWith("uastInitializer"))
if (kind != UastVariableKind.VALUE_PARAMETER) appendWithSpace(visibility.name) override fun getInitializer() = psi.initializer
appendWithSpace(renderModifiers())
if (kind != UastVariableKind.VALUE_PARAMETER) append("var ")
append(name)
append(": ")
append(type.name)
if (initializer != null && initializer !is EmptyUExpression) {
append(" = ")
append(initializer!!.renderString())
}
accessors?.let { override fun asLogString() = "UVariable (name = $name)"
appendln()
it.forEachIndexed { i, accessor -> override fun asRenderString() = buildString {
this@buildString.append(accessor.renderString().withMargin) val modifiers = PsiModifier.MODIFIERS.filter { psi.hasModifierProperty(it) }.joinToString(" ")
if ((i + 1) < it.size) appendln() if (modifiers.isNotEmpty()) append(modifiers).append(' ')
} append("var ").append(psi.name).append(": ").append(psi.type.getCanonicalText(false))
} }
}
interface UParameter : UVariable, PsiParameter {
override val psi: PsiParameter
}
interface UField : UVariable, PsiField {
override val psi: PsiField
}
interface ULocalVariable : UVariable, PsiLocalVariable {
override val psi: PsiLocalVariable
}
interface UEnumConstant : UField, UCallExpression, PsiEnumConstant {
override val psi: PsiEnumConstant
override fun asLogString() = "UEnumConstant (name = ${psi.name}"
override fun accept(visitor: UastVisitor) {
if (visitor.visitVariable(this)) return
uastAnnotations.acceptList(visitor)
methodIdentifier?.accept(visitor)
classReference?.accept(visitor)
valueArguments.acceptList(visitor)
visitor.afterVisitVariable(this)
} }
override fun logString() = "UVariable ($name, kind = ${kind.name})\n" + override fun asRenderString() = name ?: "<ERROR>"
(initializer?.let { it.logString().withMargin } ?: "<no initializer>")
}
object UVariableNotResolved : UVariable {
override val initializer = null
override val initializerKind = UastVariableInitialierKind.NO_INITIALIZER
override val kind = UastVariableKind(ERROR_NAME)
override val type = UastErrorType
override val nameElement = null
override val parent = null
override val name = ERROR_NAME
override val visibility = UastVisibility.LOCAL
override fun hasModifier(modifier: UastModifier) = false
override val annotations = emptyList<UAnnotation>()
} }
@@ -15,6 +15,8 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -38,6 +40,7 @@ interface UArrayAccessExpression : UExpression {
visitor.afterVisitArrayAccessExpression(this) visitor.afterVisitArrayAccessExpression(this)
} }
override fun logString() = log("UArrayAccessExpression", receiver, indices) override fun asLogString() = log("UArrayAccessExpression", receiver, indices)
override fun renderString() = receiver.renderString() + indices.joinToString(prefix = "[", postfix = "]") { it.renderString() } override fun asRenderString() = receiver.asRenderString() +
indices.joinToString(prefix = "[", postfix = "]") { it.asRenderString() }
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -26,15 +27,27 @@ interface UBinaryExpression : UExpression {
*/ */
val leftOperand: UExpression val leftOperand: UExpression
/**
* Returns the right operand.
*/
val rightOperand: UExpression
/** /**
* Returns the binary operator. * Returns the binary operator.
*/ */
val operator: UastBinaryOperator val operator: UastBinaryOperator
/** /**
* Returns the right operand. * Returns the operator identifier.
*/ */
val rightOperand: UExpression val operatorIdentifier: UIdentifier?
/**
* Resolve the operator method.
*
* @return the resolved method, or null if the method can't be resolved, or if the expression is not a method call.
*/
fun resolveOperator(): PsiMethod?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitBinaryExpression(this)) return if (visitor.visitBinaryExpression(this)) return
@@ -43,8 +56,10 @@ interface UBinaryExpression : UExpression {
visitor.afterVisitBinaryExpression(this) visitor.afterVisitBinaryExpression(this)
} }
override fun logString() = override fun asLogString() =
"UBinaryExpression (${operator.text})\n" + leftOperand.logString().withMargin + "\n" + rightOperand.logString().withMargin "UBinaryExpression (${operator.text})" + LINE_SEPARATOR +
leftOperand.asLogString().withMargin + LINE_SEPARATOR +
rightOperand.asLogString().withMargin
override fun renderString() = leftOperand.renderString() + ' ' + operator.text + ' ' + rightOperand.renderString() override fun asRenderString() = leftOperand.asRenderString() + ' ' + operator.text + ' ' + rightOperand.asRenderString()
} }
@@ -15,6 +15,10 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiType
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -32,22 +36,23 @@ interface UBinaryExpressionWithType : UExpression {
val operationKind: UastBinaryExpressionWithTypeKind val operationKind: UastBinaryExpressionWithTypeKind
/** /**
* Returns the type. * Returns the type reference of this expression.
*/ */
val type: UType val typeReference: UTypeReferenceExpression?
/** /**
* Returns the type reference. * Returns the type.
*/ */
val typeReference: UTypeReference? val type: PsiType
override fun logString() = log("UBinaryExpressionWithType (${getExpressionType()?.name}, ${operationKind.name})", operand) override fun asLogString() = log("UBinaryExpressionWithType " +
override fun renderString() = "${operand.renderString()} ${operationKind.name} ${type.name}" "(${getExpressionType()?.name}, ${operationKind.name})", operand)
override fun asRenderString() = "${operand.asRenderString()} ${operationKind.name} ${type.name}"
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitBinaryExpressionWithType(this)) return if (visitor.visitBinaryExpressionWithType(this)) return
operand.accept(visitor) operand.accept(visitor)
type.accept(visitor)
visitor.afterVisitBinaryExpressionWithType(this) visitor.afterVisitBinaryExpressionWithType(this)
} }
} }
@@ -15,6 +15,8 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -32,11 +34,11 @@ interface UBlockExpression : UExpression {
visitor.afterVisitBlockExpression(this) visitor.afterVisitBlockExpression(this)
} }
override fun logString() = log("UBlockExpression", expressions) override fun asLogString() = log("UBlockExpression", expressions)
override fun renderString() = buildString { override fun asRenderString() = buildString {
appendln("{") appendln("{")
expressions.forEach { appendln(it.renderString().withMargin) } expressions.forEach { appendln(it.asRenderString().withMargin) }
appendln("}") appendln("}")
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,6 +32,6 @@ interface UBreakExpression : UExpression {
visitor.afterVisitBreakExpression(this) visitor.afterVisitBreakExpression(this)
} }
override fun logString() = "UBreakExpression (" + (label ?: "<no label>") + ")" override fun asLogString() = "UBreakExpression (" + (label ?: "<no label>") + ")"
override fun renderString() = label?.let { "break@$it" } ?: "break" override fun asRenderString() = label?.let { "break@$it" } ?: "break"
} }
@@ -15,64 +15,49 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents a call expression (function call, constructor call, array initializer). * Represents a call expression (method/constructor call, array initializer).
*/ */
interface UCallExpression : UExpression, UResolvable { interface UCallExpression : UExpression, UResolvable {
val receiverType: UType?
/** /**
* Returns the call kind. * Returns the call kind.
*/ */
val kind: UastCallKind val kind: UastCallKind
/** /**
* Returns the function reference expression if the call is a function call, null otherwise. * Returns the called method name, or null if the call is not a method call.
* This property should return the actual resolved function name.
*/ */
val functionReference: USimpleReferenceExpression? val methodName: String?
/**
* Returns the expression receiver.
* For example, for call `a.b.[c()]` the receiver is `a.b`.
*/
val receiver: UExpression?
/**
* Returns the receiver type, or null if the call has not a receiver.
*/
val receiverType: PsiType?
/**
* Returns the function reference expression if the call is a non-constructor method call, null otherwise.
*/
val methodIdentifier: UIdentifier?
/** /**
* Returns the class reference if the call is a constructor call, null otherwise. * Returns the class reference if the call is a constructor call, null otherwise.
*/ */
val classReference: USimpleReferenceExpression? val classReference: UReferenceExpression?
/**
* Returns the function name if the call is a function call, null otherwise.
*
* [functionName] should only be used in debug messages.
* Use [matchesFunctionName] to check against the name.
*/
val functionName: String?
/**
* Returns an element for the function name node, or null if the node does not exist in the underlying AST (Psi).
*/
val functionNameElement: UElement?
/**
* Checks if the function name is [name].
*
* @param name the name to check against.
* @return true if the call is a function call, and the function name is [name], false otherwise.
*/
open fun matchesFunctionName(name: String) = functionName == name
/**
* Checks if the function name is [name], and the function containing class qualified name is [containingClassFqName].
*
* @param containingClassFqName the required containing class qualified name.
* @param name the function name to check against.
* @return true if the call is a function call, the function name is [name],
* and the qualified name of the function direct containing class is [containingClassFqName],
* false otherwise.
*/
open fun matchesFunctionNameWithContaining(containingClassFqName: String, name: String): Boolean {
if (!matchesFunctionName(name)) return false
val containingClass = parent as? UClass ?: return false
return containingClass.matchesFqName(containingClassFqName)
}
/** /**
* Returns the value argument count. * Returns the value argument count.
@@ -93,40 +78,35 @@ interface UCallExpression : UExpression, UResolvable {
val typeArgumentCount: Int val typeArgumentCount: Int
/** /**
* Returns the function type arguments. * Returns the type arguments for the call.
*/ */
val typeArguments: List<UType> val typeArguments: List<PsiType>
/** /**
* Resolve the call to the [UFunction] element. * Returns the return type of the called function, or null if the call is not a function call.
*
* @param context the Uast context
* @return the [UFunction] element, or null if the reference was not resolved.
*/ */
override fun resolve(context: UastContext): UFunction? val returnType: PsiType?
/** /**
* Try to resolve the call to the [UFunction] element. * Resolve the called method.
* *
* @param context the Uast context * @return the [PsiMethod], or null if the method was not resolved.
* @return the [UFunction] element, of [UFunctionNotResolved] if the reference was not resolved, * Note that the [PsiMethod] is an unwrapped [PsiMethod], not a [UMethod].
* or the call is not a function call.
*/ */
override fun resolveOrEmpty(context: UastContext): UFunction = resolve(context) ?: UFunctionNotResolved override fun resolve(): PsiMethod?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitCallExpression(this)) return if (visitor.visitCallExpression(this)) return
functionReference?.accept(visitor) methodIdentifier?.accept(visitor)
classReference?.accept(visitor) classReference?.accept(visitor)
functionNameElement?.accept(visitor)
valueArguments.acceptList(visitor) valueArguments.acceptList(visitor)
typeArguments.acceptList(visitor)
visitor.afterVisitCallExpression(this) visitor.afterVisitCallExpression(this)
} }
override fun logString() = log("UFunctionCallExpression ($kind, argCount = $valueArgumentCount)", functionReference, valueArguments) override fun asLogString() = log("UCallExpression ($kind, argCount = $valueArgumentCount)", methodIdentifier, valueArguments)
override fun renderString(): String {
val ref = functionName ?: classReference?.renderString() ?: functionReference?.renderString() ?: "<noref>" override fun asRenderString(): String {
return ref + "(" + valueArguments.joinToString { it.renderString() } + ")" val ref = classReference?.asRenderString() ?: methodName ?: methodIdentifier?.asRenderString() ?: "<noref>"
return ref + "(" + valueArguments.joinToString { it.asRenderString() } + ")"
} }
} }
@@ -15,12 +15,14 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiType
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents a callable reference expression, e.g. `Clazz::functionName`. * Represents a callable reference expression, e.g. `Clazz::methodName`.
*/ */
interface UCallableReferenceExpression : UExpression, UResolvable { interface UCallableReferenceExpression : UExpression {
/** /**
* Returns the qualifier expression. * Returns the qualifier expression.
* Can be null if the [qualifierType] is known. * Can be null if the [qualifierType] is known.
@@ -31,7 +33,7 @@ interface UCallableReferenceExpression : UExpression, UResolvable {
* Returns the qualifier type. * Returns the qualifier type.
* Can be null if the qualifier is an expression. * Can be null if the qualifier is an expression.
*/ */
val qualifierType: UType? val qualifierType: PsiType?
/** /**
* Returns the callable name. * Returns the callable name.
@@ -41,14 +43,14 @@ interface UCallableReferenceExpression : UExpression, UResolvable {
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitCallableReferenceExpression(this)) return if (visitor.visitCallableReferenceExpression(this)) return
qualifierExpression?.accept(visitor) qualifierExpression?.accept(visitor)
qualifierType?.accept(visitor)
visitor.afterVisitCallableReferenceExpression(this) visitor.afterVisitCallableReferenceExpression(this)
} }
override fun logString() = "UCallableReferenceExpression" override fun asLogString() = "UCallableReferenceExpression"
override fun renderString() = buildString {
override fun asRenderString() = buildString {
qualifierExpression?.let { qualifierExpression?.let {
append(it.renderString()) append(it.asRenderString())
} ?: qualifierType?.let { } ?: qualifierType?.let {
append(it.name) append(it.name)
} }
@@ -15,22 +15,31 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiType
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents the class literal expression, e.g. `Clazz.class`. * Represents the class literal expression, e.g. `Clazz.class`.
*/ */
interface UClassLiteralExpression : UExpression { interface UClassLiteralExpression : UExpression {
override fun logString() = "UClassLiteralExpression" override fun asLogString() = "UClassLiteralExpression"
override fun renderString() = type?.name.orEmpty() + "::class" override fun asRenderString() = (type?.name) ?: "(${expression?.asRenderString() ?: "<no expression>"})" + "::class"
/** /**
* Returns the type for this class literal expression. * Returns a type of this class literal, or null if the type can't be determined in a compile-time.
*/ */
val type: UType? val type: PsiType?
/**
* Returns an expression for this class literal expression.
* Might be null if the [type] is specified.
*/
val expression: UExpression?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitClassLiteralExpression(this) visitor.visitClassLiteralExpression(this)
expression?.accept(visitor)
visitor.afterVisitClassLiteralExpression(this) visitor.afterVisitClassLiteralExpression(this)
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,6 +32,6 @@ interface UContinueExpression : UExpression {
visitor.afterVisitContinueExpression(this) visitor.afterVisitContinueExpression(this)
} }
override fun logString() = "UContinueExpression (" + (label ?: "<no label>") + ")" override fun asLogString() = "UContinueExpression (" + (label ?: "<no label>") + ")"
override fun renderString() = label?.let { "continue@$it" } ?: "continue" override fun asRenderString() = label?.let { "continue@$it" } ?: "continue"
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -39,7 +40,6 @@ interface ULabeledExpression : UExpression {
override fun evaluate() = expression.evaluate() override fun evaluate() = expression.evaluate()
override fun logString() = log("ULabeledExpression ($label)", expression) override fun asLogString() = log("ULabeledExpression ($label)", expression)
override fun asRenderString() = "$label@ ${expression.asRenderString()}"
override fun renderString() = "$label@ ${expression.renderString()}"
} }
@@ -15,6 +15,8 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -24,7 +26,7 @@ interface ULambdaExpression : UExpression {
/** /**
* Returns the list of lambda value parameters. * Returns the list of lambda value parameters.
*/ */
val valueParameters: List<UVariable> val valueParameters: List<UParameter>
/** /**
* Returns the lambda body expression. * Returns the lambda body expression.
@@ -38,13 +40,14 @@ interface ULambdaExpression : UExpression {
visitor.afterVisitLambdaExpression(this) visitor.afterVisitLambdaExpression(this)
} }
override fun logString() = log("ULambdaExpression", valueParameters, body) override fun asLogString() = log("ULambdaExpression", valueParameters, body)
override fun renderString(): String {
override fun asRenderString(): String {
val renderedValueParameters = if (valueParameters.isEmpty()) val renderedValueParameters = if (valueParameters.isEmpty())
"" ""
else else
valueParameters.joinToString { it.renderString() } + " ->\n" valueParameters.joinToString { it.asRenderString() } + " ->" + LINE_SEPARATOR
return "{ " + renderedValueParameters + body.renderString().withMargin + "\n}" return "{ " + renderedValueParameters + body.asRenderString().withMargin + LINE_SEPARATOR + "}"
} }
} }
@@ -30,7 +30,7 @@ interface ULiteralExpression : UExpression {
/** /**
* Returns true if the literal is a `null`-literal, false otherwise. * Returns true if the literal is a `null`-literal, false otherwise.
*/ */
open val isNull: Boolean val isNull: Boolean
get() = value == null get() = value == null
/** /**
@@ -50,7 +50,7 @@ interface ULiteralExpression : UExpression {
visitor.afterVisitLiteralExpression(this) visitor.afterVisitLiteralExpression(this)
} }
override fun renderString(): String { override fun asRenderString(): String {
val value = value val value = value
return when (value) { return when (value) {
null -> "null" null -> "null"
@@ -63,5 +63,5 @@ interface ULiteralExpression : UExpression {
} }
} }
override fun logString() = "ULiteralExpression (${renderString()})" override fun asLogString() = "ULiteralExpression (${asRenderString()})"
} }
@@ -15,11 +15,12 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
class UNamedExpression( class UNamedExpression(
override val name: String, override val name: String,
override val parent: UElement override val containingElement: UElement?
): UExpression, UNamed { ): UExpression, UNamed {
lateinit var expression: UExpression lateinit var expression: UExpression
@@ -29,8 +30,16 @@ class UNamedExpression(
visitor.afterVisitElement(this) visitor.afterVisitElement(this)
} }
override fun logString() = log("UNamedExpression ($name)", expression) override fun asLogString() = log("UNamedExpression ($name)", expression)
override fun renderString() = "$name: $expression" override fun asRenderString() = name + " = " + expression.asRenderString()
override fun evaluate() = expression.evaluate() override fun evaluate() = expression.evaluate()
companion object {
inline fun create(name: String, parent: UElement?, innerExpr: UElement.() -> UExpression): UNamedExpression {
return UNamedExpression(name, parent).apply {
expression = innerExpr(this)
}
}
}
} }
@@ -15,23 +15,44 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiType
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents an object literal expression, e.g. `new Runnable() {}` in Java. * Represents an object literal expression, e.g. `new Runnable() {}` in Java.
*/ */
interface UObjectLiteralExpression : UExpression { interface UObjectLiteralExpression : UCallExpression {
/** /**
* Returns the class declaration. * Returns the class declaration.
*/ */
val declaration: UClass val declaration: UClass
override val methodIdentifier: UIdentifier?
get() = null
override val kind: UastCallKind
get() = UastCallKind.CONSTRUCTOR_CALL
override val methodName: String?
get() = null
override val receiver: UExpression?
get() = null
override val receiverType: PsiType?
get() = null
override val returnType: PsiType?
get() = null
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitObjectLiteralExpression(this)) return if (visitor.visitObjectLiteralExpression(this)) return
declaration.accept(visitor) declaration.accept(visitor)
visitor.afterVisitObjectLiteralExpression(this) visitor.afterVisitObjectLiteralExpression(this)
} }
override fun logString() = log("UObjectLiteralExpression", declaration) override fun asLogString() = log("UObjectLiteralExpression", declaration)
override fun renderString() = "anonymous " + declaration.renderString() override fun asRenderString() = "anonymous " + declaration.text
} }
@@ -15,6 +15,7 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -34,6 +35,6 @@ interface UParenthesizedExpression : UExpression {
override fun evaluate() = expression.evaluate() override fun evaluate() = expression.evaluate()
override fun logString() = log("UParenthesizedExpression", expression) override fun asLogString() = log("UParenthesizedExpression", expression)
override fun renderString() = '(' + expression.renderString() + ')' override fun asRenderString() = '(' + expression.asRenderString() + ')'
} }
@@ -15,12 +15,14 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents the qualified expression (receiver.selector). * Represents the qualified expression (receiver.selector).
*/ */
interface UQualifiedExpression : UExpression, UResolvable { interface UQualifiedReferenceExpression : UReferenceExpression {
/** /**
* Returns the expression receiver. * Returns the expression receiver.
*/ */
@@ -36,30 +38,14 @@ interface UQualifiedExpression : UExpression, UResolvable {
*/ */
val accessType: UastQualifiedExpressionAccessType val accessType: UastQualifiedExpressionAccessType
/** override fun asRenderString() = receiver.asRenderString() + accessType.name + selector.asRenderString()
* Checks if the selector is a simple reference expression, and if its identifier is [identifier].
*
* @param identifier the identifier to check agains
* @return true if the selector is a simple reference expression, and if its identifier is [identifier],
* false otherwise
*/
fun selectorMatches(identifier: String) = (selector as? USimpleReferenceExpression)?.identifier == identifier
/**
* Returns the selector identifier if the selector is a simple reference expression.
*
* @return the selector identifier if the selector is a simple reference expression, null otherwise.
*/
fun getSelectorAsIdentifier(): String? = (selector as? USimpleReferenceExpression)?.identifier
override fun renderString() = receiver.renderString() + accessType.name + selector.renderString()
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitQualifiedExpression(this)) return if (visitor.visitQualifiedReferenceExpression(this)) return
receiver.accept(visitor) receiver.accept(visitor)
selector.accept(visitor) selector.accept(visitor)
visitor.afterVisitQualifiedExpression(this) visitor.afterVisitQualifiedReferenceExpression(this)
} }
override fun logString() = log("UQualifiedExpression", receiver, selector) override fun asLogString() = log("UQualifiedExpression", receiver, selector)
} }
@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.uast.java
import org.jetbrains.uast.UastVisibility package org.jetbrains.uast.expressions
object JavaUastVisibilities { import org.jetbrains.uast.UExpression
@JvmField import org.jetbrains.uast.UResolvable
val PACKAGE_LOCAL = UastVisibility("package_local")
interface UReferenceExpression : UExpression, UResolvable {
/**
* Returns the resolved name for this reference, or null if the reference can't be resolved.
*/
val resolvedName: String?
override fun asLogString() = "UReferenceExpression"
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -33,6 +34,6 @@ interface UReturnExpression : UExpression {
visitor.afterVisitReturnExpression(this) visitor.afterVisitReturnExpression(this)
} }
override fun renderString() = returnExpression.let { if (it == null) "return" else "return " + it.renderString() } override fun asRenderString() = returnExpression.let { if (it == null) "return" else "return " + it.asRenderString() }
override fun logString() = log("UReturnExpression", returnExpression) override fun asLogString() = log("UReturnExpression", returnExpression)
} }
@@ -15,22 +15,23 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.expressions.UReferenceExpression
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents a simple reference expression (a non-qualified identifier). * Represents a simple reference expression (a non-qualified identifier).
*/ */
interface USimpleReferenceExpression : UExpression, UResolvable { interface USimpleNameReferenceExpression : UReferenceExpression {
/** /**
* Returns the identifier name. * Returns the identifier name.
*/ */
val identifier: String val identifier: String
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitSimpleReferenceExpression(this) visitor.visitSimpleNameReferenceExpression(this)
visitor.afterVisitSimpleReferenceExpression(this) visitor.afterVisitSimpleNameReferenceExpression(this)
} }
override fun logString() = "USimpleReferenceExpression ($identifier)" override fun asLogString() = "USimpleReferenceExpression ($identifier)"
override fun renderString() = identifier override fun asRenderString() = identifier
} }
@@ -22,8 +22,8 @@ import org.jetbrains.uast.visitor.UastVisitor
* Qualified `super` is not supported at the moment. * Qualified `super` is not supported at the moment.
*/ */
interface USuperExpression : UExpression { interface USuperExpression : UExpression {
override fun logString() = "USuperExpression" override fun asLogString() = "USuperExpression"
override fun renderString() = "super" override fun asRenderString() = "super"
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitSuperExpression(this) visitor.visitSuperExpression(this)
@@ -22,8 +22,8 @@ import org.jetbrains.uast.visitor.UastVisitor
* Qualified `this` is not supported at the moment. * Qualified `this` is not supported at the moment.
*/ */
interface UThisExpression : UExpression { interface UThisExpression : UExpression {
override fun logString() = "UThisExpression" override fun asLogString() = "UThisExpression"
override fun renderString() = "this" override fun asRenderString() = "this"
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
visitor.visitThisExpression(this) visitor.visitThisExpression(this)
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
@@ -33,7 +34,6 @@ interface UThrowExpression : UExpression {
visitor.afterVisitThrowExpression(this) visitor.afterVisitThrowExpression(this)
} }
override fun renderString() = "throw " + thrownExpression.renderString() override fun asRenderString() = "throw " + thrownExpression.asRenderString()
override fun asLogString() = log("UThrowExpression", thrownExpression)
override fun logString() = log("UThrowExpression", thrownExpression)
} }
@@ -0,0 +1,27 @@
package org.jetbrains.uast.expressions
import com.intellij.psi.PsiType
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.name
import org.jetbrains.uast.visitor.UastVisitor
interface UTypeReferenceExpression : UExpression {
/**
* Returns the resolved type for this reference.
*/
val type: PsiType
/**
* Returns the qualified name of the class type, or null if the [type] is not a class type.
*/
fun getQualifiedName() = PsiTypesUtil.getPsiClass(type)?.qualifiedName
override fun accept(visitor: UastVisitor) {
visitor.visitTypeReferenceExpression(this)
visitor.afterVisitTypeReferenceExpression(this)
}
override fun asLogString() = "UTypeReferenceExpression (${type.name})"
override fun asRenderString() = type.name
}
@@ -15,12 +15,33 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
interface UUnaryExpression : UExpression { interface UUnaryExpression : UExpression {
/**
* Returns the expression operand.
*/
val operand: UExpression val operand: UExpression
/**
* Returns the expression operator.
*/
val operator: UastOperator val operator: UastOperator
/**
* Returns the operator identifier.
*/
val operatorIdentifier: UIdentifier?
/**
* Resolve the operator method.
*
* @return the resolved method, or null if the method can't be resolved, or if the expression is not a method call.
*/
fun resolveOperator(): PsiMethod?
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitUnaryExpression(this)) return if (visitor.visitUnaryExpression(this)) return
operand.accept(visitor) operand.accept(visitor)
@@ -37,8 +58,8 @@ interface UPrefixExpression : UUnaryExpression {
visitor.afterVisitPrefixExpression(this) visitor.afterVisitPrefixExpression(this)
} }
override fun logString() = log("UPrefixExpression (${operator.text})", operand) override fun asLogString() = log("UPrefixExpression (${operator.text})", operand)
override fun renderString() = operator.text + operand.renderString() override fun asRenderString() = operator.text + operand.asRenderString()
} }
interface UPostfixExpression : UUnaryExpression { interface UPostfixExpression : UUnaryExpression {
@@ -50,6 +71,6 @@ interface UPostfixExpression : UUnaryExpression {
visitor.afterVisitPostfixExpression(this) visitor.afterVisitPostfixExpression(this)
} }
override fun logString() = log("UPostfixExpression (${operator.text})", operand) override fun asLogString() = log("UPostfixExpression (${operator.text})", operand)
override fun renderString() = operand.renderString() + operator.text override fun asRenderString() = operand.asRenderString() + operator.text
} }
@@ -15,35 +15,26 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.internal.log
import org.jetbrains.uast.visitor.UastVisitor import org.jetbrains.uast.visitor.UastVisitor
/** /**
* Represents a list of declarations. * Represents a list of declarations.
* Example in Java: `int a = 4, b = 3`. * Example in Java: `int a = 4, b = 3`.
*/ */
interface UDeclarationsExpression : UExpression { interface UVariableDeclarationsExpression : UExpression {
/** /**
* Returns the list of declarations inside this [UDeclarationsExpression]. * Returns the list of variables inside this [UVariableDeclarationsExpression].
*/
val declarations: List<UElement>
/**
* Returns the list of variables inside this [UDeclarationsExpression].
*/ */
val variables: List<UVariable> val variables: List<UVariable>
get() = declarations.filterIsInstance<UVariable>()
override fun accept(visitor: UastVisitor) { override fun accept(visitor: UastVisitor) {
if (visitor.visitDeclarationsExpression(this)) return if (visitor.visitDeclarationsExpression(this)) return
declarations.acceptList(visitor) variables.acceptList(visitor)
visitor.afterVisitDeclarationsExpression(this) visitor.afterVisitDeclarationsExpression(this)
} }
override fun renderString() = declarations.joinToString("\n") { it.renderString() } override fun asRenderString() = variables.joinToString(LINE_SEPARATOR) { it.asRenderString() }
override fun logString() = log("UDeclarationsExpression", declarations) override fun asLogString() = log("UDeclarationsExpression", variables)
} }
class SimpleUDeclarationsExpression(
override val parent: UElement,
override val declarations: List<UElement>
) : UDeclarationsExpression
@@ -23,6 +23,27 @@ package org.jetbrains.uast
*/ */
fun UElement.isNullLiteral(): Boolean = this is ULiteralExpression && this.isNull fun UElement.isNullLiteral(): Boolean = this is ULiteralExpression && this.isNull
/**
* Checks if the [UElement] is a boolean literal.
*
* @return true if the receiver is a boolean literal, false otherwise.
*/
fun UElement.isBooleanLiteral(): Boolean = this is ULiteralExpression && this.isBoolean
/**
* Checks if the [UElement] is a `true` boolean literal.
*
* @return true if the receiver is a `true` boolean literal, false otherwise.
*/
fun UElement.isTrueLiteral(): Boolean = this is ULiteralExpression && this.isBoolean && this.value == true
/**
* Checks if the [UElement] is a `false` boolean literal.
*
* @return true if the receiver is a `false` boolean literal, false otherwise.
*/
fun UElement.isFalseLiteral(): Boolean = this is ULiteralExpression && this.isBoolean && this.value == false
/** /**
* Checks if the [UElement] is a [String] literal. * Checks if the [UElement] is a [String] literal.
* *
@@ -0,0 +1,41 @@
package org.jetbrains.uast.internal
import com.intellij.psi.PsiElement
import org.jetbrains.uast.LINE_SEPARATOR
import org.jetbrains.uast.UElement
import org.jetbrains.uast.asLogString
import org.jetbrains.uast.visitor.UastVisitor
import org.jetbrains.uast.withMargin
/**
* Builds the log message for the [UElement.asLogString] function.
*
* @param firstLine the message line (the interface name, some optional information).
* @param nested nested UElements. Could be `List<UElement>`, [UElement] or `null`.
* @throws IllegalStateException if the [nested] argument is invalid.
* @return the rendered log string.
*/
fun UElement.log(firstLine: String, vararg nested: Any?): String {
return (if (firstLine.isBlank()) "" else firstLine + LINE_SEPARATOR) + nested.joinToString(LINE_SEPARATOR) {
when (it) {
null -> "<no element>".withMargin
is List<*> -> {
if (it.firstOrNull() is PsiElement) {
@Suppress("UNCHECKED_CAST")
(it as List<PsiElement>).joinToString(LINE_SEPARATOR) { it.text }
} else {
@Suppress("UNCHECKED_CAST")
(it as List<UElement>).asLogString()
}
}
is UElement -> it.asLogString().withMargin
else -> error("Invalid element type: $it")
}
}
}
fun List<UElement>.acceptList(visitor: UastVisitor) {
for (element in this) {
element.accept(visitor)
}
}
@@ -15,11 +15,18 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
internal fun List<UElement>.logString() = joinToString("\n") { it.logString().withMargin } import com.intellij.psi.PsiType
internal fun UModifierOwner.renderModifiers() = UastModifier.VALUES internal val ERROR_NAME = "<error>"
.filter { hasModifier(it) }
.joinToString(" ") { it.name } internal val LINE_SEPARATOR = System.getProperty("line.separator") ?: "\n"
val String.withMargin: String
get() = lines().joinToString(LINE_SEPARATOR) { " " + it }
internal operator fun String.times(n: Int) = this.repeat(n)
internal fun List<UElement>.asLogString() = joinToString(LINE_SEPARATOR) { it.asLogString().withMargin }
internal fun StringBuilder.appendWithSpace(s: String) { internal fun StringBuilder.appendWithSpace(s: String) {
if (s.isNotEmpty()) { if (s.isNotEmpty()) {
@@ -27,3 +34,13 @@ internal fun StringBuilder.appendWithSpace(s: String) {
append(' ') append(' ')
} }
} }
internal tailrec fun UExpression.unwrapParenthesis(): UExpression = when (this) {
is UParenthesizedExpression -> expression.unwrapParenthesis()
else -> this
}
internal fun <T> lz(f: () -> T) = lazy(LazyThreadSafetyMode.NONE, f)
internal val PsiType.name: String
get() = getCanonicalText(false)
@@ -35,7 +35,3 @@ open class UastBinaryExpressionWithTypeKind(val name: String) {
val UNKNOWN = UastBinaryExpressionWithTypeKind("<unknown>") val UNKNOWN = UastBinaryExpressionWithTypeKind("<unknown>")
} }
} }
fun UElement.isTypeCast() = this is UBinaryExpressionWithType && this.operationKind is UastBinaryExpressionWithTypeKind.TypeCast
fun UElement.isInstanceCheck() = this is UBinaryExpressionWithType && this.operationKind is UastBinaryExpressionWithTypeKind.InstanceCheck
@@ -20,7 +20,7 @@ package org.jetbrains.uast
*/ */
open class UastBinaryOperator(override val text: String): UastOperator { open class UastBinaryOperator(override val text: String): UastOperator {
class LogicalOperator(text: String): UastBinaryOperator(text) class LogicalOperator(text: String): UastBinaryOperator(text)
class ComparationOperator(text: String): UastBinaryOperator(text) class ComparisonOperator(text: String): UastBinaryOperator(text)
class ArithmeticOperator(text: String): UastBinaryOperator(text) class ArithmeticOperator(text: String): UastBinaryOperator(text)
class BitwiseOperator(text: String): UastBinaryOperator(text) class BitwiseOperator(text: String): UastBinaryOperator(text)
class AssignOperator(text: String): UastBinaryOperator(text) class AssignOperator(text: String): UastBinaryOperator(text)
@@ -36,7 +36,7 @@ open class UastBinaryOperator(override val text: String): UastOperator {
val MINUS = ArithmeticOperator("-") val MINUS = ArithmeticOperator("-")
@JvmField @JvmField
val MULT = ArithmeticOperator("*") val MULTIPLY = ArithmeticOperator("*")
@JvmField @JvmField
val DIV = ArithmeticOperator("/") val DIV = ArithmeticOperator("/")
@@ -60,28 +60,28 @@ open class UastBinaryOperator(override val text: String): UastOperator {
val BITWISE_XOR = BitwiseOperator("^") val BITWISE_XOR = BitwiseOperator("^")
@JvmField @JvmField
val EQUALS = ComparationOperator("==") val EQUALS = ComparisonOperator("==")
@JvmField @JvmField
val NOT_EQUALS = ComparationOperator("!=") val NOT_EQUALS = ComparisonOperator("!=")
@JvmField @JvmField
val IDENTITY_EQUALS = ComparationOperator("===") val IDENTITY_EQUALS = ComparisonOperator("===")
@JvmField @JvmField
val IDENTITY_NOT_EQUALS = ComparationOperator("!==") val IDENTITY_NOT_EQUALS = ComparisonOperator("!==")
@JvmField @JvmField
val GREATER = ComparationOperator(">") val GREATER = ComparisonOperator(">")
@JvmField @JvmField
val GREATER_OR_EQUAL = ComparationOperator(">=") val GREATER_OR_EQUAL = ComparisonOperator(">=")
@JvmField @JvmField
val LESS = ComparationOperator("<") val LESS = ComparisonOperator("<")
@JvmField @JvmField
val LESS_OR_EQUAL = ComparationOperator("<=") val LESS_OR_EQUAL = ComparisonOperator("<=")
@JvmField @JvmField
val SHIFT_LEFT = BitwiseOperator("<<") val SHIFT_LEFT = BitwiseOperator("<<")
@@ -93,7 +93,7 @@ open class UastBinaryOperator(override val text: String): UastOperator {
val UNSIGNED_SHIFT_RIGHT = BitwiseOperator(">>>") val UNSIGNED_SHIFT_RIGHT = BitwiseOperator(">>>")
@JvmField @JvmField
val UNKNOWN = UastBinaryOperator("<unknown>") val OTHER = UastBinaryOperator("<other>")
@JvmField @JvmField
val PLUS_ASSIGN = AssignOperator("+=") val PLUS_ASSIGN = AssignOperator("+=")
@@ -21,13 +21,24 @@ package org.jetbrains.uast
open class UastCallKind(val name: String) { open class UastCallKind(val name: String) {
companion object { companion object {
@JvmField @JvmField
val FUNCTION_CALL = UastCallKind("function_call") val METHOD_CALL = UastCallKind("method_call")
@JvmField @JvmField
val CONSTRUCTOR_CALL = UastCallKind("constructor_call") val CONSTRUCTOR_CALL = UastCallKind("constructor_call")
@JvmField @JvmField
val ARRAY_INITIALIZER = UastCallKind("array_initializer") val NEW_ARRAY_WITH_DIMENSIONS = UastCallKind("new_array_with_dimensions")
/**
* Initializer parts are available in call expression as value arguments.
* [NEW_ARRAY_WITH_INITIALIZER] is a top-level initializer. In case of multi-dimensional arrays, inner initializers
* have type of [NESTED_ARRAY_INITIALIZER].
*/
@JvmField
val NEW_ARRAY_WITH_INITIALIZER = UastCallKind("new_array_with_initializer")
@JvmField
val NESTED_ARRAY_INITIALIZER = UastCallKind("array_initializer")
} }
override fun toString(): String{ override fun toString(): String{
@@ -1,42 +0,0 @@
/*
* Copyright 2000-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.uast
/**
* Kinds of [UFunction].
*/
open class UastFunctionKind(val text: String) {
class UastInitializerKind(val name: String) : UastFunctionKind("INITIALIZER ($name)")
class UastVariableAccessor(val name: String) : UastFunctionKind(name)
companion object {
@JvmField
val FUNCTION = UastFunctionKind("function")
@JvmField
val CONSTRUCTOR = UastFunctionKind("constructor")
@JvmField
val GETTER = UastVariableAccessor("getter")
@JvmField
val SETTER = UastVariableAccessor("setter")
}
override fun toString(): String{
return "UastFunctionKind(text='$text')"
}
}
@@ -1,47 +0,0 @@
/*
* Copyright 2000-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.uast
/**
* Uast declaration modifiers.
*
* @see UModifierOwner
*/
open class UastModifier(val name: String) {
companion object {
@JvmField
val ABSTRACT = UastModifier("abstract")
@JvmField
val STATIC = UastModifier("static")
@JvmField
val FINAL = UastModifier("final")
@JvmField
val IMMUTABLE = UastModifier("immutable")
@JvmField
val VARARG = UastModifier("vararg")
@JvmField
val OVERRIDE = UastModifier("override")
@JvmField
val JVM_FIELD = UastModifier("field")
// JVM-related modifiers are not listed here
val VALUES = listOf(ABSTRACT, STATIC, FINAL, IMMUTABLE, VARARG, OVERRIDE)
}
override fun toString(): String{
return "UastModifier(name='$name')"
}
}
@@ -16,13 +16,13 @@
package org.jetbrains.uast package org.jetbrains.uast
/** /**
* Uast operator base inteface. * Uast operator base interface.
* *
* @see [UastPrefixOperator], [UastPostfixOperator], [UastBinaryOperator] * @see [UastPrefixOperator], [UastPostfixOperator], [UastBinaryOperator]
*/ */
interface UastOperator { interface UastOperator {
/** /**
* Returns the operator text to render in [UElement.renderString]. * Returns the operator text to render in [UElement.asRenderString].
*/ */
val text: String val text: String
} }
@@ -16,7 +16,7 @@
package org.jetbrains.uast package org.jetbrains.uast
/** /**
* Access types of [UQualifiedExpression]. * Access types of [UQualifiedReferenceExpression].
* Additional type examples: Kotlin safe call (?.). * Additional type examples: Kotlin safe call (?.).
*/ */
open class UastQualifiedExpressionAccessType(val name: String) { open class UastQualifiedExpressionAccessType(val name: String) {
@@ -16,7 +16,7 @@
package org.jetbrains.uast package org.jetbrains.uast
/** /**
* Kinds of [USpecialExpressionList]. * Kinds of [UExpressionList].
*/ */
open class UastSpecialExpressionKind(val name: String) { open class UastSpecialExpressionKind(val name: String) {
override fun toString(): String{ override fun toString(): String{
@@ -1,29 +0,0 @@
/*
* 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.uast.kinds
open class UastVariableInitialierKind(val name: String) {
class Expression(name: String) : UastVariableInitialierKind(name)
companion object {
@JvmField
val EXPRESSION = Expression("expression")
@JvmField
val NO_INITIALIZER = UastVariableInitialierKind("no_initializer")
}
}
@@ -1,40 +0,0 @@
/*
* Copyright 2000-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.uast
/**
* Kinds of [UVariable].
*/
open class UastVariableKind(val name: String) {
class Member(name: String) : UastVariableKind(name)
class LocalVariable(name: String) : UastVariableKind(name)
class ValueParameter(name: String) : UastVariableKind(name)
companion object {
@JvmField
val LOCAL_VARIABLE = LocalVariable("local")
@JvmField
val MEMBER = Member("member")
@JvmField
val VALUE_PARAMETER = ValueParameter("parameter")
}
override fun toString(): String{
return "UastVariableKind(name='$name')"
}
}
@@ -15,24 +15,26 @@
*/ */
package org.jetbrains.uast package org.jetbrains.uast
/** import com.intellij.psi.PsiLocalVariable
* Uast visibility list. import com.intellij.psi.PsiModifier
*/ import com.intellij.psi.PsiModifierListOwner
open class UastVisibility(val name: String) {
enum class UastVisibility(val text: String) {
PUBLIC("public"),
PRIVATE("private"),
PROTECTED("protected"),
PACKAGE_LOCAL("packageLocal"),
LOCAL("local");
override fun toString() = text
companion object { companion object {
@JvmField operator fun get(declaration: PsiModifierListOwner): UastVisibility {
val PUBLIC = UastVisibility("public") if (declaration.hasModifierProperty(PsiModifier.PUBLIC)) return UastVisibility.PUBLIC
@JvmField if (declaration.hasModifierProperty(PsiModifier.PROTECTED)) return UastVisibility.PROTECTED
val PRIVATE = UastVisibility("private") if (declaration.hasModifierProperty(PsiModifier.PRIVATE)) return UastVisibility.PRIVATE
@JvmField if (declaration is PsiLocalVariable) return UastVisibility.LOCAL
val PROTECTED = UastVisibility("protected") return UastVisibility.PACKAGE_LOCAL
@JvmField }
val LOCAL = UastVisibility("local")
}
fun isPublic() = this == PUBLIC
override fun toString(): String {
return "UastVisibility(name='$name')"
} }
} }
@@ -22,6 +22,6 @@ import org.jetbrains.uast.UElement
interface PsiElementBacked : UElement { interface PsiElementBacked : UElement {
val psi: PsiElement? val psi: PsiElement?
override val isValid: Boolean override val isPsiValid: Boolean
get() = psi?.isValid ?: true get() = psi?.isValid ?: true
} }
@@ -0,0 +1,6 @@
package org.jetbrains.uast.psi
import com.intellij.openapi.util.Segment
import org.jetbrains.uast.UElement
interface UElementWithLocation : UElement, Segment
@@ -0,0 +1,11 @@
package org.jetbrains.uast.psi
import com.intellij.lang.Language
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.light.LightParameter
import org.jetbrains.uast.UastErrorType
class UastPsiParameterNotResolved(
declarationScope: PsiElement,
language: Language
) : LightParameter("error", UastErrorType, declarationScope, language)
@@ -0,0 +1,160 @@
@file:JvmMultifileClass
@file:JvmName("UastUtils")
package org.jetbrains.uast
/**
* Get the topmost parent qualified expression for the call expression.
*
* Example 1:
* Code: variable.call(args)
* Call element: E = call(args)
* Qualified parent (return value): Q = [getQualifiedCallElement](E) = variable.call(args)
*
* Example 2:
* Code: call(args)
* Call element: E = call(args)
* Qualified parent (return value): 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 UExpression.getQualifiedParentOrThis(): UExpression {
fun findParent(current: UExpression?, previous: UExpression): UExpression? = when (current) {
is UQualifiedReferenceExpression -> {
if (current.selector == previous)
findParent(current.containingElement as? UExpression, current) ?: current
else
previous
}
is UParenthesizedExpression -> findParent(current.expression, previous) ?: previous
else -> null
}
return findParent(containingElement as? UExpression, this) ?: this
}
fun UExpression.asQualifiedPath(): List<String>? {
if (this is USimpleNameReferenceExpression) {
return listOf(this.identifier)
} else if (this !is UQualifiedReferenceExpression) {
return null
}
var error = false
val list = mutableListOf<String>()
fun addIdentifiers(expr: UQualifiedReferenceExpression) {
val receiver = expr.receiver.unwrapParenthesis()
val selector = expr.selector as? USimpleNameReferenceExpression ?: run { error = true; return }
when (receiver) {
is UQualifiedReferenceExpression -> addIdentifiers(receiver)
is USimpleNameReferenceExpression -> list += receiver.identifier
else -> {
error = true
return
}
}
list += selector.identifier
}
addIdentifiers(this)
return if (error) null else 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<UExpression> {
fun collect(expr: UQualifiedReferenceExpression, chains: MutableList<UExpression>) {
val receiver = expr.receiver.unwrapParenthesis()
if (receiver is UQualifiedReferenceExpression) {
collect(receiver, chains)
} else {
chains += receiver
}
val selector = expr.selector.unwrapParenthesis()
if (selector is UQualifiedReferenceExpression) {
collect(selector, chains)
} else {
chains += selector
}
}
if (this == null) return emptyList()
val qualifiedExpression = this as? UQualifiedReferenceExpression ?: return listOf(this)
val chains = mutableListOf<UExpression>()
collect(qualifiedExpression, chains)
return chains
}
/**
* 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.
*
* Example:
* Code: a.b.c(asd).g
* Call element: c(asd)
* Outermost qualified (return value): a.b.c(asd).g
*/
fun UExpression.getOutermostQualified(): UQualifiedReferenceExpression? {
tailrec fun getOutermostQualified(current: UElement?, previous: UExpression): UQualifiedReferenceExpression? = when (current) {
is UQualifiedReferenceExpression -> getOutermostQualified(current.containingElement, current)
is UParenthesizedExpression -> getOutermostQualified(current.containingElement, previous)
else -> if (previous is UQualifiedReferenceExpression) previous else null
}
return getOutermostQualified(this.containingElement, this)
}
/**
* 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.matchesQualified(fqName: String): Boolean {
val identifiers = this.asQualifiedPath() ?: return false
val passedIdentifiers = fqName.trim('.').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.asQualifiedPath() ?: return false
val passedIdentifiers = fqName.trim('.').split('.')
if (identifiers.size < passedIdentifiers.size) return false
passedIdentifiers.forEachIndexed { i, passedIdentifier ->
if (passedIdentifier != identifiers[i]) return false
}
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.asQualifiedPath()?.asReversed() ?: return false
val passedIdentifiers = fqName.trim('.').split('.').asReversed()
if (identifiers.size < passedIdentifiers.size) return false
passedIdentifiers.forEachIndexed { i, passedIdentifier ->
if (passedIdentifier != identifiers[i]) return false
}
return true
}
@@ -0,0 +1,38 @@
/*
* Copyright 2000-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.
*/
@file:JvmName("UastExpressionUtils")
package org.jetbrains.uast.util
import org.jetbrains.uast.*
fun UElement.isConstructorCall() = (this as? UCallExpression)?.kind == UastCallKind.CONSTRUCTOR_CALL
fun UElement.isMethodCall() = (this as? UCallExpression)?.kind == UastCallKind.METHOD_CALL
fun UElement.isNewArray() = isNewArrayWithDimensions() || isNewArrayWithInitializer()
fun UElement.isNewArrayWithDimensions() = (this as? UCallExpression)?.kind == UastCallKind.NEW_ARRAY_WITH_DIMENSIONS
fun UElement.isNewArrayWithInitializer() = (this as? UCallExpression)?.kind == UastCallKind.NEW_ARRAY_WITH_INITIALIZER
fun UElement.isNestedArrayInitializer() = (this as? UCallExpression)?.kind == UastCallKind.NESTED_ARRAY_INITIALIZER
fun UElement.isTypeCast() = (this as? UBinaryExpressionWithType)?.operationKind is UastBinaryExpressionWithTypeKind.TypeCast
fun UElement.isInstanceCheck() = (this as? UBinaryExpressionWithType)?.operationKind is UastBinaryExpressionWithTypeKind.InstanceCheck
fun UElement.isAssignment() = (this as? UBinaryExpression)?.operator is UastBinaryOperator.AssignOperator
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,49 +17,27 @@
package org.jetbrains.uast.visitor package org.jetbrains.uast.visitor
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UTypeReferenceExpression
class DelegatingUastVisitor(private val visitors: List<UastVisitor>): UastVisitor { class DelegatingUastVisitor(private val visitors: List<UastVisitor>): UastVisitor {
override fun visitElement(node: UElement): Boolean { override fun visitElement(node: UElement): Boolean {
return visitors.all { it.visitElement(node) } return visitors.all { it.visitElement(node) }
} }
override fun visitFile(node: UFile): Boolean {
return visitors.all { it.visitFile(node) }
}
override fun visitImportStatement(node: UImportStatement): Boolean {
return visitors.all { it.visitImportStatement(node) }
}
override fun visitAnnotation(node: UAnnotation): Boolean {
return visitors.all { it.visitAnnotation(node) }
}
override fun visitCatchClause(node: UCatchClause): Boolean {
return visitors.all { it.visitCatchClause(node) }
}
override fun visitType(node: UType): Boolean {
return visitors.all { it.visitType(node) }
}
override fun visitClass(node: UClass): Boolean {
return visitors.all { it.visitClass(node) }
}
override fun visitFunction(node: UFunction): Boolean {
return visitors.all { it.visitFunction(node) }
}
override fun visitVariable(node: UVariable): Boolean { override fun visitVariable(node: UVariable): Boolean {
return visitors.all { it.visitVariable(node) } return visitors.all { it.visitVariable(node) }
} }
override fun visitMethod(node: UMethod): Boolean {
return visitors.all { it.visitMethod(node) }
}
override fun visitLabeledExpression(node: ULabeledExpression): Boolean { override fun visitLabeledExpression(node: ULabeledExpression): Boolean {
return visitors.all { it.visitLabeledExpression(node) } return visitors.all { it.visitLabeledExpression(node) }
} }
override fun visitDeclarationsExpression(node: UDeclarationsExpression): Boolean { override fun visitDeclarationsExpression(node: UVariableDeclarationsExpression): Boolean {
return visitors.all { it.visitDeclarationsExpression(node) } return visitors.all { it.visitDeclarationsExpression(node) }
} }
@@ -67,12 +45,16 @@ class DelegatingUastVisitor(private val visitors: List<UastVisitor>): UastVisito
return visitors.all { it.visitBlockExpression(node) } return visitors.all { it.visitBlockExpression(node) }
} }
override fun visitQualifiedExpression(node: UQualifiedExpression): Boolean { override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression): Boolean {
return visitors.all { it.visitQualifiedExpression(node) } return visitors.all { it.visitQualifiedReferenceExpression(node) }
} }
override fun visitSimpleReferenceExpression(node: USimpleReferenceExpression): Boolean { override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean {
return visitors.all { it.visitSimpleReferenceExpression(node) } return visitors.all { it.visitSimpleNameReferenceExpression(node) }
}
override fun visitTypeReferenceExpression(node: UTypeReferenceExpression): Boolean {
return visitors.all { it.visitTypeReferenceExpression(node) }
} }
override fun visitCallExpression(node: UCallExpression): Boolean { override fun visitCallExpression(node: UCallExpression): Boolean {
@@ -103,8 +85,8 @@ class DelegatingUastVisitor(private val visitors: List<UastVisitor>): UastVisito
return visitors.all { it.visitPostfixExpression(node) } return visitors.all { it.visitPostfixExpression(node) }
} }
override fun visitSpecialExpressionList(node: USpecialExpressionList): Boolean { override fun visitExpressionList(node: UExpressionList): Boolean {
return visitors.all { it.visitSpecialExpressionList(node) } return visitors.all { it.visitExpressionList(node) }
} }
override fun visitIfExpression(node: UIfExpression): Boolean { override fun visitIfExpression(node: UIfExpression): Boolean {
@@ -139,6 +121,10 @@ class DelegatingUastVisitor(private val visitors: List<UastVisitor>): UastVisito
return visitors.all { it.visitTryExpression(node) } return visitors.all { it.visitTryExpression(node) }
} }
override fun visitCatchClause(node: UCatchClause): Boolean {
return visitors.all { it.visitCatchClause(node) }
}
override fun visitLiteralExpression(node: ULiteralExpression): Boolean { override fun visitLiteralExpression(node: ULiteralExpression): Boolean {
return visitors.all { it.visitLiteralExpression(node) } return visitors.all { it.visitLiteralExpression(node) }
} }
@@ -1,244 +0,0 @@
/*
* 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.uast.visitor
import org.jetbrains.uast.*
import org.jetbrains.uast.visitor.UastVisitor
class UastExtendableVisitor(
private val original: UastVisitor,
private val context: UastContext,
private val extensions: List<UastVisitorExtension>
) : UastVisitor {
private fun handleExtensions(node: UElement) {
if (node !is SynthesizedUElement) {
for (extension in extensions) {
extension.invoke(node, this, context)
}
}
}
override fun visitElement(node: UElement): Boolean {
handleExtensions(node)
return original.visitElement(node)
}
override fun visitFile(node: UFile): Boolean {
handleExtensions(node)
return original.visitFile(node)
}
override fun visitImportStatement(node: UImportStatement): Boolean {
handleExtensions(node)
return original.visitImportStatement(node)
}
override fun visitAnnotation(node: UAnnotation): Boolean {
handleExtensions(node)
return original.visitAnnotation(node)
}
override fun visitCatchClause(node: UCatchClause): Boolean {
handleExtensions(node)
return original.visitCatchClause(node)
}
override fun visitType(node: UType): Boolean {
handleExtensions(node)
return original.visitType(node)
}
override fun visitClass(node: UClass): Boolean {
handleExtensions(node)
return original.visitClass(node)
}
override fun visitFunction(node: UFunction): Boolean {
handleExtensions(node)
return original.visitFunction(node)
}
override fun visitVariable(node: UVariable): Boolean {
handleExtensions(node)
return original.visitVariable(node)
}
override fun visitLabeledExpression(node: ULabeledExpression): Boolean {
handleExtensions(node)
return original.visitLabeledExpression(node)
}
override fun visitDeclarationsExpression(node: UDeclarationsExpression): Boolean {
handleExtensions(node)
return original.visitDeclarationsExpression(node)
}
override fun visitBlockExpression(node: UBlockExpression): Boolean {
handleExtensions(node)
return original.visitBlockExpression(node)
}
override fun visitQualifiedExpression(node: UQualifiedExpression): Boolean {
handleExtensions(node)
return original.visitQualifiedExpression(node)
}
override fun visitSimpleReferenceExpression(node: USimpleReferenceExpression): Boolean {
handleExtensions(node)
return original.visitSimpleReferenceExpression(node)
}
override fun visitCallExpression(node: UCallExpression): Boolean {
handleExtensions(node)
return original.visitCallExpression(node)
}
override fun visitBinaryExpression(node: UBinaryExpression): Boolean {
handleExtensions(node)
return original.visitBinaryExpression(node)
}
override fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType): Boolean {
handleExtensions(node)
return original.visitBinaryExpressionWithType(node)
}
override fun visitParenthesizedExpression(node: UParenthesizedExpression): Boolean {
handleExtensions(node)
return original.visitParenthesizedExpression(node)
}
override fun visitUnaryExpression(node: UUnaryExpression): Boolean {
handleExtensions(node)
return original.visitUnaryExpression(node)
}
override fun visitPrefixExpression(node: UPrefixExpression): Boolean {
handleExtensions(node)
return original.visitPrefixExpression(node)
}
override fun visitPostfixExpression(node: UPostfixExpression): Boolean {
handleExtensions(node)
return original.visitPostfixExpression(node)
}
override fun visitSpecialExpressionList(node: USpecialExpressionList): Boolean {
handleExtensions(node)
return original.visitSpecialExpressionList(node)
}
override fun visitIfExpression(node: UIfExpression): Boolean {
handleExtensions(node)
return original.visitIfExpression(node)
}
override fun visitSwitchExpression(node: USwitchExpression): Boolean {
handleExtensions(node)
return original.visitSwitchExpression(node)
}
override fun visitSwitchClauseExpression(node: USwitchClauseExpression): Boolean {
handleExtensions(node)
return original.visitSwitchClauseExpression(node)
}
override fun visitWhileExpression(node: UWhileExpression): Boolean {
handleExtensions(node)
return original.visitWhileExpression(node)
}
override fun visitDoWhileExpression(node: UDoWhileExpression): Boolean {
handleExtensions(node)
return original.visitDoWhileExpression(node)
}
override fun visitForExpression(node: UForExpression): Boolean {
handleExtensions(node)
return original.visitForExpression(node)
}
override fun visitForEachExpression(node: UForEachExpression): Boolean {
handleExtensions(node)
return original.visitForEachExpression(node)
}
override fun visitTryExpression(node: UTryExpression): Boolean {
handleExtensions(node)
return original.visitTryExpression(node)
}
override fun visitLiteralExpression(node: ULiteralExpression): Boolean {
handleExtensions(node)
return original.visitLiteralExpression(node)
}
override fun visitThisExpression(node: UThisExpression): Boolean {
handleExtensions(node)
return original.visitThisExpression(node)
}
override fun visitSuperExpression(node: USuperExpression): Boolean {
handleExtensions(node)
return original.visitSuperExpression(node)
}
override fun visitReturnExpression(node: UReturnExpression): Boolean {
handleExtensions(node)
return super.visitReturnExpression(node)
}
override fun visitBreakExpression(node: UBreakExpression): Boolean {
handleExtensions(node)
return original.visitBreakExpression(node)
}
override fun visitContinueExpression(node: UContinueExpression): Boolean {
handleExtensions(node)
return original.visitContinueExpression(node)
}
override fun visitThrowExpression(node: UThrowExpression): Boolean {
handleExtensions(node)
return original.visitThrowExpression(node)
}
override fun visitArrayAccessExpression(node: UArrayAccessExpression): Boolean {
handleExtensions(node)
return original.visitArrayAccessExpression(node)
}
override fun visitCallableReferenceExpression(node: UCallableReferenceExpression): Boolean {
handleExtensions(node)
return original.visitCallableReferenceExpression(node)
}
override fun visitClassLiteralExpression(node: UClassLiteralExpression): Boolean {
handleExtensions(node)
return original.visitClassLiteralExpression(node)
}
override fun visitLambdaExpression(node: ULambdaExpression): Boolean {
handleExtensions(node)
return original.visitLambdaExpression(node)
}
override fun visitObjectLiteralExpression(node: UObjectLiteralExpression): Boolean {
handleExtensions(node)
return original.visitObjectLiteralExpression(node)
}
}
@@ -16,109 +16,109 @@
package org.jetbrains.uast.visitor package org.jetbrains.uast.visitor
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.expressions.UTypeReferenceExpression
interface UastVisitor { interface UastVisitor {
open fun visitElement(node: UElement): Boolean fun visitElement(node: UElement): Boolean
open fun visitFile(node: UFile) = visitElement(node) fun visitFile(node: UFile): Boolean = visitElement(node)
open fun visitImportStatement(node: UImportStatement) = visitElement(node) fun visitImportStatement(node: UImportStatement): Boolean = visitElement(node)
open fun visitAnnotation(node: UAnnotation) = visitElement(node) fun visitClass(node: UClass): Boolean = visitElement(node)
open fun visitCatchClause(node: UCatchClause) = visitElement(node) fun visitInitializer(node: UClassInitializer): Boolean = visitElement(node)
open fun visitType(node: UType) = visitElement(node) fun visitMethod(node: UMethod): Boolean = visitElement(node)
fun visitVariable(node: UVariable): Boolean = visitElement(node)
// Declarations fun visitAnnotation(node: UAnnotation): Boolean = visitElement(node)
open fun visitClass(node: UClass) = visitElement(node)
open fun visitFunction(node: UFunction) = visitElement(node)
open fun visitVariable(node: UVariable) = visitElement(node)
// Expressions // Expressions
open fun visitLabeledExpression(node: ULabeledExpression) = visitElement(node) fun visitLabeledExpression(node: ULabeledExpression) = visitElement(node)
open fun visitDeclarationsExpression(node: UDeclarationsExpression) = visitElement(node) fun visitDeclarationsExpression(node: UVariableDeclarationsExpression) = visitElement(node)
open fun visitBlockExpression(node: UBlockExpression) = visitElement(node) fun visitBlockExpression(node: UBlockExpression) = visitElement(node)
open fun visitQualifiedExpression(node: UQualifiedExpression) = visitElement(node) fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) = visitElement(node)
open fun visitSimpleReferenceExpression(node: USimpleReferenceExpression) = visitElement(node) fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression) = visitElement(node)
open fun visitCallExpression(node: UCallExpression) = visitElement(node) fun visitTypeReferenceExpression(node: UTypeReferenceExpression) = visitElement(node)
open fun visitBinaryExpression(node: UBinaryExpression) = visitElement(node) fun visitCallExpression(node: UCallExpression) = visitElement(node)
open fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType) = visitElement(node) fun visitBinaryExpression(node: UBinaryExpression) = visitElement(node)
open fun visitParenthesizedExpression(node: UParenthesizedExpression) = visitElement(node) fun visitBinaryExpressionWithType(node: UBinaryExpressionWithType) = visitElement(node)
open fun visitUnaryExpression(node: UUnaryExpression) = visitElement(node) fun visitParenthesizedExpression(node: UParenthesizedExpression) = visitElement(node)
open fun visitPrefixExpression(node: UPrefixExpression) = visitElement(node) fun visitUnaryExpression(node: UUnaryExpression) = visitElement(node)
open fun visitPostfixExpression(node: UPostfixExpression) = visitElement(node) fun visitPrefixExpression(node: UPrefixExpression) = visitElement(node)
open fun visitSpecialExpressionList(node: USpecialExpressionList) = visitElement(node) fun visitPostfixExpression(node: UPostfixExpression) = visitElement(node)
open fun visitIfExpression(node: UIfExpression) = visitElement(node) fun visitExpressionList(node: UExpressionList) = visitElement(node)
open fun visitSwitchExpression(node: USwitchExpression) = visitElement(node) fun visitIfExpression(node: UIfExpression) = visitElement(node)
open fun visitSwitchClauseExpression(node: USwitchClauseExpression) = visitElement(node) fun visitSwitchExpression(node: USwitchExpression) = visitElement(node)
open fun visitWhileExpression(node: UWhileExpression) = visitElement(node) fun visitSwitchClauseExpression(node: USwitchClauseExpression) = visitElement(node)
open fun visitDoWhileExpression(node: UDoWhileExpression) = visitElement(node) fun visitWhileExpression(node: UWhileExpression) = visitElement(node)
open fun visitForExpression(node: UForExpression) = visitElement(node) fun visitDoWhileExpression(node: UDoWhileExpression) = visitElement(node)
open fun visitForEachExpression(node: UForEachExpression) = visitElement(node) fun visitForExpression(node: UForExpression) = visitElement(node)
open fun visitTryExpression(node: UTryExpression) = visitElement(node) fun visitForEachExpression(node: UForEachExpression) = visitElement(node)
open fun visitLiteralExpression(node: ULiteralExpression) = visitElement(node) fun visitTryExpression(node: UTryExpression) = visitElement(node)
open fun visitThisExpression(node: UThisExpression) = visitElement(node) fun visitCatchClause(node: UCatchClause) = visitElement(node)
open fun visitSuperExpression(node: USuperExpression) = visitElement(node) fun visitLiteralExpression(node: ULiteralExpression) = visitElement(node)
open fun visitReturnExpression(node: UReturnExpression) = visitElement(node) fun visitThisExpression(node: UThisExpression) = visitElement(node)
open fun visitBreakExpression(node: UBreakExpression) = visitElement(node) fun visitSuperExpression(node: USuperExpression) = visitElement(node)
open fun visitContinueExpression(node: UContinueExpression) = visitElement(node) fun visitReturnExpression(node: UReturnExpression) = visitElement(node)
open fun visitThrowExpression(node: UThrowExpression) = visitElement(node) fun visitBreakExpression(node: UBreakExpression) = visitElement(node)
open fun visitArrayAccessExpression(node: UArrayAccessExpression) = visitElement(node) fun visitContinueExpression(node: UContinueExpression) = visitElement(node)
open fun visitCallableReferenceExpression(node: UCallableReferenceExpression) = visitElement(node) fun visitThrowExpression(node: UThrowExpression) = visitElement(node)
open fun visitClassLiteralExpression(node: UClassLiteralExpression) = visitElement(node) fun visitArrayAccessExpression(node: UArrayAccessExpression) = visitElement(node)
open fun visitLambdaExpression(node: ULambdaExpression) = visitElement(node) fun visitCallableReferenceExpression(node: UCallableReferenceExpression) = visitElement(node)
open fun visitObjectLiteralExpression(node: UObjectLiteralExpression) = visitElement(node) fun visitClassLiteralExpression(node: UClassLiteralExpression) = visitElement(node)
fun visitLambdaExpression(node: ULambdaExpression) = visitElement(node)
fun visitObjectLiteralExpression(node: UObjectLiteralExpression) = visitElement(node)
// After // After
open fun afterVisitElement(node: UElement) {} fun afterVisitElement(node: UElement) {}
open fun afterVisitFile(node: UFile) {} fun afterVisitFile(node: UFile) { afterVisitElement(node) }
open fun afterVisitImportStatement(node: UImportStatement) {} fun afterVisitImportStatement(node: UImportStatement) { afterVisitElement(node) }
open fun afterVisitAnnotation(node: UAnnotation) {} fun afterVisitClass(node: UClass) { afterVisitElement(node) }
open fun afterVisitCatchClause(node: UCatchClause) {} fun afterVisitInitializer(node: UClassInitializer) { afterVisitElement(node) }
open fun afterVisitType(node: UType) {} fun afterVisitMethod(node: UMethod) { afterVisitElement(node) }
fun afterVisitVariable(node: UVariable) { afterVisitElement(node) }
// Declarations fun afterVisitAnnotation(node: UAnnotation) { afterVisitElement(node) }
open fun afterVisitClass(node: UClass) {}
open fun afterVisitFunction(node: UFunction) {}
open fun afterVisitVariable(node: UVariable) {}
// Expressions // Expressions
open fun afterVisitLabeledExpression(node: ULabeledExpression) {} fun afterVisitLabeledExpression(node: ULabeledExpression) { afterVisitElement(node) }
open fun afterVisitDeclarationsExpression(node: UDeclarationsExpression) {} fun afterVisitDeclarationsExpression(node: UVariableDeclarationsExpression) { afterVisitElement(node) }
open fun afterVisitBlockExpression(node: UBlockExpression) {} fun afterVisitBlockExpression(node: UBlockExpression) { afterVisitElement(node) }
open fun afterVisitQualifiedExpression(node: UQualifiedExpression) {} fun afterVisitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) { afterVisitElement(node) }
open fun afterVisitSimpleReferenceExpression(node: USimpleReferenceExpression) {} fun afterVisitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression) { afterVisitElement(node) }
open fun afterVisitCallExpression(node: UCallExpression) {} fun afterVisitTypeReferenceExpression(node: UTypeReferenceExpression) { afterVisitElement(node) }
open fun afterVisitBinaryExpression(node: UBinaryExpression) {} fun afterVisitCallExpression(node: UCallExpression) { afterVisitElement(node) }
open fun afterVisitBinaryExpressionWithType(node: UBinaryExpressionWithType) {} fun afterVisitBinaryExpression(node: UBinaryExpression) { afterVisitElement(node) }
open fun afterVisitParenthesizedExpression(node: UParenthesizedExpression) {} fun afterVisitBinaryExpressionWithType(node: UBinaryExpressionWithType) { afterVisitElement(node) }
open fun afterVisitUnaryExpression(node: UUnaryExpression) {} fun afterVisitParenthesizedExpression(node: UParenthesizedExpression) { afterVisitElement(node) }
open fun afterVisitPrefixExpression(node: UPrefixExpression) {} fun afterVisitUnaryExpression(node: UUnaryExpression) { afterVisitElement(node) }
open fun afterVisitPostfixExpression(node: UPostfixExpression) {} fun afterVisitPrefixExpression(node: UPrefixExpression) { afterVisitElement(node) }
open fun afterVisitSpecialExpressionList(node: USpecialExpressionList) {} fun afterVisitPostfixExpression(node: UPostfixExpression) { afterVisitElement(node) }
open fun afterVisitIfExpression(node: UIfExpression) {} fun afterVisitExpressionList(node: UExpressionList) { afterVisitElement(node) }
open fun afterVisitSwitchExpression(node: USwitchExpression) {} fun afterVisitIfExpression(node: UIfExpression) { afterVisitElement(node) }
open fun afterVisitSwitchClauseExpression(node: USwitchClauseExpression) {} fun afterVisitSwitchExpression(node: USwitchExpression) { afterVisitElement(node) }
open fun afterVisitWhileExpression(node: UWhileExpression) {} fun afterVisitSwitchClauseExpression(node: USwitchClauseExpression) { afterVisitElement(node) }
open fun afterVisitDoWhileExpression(node: UDoWhileExpression) {} fun afterVisitWhileExpression(node: UWhileExpression) { afterVisitElement(node) }
open fun afterVisitForExpression(node: UForExpression) {} fun afterVisitDoWhileExpression(node: UDoWhileExpression) { afterVisitElement(node) }
open fun afterVisitForEachExpression(node: UForEachExpression) {} fun afterVisitForExpression(node: UForExpression) { afterVisitElement(node) }
open fun afterVisitTryExpression(node: UTryExpression) {} fun afterVisitForEachExpression(node: UForEachExpression) { afterVisitElement(node) }
open fun afterVisitLiteralExpression(node: ULiteralExpression) {} fun afterVisitTryExpression(node: UTryExpression) { afterVisitElement(node) }
open fun afterVisitThisExpression(node: UThisExpression) {} fun afterVisitCatchClause(node: UCatchClause) { afterVisitElement(node) }
open fun afterVisitSuperExpression(node: USuperExpression) {} fun afterVisitLiteralExpression(node: ULiteralExpression) { afterVisitElement(node) }
open fun afterVisitReturnExpression(node: UReturnExpression) {} fun afterVisitThisExpression(node: UThisExpression) { afterVisitElement(node) }
open fun afterVisitBreakExpression(node: UBreakExpression) {} fun afterVisitSuperExpression(node: USuperExpression) { afterVisitElement(node) }
open fun afterVisitContinueExpression(node: UContinueExpression) {} fun afterVisitReturnExpression(node: UReturnExpression) { afterVisitElement(node) }
open fun afterVisitThrowExpression(node: UThrowExpression) {} fun afterVisitBreakExpression(node: UBreakExpression) { afterVisitElement(node) }
open fun afterVisitArrayAccessExpression(node: UArrayAccessExpression) {} fun afterVisitContinueExpression(node: UContinueExpression) { afterVisitElement(node) }
open fun afterVisitCallableReferenceExpression(node: UCallableReferenceExpression) {} fun afterVisitThrowExpression(node: UThrowExpression) { afterVisitElement(node) }
open fun afterVisitClassLiteralExpression(node: UClassLiteralExpression) {} fun afterVisitArrayAccessExpression(node: UArrayAccessExpression) { afterVisitElement(node) }
open fun afterVisitLambdaExpression(node: ULambdaExpression) {} fun afterVisitCallableReferenceExpression(node: UCallableReferenceExpression) { afterVisitElement(node) }
open fun afterVisitObjectLiteralExpression(node: UObjectLiteralExpression) {} fun afterVisitClassLiteralExpression(node: UClassLiteralExpression) { afterVisitElement(node) }
fun afterVisitLambdaExpression(node: ULambdaExpression) { afterVisitElement(node) }
fun afterVisitObjectLiteralExpression(node: UObjectLiteralExpression) { afterVisitElement(node) }
} }
abstract class AbstractUastVisitor : UastVisitor { abstract class AbstractUastVisitor : UastVisitor {
override fun visitElement(node: UElement): Boolean = false override fun visitElement(node: UElement): Boolean = false
} }
object EmptyUastVisitor : AbstractUastVisitor() object EmptyUastVisitor : AbstractUastVisitor()
+1
View File
@@ -8,5 +8,6 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" /> <orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="library" exported="" name="intellij-core" level="project" />
</component> </component>
</module> </module>
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,15 +16,42 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import org.jetbrains.uast.UElement import com.intellij.psi.*
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.java.internal.JavaUElementWithComments
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
abstract class JavaAbstractUElement : UElement { abstract class JavaAbstractUElement : JavaUElementWithComments {
private val psiElement: PsiElement?
get() = (this as? PsiElementBacked)?.psi
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this !is PsiElementBacked || other !is PsiElementBacked) { if (this !is PsiElementBacked || other !is PsiElementBacked) {
return this === other return this === other
} }
if (other.javaClass != this.javaClass) return false
return this.psi == other.psi return this.psi == other.psi
} }
override fun asSourceString(): String {
if (this is PsiElementBacked) {
return this.psi?.text ?: super<JavaUElementWithComments>.asSourceString()
}
return super<JavaUElementWithComments>.asSourceString()
}
override fun toString() = asRenderString()
}
abstract class JavaAbstractUExpression : JavaAbstractUElement(), UExpression {
override fun evaluate(): Any? {
val psi = (this as? PsiElementBacked)?.psi ?: return null
return JavaPsiFacade.getInstance(psi.project).constantEvaluationHelper.computeConstantExpression(psi)
}
override fun getExpressionType(): PsiType? {
val expression = (this as? PsiElementBacked)?.psi as? PsiExpression ?: return null
return expression.type
}
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2000-2015 JetBrains s.r.o. * Copyright 2000-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,215 +16,274 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.lang.Language
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.project.Project
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.java.expressions.JavaUSynchronizedExpression import org.jetbrains.uast.java.expressions.JavaUSynchronizedExpression
import org.jetbrains.uast.psi.PsiElementBacked
object JavaUastLanguagePlugin : UastLanguagePlugin { class JavaUastLanguagePlugin(override val project: Project) : UastLanguagePlugin {
override val converter: UastConverter = JavaConverter override val priority = 0
override val visitorExtensions: List<UastVisitorExtension>
get() = emptyList()
}
internal object JavaConverter : UastConverter { override fun isFileSupported(fileName: String) = fileName.endsWith(".java", ignoreCase = true)
override fun isFileSupported(name: String): Boolean {
return name.endsWith(".java", ignoreCase = true)
}
fun convert(file: PsiJavaFile): UFile = JavaUFile(file) override val language: Language
get() = JavaLanguage.INSTANCE
override fun convert(element: Any?, parent: UElement): UElement? { override fun isExpressionValueUsed(element: UExpression): Boolean = when (element) {
if (element !is PsiElement) return null is JavaUVariableDeclarationsExpression -> false
return convertPsiElement(element, parent) is UnknownJavaExpression -> (element.containingElement as? UExpression)?.let { isExpressionValueUsed(it) } ?: false
} else -> {
val statement = (element as? PsiElementBacked)?.psi as? PsiStatement
override fun convertWithParent(element: Any?): UElement? { statement != null && statement.parent !is PsiExpressionStatement
if (element !is PsiElement) return null
if (element is PsiJavaFile) return JavaUFile(element)
val parent = element.parent ?: return null
val parentUElement = convertWithParent(parent) ?: return null
return convertPsiElement(element, parentUElement)
}
private fun convertPsiElement(element: PsiElement?, parent: UElement) = when (element) {
is PsiJavaFile -> JavaUFile(element)
is PsiClass -> JavaUClass(element, parent)
is PsiCodeBlock -> convert(element, parent)
is PsiMethod -> convert(element, parent)
is PsiField -> convert(element, parent)
is PsiVariable -> convert(element, parent)
is PsiClassInitializer -> convert(element, parent)
is PsiAnnotation -> convert(element, parent)
is PsiResourceExpression -> convert(element.expression, parent)
is PsiExpression -> convert(element, parent)
is PsiStatement -> convert(element, parent)
is PsiIdentifier -> JavaUSimpleReferenceExpression(element, element.text, parent)
is PsiImportStatementBase -> convert(element, parent)
is PsiParameter -> convert(element, parent)
is PsiTypeParameter -> convert(element, parent)
is PsiNameValuePair -> convert(element, parent)
is PsiType -> convert(element, parent)
is PsiArrayInitializerMemberValue -> JavaAnnotationArrayInitializerUCallExpression(element, parent)
else -> null
}
internal fun convert(importStatement: PsiImportStatementBase, parent: UElement): UImportStatement? = when (importStatement) {
is PsiImportStatement -> JavaUImportStatement(importStatement, parent)
is PsiImportStaticStatement -> JavaUStaticImportStatement(importStatement, parent)
else -> null
}
internal fun convert(type: PsiType?, parent: UElement) = JavaUType(type, parent)
internal fun convert(parameter: PsiParameter, parent: UElement) = JavaValueParameterUVariable(parameter, parent)
internal fun convert(block: PsiCodeBlock, parent: UElement) = JavaUCodeBlockExpression(block, parent)
internal fun convert(method: PsiMethod, parent: UElement) = JavaUFunction(method, parent)
internal fun convert(field: PsiField, parent: UElement) = JavaUVariable(field, parent)
internal fun convert(variable: PsiVariable, parent: UElement) = JavaUVariable(variable, parent)
internal fun convert(annotation: PsiAnnotation, parent: UElement) = JavaUAnnotation(annotation, parent)
internal fun convert(clazz: PsiClass, parent: UElement) = JavaUClass(clazz, parent)
internal fun convert(initializer: PsiClassInitializer, parent: UElement) = JavaClassInitializerUFunction(initializer, parent)
internal fun convert(parameter: PsiTypeParameter, parent: UElement) = JavaParameterUTypeReference(parameter, parent)
internal fun convert(pair: PsiNameValuePair, parent: UElement) = UNamedExpression(pair.name.orAnonymous(), parent).apply {
val value = pair.value
expression = convert(value, this) as? UExpression ?: UnknownJavaExpression(value ?: pair, this)
}
internal fun convert(expression: PsiReferenceExpression, parent: UElement): UExpression {
return if (expression.isQualified) {
JavaUQualifiedExpression(expression, parent)
} else {
val name = expression.referenceName ?: "<error name>"
val element = expression.referenceNameElement ?: expression
JavaUSimpleReferenceExpression(element, name, parent)
} }
} }
internal fun convert(expression: PsiQualifiedReferenceElement, parent: UElement): UExpression { override fun getMethodCallExpression(
val referenceName = expression.referenceName ?: "<error name>" element: PsiElement,
val referenceNameElement = expression.element ?: expression containingClassFqName: String?,
methodName: String
): UastLanguagePlugin.ResolvedMethod? {
if (element !is PsiMethodCallExpression) return null
if (element.methodExpression.referenceName != methodName) return null
return JavaUCompositeQualifiedExpression(parent).apply { val uElement = convertElementWithParent(element, null)
receiver = expression.qualifier?.let { convert(it, this) } as? UExpression ?: EmptyUExpression(parent) val callExpression = when (uElement) {
selector = JavaUSimpleReferenceExpression(referenceNameElement, referenceName, this) is UCallExpression -> uElement
is UQualifiedReferenceExpression -> uElement.selector as UCallExpression
else -> error("Invalid element type: $uElement")
}
val method = callExpression.resolve() ?: return null
if (containingClassFqName != null) {
val containingClass = method.containingClass ?: return null
if (containingClass.qualifiedName != containingClassFqName) return null
}
return UastLanguagePlugin.ResolvedMethod(callExpression, method)
}
override fun getConstructorCallExpression(
element: PsiElement,
fqName: String
): UastLanguagePlugin.ResolvedConstructor? {
if (element !is PsiNewExpression) return null
val simpleName = fqName.substringAfterLast('.')
if (element.classReference?.referenceName != simpleName) return null
val callExpression = convertElementWithParent(element, null) as? UCallExpression ?: return null
val constructorMethod = element.resolveConstructor() ?: return null
val containingClass = constructorMethod.containingClass ?: return null
if (containingClass.qualifiedName != fqName) return null
return UastLanguagePlugin.ResolvedConstructor(callExpression, constructorMethod, containingClass)
}
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
if (element !is PsiElement) return null
return convertDeclaration(element, parent, requiredType) ?: JavaConverter.convertPsiElement(element, parent, requiredType)
}
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
if (element !is PsiElement) return null
if (element is PsiJavaFile) return JavaUFile(element, this)
JavaConverter.getCached<UElement>(element)?.let { return it }
val parent = JavaConverter.unwrapElements(element.parent) ?: return null
val parentUElement = convertElementWithParent(parent, null) ?: return null
return convertElement(element, parentUElement, requiredType)
}
private fun convertDeclaration(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
if (element.isValid) element.getUserData(JAVA_CACHED_UELEMENT_KEY)?.let { ref ->
ref.get()?.let { return it }
}
return with (requiredType) { when (element) {
is PsiJavaFile -> el<UFile> { JavaUFile(element, this@JavaUastLanguagePlugin) }
is UDeclaration -> element
is PsiClass -> el<UClass> { JavaUClass.create(element, parent) }
is PsiMethod -> el<UMethod> { JavaUMethod.create(element, this@JavaUastLanguagePlugin, parent) }
is PsiClassInitializer -> el<UClassInitializer> { JavaUClassInitializer(element, parent) }
is PsiVariable -> el<UVariable> { JavaUVariable.create(element, parent) }
is UAnnotation -> el<UAnnotation> { SimpleUAnnotation(element, parent) } //???
else -> null
}}
}
}
internal inline fun <reified T : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
return if (this == null || T::class.java == this) f() else null
}
internal inline fun <reified T : UElement> Class<out UElement>?.expr(f: () -> UExpression): UExpression {
return if (this == null || T::class.java == this) f() else UastEmptyExpression
}
internal object JavaConverter {
internal inline fun <reified T : UElement> getCached(element: PsiElement): T? {
return null
//todo
}
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
is PsiExpressionStatement -> unwrapElements(element.parent)
is PsiParameterList -> unwrapElements(element.parent)
is PsiAnnotationParameterList -> unwrapElements(element.parent)
else -> element
}
internal fun convertPsiElement(el: PsiElement, parent: UElement?, requiredType: Class<out UElement>? = null): UElement? {
getCached<UElement>(el)?.let { return it }
return with (requiredType) { when (el) {
is PsiCodeBlock -> el<UBlockExpression> { convertBlock(el, parent) }
is PsiResourceExpression -> convertExpression(el.expression, parent, requiredType)
is PsiExpression -> convertExpression(el, parent, requiredType)
is PsiStatement -> convertStatement(el, parent, requiredType)
is PsiIdentifier -> el<USimpleNameReferenceExpression> { JavaUSimpleNameReferenceExpression(el, el.text, parent) }
is PsiNameValuePair -> el<UNamedExpression> { convertNameValue(el, parent) }
is PsiArrayInitializerMemberValue -> el<UCallExpression> { JavaAnnotationArrayInitializerUCallExpression(el, parent) }
else -> null
}}
}
internal fun convertBlock(block: PsiCodeBlock, parent: UElement?): UBlockExpression =
getCached(block) ?: JavaUCodeBlockExpression(block, parent)
internal fun convertNameValue(pair: PsiNameValuePair, parent: UElement?): UNamedExpression {
return UNamedExpression.create(pair.name.orAnonymous(), parent) {
val value = pair.value as? PsiElement
value?.let { convertPsiElement(it, this, null) as? UExpression } ?: UnknownJavaExpression(value ?: pair, this)
}
}
internal fun convertReference(expression: PsiReferenceExpression, parent: UElement?, requiredType: Class<out UElement>?): UExpression {
return with (requiredType) {
if (expression.isQualified) {
expr<UQualifiedReferenceExpression> { JavaUQualifiedReferenceExpression(expression, parent) }
} else {
val name = expression.referenceName ?: "<error name>"
expr<USimpleNameReferenceExpression> { JavaUSimpleNameReferenceExpression(expression, name, parent, expression) }
}
} }
} }
private fun convertPolyadicExpression( private fun convertPolyadicExpression(
expression: PsiPolyadicExpression, expression: PsiPolyadicExpression,
parent: UElement, parent: UElement?,
i: Int i: Int
): UExpression { ): UBinaryExpression {
return if (i == 1) JavaSeparatedPolyadicUBinaryExpression(expression, parent).apply { return if (i == 1) JavaSeparatedPolyadicUBinaryExpression(expression, parent).apply {
leftOperand = convert(expression.operands[0], this) leftOperand = convertExpression(expression.operands[0], this)
rightOperand = convert(expression.operands[1], this) rightOperand = convertExpression(expression.operands[1], this)
} else JavaSeparatedPolyadicUBinaryExpression(expression, parent).apply { } else JavaSeparatedPolyadicUBinaryExpression(expression, parent).apply {
leftOperand = convertPolyadicExpression(expression, parent, i - 1) leftOperand = convertPolyadicExpression(expression, parent, i - 1)
rightOperand = convert(expression.operands[i], this) rightOperand = convertExpression(expression.operands[i], this)
} }
} }
internal fun convert(expression: PsiExpression, parent: UElement): UExpression = when (expression) { internal fun convertExpression(el: PsiExpression, parent: UElement?, requiredType: Class<out UElement>? = null): UExpression {
is PsiPolyadicExpression -> convertPolyadicExpression(expression, parent, expression.operands.size - 1) getCached<UExpression>(el)?.let { return it }
is PsiAssignmentExpression -> JavaUAssignmentExpression(expression, parent)
is PsiConditionalExpression -> JavaUTernaryIfExpression(expression, parent) return with (requiredType) { when (el) {
is PsiNewExpression -> { is PsiPolyadicExpression -> expr<UBinaryExpression> { convertPolyadicExpression(el, parent, el.operands.size - 1) }
if (expression.anonymousClass != null) { is PsiAssignmentExpression -> expr<UBinaryExpression> { JavaUAssignmentExpression(el, parent) }
JavaUObjectLiteralExpression(expression, parent) is PsiConditionalExpression -> expr<UIfExpression> { JavaUTernaryIfExpression(el, parent) }
} else { is PsiNewExpression -> {
JavaConstructorUCallExpression(expression, parent) if (el.anonymousClass != null)
expr<UObjectLiteralExpression> { JavaUObjectLiteralExpression(el, parent) }
else
expr<UCallExpression> { JavaConstructorUCallExpression(el, parent) }
} }
} is PsiMethodCallExpression -> {
is PsiMethodCallExpression -> { if (el.methodExpression.qualifierExpression != null)
val qualifier = expression.methodExpression.qualifierExpression expr<UQualifiedReferenceExpression> {
if (qualifier != null) { JavaUCompositeQualifiedExpression(el, parent).apply {
JavaUCompositeQualifiedExpression(parent).apply { receiver = convertExpression(el.methodExpression.qualifierExpression!!, this)
receiver = convert(qualifier, this) selector = JavaUCallExpression(el, this)
selector = JavaUCallExpression(expression, this) }
} }
} else { else
JavaUCallExpression(expression, parent) expr<UCallExpression> { JavaUCallExpression(el, parent) }
} }
} is PsiArrayInitializerExpression -> expr<UCallExpression> { JavaArrayInitializerUCallExpression(el, parent) }
is PsiArrayInitializerExpression -> JavaArrayInitializerUCallExpression(expression, parent) is PsiBinaryExpression -> expr<UBinaryExpression> { JavaUBinaryExpression(el, parent) }
is PsiBinaryExpression -> JavaUBinaryExpression(expression, parent) is PsiParenthesizedExpression -> expr<UParenthesizedExpression> { JavaUParenthesizedExpression(el, parent) }
is PsiParenthesizedExpression -> JavaUParenthesizedExpression(expression, parent) is PsiPrefixExpression -> expr<UPrefixExpression> { JavaUPrefixExpression(el, parent) }
is PsiPrefixExpression -> JavaUPrefixExpression(expression, parent) is PsiPostfixExpression -> expr<UPostfixExpression> { JavaUPostfixExpression(el, parent) }
is PsiPostfixExpression -> JavaUPostfixExpression(expression, parent) is PsiLiteralExpression -> expr<ULiteralExpression> { JavaULiteralExpression(el, parent) }
is PsiLiteralExpression -> JavaULiteralExpression(expression, parent) is PsiReferenceExpression -> convertReference(el, parent, requiredType)
is PsiReferenceExpression -> convert(expression, parent) is PsiThisExpression -> expr<UThisExpression> { JavaUThisExpression(el, parent) }
is PsiThisExpression -> JavaUThisExpression(expression, parent) is PsiSuperExpression -> expr<USuperExpression> { JavaUSuperExpression(el, parent) }
is PsiSuperExpression -> JavaUSuperExpression(expression, parent) is PsiInstanceOfExpression -> expr<UBinaryExpressionWithType> { JavaUInstanceCheckExpression(el, parent) }
is PsiInstanceOfExpression -> JavaUInstanceCheckExpression(expression, parent) is PsiTypeCastExpression -> expr<UBinaryExpressionWithType> { JavaUTypeCastExpression(el, parent) }
is PsiTypeCastExpression -> JavaUTypeCastExpression(expression, parent) is PsiClassObjectAccessExpression -> expr<UClassLiteralExpression> { JavaUClassLiteralExpression(el, parent) }
is PsiClassObjectAccessExpression -> JavaUClassLiteralExpression(expression, parent) is PsiArrayAccessExpression -> expr<UArrayAccessExpression> { JavaUArrayAccessExpression(el, parent) }
is PsiArrayAccessExpression -> JavaUArrayAccessExpression(expression, parent) is PsiLambdaExpression -> expr<ULambdaExpression> { JavaULambdaExpression(el, parent) }
is PsiLambdaExpression -> JavaULambdaExpression(expression, parent) is PsiMethodReferenceExpression -> expr<UCallableReferenceExpression> { JavaUCallableReferenceExpression(el, parent) }
is PsiMethodReferenceExpression -> JavaUCallableReferenceExpression(expression, parent) else -> UnknownJavaExpression(el, parent)
}}
else -> UnknownJavaExpression(expression, parent)
} }
internal fun convert(statement: PsiStatement, parent: UElement): UExpression = when (statement) { internal fun convertStatement(el: PsiStatement, parent: UElement?, requiredType: Class<out UElement>? = null): UExpression {
is PsiDeclarationStatement -> convertDeclarations(statement.declaredElements, parent) getCached<UExpression>(el)?.let { return it }
is PsiExpressionListStatement -> convertDeclarations(statement.expressionList.expressions, parent)
is PsiBlockStatement -> JavaUBlockExpression(statement, parent)
is PsiLabeledStatement -> JavaULabeledExpression(statement, parent)
is PsiExpressionStatement -> convert(statement.expression, parent)
is PsiIfStatement -> JavaUIfExpression(statement, parent)
is PsiSwitchStatement -> JavaUSwitchExpression(statement, parent)
is PsiSwitchLabelStatement -> {
if (statement.isDefaultCase)
DefaultUSwitchClauseExpression(parent)
else JavaUCaseSwitchClauseExpression(statement, parent)
}
is PsiWhileStatement -> JavaUWhileExpression(statement, parent)
is PsiDoWhileStatement -> JavaUDoWhileExpression(statement, parent)
is PsiForStatement -> JavaUForExpression(statement, parent)
is PsiForeachStatement -> JavaUForEachExpression(statement, parent)
is PsiBreakStatement -> JavaUBreakExpression(statement, parent)
is PsiContinueStatement -> JavaUContinueExpression(statement, parent)
is PsiReturnStatement -> JavaUReturnExpression(statement, parent)
is PsiAssertStatement -> JavaUAssertExpression(statement, parent)
is PsiThrowStatement -> JavaUThrowExpression(statement, parent)
is PsiSynchronizedStatement -> JavaUSynchronizedExpression(statement, parent)
is PsiTryStatement -> JavaUTryExpression(statement, parent)
else -> UnknownJavaExpression(statement, parent) return with (requiredType) { when (el) {
is PsiDeclarationStatement -> expr<UVariableDeclarationsExpression> { convertDeclarations(el.declaredElements, parent!!) }
is PsiExpressionListStatement -> expr<UVariableDeclarationsExpression> { convertDeclarations(el.expressionList.expressions, parent!!) }
is PsiBlockStatement -> expr<UBlockExpression> { JavaUBlockExpression(el, parent) }
is PsiLabeledStatement -> expr<ULabeledExpression> { JavaULabeledExpression(el, parent) }
is PsiExpressionStatement -> convertExpression(el.expression, parent, requiredType)
is PsiIfStatement -> expr<UIfExpression> { JavaUIfExpression(el, parent) }
is PsiSwitchStatement -> expr<USwitchExpression> { JavaUSwitchExpression(el, parent) }
is PsiSwitchLabelStatement -> expr<USwitchClauseExpression> {
if (el.isDefaultCase)
DefaultUSwitchClauseExpression(parent)
else JavaUCaseSwitchClauseExpression(el, parent)
}
is PsiWhileStatement -> expr<UWhileExpression> { JavaUWhileExpression(el, parent) }
is PsiDoWhileStatement -> expr<UDoWhileExpression> { JavaUDoWhileExpression(el, parent) }
is PsiForStatement -> expr<UForExpression> { JavaUForExpression(el, parent) }
is PsiForeachStatement -> expr<UForEachExpression> { JavaUForEachExpression(el, parent) }
is PsiBreakStatement -> expr<UBreakExpression> { JavaUBreakExpression(el, parent) }
is PsiContinueStatement -> expr<UContinueExpression> { JavaUContinueExpression(el, parent) }
is PsiReturnStatement -> expr<UReturnExpression> { JavaUReturnExpression(el, parent) }
is PsiAssertStatement -> expr<UCallExpression> { JavaUAssertExpression(el, parent) }
is PsiThrowStatement -> expr<UThrowExpression> { JavaUThrowExpression(el, parent) }
is PsiSynchronizedStatement -> expr<UBlockExpression> { JavaUSynchronizedExpression(el, parent) }
is PsiTryStatement -> expr<UTryExpression> { JavaUTryExpression(el, parent) }
else -> UnknownJavaExpression(el, parent)
}}
} }
internal fun convertOrEmpty(statement: PsiStatement?, parent: UElement): UExpression { private fun convertDeclarations(elements: Array<out PsiElement>, parent: UElement): UVariableDeclarationsExpression {
return if (statement != null) convert(statement, parent) else EmptyUExpression(parent) return JavaUVariableDeclarationsExpression(parent).apply {
} val variables = mutableListOf<UVariable>()
internal fun convertOrEmpty(expression: PsiExpression?, parent: UElement): UExpression {
return if (expression != null) convert(expression, parent) else EmptyUExpression(parent)
}
internal fun convertOrNull(expression: PsiExpression?, parent: UElement): UExpression? {
return if (expression != null) convert(expression, parent) else null
}
internal fun convertOrEmpty(block: PsiCodeBlock?, parent: UElement): UExpression {
return if (block != null) convert(block, parent) else EmptyUExpression(parent)
}
private fun convertDeclarations(elements: Array<out PsiElement>, parent: UElement): SimpleUDeclarationsExpression {
val uelements = arrayListOf<UElement>()
return SimpleUDeclarationsExpression(parent, uelements).apply {
for (element in elements) { for (element in elements) {
convert(element, this)?.let { uelements += it } if (element !is PsiVariable) continue
variables += JavaUVariable.create(element, this)
} }
this.variables = variables
} }
} }
internal fun convertOrEmpty(statement: PsiStatement?, parent: UElement?): UExpression {
return statement?.let { convertStatement(it, parent, null) } ?: UastEmptyExpression
}
internal fun convertOrEmpty(expression: PsiExpression?, parent: UElement?): UExpression {
return expression?.let { convertExpression(it, parent) } ?: UastEmptyExpression
}
internal fun convertOrNull(expression: PsiExpression?, parent: UElement?): UExpression? {
return if (expression != null) convertExpression(expression, parent) else null
}
internal fun convertOrEmpty(block: PsiCodeBlock?, parent: UElement?): UExpression {
return if (block != null) convertBlock(block, parent) else UastEmptyExpression
}
} }
@@ -16,14 +16,21 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiDoWhileStatement import com.intellij.psi.PsiDoWhileStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.UDoWhileExpression import org.jetbrains.uast.UDoWhileExpression
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUDoWhileExpression( class JavaUDoWhileExpression(
override val psi: PsiDoWhileStatement, override val psi: PsiDoWhileStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UDoWhileExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UDoWhileExpression, PsiElementBacked {
override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) }
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
override val doIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.DO_KEYWORD), this)
override val whileIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.WHILE_KEYWORD), this)
} }
@@ -16,16 +16,23 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiForeachStatement import com.intellij.psi.PsiForeachStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UForEachExpression import org.jetbrains.uast.UForEachExpression
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UParameter
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUForEachExpression( class JavaUForEachExpression(
override val psi: PsiForeachStatement, override val psi: PsiForeachStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UForEachExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UForEachExpression, PsiElementBacked {
override val variable by lz { JavaConverter.convert(psi.iterationParameter, this) } override val variable: UParameter
get() = JavaUParameter(psi.iterationParameter, this)
override val iteratedValue by lz { JavaConverter.convertOrEmpty(psi.iteratedValue, this) } override val iteratedValue by lz { JavaConverter.convertOrEmpty(psi.iteratedValue, this) }
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
override val forIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.FOR_KEYWORD), this)
} }
@@ -16,16 +16,21 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiForStatement import com.intellij.psi.PsiForStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UForExpression import org.jetbrains.uast.UForExpression
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUForExpression( class JavaUForExpression(
override val psi: PsiForStatement, override val psi: PsiForStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UForExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UForExpression, PsiElementBacked {
override val declaration by lz { psi.initialization?.let { JavaConverter.convert(it, this) } } override val declaration by lz { psi.initialization?.let { JavaConverter.convertStatement(it, this) } }
override val condition by lz { psi.condition?.let { JavaConverter.convert(it, this) } } override val condition by lz { psi.condition?.let { JavaConverter.convertExpression(it, this) } }
override val update by lz { psi.update?.let { JavaConverter.convert(it, this) } } override val update by lz { psi.update?.let { JavaConverter.convertStatement(it, this) } }
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
override val forIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.FOR_KEYWORD), this)
} }
@@ -16,18 +16,26 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiIfStatement import com.intellij.psi.PsiIfStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UIfExpression import org.jetbrains.uast.UIfExpression
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUIfExpression( class JavaUIfExpression(
override val psi: PsiIfStatement, override val psi: PsiIfStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UIfExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UIfExpression, PsiElementBacked {
override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) }
override val thenBranch by lz { JavaConverter.convertOrEmpty(psi.thenBranch, this) } override val thenExpression by lz { JavaConverter.convertOrEmpty(psi.thenBranch, this) }
override val elseBranch by lz { JavaConverter.convertOrEmpty(psi.elseBranch, this) } override val elseExpression by lz { JavaConverter.convertOrEmpty(psi.elseBranch, this) }
override val isTernary: Boolean override val isTernary: Boolean
get() = false get() = false
override val ifIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.IF_KEYWORD), this)
override val elseIdentifier: UIdentifier?
get() = psi.getChildByRole(ChildRole.ELSE_KEYWORD)?.let { UIdentifier(it, this) }
} }
@@ -1,33 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiElement
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked
open class JavaUSpecialExpressionList(
override val psi: PsiElement,
override val kind: UastSpecialExpressionKind, // original element
override val parent: UElement
) : JavaAbstractUElement(), USpecialExpressionList, PsiElementBacked {
class Empty(psi: PsiElement, expressionType: UastSpecialExpressionKind, parent: UElement) :
JavaUSpecialExpressionList(psi, expressionType, parent) {
init { expressions = emptyList() }
}
override lateinit var expressions: List<UExpression>
}
@@ -17,31 +17,35 @@ package org.jetbrains.uast.java
import com.intellij.psi.PsiSwitchLabelStatement import com.intellij.psi.PsiSwitchLabelStatement
import com.intellij.psi.PsiSwitchStatement import com.intellij.psi.PsiSwitchStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUSwitchExpression( class JavaUSwitchExpression(
override val psi: PsiSwitchStatement, override val psi: PsiSwitchStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), USwitchExpression, PsiElementBacked { ) : JavaAbstractUExpression(), USwitchExpression, PsiElementBacked {
override val expression by lz { JavaConverter.convertOrEmpty(psi.expression, this) } override val expression by lz { JavaConverter.convertOrEmpty(psi.expression, this) }
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
override val switchIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.SWITCH_KEYWORD), this)
} }
class JavaUCaseSwitchClauseExpression( class JavaUCaseSwitchClauseExpression(
override val psi: PsiSwitchLabelStatement, override val psi: PsiSwitchLabelStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), USwitchClauseExpression, PsiElementBacked { ) : JavaAbstractUExpression(), USwitchClauseExpression, PsiElementBacked {
override val caseValues by lz { override val caseValues by lz {
val value = psi.caseValue ?: return@lz null val value = psi.caseValue ?: return@lz null
listOf(JavaConverter.convert(value, this)) listOf(JavaConverter.convertExpression(value, this))
} }
} }
class DefaultUSwitchClauseExpression(override val parent: UElement) : USwitchClauseExpression { class DefaultUSwitchClauseExpression(override val containingElement: UElement?) : USwitchClauseExpression {
override val caseValues: List<UExpression>? override val caseValues: List<UExpression>?
get() = null get() = null
override fun logString() = "DefaultUSwitchClauseExpression" override fun asLogString() = "DefaultUSwitchClauseExpression"
override fun renderString() = "else -> " override fun asRenderString() = "else -> "
} }
@@ -17,17 +17,24 @@ package org.jetbrains.uast.java
import com.intellij.psi.PsiConditionalExpression import com.intellij.psi.PsiConditionalExpression
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UIfExpression import org.jetbrains.uast.UIfExpression
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUTernaryIfExpression( class JavaUTernaryIfExpression(
override val psi: PsiConditionalExpression, override val psi: PsiConditionalExpression,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UIfExpression, PsiElementBacked, JavaUElementWithType, JavaEvaluatableUElement { ) : JavaAbstractUExpression(), UIfExpression, PsiElementBacked {
override val condition by lz { JavaConverter.convert(psi.condition, this) } override val condition by lz { JavaConverter.convertExpression(psi.condition, this) }
override val thenBranch by lz { JavaConverter.convertOrEmpty(psi.thenExpression, this) } override val thenExpression by lz { JavaConverter.convertOrEmpty(psi.thenExpression, this) }
override val elseBranch by lz { JavaConverter.convertOrEmpty(psi.elseExpression, this) } override val elseExpression by lz { JavaConverter.convertOrEmpty(psi.elseExpression, this) }
override val isTernary: Boolean override val isTernary: Boolean
get() = true get() = true
override val ifIdentifier: UIdentifier
get() = UIdentifier(null, this)
override val elseIdentifier: UIdentifier?
get() = UIdentifier(null, this)
} }
@@ -15,30 +15,50 @@
*/ */
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiCatchSection import com.intellij.psi.*
import com.intellij.psi.PsiTryStatement import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.* import org.jetbrains.uast.UCatchClause
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UTryExpression
import org.jetbrains.uast.expressions.UTypeReferenceExpression
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUTryExpression( class JavaUTryExpression(
override val psi: PsiTryStatement, override val psi: PsiTryStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UTryExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UTryExpression, PsiElementBacked {
override val tryClause by lz { JavaConverter.convertOrEmpty(psi.tryBlock, this) } override val tryClause by lz { JavaConverter.convertOrEmpty(psi.tryBlock, this) }
override val catchClauses by lz { psi.catchSections.map { JavaUCatchClause(it, this) } } override val catchClauses by lz { psi.catchSections.map { JavaUCatchClause(it, this) } }
override val finallyClause by lz { psi.finallyBlock?.let { JavaConverter.convert(it, this) } } override val finallyClause by lz { psi.finallyBlock?.let { JavaConverter.convertBlock(it, this) } }
override val resources by lz { override val resources: List<PsiResourceListElement>?
val vars = psi.resourceList ?: return@lz null get() = psi.resourceList?.toList() ?: emptyList<PsiResourceListElement>()
val resources = vars.map { JavaConverter.convert(it, this) ?: UDeclarationNotResolved } override val isResources: Boolean
if (resources.isEmpty()) null else resources get() = psi.resourceList != null
}
override val tryIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.TRY_KEYWORD), this)
override val finallyIdentifier: UIdentifier?
get() = psi.getChildByRole(ChildRole.FINALLY_KEYWORD)?.let { UIdentifier(it, this) }
} }
class JavaUCatchClause( class JavaUCatchClause(
override val psi: PsiCatchSection, override val psi: PsiCatchSection,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UCatchClause, PsiElementBacked { ) : JavaAbstractUElement(), UCatchClause, PsiElementBacked {
override val body by lz { JavaConverter.convertOrEmpty(psi.catchBlock, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.catchBlock, this) }
override val parameters by lz { psi.parameter?.let { listOf(JavaConverter.convert(it, this)) } ?: emptyList() }
override val types by lz { psi.preciseCatchTypes.map { JavaConverter.convert(it, this) } } override val parameters by lz {
(psi.parameter?.let { listOf(it) } ?: emptyList()).map { JavaUParameter(it, this) }
}
override val typeReferences by lz {
val typeElement = psi.parameter?.typeElement ?: return@lz emptyList<UTypeReferenceExpression>()
if (typeElement.type is PsiDisjunctionType) {
typeElement.children.filterIsInstance<PsiTypeElement>().map { JavaUTypeReferenceExpression(it, this) }
} else {
listOf(JavaUTypeReferenceExpression(typeElement, this))
}
}
} }
@@ -16,14 +16,19 @@
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiWhileStatement import com.intellij.psi.PsiWhileStatement
import com.intellij.psi.impl.source.tree.ChildRole
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UWhileExpression import org.jetbrains.uast.UWhileExpression
import org.jetbrains.uast.psi.PsiElementBacked import org.jetbrains.uast.psi.PsiElementBacked
class JavaUWhileExpression( class JavaUWhileExpression(
override val psi: PsiWhileStatement, override val psi: PsiWhileStatement,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UWhileExpression, PsiElementBacked { ) : JavaAbstractUExpression(), UWhileExpression, PsiElementBacked {
override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) } override val condition by lz { JavaConverter.convertOrEmpty(psi.condition, this) }
override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) } override val body by lz { JavaConverter.convertOrEmpty(psi.body, this) }
override val whileIdentifier: UIdentifier
get() = UIdentifier(psi.getChildByRole(ChildRole.WHILE_KEYWORD), this)
} }
@@ -1,63 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiClassInitializer
import com.intellij.psi.PsiModifier
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked
class JavaClassInitializerUFunction(
override val psi: PsiClassInitializer,
override val parent: UElement
) : JavaAbstractUElement(), UFunction, PsiElementBacked, NoAnnotations {
override val kind: UastFunctionKind.UastInitializerKind
get() {
return if (psi.hasModifierProperty(PsiModifier.STATIC))
JavaFunctionKinds.STATIC_INITIALIZER
else
JavaFunctionKinds.INSTANCE_INITIALIZER
}
override val valueParameters: List<UVariable>
get() = emptyList()
override val valueParameterCount: Int
get() = 0
override val typeParameters: List<UTypeReference>
get() = emptyList()
override val typeParameterCount: Int
get() = 0
override val returnType: UType?
get() = null
override val body by lz { JavaConverter.convert(psi.body, this) }
override val visibility: UastVisibility
get() = UastVisibility.LOCAL
override val nameElement: UElement?
get() = null
override val name: String
get() = "<static>"
override fun getSuperFunctions(context: UastContext) = emptyList<UFunction>()
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
}
@@ -1,35 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiTypeParameter
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UTypeReference
import org.jetbrains.uast.UastContext
import org.jetbrains.uast.psi.PsiElementBacked
class JavaParameterUTypeReference(
override val psi: PsiTypeParameter,
override val parent: UElement
) : JavaAbstractUElement(), UTypeReference, PsiElementBacked {
override val name: String
get() = psi.name.orAnonymous()
override val nameElement by lz { psi.nameIdentifier?.let { JavaDumbUElement(it, this) } }
override fun resolve(context: UastContext) = psi.reference?.resolve()?.let { JavaConverter.convertWithParent(it) } as? UClass
}
@@ -1,42 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiAnnotation
import org.jetbrains.uast.UAnnotation
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UastContext
import org.jetbrains.uast.psi.PsiElementBacked
class JavaUAnnotation(
override val psi: PsiAnnotation,
override val parent: UElement
) : JavaAbstractUElement(), UAnnotation, PsiElementBacked {
override val name: String
get() = psi.nameReferenceElement?.referenceName.orAnonymous()
override val fqName: String?
get() = psi.qualifiedName
override val valueArguments by lz {
psi.parameterList.attributes.map {
JavaConverter.convert(it, this)
}
}
override fun resolve(context: UastContext) = context.convert(psi.reference?.resolve()) as? UClass
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2000-2016 JetBrains s.r.o. * Copyright 2010-2016 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,199 +13,54 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.uast.java package org.jetbrains.uast.java
import com.intellij.ide.util.JavaAnonymousClassesHelper import com.intellij.psi.PsiAnonymousClass
import com.intellij.psi.* import com.intellij.psi.PsiClass
import com.intellij.psi.util.ClassUtil
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.uast.* import org.jetbrains.uast.*
import org.jetbrains.uast.kinds.UastVariableInitialierKind import org.jetbrains.uast.java.internal.JavaUElementWithComments
import org.jetbrains.uast.psi.PsiElementBacked
class JavaUClass( abstract class AbstractJavaUClass : UClass, JavaUElementWithComments {
override val psi: PsiClass, override val uastDeclarations by lz {
override val parent: UElement, mutableListOf<UDeclaration>().apply {
val newExpression: PsiNewExpression? = null addAll(uastFields)
) : JavaAbstractUElement(), UClass, PsiElementBacked { addAll(uastInitializers)
override val name: String addAll(uastMethods)
get() = psi.name.orAnonymous() addAll(uastNestedClasses)
override val nameElement by lz {
if (psi is PsiAnonymousClass && newExpression != null) {
newExpression.classOrAnonymousClassReference?.referenceNameElement?.let { JavaDumbUElement(it, this) }
} else {
JavaConverter.convert(psi.nameIdentifier, this)
} }
} }
override val fqName: String? override val uastAnchor: UElement?
get() = psi.qualifiedName get() = UIdentifier(psi.nameIdentifier, this)
override val kind by lz { override val uastAnnotations by lz { psi.annotations.map { SimpleUAnnotation(it, this) } }
when {
psi.isEnum -> UastClassKind.ENUM
psi.isAnnotationType -> UastClassKind.ANNOTATION
psi.isInterface -> UastClassKind.INTERFACE
psi is PsiAnonymousClass -> UastClassKind.OBJECT
else -> UastClassKind.CLASS
}
}
override val defaultType by lz { JavaConverter.convert(PsiTypesUtil.getClassType(psi), this) } override val uastFields: List<UVariable> by lz { psi.fields.map { getLanguagePlugin().convert<UVariable>(it, this) } }
override val uastInitializers: List<UClassInitializer> by lz { psi.initializers.map { getLanguagePlugin().convert<UClassInitializer>(it, this) } }
override val uastMethods: List<UMethod> by lz { psi.methods.map { getLanguagePlugin().convert<UMethod>(it, this) } }
override val uastNestedClasses: List<UClass> by lz { psi.innerClasses.map { getLanguagePlugin().convert<UClass>(it, this) } }
override val companions: List<UClass> override fun equals(other: Any?) = this === other
get() = emptyList() override fun hashCode() = psi.hashCode()
}
override val isAnonymous: Boolean class JavaUClass private constructor(psi: PsiClass, override val containingElement: UElement?) : AbstractJavaUClass(), PsiClass by psi {
get() = psi is PsiAnonymousClass override val psi = unwrap<UClass, PsiClass>(psi)
override val internalName by lz { getInternalName(psi) } companion object {
fun create(psi: PsiClass, containingElement: UElement?): UClass {
override val superTypes by lz { return if (psi is PsiAnonymousClass)
psi.extendsListTypes.map { JavaConverter.convert(it, this) } + psi.implementsListTypes.map { JavaConverter.convert(it, this) } JavaUAnonymousClass(psi, containingElement)
} else
JavaUClass(psi, containingElement)
override fun getSuperClass(context: UastContext) = context.convert(psi.superClass) as? UClass
override val visibility: UastVisibility
get() = psi.getVisibility()
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
override val annotations by lz { psi.modifierList.getAnnotations(this) }
override val declarations by lz {
val declarations = arrayListOf<UDeclaration>()
psi.fields.mapTo(declarations) { JavaConverter.convert(it, this) }
if (psi is PsiAnonymousClass && newExpression != null) {
declarations += JavaUAnonymousClassConstructor(psi, newExpression, this)
}
psi.methods.mapTo(declarations) { JavaConverter.convert(it, this) }
psi.innerClasses.mapTo(declarations) { JavaConverter.convert(it, this) }
psi.initializers.mapTo(declarations) { JavaConverter.convert(it, this) }
declarations
}
override fun isSubclassOf(fqName: String): Boolean {
return psi.supers.any { base -> psi.isInheritor(base, false) }
}
private companion object {
/* Primarily copied from IntellijLintUtils and ClassContext classes from the Android IDEA plugin */
private fun getInternalName(psiClass: PsiClass): String? {
if (psiClass is PsiAnonymousClass) {
val parent = PsiTreeUtil.getParentOfType(psiClass, PsiClass::class.java)
if (parent != null) {
val internalName = getInternalName(parent) ?: return null
return internalName + JavaAnonymousClassesHelper.getName(psiClass)
}
}
var sig = ClassUtil.getJVMClassName(psiClass)
if (sig == null) {
val qualifiedName = psiClass.qualifiedName
if (qualifiedName != null) {
return getInternalName(qualifiedName)
}
return null
}
else if (sig.indexOf('.') != -1) {
// Workaround -- ClassUtil doesn't treat this correctly!
// .replace('.', '/');
sig = getInternalName(sig)
}
return sig
}
private fun getInternalName(fqcn: String): String {
if (fqcn.indexOf('.') == -1) {
return fqcn
}
// If class name contains $, it's not an ambiguous inner class name.
if (fqcn.indexOf('$') != -1) {
return fqcn.replace('.', '/')
}
// Let's assume that components that start with Caps are class names.
val sb = StringBuilder(fqcn.length)
var prev: String? = null
for (part in fqcn.split('.')) {
if (prev != null && !prev.isEmpty()) {
if (Character.isUpperCase(prev[0])) {
sb.append('$')
}
else {
sb.append('/')
}
}
sb.append(part)
prev = part
}
return sb.toString()
} }
} }
} }
private class JavaUAnonymousClassConstructor( class JavaUAnonymousClass(
override val psi: PsiAnonymousClass, psi: PsiAnonymousClass,
newExpression: PsiNewExpression, override val containingElement: UElement?
override val parent: UElement ) : AbstractJavaUClass(), UAnonymousClass, PsiAnonymousClass by psi {
) : JavaAbstractUElement(), UFunction, PsiElementBacked, NoAnnotations, NoModifiers { override val psi: PsiAnonymousClass = unwrap<UAnonymousClass, PsiAnonymousClass>(psi)
override val kind = UastFunctionKind.CONSTRUCTOR
override val valueParameterCount by lz { newExpression.argumentList?.expressions?.size ?: 0 }
override val valueParameters by lz {
val args = newExpression.argumentList ?: return@lz emptyList<UVariable>()
args.expressions.mapIndexed { i, psiExpression -> JavaUAnonymousClassConstructorParameter(args, i, this) }
}
override val typeParameters by lz { psi.typeParameters.map { JavaConverter.convert(it, this) } }
override val typeParameterCount: Int
get() = psi.typeParameters.size
override val returnType: UType?
get() = null
override val body: UExpression?
get() = null
override val visibility: UastVisibility
get() = UastVisibility.LOCAL
override fun getSuperFunctions(context: UastContext) = emptyList<UFunction>()
override val nameElement: UElement?
get() = null
override val name: String
get() = "<init>"
}
private class JavaUAnonymousClassConstructorParameter(
val psi: PsiExpressionList,
val index: Int,
override val parent: UElement
) : JavaAbstractUElement(), UVariable, NoAnnotations, NoModifiers {
override val initializer by lz { JavaConverter.convert(psi.expressions[index], this) }
override val initializerKind: UastVariableInitialierKind
get() = UastVariableInitialierKind.EXPRESSION
override val kind: UastVariableKind
get() = UastVariableKind.VALUE_PARAMETER
override val type by lz { JavaConverter.convert(psi.expressionTypes[index], this) }
override val nameElement: UElement?
get() = null
override val name: String
get() = "p$index"
override val visibility: UastVisibility
get() = UastVisibility.LOCAL
} }
@@ -0,0 +1,40 @@
/*
* 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.uast.java
import com.intellij.psi.PsiClassInitializer
import org.jetbrains.uast.*
import org.jetbrains.uast.java.internal.JavaUElementWithComments
class JavaUClassInitializer(
psi: PsiClassInitializer,
override val containingElement: UElement?
) : UClassInitializer, JavaUElementWithComments, PsiClassInitializer by psi {
override val psi = unwrap<UClassInitializer, PsiClassInitializer>(psi)
override val uastAnchor: UElement?
get() = null
override val uastBody by lz {
getLanguagePlugin().convertElement(psi.body, this, null) as? UExpression ?: UastEmptyExpression
}
override val uastAnnotations by lz { psi.annotations.map { SimpleUAnnotation(it, this) } }
override fun equals(other: Any?) = this === other
override fun hashCode() = psi.hashCode()
}
@@ -1,32 +1,32 @@
/*
* Copyright 2000-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.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import org.jetbrains.uast.UComment
import org.jetbrains.uast.UFile import org.jetbrains.uast.UFile
import org.jetbrains.uast.UImportStatement import org.jetbrains.uast.UastLanguagePlugin
import org.jetbrains.uast.psi.PsiElementBacked import java.util.*
class JavaUFile(override val psi: PsiJavaFile): JavaAbstractUElement(), UFile, PsiElementBacked { class JavaUFile(override val psi: PsiJavaFile, override val languagePlugin: UastLanguagePlugin) : UFile {
override val packageFqName by lz { psi.packageName } override val packageName: String
get() = psi.packageName
override val importStatements: List<UImportStatement> by lz { override val imports by lz {
val importList = psi.importList ?: return@lz emptyList<UImportStatement>() psi.importList?.allImportStatements?.map { JavaUImportStatement(it, this) } ?: listOf()
importList.importStatements.map { JavaConverter.convert(it, this) }.filterNotNull()
} }
override val declarations by lz { psi.classes.map { JavaUClass(it, this) } } override val classes by lz { psi.classes.map { JavaUClass.create(it, this) } }
override val allCommentsInFile by lz {
val comments = ArrayList<UComment>(0)
psi.accept(object : PsiRecursiveElementWalkingVisitor() {
override fun visitComment(comment: PsiComment) {
comments += UComment(comment, this@JavaUFile)
}
})
comments
}
override fun equals(other: Any?) = (other as? JavaUFile)?.psi == psi
} }
@@ -1,92 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiArrayType
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.PsiElementBacked
class JavaUFunction(
override val psi: PsiMethod,
override val parent: UElement
) : JavaAbstractUElement(), UFunction, PsiElementBacked {
override val kind: UastFunctionKind
get() = if (psi.isConstructor) UastFunctionKind.CONSTRUCTOR else UastFunctionKind.FUNCTION
override val name: String
get() = if (psi.isConstructor) "<init>" else psi.name
override val nameElement by lz { JavaDumbUElement(psi.nameIdentifier, this) }
override val valueParameters by lz { psi.parameterList.parameters.map { JavaConverter.convert(it, this) } }
override val valueParameterCount: Int
get() = psi.parameterList.parametersCount
override val typeParameters by lz { psi.typeParameters.map { JavaConverter.convert(it, this) } }
override val typeParameterCount: Int
get() = psi.typeParameters.size
override val returnType by lz { psi.returnType?.let { JavaConverter.convert(it, this) } }
override fun hasModifier(modifier: UastModifier) = psi.hasModifier(modifier)
val thrownExceptions: List<UType> by lz {
psi.throwsList.referencedTypes.map { JavaConverter.convert(it, this) }
}
override val annotations by lz { psi.modifierList.getAnnotations(this) }
override val visibility: UastVisibility
get() = psi.getVisibility()
override val body by lz { psi.body?.let { JavaConverter.convert(it, this) } }
override val bytecodeDescriptor by lz { getDescriptor(psi) }
override fun getSuperFunctions(context: UastContext): List<UFunction> {
return psi.findSuperMethods().map { context.convert(it) as? UFunction }.filterNotNull()
}
private companion object {
fun getDescriptor(psi: PsiMethod): String? {
val parameterTypes = psi.parameterList.parameters.map {
renderType(it.type) ?: return null
}
val returnType = renderType(psi.returnType) ?: return null
return parameterTypes.joinToString("", "(", ")") + returnType
}
fun renderType(type: PsiType?): String? = when (type) {
null -> null
PsiType.CHAR -> "C"
PsiType.DOUBLE -> "D"
PsiType.FLOAT -> "F"
PsiType.INT -> "I"
PsiType.LONG -> "J"
PsiType.SHORT -> "S"
PsiType.BOOLEAN -> "Z"
PsiType.VOID -> "V"
is PsiArrayType -> renderType(type.componentType)?.let { "[$it" }
is PsiClassType -> type.resolve()?.qualifiedName?.replace('.', '/')?.let { "L$it;" }
else -> null
}
}
}
@@ -1,40 +1,15 @@
/*
* Copyright 2000-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.uast.java package org.jetbrains.uast.java
import com.intellij.psi.PsiImportStatement import com.intellij.psi.PsiImportStatementBase
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement import org.jetbrains.uast.UElement
import org.jetbrains.uast.UImportStatement import org.jetbrains.uast.UImportStatement
import org.jetbrains.uast.UastContext
import org.jetbrains.uast.psi.PsiElementBacked
class JavaUImportStatement( class JavaUImportStatement(
override val psi: PsiImportStatement, override val psi: PsiImportStatementBase,
override val parent: UElement override val containingElement: UElement?
) : JavaAbstractUElement(), UImportStatement, PsiElementBacked { ) : UImportStatement {
override val fqNameToImport: String? override val isOnDemand: Boolean
get() = psi.qualifiedName
override val isStarImport: Boolean
get() = psi.isOnDemand get() = psi.isOnDemand
override val importReference by lz { psi.importReference?.let { JavaDumbUElement(it, this) } }
override fun resolve(context: UastContext): UDeclaration? { override fun resolve() = psi.resolve()
if (psi.isOnDemand) return null
val resolvedElement = psi.resolve() ?: return null
return context.convert(resolvedElement) as? UDeclaration
}
} }
@@ -0,0 +1,65 @@
/*
* 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.uast.java
import com.intellij.psi.PsiAnnotationMethod
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiNameIdentifierOwner
import org.jetbrains.uast.*
import org.jetbrains.uast.java.internal.JavaUElementWithComments
open class JavaUMethod(
psi: PsiMethod,
override val containingElement: UElement?
) : UMethod, JavaUElementWithComments, PsiMethod by psi {
override val psi = unwrap<UMethod, PsiMethod>(psi)
override val uastBody by lz {
val body = psi.body ?: return@lz null
getLanguagePlugin().convertElement(body, this) as? UExpression
}
override val uastAnnotations by lz { psi.annotations.map { SimpleUAnnotation(it, this) } }
override val uastParameters by lz {
psi.parameterList.parameters.map { JavaUParameter(it, this) }
}
override val uastAnchor: UElement
get() = UIdentifier((psi.originalElement as? PsiNameIdentifierOwner)?.nameIdentifier ?: psi.nameIdentifier, this)
override fun equals(other: Any?) = this === other
override fun hashCode() = psi.hashCode()
companion object {
fun create(psi: PsiMethod, languagePlugin: UastLanguagePlugin, containingElement: UElement?) = when (psi) {
is PsiAnnotationMethod -> JavaUAnnotationMethod(psi, languagePlugin, containingElement)
else -> JavaUMethod(psi, containingElement)
}
}
}
class JavaUAnnotationMethod(
override val psi: PsiAnnotationMethod,
languagePlugin: UastLanguagePlugin,
containingElement: UElement?
) : JavaUMethod(psi, containingElement), UAnnotationMethod {
override val uastDefaultValue by lz {
val defaultValue = psi.defaultValue ?: return@lz null
languagePlugin.convertElement(defaultValue, this, null) as? UExpression
}
}
@@ -1,40 +0,0 @@
/*
* Copyright 2000-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.uast.java
import com.intellij.psi.PsiImportStaticStatement
import org.jetbrains.uast.UDeclaration
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UImportStatement
import org.jetbrains.uast.UastContext
import org.jetbrains.uast.psi.PsiElementBacked
class JavaUStaticImportStatement(
override val psi: PsiImportStaticStatement,
override val parent: UElement
) : JavaAbstractUElement(), UImportStatement, PsiElementBacked {
override val fqNameToImport: String?
get() = psi.referenceName
override val isStarImport: Boolean
get() = psi.isOnDemand
override fun resolve(context: UastContext): UDeclaration? {
if (psi.isOnDemand) return null
val resolvedElement = psi.resolve() ?: return null
return context.convert(resolvedElement) as? UDeclaration
}
}

Some files were not shown because too many files have changed in this diff Show More