javac-wrapper: identifier resolver
This commit is contained in:
committed by
Alexander Baratynskiy
parent
01883a41cb
commit
4f180e1292
@@ -41,14 +41,15 @@ import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Log
|
||||
import com.sun.tools.javac.util.Names
|
||||
import com.sun.tools.javac.util.Options
|
||||
import org.jetbrains.kotlin.javac.resolve.ClassifierResolver
|
||||
import org.jetbrains.kotlin.javac.resolve.IdentifierResolver
|
||||
import org.jetbrains.kotlin.javac.resolve.KotlinClassifiersCache
|
||||
import org.jetbrains.kotlin.javac.resolve.classId
|
||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClass
|
||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClassifierType
|
||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedPackage
|
||||
import org.jetbrains.kotlin.javac.wrappers.trees.*
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.Closeable
|
||||
@@ -67,7 +68,7 @@ class JavacWrapper(
|
||||
jvmClasspathRoots: List<File>,
|
||||
bootClasspath: List<File>?,
|
||||
sourcePath: List<File>?,
|
||||
val kotlinSupertypeResolver: KotlinSupertypeResolver,
|
||||
val kotlinResolver: JavacWrapperKotlinResolver,
|
||||
private val compileJava: Boolean,
|
||||
private val outputDirectory: File?,
|
||||
private val context: Context
|
||||
@@ -174,6 +175,7 @@ class JavacWrapper(
|
||||
}
|
||||
|
||||
val classifierResolver = ClassifierResolver(this)
|
||||
private val identifierResolver = IdentifierResolver(this)
|
||||
private val kotlinClassifiersCache = KotlinClassifiersCache(if (javaFiles.isNotEmpty()) kotlinFiles else emptyList(), this)
|
||||
private val symbolBasedPackagesCache = hashMapOf<String, SymbolBasedPackage?>()
|
||||
|
||||
@@ -281,6 +283,9 @@ class JavacWrapper(
|
||||
fun resolve(treePath: TreePath): JavaClassifier? =
|
||||
classifierResolver.resolve(treePath)
|
||||
|
||||
fun resolveField(treePath: TreePath, containingClass: JavaClass): JavaField? =
|
||||
identifierResolver.resolve(treePath, containingClass)
|
||||
|
||||
fun toVirtualFile(javaFileObject: JavaFileObject): VirtualFile? =
|
||||
javaFileObject.toUri().let { uri ->
|
||||
if (uri.scheme == "jar") {
|
||||
|
||||
+4
-1
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.javac
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
interface KotlinSupertypeResolver {
|
||||
interface JavacWrapperKotlinResolver {
|
||||
fun resolveSupertypes(classOrObject: KtClassOrObject): List<ClassId>
|
||||
|
||||
fun findField(classOrObject: KtClassOrObject, name: String): JavaField?
|
||||
}
|
||||
+20
-87
@@ -14,15 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.javac.wrappers.trees
|
||||
package org.jetbrains.kotlin.javac.resolve
|
||||
|
||||
import com.sun.source.tree.Tree
|
||||
import com.sun.source.util.TreePath
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.javac.MockKotlinClassifier
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedClass
|
||||
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedTypeParameter
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -111,80 +110,14 @@ class ClassifierResolver(private val javac: JavacWrapper) {
|
||||
}
|
||||
|
||||
private abstract class Scope(protected val javac: JavacWrapper,
|
||||
protected val treePath: TreePath) {
|
||||
protected val treePath: TreePath) {
|
||||
|
||||
protected val helper = ResolveHelper(javac, treePath)
|
||||
|
||||
abstract val parent: Scope?
|
||||
|
||||
abstract fun findClass(name: String, pathSegments: List<String>): JavaClassifier?
|
||||
|
||||
protected fun getJavaClassFromPathSegments(javaClass: JavaClass,
|
||||
pathSegments: List<String>) =
|
||||
if (pathSegments.size == 1) {
|
||||
javaClass
|
||||
}
|
||||
else {
|
||||
javaClass.findInnerOrNested(pathSegments.drop(1))
|
||||
}
|
||||
|
||||
protected fun findImport(pathSegments: List<String>): JavaClass? {
|
||||
pathSegments.forEachIndexed { index, _ ->
|
||||
if (index == pathSegments.lastIndex) return null
|
||||
val packageFqName = pathSegments.dropLast(index + 1).joinToString(separator = ".")
|
||||
findPackage(packageFqName)?.let { pack ->
|
||||
val className = pathSegments.takeLast(index + 1)
|
||||
return findJavaOrKotlinClass(ClassId(pack, Name.identifier(className.first())))?.let { javaClass ->
|
||||
getJavaClassFromPathSegments(javaClass, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
protected fun findJavaOrKotlinClass(classId: ClassId) = javac.findClass(classId) ?: javac.getKotlinClassifier(classId)
|
||||
|
||||
protected fun JavaClass.findInnerOrNested(name: Name, checkedSupertypes: HashSet<JavaClass> = hashSetOf()): JavaClass? {
|
||||
findVisibleInnerOrNestedClass(name)?.let {
|
||||
checkedSupertypes.addAll(collectAllSupertypes())
|
||||
return it
|
||||
}
|
||||
|
||||
return supertypes
|
||||
.mapNotNull {
|
||||
(it.classifier as? JavaClass)?.let { supertype ->
|
||||
if (supertype !in checkedSupertypes) {
|
||||
supertype.findInnerOrNested(name, checkedSupertypes)
|
||||
} else null
|
||||
}
|
||||
}.singleOrNull()
|
||||
}
|
||||
|
||||
protected fun findPackage(packageName: String): FqName? {
|
||||
val fqName = if (packageName.isNotBlank()) FqName(packageName) else FqName.ROOT
|
||||
javac.hasKotlinPackage(fqName)?.let { return it }
|
||||
|
||||
return javac.findPackage(fqName)?.fqName
|
||||
}
|
||||
|
||||
private fun JavaClass.findVisibleInnerOrNestedClass(name: Name) = findInnerClass(name)?.let { innerOrNestedClass ->
|
||||
when (innerOrNestedClass.visibility) {
|
||||
Visibilities.PRIVATE -> null
|
||||
JavaVisibilities.PACKAGE_VISIBILITY -> {
|
||||
val classId = (innerOrNestedClass as? MockKotlinClassifier)?.classId ?: innerOrNestedClass.computeClassId()
|
||||
if (classId?.packageFqName?.asString() == (treePath.compilationUnit.packageName?.toString() ?: "")) innerOrNestedClass else null
|
||||
}
|
||||
else -> innerOrNestedClass
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaClass.collectAllSupertypes(): Set<JavaClass> =
|
||||
hashSetOf(this).apply {
|
||||
supertypes.mapNotNull { it.classifier as? JavaClass }.forEach { addAll(it.collectAllSupertypes()) }
|
||||
}
|
||||
|
||||
private fun JavaClass.findInnerOrNested(pathSegments: List<String>): JavaClass? =
|
||||
pathSegments.fold(this) { javaClass, it -> javaClass.findInnerOrNested(Name.identifier(it)) ?: return null }
|
||||
|
||||
}
|
||||
|
||||
private class GlobalScope(javac: JavacWrapper, treePath: TreePath) : Scope(javac, treePath) {
|
||||
@@ -195,8 +128,8 @@ private class GlobalScope(javac: JavacWrapper, treePath: TreePath) : Scope(javac
|
||||
override fun findClass(name: String, pathSegments: List<String>): JavaClass? {
|
||||
findByFqName(pathSegments)?.let { return it }
|
||||
|
||||
return findJavaOrKotlinClass(classId("java.lang", name))?.let { javaClass ->
|
||||
getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
return helper.findJavaOrKotlinClass(classId("java.lang", name))?.let { javaClass ->
|
||||
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,18 +137,18 @@ private class GlobalScope(javac: JavacWrapper, treePath: TreePath) : Scope(javac
|
||||
pathSegments.forEachIndexed { index, _ ->
|
||||
if (index != 0) {
|
||||
val packageFqName = pathSegments.take(index).joinToString(separator = ".")
|
||||
findPackage(packageFqName)?.let { pack ->
|
||||
helper.findPackage(packageFqName)?.let { pack ->
|
||||
val className = pathSegments.drop(index)
|
||||
findJavaOrKotlinClass(ClassId(pack, Name.identifier(className.first())))?.let { javaClass ->
|
||||
return getJavaClassFromPathSegments(javaClass, className)
|
||||
helper.findJavaOrKotlinClass(ClassId(pack, Name.identifier(className.first())))?.let { javaClass ->
|
||||
return helper.getJavaClassFromPathSegments(javaClass, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try to find in <root>
|
||||
return findJavaOrKotlinClass(classId("", pathSegments.first()))?.let { javaClass ->
|
||||
getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
return helper.findJavaOrKotlinClass(classId("", pathSegments.first()))?.let { javaClass ->
|
||||
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,11 +162,11 @@ private class ImportOnDemandScope(javac: JavacWrapper,
|
||||
|
||||
override fun findClass(name: String, pathSegments: List<String>): JavaClassifier? {
|
||||
asteriskImports()
|
||||
.mapNotNullTo(hashSetOf()) { findImport("$it$name".split(".")) }
|
||||
.mapNotNullTo(hashSetOf()) { helper.findImport("$it$name".split(".")) }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let {
|
||||
return it.singleOrNull()?.let { javaClass ->
|
||||
getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
helper.getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,9 +192,9 @@ private class PackageScope(javac: JavacWrapper,
|
||||
get() = ImportOnDemandScope(javac, treePath)
|
||||
|
||||
override fun findClass(name: String, pathSegments: List<String>): JavaClassifier? {
|
||||
findJavaOrKotlinClass(classId(treePath.compilationUnit.packageName?.toString() ?: "", name))
|
||||
helper.findJavaOrKotlinClass(classId(treePath.compilationUnit.packageName?.toString() ?: "", name))
|
||||
?.let { javaClass ->
|
||||
return getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
return helper.getJavaClassFromPathSegments(javaClass, pathSegments)
|
||||
}
|
||||
|
||||
return parent.findClass(name, pathSegments)
|
||||
@@ -281,8 +214,8 @@ private class SingleTypeImportScope(javac: JavacWrapper,
|
||||
|
||||
imports.singleOrNull() ?: return null
|
||||
|
||||
return findImport(imports.first().split("."))
|
||||
?.let { javaClass -> getJavaClassFromPathSegments(javaClass, pathSegments) }
|
||||
return helper.findImport(imports.first().split("."))
|
||||
?.let { javaClass -> helper.getJavaClassFromPathSegments(javaClass, pathSegments) }
|
||||
}
|
||||
|
||||
private fun imports(firstSegment: String) =
|
||||
@@ -310,7 +243,7 @@ private class CurrentClassAndInnerScope(javac: JavacWrapper,
|
||||
?.find { typeParameter -> typeParameter.name == identifier }
|
||||
?.let { typeParameter -> return typeParameter }
|
||||
|
||||
it.findInnerOrNested(identifier)?.let { javaClass -> return getJavaClassFromPathSegments(javaClass, pathSegments) }
|
||||
helper.findInnerOrNested(it, identifier)?.let { javaClass -> return helper.getJavaClassFromPathSegments(javaClass, pathSegments) }
|
||||
|
||||
if (it.name == identifier && pathSegments.size == 1) return it
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.javac.resolve
|
||||
|
||||
import com.sun.source.util.TreePath
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class IdentifierResolver(private val javac: JavacWrapper) {
|
||||
|
||||
fun resolve(treePath: TreePath, containingClass: JavaClass): JavaField? {
|
||||
val leaf = treePath.leaf
|
||||
if (leaf is JCTree.JCIdent) {
|
||||
val fieldName = Name.identifier(leaf.name.toString())
|
||||
return CurrentClassAndInnerFieldScope(javac, treePath).findField(containingClass, fieldName)
|
||||
}
|
||||
else if (leaf is JCTree.JCFieldAccess) {
|
||||
val javaClassTreePath = javac.getTreePath(leaf.selected, treePath.compilationUnit)
|
||||
val javaClass = javac.resolve(javaClassTreePath) as? JavaClass ?: return null
|
||||
if (javaClass is MockKotlinClassifier) {
|
||||
return javaClass.findField(leaf.name.toString())
|
||||
}
|
||||
|
||||
val fieldName = Name.identifier(leaf.name.toString())
|
||||
return CurrentClassAndInnerFieldScope(javac, treePath, null).findField(javaClass, fieldName)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract class FieldScope(protected val javac: JavacWrapper,
|
||||
protected val treePath: TreePath) {
|
||||
|
||||
protected val helper = ResolveHelper(javac, treePath)
|
||||
|
||||
abstract val parent: FieldScope?
|
||||
|
||||
abstract fun findField(javaClass: JavaClass, name: Name): JavaField?
|
||||
|
||||
protected fun JavaClass.findFieldIncludingSupertypes(name: Name, checkedSupertypes: HashSet<JavaClass> = hashSetOf()): JavaField? {
|
||||
fields.find { it.name == name }?.let {
|
||||
checkedSupertypes.addAll(collectAllSupertypes())
|
||||
return it
|
||||
}
|
||||
return supertypes
|
||||
.mapNotNull {
|
||||
val classifier = it.classifier as? JavaClass
|
||||
if (classifier !in checkedSupertypes) {
|
||||
classifier?.findFieldIncludingSupertypes(name, checkedSupertypes)
|
||||
}
|
||||
else null
|
||||
}.singleOrNull()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class StaticImportOnDemandFieldScope(javac: JavacWrapper,
|
||||
treePath: TreePath) : FieldScope(javac, treePath) {
|
||||
override val parent: FieldScope?
|
||||
get() = null
|
||||
|
||||
override fun findField(javaClass: JavaClass, name: Name): JavaField? {
|
||||
val foundFields = hashSetOf<JavaField>()
|
||||
|
||||
staticAsteriskImports().forEach { import ->
|
||||
val pathSegments = import.split(".")
|
||||
val importedClass = helper.findImport(pathSegments)
|
||||
if (importedClass is MockKotlinClassifier) {
|
||||
return importedClass.findField(name.asString())
|
||||
}
|
||||
|
||||
importedClass?.findFieldIncludingSupertypes(name)?.let { foundFields.add(it) }
|
||||
}
|
||||
|
||||
return foundFields.singleOrNull()
|
||||
}
|
||||
|
||||
private fun staticAsteriskImports() =
|
||||
(treePath.compilationUnit as JCTree.JCCompilationUnit).imports
|
||||
.filter { it.staticImport }
|
||||
.mapNotNull {
|
||||
val fqName = it.qualifiedIdentifier.toString()
|
||||
if (fqName.endsWith("*")) {
|
||||
fqName.dropLast(2)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class StaticImportFieldScope(javac: JavacWrapper,
|
||||
treePath: TreePath) : FieldScope(javac, treePath) {
|
||||
|
||||
override val parent: FieldScope
|
||||
get() = StaticImportOnDemandFieldScope(javac, treePath)
|
||||
|
||||
override fun findField(javaClass: JavaClass, name: Name): JavaField? {
|
||||
val staticImports = staticImports(name.asString()).toSet().takeIf { it.isNotEmpty() }
|
||||
?: return parent.findField(javaClass, name)
|
||||
|
||||
val import = staticImports.singleOrNull() ?: return null
|
||||
val pathSegments = import.split(".").dropLast(1)
|
||||
val importedClass = helper.findImport(pathSegments)
|
||||
if (importedClass is MockKotlinClassifier) {
|
||||
return importedClass.findField(name.asString())
|
||||
}
|
||||
|
||||
return importedClass?.findFieldIncludingSupertypes(name)
|
||||
|
||||
}
|
||||
|
||||
private fun staticImports(fieldName: String) =
|
||||
(treePath.compilationUnit as JCTree.JCCompilationUnit).imports
|
||||
.filter { it.staticImport }
|
||||
.mapNotNull {
|
||||
val import = it.qualifiedIdentifier as? JCTree.JCFieldAccess
|
||||
val importedField = import?.name?.toString()
|
||||
if (importedField == fieldName) {
|
||||
import.toString()
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class CurrentClassAndInnerFieldScope(javac: JavacWrapper,
|
||||
treePath: TreePath,
|
||||
override val parent: FieldScope? = StaticImportFieldScope(javac, treePath)) : FieldScope(javac, treePath) {
|
||||
|
||||
override fun findField(javaClass: JavaClass, name: Name): JavaField? {
|
||||
javaClass.enclosingClasses().forEach {
|
||||
it.findFieldIncludingSupertypes(name)?.let { return it }
|
||||
}
|
||||
|
||||
return parent?.findField(javaClass, name)
|
||||
}
|
||||
|
||||
private fun JavaClass.enclosingClasses(): List<JavaClass> = arrayListOf<JavaClass>().also { classes ->
|
||||
classes.add(this)
|
||||
outerClass?.let { classes.addAll(it.enclosingClasses()) }
|
||||
}
|
||||
|
||||
}
|
||||
+41
-68
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.javac
|
||||
package org.jetbrains.kotlin.javac.resolve
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiField
|
||||
import com.intellij.psi.PsiLiteralExpression
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
@@ -85,15 +88,6 @@ class MockKotlinClassifier(val classId: ClassId,
|
||||
override val fqName: FqName
|
||||
get() = classId.asSingleFqName()
|
||||
|
||||
override val isAbstract: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isStatic: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isFinal: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val visibility: Visibility
|
||||
get() = when (classOrObject.visibilityModifierType()) {
|
||||
null, KtTokens.PUBLIC_KEYWORD -> Visibilities.PUBLIC
|
||||
@@ -102,11 +96,8 @@ class MockKotlinClassifier(val classId: ClassId,
|
||||
else -> JavaVisibilities.PACKAGE_VISIBILITY
|
||||
}
|
||||
|
||||
override val typeParameters: List<JavaTypeParameter>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val supertypes: Collection<JavaClassifierType>
|
||||
get() = javac.kotlinSupertypeResolver.resolveSupertypes(classOrObject)
|
||||
get() = javac.kotlinResolver.resolveSupertypes(classOrObject)
|
||||
.mapNotNull { javac.getKotlinClassifier(it) ?: javac.findClass(it) }
|
||||
.map { MockKotlinClassifierType(it) }
|
||||
|
||||
@@ -118,53 +109,17 @@ class MockKotlinClassifier(val classId: ClassId,
|
||||
}
|
||||
}
|
||||
|
||||
override val outerClass: JavaClass?
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isInterface: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isAnnotationType: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isEnum: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val lightClassOriginKind
|
||||
get() = LightClassOriginKind.SOURCE
|
||||
|
||||
override val virtualFile: VirtualFile?
|
||||
get() = null
|
||||
|
||||
override val methods: Collection<JavaMethod>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val fields: Collection<JavaField>
|
||||
get() = classOrObject.declarations
|
||||
.filterIsInstance<KtProperty>()
|
||||
.map(::MockKotlinField) + classOrObject.companionObjects.flatMap {
|
||||
it.declarations
|
||||
.filterIsInstance<KtProperty>()
|
||||
.map(::MockKotlinField)
|
||||
}
|
||||
|
||||
override val constructors: Collection<JavaConstructor>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val name
|
||||
get() = fqName.shortNameOrSpecial()
|
||||
|
||||
override val annotations
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override fun isFromSourceCodeInScope(scope: SearchScope) = true
|
||||
|
||||
override fun findAnnotation(fqName: FqName) =
|
||||
throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val innerClassNames
|
||||
get() = innerClasses.map(JavaClass::name)
|
||||
|
||||
@@ -177,36 +132,62 @@ class MockKotlinClassifier(val classId: ClassId,
|
||||
val hasTypeParameters: Boolean
|
||||
get() = typeParametersNumber > 0
|
||||
|
||||
fun findField(name: String) = javac.kotlinResolver.findField(classOrObject, name)
|
||||
|
||||
override val isAbstract: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isStatic: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isFinal: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val typeParameters: List<JavaTypeParameter>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val outerClass: JavaClass?
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isInterface: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isAnnotationType: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isEnum: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val methods: Collection<JavaMethod>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val fields: Collection<JavaField>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val constructors: Collection<JavaConstructor>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val annotations
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override fun findAnnotation(fqName: FqName) =
|
||||
throw UnsupportedOperationException("Should not be called")
|
||||
}
|
||||
|
||||
class MockKotlinClassifierType(override val classifier: JavaClassifier) : JavaClassifierType {
|
||||
|
||||
override val typeArguments: List<JavaType>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isRaw: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val classifierQualifiedName: String
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val presentableText: String
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override fun findAnnotation(fqName: FqName) =
|
||||
throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
}
|
||||
|
||||
class MockKotlinField(private val property: KtProperty) : JavaField {
|
||||
class MockKotlinField(private val psiField: PsiField) : JavaField {
|
||||
|
||||
override val initializerValue: Any?
|
||||
get() = (psiField.initializer as? PsiLiteralExpression)?.value
|
||||
|
||||
override val name: Name
|
||||
get() = property.nameAsSafeName
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
@@ -225,16 +206,8 @@ class MockKotlinField(private val property: KtProperty) : JavaField {
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val type: JavaType
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
override val initializerValue: Any?
|
||||
get() {
|
||||
if (!property.hasModifier(KtTokens.CONST_KEYWORD)) return null
|
||||
val initializer = property.initializer ?: return null
|
||||
|
||||
return initializer.text.toIntOrNull() ?: initializer.text
|
||||
}
|
||||
override val hasConstantNotNullInitializer: Boolean
|
||||
get() = throw UnsupportedOperationException("Should not be called")
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = throw UnsupportedOperationException("Should not be called")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.javac.resolve
|
||||
|
||||
import com.sun.source.util.TreePath
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.javac.wrappers.trees.computeClassId
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class ResolveHelper(private val javac: JavacWrapper,
|
||||
private val treePath: TreePath) {
|
||||
|
||||
fun getJavaClassFromPathSegments(javaClass: JavaClass,
|
||||
pathSegments: List<String>) =
|
||||
if (pathSegments.size == 1) {
|
||||
javaClass
|
||||
}
|
||||
else {
|
||||
javaClass.findInnerOrNested(pathSegments.drop(1))
|
||||
}
|
||||
|
||||
fun findImport(pathSegments: List<String>): JavaClass? {
|
||||
pathSegments.forEachIndexed { index, _ ->
|
||||
if (index == pathSegments.lastIndex) return null
|
||||
val packageFqName = pathSegments.dropLast(index + 1).joinToString(separator = ".")
|
||||
findPackage(packageFqName)?.let { pack ->
|
||||
val className = pathSegments.takeLast(index + 1)
|
||||
return findJavaOrKotlinClass(ClassId(pack, Name.identifier(className.first())))?.let { javaClass ->
|
||||
getJavaClassFromPathSegments(javaClass, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun findJavaOrKotlinClass(classId: ClassId) = javac.findClass(classId) ?: javac.getKotlinClassifier(classId)
|
||||
|
||||
fun findInnerOrNested(javaClass: JavaClass, name: Name, checkedSupertypes: HashSet<JavaClass> = hashSetOf()): JavaClass? {
|
||||
javaClass.findVisibleInnerOrNestedClass(name)?.let {
|
||||
checkedSupertypes.addAll(javaClass.collectAllSupertypes())
|
||||
return it
|
||||
}
|
||||
|
||||
return javaClass.supertypes
|
||||
.mapNotNull {
|
||||
(it.classifier as? JavaClass)?.let { supertype ->
|
||||
if (supertype !in checkedSupertypes) {
|
||||
findInnerOrNested(supertype, name, checkedSupertypes)
|
||||
} else null
|
||||
}
|
||||
}.singleOrNull()
|
||||
}
|
||||
|
||||
fun findPackage(packageName: String): FqName? {
|
||||
val fqName = if (packageName.isNotBlank()) FqName(packageName) else FqName.ROOT
|
||||
javac.hasKotlinPackage(fqName)?.let { return it }
|
||||
|
||||
return javac.findPackage(fqName)?.fqName
|
||||
}
|
||||
|
||||
private fun JavaClass.findVisibleInnerOrNestedClass(name: Name) = findInnerClass(name)?.let { innerOrNestedClass ->
|
||||
when (innerOrNestedClass.visibility) {
|
||||
Visibilities.PRIVATE -> null
|
||||
JavaVisibilities.PACKAGE_VISIBILITY -> {
|
||||
val classId = (innerOrNestedClass as? MockKotlinClassifier)?.classId ?: innerOrNestedClass.computeClassId()
|
||||
if (classId?.packageFqName?.asString() == (treePath.compilationUnit.packageName?.toString() ?: "")) innerOrNestedClass else null
|
||||
}
|
||||
else -> innerOrNestedClass
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaClass.findInnerOrNested(pathSegments: List<String>): JavaClass? =
|
||||
pathSegments.fold(this) { javaClass, it -> findInnerOrNested(javaClass, Name.identifier(it)) ?: return null }
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun JavaClass.collectAllSupertypes(): Set<JavaClass> =
|
||||
hashSetOf(this).apply {
|
||||
supertypes.mapNotNull { it.classifier as? JavaClass }.forEach { addAll(it.collectAllSupertypes()) }
|
||||
}
|
||||
+2
-14
@@ -87,10 +87,8 @@ class ValueCalculator(private val containingClass: JavaClass,
|
||||
}
|
||||
else expr.value
|
||||
}
|
||||
is JCTree.JCIdent -> containingClass.fields
|
||||
.find { it.name == expr.name.toString().let { Name.identifier(it) } }
|
||||
?.initializerValue
|
||||
is JCTree.JCFieldAccess -> fieldAccessValue(expr)
|
||||
is JCTree.JCIdent,
|
||||
is JCTree.JCFieldAccess -> javac.resolveField(javac.getTreePath(expr, treePath.compilationUnit), containingClass)?.initializerValue
|
||||
is JCTree.JCBinary -> binaryInitializerValue(expr)
|
||||
is JCTree.JCParens -> getValue(expr.expr)
|
||||
is JCTree.JCUnary -> unaryInitializerValue(expr)
|
||||
@@ -98,16 +96,6 @@ class ValueCalculator(private val containingClass: JavaClass,
|
||||
}
|
||||
}
|
||||
|
||||
private fun fieldAccessValue(value: JCTree.JCFieldAccess): Any? {
|
||||
val newTreePath = javac.getTreePath(value.selected, treePath.compilationUnit)
|
||||
val javaClass = javac.resolve(newTreePath) as? JavaClass ?: return null
|
||||
val fieldName = value.name.toString().let { Name.identifier(it) }
|
||||
|
||||
return javaClass.fields
|
||||
.find { it.name == fieldName }
|
||||
?.initializerValue
|
||||
}
|
||||
|
||||
private fun unaryInitializerValue(value: JCTree.JCUnary): Any? {
|
||||
val argValue = getValue(value.arg)
|
||||
return when (value.tag) {
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ import com.sun.tools.javac.code.BoundKind
|
||||
import com.sun.tools.javac.tree.JCTree
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.javac.MockKotlinClassifier
|
||||
import org.jetbrains.kotlin.javac.resolve.MockKotlinClassifier
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
|
||||
Reference in New Issue
Block a user