javac-wrapper: fixes after rebase and review

This commit is contained in:
baratynskiy
2017-08-14 13:28:35 +03:00
committed by Alexander Baratynskiy
parent 2dc0c55e76
commit 67fdd9f76e
39 changed files with 984 additions and 177 deletions
@@ -150,10 +150,10 @@ class JavacWrapper(
it.sourceFile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE) &&
it.packageName != null
}.associateBy({ FqName(it.packageName!!.toString()) }) { compilationUnit ->
compilationUnit.packageAnnotations/*.map { TreeBasedAnnotation(it, compilationUnit, this) }*/
compilationUnit.packageAnnotations
}
val classifierResolver = ClassifierResolver(this)
private val classifierResolver = ClassifierResolver(this)
private val identifierResolver = IdentifierResolver(this)
private val kotlinClassifiersCache by lazy { KotlinClassifiersCache(if (javaFiles.isNotEmpty()) kotlinFiles else emptyList(), this) }
private val symbolBasedPackagesCache = hashMapOf<String, SymbolBasedPackage?>()
@@ -35,7 +35,7 @@ class ClassifierResolver(private val javac: JavacWrapper) {
if (tree in beingResolved) return null
beingResolved(tree)
return tryToResolve2(tree, unit, containingElement).apply {
return tryToResolve(tree, unit, containingElement).apply {
cache[tree] = this
removeBeingResolved(tree)
}
@@ -67,7 +67,7 @@ class ClassifierResolver(private val javac: JavacWrapper) {
private fun pathSegments(path: String): List<String> {
val pathSegments = arrayListOf<String>()
var numberOfBrackets = 0
var builder = StringBuilder()
val builder = StringBuilder()
path.forEach { char ->
when (char) {
'<' -> numberOfBrackets++
@@ -75,7 +75,7 @@ class ClassifierResolver(private val javac: JavacWrapper) {
'.' -> {
if (numberOfBrackets == 0) {
pathSegments.add(builder.toString())
builder = StringBuilder()
builder.setLength(0)
}
}
'@' -> {}
@@ -86,15 +86,18 @@ class ClassifierResolver(private val javac: JavacWrapper) {
return pathSegments.apply { add(builder.toString()) }
}
private fun tryToResolve2(tree: Tree, unit: CompilationUnitTree, containingElement: JavaElement): JavaClassifier? {
private fun tryToResolve(tree: Tree, unit: CompilationUnitTree, containingElement: JavaElement): JavaClassifier? {
val pathSegments = pathSegments(tree.toString())
val containingClass = when (containingElement) {
is JavaClass -> containingElement
is JavaTypeParameterListOwner -> {
val identifier = Name.identifier(pathSegments.first())
containingElement.typeParameters.find { it.name == identifier }?.let { return it }
pathSegments.singleOrNull()?.let { pathSegment ->
val identifier = Name.identifier(pathSegment)
containingElement.typeParameters.find { it.name == identifier }?.let { return it }
}
(containingElement as JavaMember).containingClass
}
is JavaPackage -> return SingleTypeImportScope(javac, unit).findClass(pathSegments.first(), pathSegments)
else -> throw UnsupportedOperationException()
}
@@ -110,6 +113,10 @@ private abstract class Scope(protected val javac: JavacWrapper,
abstract val parent: Scope?
/**
* @param name name of a class to find
* @param pathSegments name of a class to find that is split into path segments (e.g. Outer<String>.Inner -> {"Outer", "Inner"})
*/
abstract fun findClass(name: String, pathSegments: List<String>): JavaClassifier?
}
@@ -132,9 +139,9 @@ private class GlobalScope(javac: JavacWrapper,
pathSegments.forEachIndexed { index, _ ->
if (index != 0) {
val packageFqName = pathSegments.take(index).joinToString(separator = ".")
helper.findPackage(packageFqName)?.let { pack ->
helper.findPackage(packageFqName)?.let { packageName ->
val className = pathSegments.drop(index)
helper.findJavaOrKotlinClass(ClassId(pack, Name.identifier(className.first())))?.let { javaClass ->
helper.findJavaOrKotlinClass(ClassId(packageName, Name.identifier(className.first())))?.let { javaClass ->
return helper.getJavaClassFromPathSegments(javaClass, className)
}
}
@@ -169,14 +176,8 @@ private class ImportOnDemandScope(javac: JavacWrapper,
}
private fun asteriskImports() =
compilationUnit.imports
.mapNotNull {
val fqName = it.qualifiedIdentifier.toString()
if (fqName.endsWith("*")) {
fqName.dropLast(1)
}
else null
}
compilationUnit.imports
.mapNotNull { it.qualifiedIdentifier.toString().takeIf { it.endsWith("*") }?.dropLast(1) }
}
@@ -214,14 +215,8 @@ private class SingleTypeImportScope(javac: JavacWrapper,
}
private fun imports(firstSegment: String) =
(compilationUnit as JCTree.JCCompilationUnit).imports
.mapNotNull {
val fqName = it.qualifiedIdentifier.toString()
if (fqName.endsWith(".$firstSegment")) {
fqName
}
else null
}
compilationUnit.imports
.mapNotNull { it.qualifiedIdentifier.toString().takeIf { it.endsWith(".$firstSegment") } }
}
private class CurrentClassAndInnerScope(javac: JavacWrapper,
@@ -36,14 +36,14 @@ class ConstantEvaluator(private val containingClass: JavaClass,
}
is JCTree.JCIdent,
is JCTree.JCFieldAccess -> javac.resolveField(expr, compilationUnit, containingClass)?.initializerValue
is JCTree.JCBinary -> binaryInitializerValue(expr)
is JCTree.JCBinary -> evaluateBinaryExpression(expr)
is JCTree.JCParens -> getValue(expr.expr)
is JCTree.JCUnary -> unaryInitializerValue(expr)
is JCTree.JCUnary -> evaluateUnaryExpression(expr)
else -> null
}
}
private fun unaryInitializerValue(value: JCTree.JCUnary): Any? {
private fun evaluateUnaryExpression(value: JCTree.JCUnary): Any? {
val argValue = getValue(value.arg)
return when (value.tag) {
JCTree.Tag.COMPL -> {
@@ -60,7 +60,7 @@ class ConstantEvaluator(private val containingClass: JavaClass,
}
}
private fun binaryInitializerValue(value: JCTree.JCBinary): Any? {
private fun evaluateBinaryExpression(value: JCTree.JCBinary): Any? {
val lhsValue = getValue(value.lhs) ?: return null
val rhsValue = getValue(value.rhs) ?: return null
@@ -30,7 +30,7 @@ internal class ResolveHelper(private val javac: JavacWrapper,
private val compilationUnit: CompilationUnitTree) {
fun getJavaClassFromPathSegments(javaClass: JavaClass,
pathSegments: List<String>) =
pathSegments: List<String>) =
if (pathSegments.size == 1) {
javaClass
}
@@ -66,7 +66,8 @@ internal class ResolveHelper(private val javac: JavacWrapper,
(it.classifier as? JavaClass)?.let { supertype ->
if (supertype !in checkedSupertypes) {
findInnerOrNested(supertype, name, checkedSupertypes)
} else null
}
else null
}
}.singleOrNull()
}
@@ -80,7 +80,7 @@ class SymbolBasedClass(
val innerClasses: Map<Name, JavaClass>
by lazy {
element.enclosedElements
enclosedElements
.filterIsInstance(TypeElement::class.java)
.map { SymbolBasedClass(it, javac, classId?.createNestedClassId(Name.identifier(it.simpleName.toString())), file) }
.associateBy(JavaClass::name)
@@ -106,7 +106,7 @@ class SymbolBasedClass(
get() = null
override val methods: Collection<JavaMethod>
get() = element.enclosedElements
get() = enclosedElements
.filter { it.kind == ElementKind.METHOD && !isEnumValuesOrValueOf(it as ExecutableElement) }
.map { SymbolBasedMethod(it as ExecutableElement, this, javac) }
@@ -119,12 +119,12 @@ class SymbolBasedClass(
}
override val fields: Collection<JavaField>
get() = element.enclosedElements
get() = enclosedElements
.filter { it.kind.isField && Name.isValidIdentifier(it.simpleName.toString()) }
.map { SymbolBasedField(it as VariableElement, this, javac) }
override val constructors: Collection<JavaConstructor>
get() = element.enclosedElements
get() = enclosedElements
.filter { it.kind == ElementKind.CONSTRUCTOR }
.map { SymbolBasedConstructor(it as ExecutableElement, this, javac) }
@@ -139,4 +139,6 @@ class SymbolBasedClass(
override fun findInnerClass(name: Name) = innerClasses[name]
private val enclosedElements by lazy { element.enclosedElements }
}
@@ -64,7 +64,7 @@ class SymbolBasedReferenceAnnotationArgument(
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaEnumValueAnnotationArgument {
override val entryName: Name?
get() = Name.identifier(name)
get() = name
override fun resolve(): SymbolBasedField {
val containingClass = (element.enclosingElement as Symbol.ClassSymbol).let {
@@ -55,6 +55,8 @@ class TreeBasedReferenceAnnotationArgument(name: Name,
private val field: JCTree.JCFieldAccess,
javac: JavacWrapper,
private val onElement: JavaElement) : TreeBasedAnnotationArgument(name, javac), JavaEnumValueAnnotationArgument {
override val entryName: Name?
get() = name
override fun resolve(): JavaField? {
val javaClass = javac.resolve(field.selected, compilationUnit, onElement) as? JavaClass ?: return null
@@ -67,7 +69,7 @@ class TreeBasedReferenceAnnotationArgument(name: Name,
class TreeBasedArrayAnnotationArgument(val args: List<JavaAnnotationArgument>,
name: Name,
javac: JavacWrapper): TreeBasedAnnotationArgument(name, javac), JavaArrayAnnotationArgument {
javac: JavacWrapper) : TreeBasedAnnotationArgument(name, javac), JavaArrayAnnotationArgument {
override fun getElements() = args
}
@@ -76,10 +78,10 @@ class TreeBasedJavaClassObjectAnnotationArgument(private val type: JCTree.JCExpr
name: Name,
private val compilationUnit: CompilationUnitTree,
javac: JavacWrapper,
private val onElement: JavaElement): TreeBasedAnnotationArgument(name, javac), JavaClassObjectAnnotationArgument {
private val onElement: JavaElement) : TreeBasedAnnotationArgument(name, javac), JavaClassObjectAnnotationArgument {
override fun getReferencedType(): JavaType =
TreeBasedType.create(type, compilationUnit, javac, emptyList(), onElement)
TreeBasedType.create(type, compilationUnit, javac, emptyList(), onElement)
}
@@ -87,25 +89,19 @@ class TreeBasedAnnotationAsAnnotationArgument(private val annotation: JCTree.JCA
name: Name,
private val compilationUnit: CompilationUnitTree,
javac: JavacWrapper,
private val onElement: JavaElement): TreeBasedAnnotationArgument(name, javac), JavaAnnotationAsAnnotationArgument {
private val onElement: JavaElement) : TreeBasedAnnotationArgument(name, javac), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation(): JavaAnnotation =
TreeBasedAnnotation(annotation, compilationUnit, javac, onElement)
TreeBasedAnnotation(annotation, compilationUnit, javac, onElement)
}
private fun createAnnotationArguments(annotation: TreeBasedAnnotation,
javac: JavacWrapper,
onElement: JavaElement): Collection<JavaAnnotationArgument> {
val arguments = annotation.annotation.arguments
val javaClass = annotation.resolve() ?: return emptyList()
val methods = javaClass.methods
if (arguments.size != methods.size) return emptyList()
return methods.mapIndexedNotNull { index, it ->
createAnnotationArgument(arguments[index], it.name, annotation.compilationUnit, javac, annotation, onElement)
}
}
onElement: JavaElement): Collection<JavaAnnotationArgument> =
annotation.annotation.arguments.mapNotNull {
val name = if (it is JCTree.JCAssign) Name.identifier(it.lhs.toString()) else Name.identifier("value")
createAnnotationArgument(it, name, annotation.compilationUnit, javac, annotation, onElement)
}
private fun createAnnotationArgument(argument: JCTree.JCExpression,
name: Name,
@@ -118,17 +114,18 @@ private fun createAnnotationArgument(argument: JCTree.JCExpression,
is JCTree.JCFieldAccess -> {
if (argument.name.contentEquals("class")) {
TreeBasedJavaClassObjectAnnotationArgument(argument.selected, name, compilationUnit, javac, onElement)
} else {
}
else {
TreeBasedReferenceAnnotationArgument(name, compilationUnit, argument, javac, onElement)
}
}
is JCTree.JCAssign -> createAnnotationArgument(argument.rhs, name, compilationUnit, javac, annotation, onElement)
is JCTree.JCNewArray -> arrayAnnotationArguments(argument.elems, name, compilationUnit, javac, annotation, onElement)
is JCTree.JCNewArray -> TreeBasedArrayAnnotationArgument(argument.elems.mapNotNull { createAnnotationArgument(it, name, compilationUnit, javac, annotation, onElement) }, name, javac)
is JCTree.JCAnnotation -> TreeBasedAnnotationAsAnnotationArgument(argument, name, compilationUnit, javac, onElement)
is JCTree.JCParens -> createAnnotationArgument(argument.expr, name, compilationUnit, javac, annotation, onElement)
is JCTree.JCBinary -> resolveArgumentValue(argument, annotation, name, compilationUnit, javac)
is JCTree.JCUnary -> resolveArgumentValue(argument, annotation, name, compilationUnit, javac)
else -> null
else -> throw UnsupportedOperationException("Unknown annotation argument $argument")
}
private fun resolveArgumentValue(argument: JCTree.JCExpression,
@@ -140,19 +137,4 @@ private fun resolveArgumentValue(argument: JCTree.JCExpression,
val evaluator = ConstantEvaluator(containingAnnotation, javac, compilationUnit)
return evaluator.getValue(argument)?.let { TreeBasedLiteralAnnotationArgument(name, it, javac) }
}
private fun arrayAnnotationArguments(values: List<JCTree.JCExpression>,
name: Name,
compilationUnit: CompilationUnitTree,
javac: JavacWrapper,
annotation: TreeBasedAnnotation,
onElement: JavaElement): JavaArrayAnnotationArgument =
values.mapNotNull {
if (it is JCTree.JCNewArray) {
arrayAnnotationArguments(it.elems, name, compilationUnit, javac, annotation, onElement)
}
else {
createAnnotationArgument(it, name, compilationUnit, javac, annotation, onElement)
}
}.let { TreeBasedArrayAnnotationArgument(it, name, javac) }
}
@@ -77,7 +77,7 @@ class TreeBasedClass(
by lazy {
arrayListOf<JavaClassifierType>().also { list ->
if (isEnum) {
EnumSupertype(this, javac).let { list.add(it) }
list.add(EnumSupertype(this, javac))
}
else if (isAnnotationType) {
javac.JAVA_LANG_ANNOTATION_ANNOTATION?.let { list.add(it) }
@@ -35,7 +35,7 @@ class TreeBasedMethod(
get() = Name.identifier(tree.name.toString())
override val isAbstract: Boolean
get() = (containingClass.isInterface && !tree.modifiers.hasDefaultModifier) || tree.modifiers.isAbstract
get() = (containingClass.isInterface && !tree.modifiers.hasDefaultModifier && !isStatic) || tree.modifiers.isAbstract
override val isStatic: Boolean
get() = tree.modifiers.isStatic