Support package level annotations in Java
#KT-10942 In Progress
This commit is contained in:
+1
-1
@@ -64,7 +64,7 @@ internal fun typeParameters(typeParameters: Array<PsiTypeParameter>): List<JavaT
|
|||||||
internal fun classifierTypes(classTypes: Array<PsiClassType>): Collection<JavaClassifierType> =
|
internal fun classifierTypes(classTypes: Array<PsiClassType>): Collection<JavaClassifierType> =
|
||||||
classTypes.convert(::JavaClassifierTypeImpl)
|
classTypes.convert(::JavaClassifierTypeImpl)
|
||||||
|
|
||||||
internal fun annotations(annotations: Array<PsiAnnotation>): Collection<JavaAnnotation> =
|
internal fun annotations(annotations: Array<out PsiAnnotation>): Collection<JavaAnnotation> =
|
||||||
annotations.convert(::JavaAnnotationImpl)
|
annotations.convert(::JavaAnnotationImpl)
|
||||||
|
|
||||||
internal fun namedAnnotationArguments(nameValuePairs: Array<PsiNameValuePair>): Collection<JavaAnnotationArgument> =
|
internal fun namedAnnotationArguments(nameValuePairs: Array<PsiNameValuePair>): Collection<JavaAnnotationArgument> =
|
||||||
|
|||||||
+9
-3
@@ -18,12 +18,13 @@ package org.jetbrains.kotlin.load.java.structure.impl
|
|||||||
|
|
||||||
import com.intellij.psi.PsiPackage
|
import com.intellij.psi.PsiPackage
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class JavaPackageImpl(psiPackage: PsiPackage, private val scope: GlobalSearchScope) : JavaElementImpl<PsiPackage>(psiPackage), JavaPackage {
|
class JavaPackageImpl(
|
||||||
|
psiPackage: PsiPackage, private val scope: GlobalSearchScope
|
||||||
|
) : JavaElementImpl<PsiPackage>(psiPackage), JavaPackage, MapBasedJavaAnnotationOwner {
|
||||||
|
|
||||||
override fun getClasses(nameFilter: (Name) -> Boolean): Collection<JavaClass> {
|
override fun getClasses(nameFilter: (Name) -> Boolean): Collection<JavaClass> {
|
||||||
val psiClasses = psi.getClasses(scope).filter {
|
val psiClasses = psi.getClasses(scope).filter {
|
||||||
@@ -38,4 +39,9 @@ class JavaPackageImpl(psiPackage: PsiPackage, private val scope: GlobalSearchSco
|
|||||||
|
|
||||||
override val fqName: FqName
|
override val fqName: FqName
|
||||||
get() = FqName(psi.qualifiedName)
|
get() = FqName(psi.qualifiedName)
|
||||||
|
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = org.jetbrains.kotlin.load.java.structure.impl.annotations(psi.annotationList?.annotations.orEmpty())
|
||||||
|
|
||||||
|
override val annotationsByFqName: Map<FqName?, JavaAnnotation> by buildLazyValueForMap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,8 @@ import com.sun.tools.javac.util.Options
|
|||||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClass
|
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClass
|
||||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClassifierType
|
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedClassifierType
|
||||||
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedPackage
|
import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedPackage
|
||||||
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedClass
|
import org.jetbrains.kotlin.javac.wrappers.trees.*
|
||||||
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||||
import org.jetbrains.kotlin.javac.wrappers.trees.TreePathResolverCache
|
|
||||||
import org.jetbrains.kotlin.javac.wrappers.trees.computeClassId
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||||
@@ -142,6 +140,14 @@ class JavacWrapper(
|
|||||||
}
|
}
|
||||||
.associateBy(TreeBasedPackage::fqName)
|
.associateBy(TreeBasedPackage::fqName)
|
||||||
|
|
||||||
|
private val packageSourceAnnotations = compilationUnits
|
||||||
|
.filter {
|
||||||
|
it.sourceFile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE) &&
|
||||||
|
it.packageName != null
|
||||||
|
}.associateBy({ FqName(it.packageName!!.toString()) }) { compilationUnit ->
|
||||||
|
compilationUnit.packageAnnotations.map { TreeBasedAnnotation(it, compilationUnit, this) }
|
||||||
|
}
|
||||||
|
|
||||||
private val kotlinClassifiersCache = KotlinClassifiersCache(if (javaFiles.isNotEmpty()) kotlinFiles else emptyList(), this)
|
private val kotlinClassifiersCache = KotlinClassifiersCache(if (javaFiles.isNotEmpty()) kotlinFiles else emptyList(), this)
|
||||||
private val treePathResolverCache = TreePathResolverCache(this)
|
private val treePathResolverCache = TreePathResolverCache(this)
|
||||||
private val symbolBasedClassesCache = hashMapOf<String, SymbolBasedClass?>()
|
private val symbolBasedClassesCache = hashMapOf<String, SymbolBasedClass?>()
|
||||||
@@ -212,6 +218,9 @@ class JavacWrapper(
|
|||||||
.filterKeys { it.isSubpackageOf(fqName) && it != fqName }
|
.filterKeys { it.isSubpackageOf(fqName) && it != fqName }
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
|
|
||||||
|
fun getPackageAnnotationsFromSources(fqName: FqName): List<JavaAnnotation> =
|
||||||
|
packageSourceAnnotations[fqName] ?: emptyList()
|
||||||
|
|
||||||
fun findClassesFromPackage(fqName: FqName): List<JavaClass> =
|
fun findClassesFromPackage(fqName: FqName): List<JavaClass> =
|
||||||
javaClasses
|
javaClasses
|
||||||
.filterKeys { it?.parentOrNull() == fqName }
|
.filterKeys { it?.parentOrNull() == fqName }
|
||||||
@@ -329,4 +338,4 @@ class JavacWrapper(
|
|||||||
return symbol.let { SymbolBasedClass(it, this@JavacWrapper, it.classfile) }
|
return symbol.let { SymbolBasedClass(it, this@JavacWrapper, it.classfile) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -17,7 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.javac.wrappers.symbols
|
package org.jetbrains.kotlin.javac.wrappers.symbols
|
||||||
|
|
||||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.MapBasedJavaAnnotationOwner
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.buildLazyValueForMap
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import javax.lang.model.element.PackageElement
|
import javax.lang.model.element.PackageElement
|
||||||
@@ -25,7 +28,7 @@ import javax.lang.model.element.PackageElement
|
|||||||
class SymbolBasedPackage(
|
class SymbolBasedPackage(
|
||||||
element: PackageElement,
|
element: PackageElement,
|
||||||
javac: JavacWrapper
|
javac: JavacWrapper
|
||||||
) : SymbolBasedElement<PackageElement>(element, javac), JavaPackage {
|
) : SymbolBasedElement<PackageElement>(element, javac), JavaPackage, MapBasedJavaAnnotationOwner {
|
||||||
|
|
||||||
override val fqName: FqName
|
override val fqName: FqName
|
||||||
get() = FqName(element.qualifiedName.toString())
|
get() = FqName(element.qualifiedName.toString())
|
||||||
@@ -33,9 +36,15 @@ class SymbolBasedPackage(
|
|||||||
override val subPackages: Collection<JavaPackage>
|
override val subPackages: Collection<JavaPackage>
|
||||||
get() = javac.findSubPackages(FqName(element.qualifiedName.toString()))
|
get() = javac.findSubPackages(FqName(element.qualifiedName.toString()))
|
||||||
|
|
||||||
|
|
||||||
|
override val annotations: Collection<JavaAnnotation>
|
||||||
|
get() = element.annotationMirrors.map { SymbolBasedAnnotation(it, javac) }
|
||||||
|
|
||||||
|
override val annotationsByFqName: Map<FqName?, JavaAnnotation> by buildLazyValueForMap()
|
||||||
|
|
||||||
override fun getClasses(nameFilter: (Name) -> Boolean) =
|
override fun getClasses(nameFilter: (Name) -> Boolean) =
|
||||||
javac.findClassesFromPackage(fqName).filter { nameFilter(it.name) }
|
javac.findClassesFromPackage(fqName).filter { nameFilter(it.name) }
|
||||||
|
|
||||||
override fun toString() = element.qualifiedName.toString()
|
override fun toString() = element.qualifiedName.toString()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.javac.wrappers.trees
|
package org.jetbrains.kotlin.javac.wrappers.trees
|
||||||
|
|
||||||
|
import com.sun.source.tree.CompilationUnitTree
|
||||||
import com.sun.source.util.TreePath
|
import com.sun.source.util.TreePath
|
||||||
import com.sun.tools.javac.tree.JCTree
|
import com.sun.tools.javac.tree.JCTree
|
||||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||||
@@ -27,11 +28,17 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class TreeBasedAnnotation(
|
class TreeBasedAnnotation(
|
||||||
val annotation: JCTree.JCAnnotation,
|
private val annotation: JCTree.JCAnnotation,
|
||||||
val treePath: TreePath,
|
private val compilationUnit: CompilationUnitTree,
|
||||||
val javac: JavacWrapper
|
private val javac: JavacWrapper
|
||||||
) : JavaElement, JavaAnnotation {
|
) : JavaElement, JavaAnnotation {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
annotation: JCTree.JCAnnotation,
|
||||||
|
treePath: TreePath,
|
||||||
|
javac: JavacWrapper
|
||||||
|
) : this(annotation, treePath.compilationUnit, javac)
|
||||||
|
|
||||||
override val arguments: Collection<JavaAnnotationArgument>
|
override val arguments: Collection<JavaAnnotationArgument>
|
||||||
get() = annotation.arguments.map { TreeBasedAnnotationArgument(Name.identifier(it.toString())) }
|
get() = annotation.arguments.map { TreeBasedAnnotationArgument(Name.identifier(it.toString())) }
|
||||||
|
|
||||||
@@ -39,8 +46,8 @@ class TreeBasedAnnotation(
|
|||||||
get() = resolve()?.computeClassId()
|
get() = resolve()?.computeClassId()
|
||||||
|
|
||||||
override fun resolve() =
|
override fun resolve() =
|
||||||
javac.resolve(TreePath.getPath(treePath.compilationUnit, annotation.annotationType)) as? JavaClass
|
javac.resolve(TreePath.getPath(compilationUnit, annotation.annotationType)) as? JavaClass
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeBasedAnnotationArgument(override val name: Name) : JavaAnnotationArgument, JavaElement
|
class TreeBasedAnnotationArgument(override val name: Name) : JavaAnnotationArgument, JavaElement
|
||||||
|
|||||||
+1
-1
@@ -154,4 +154,4 @@ class TreeBasedClass(
|
|||||||
|
|
||||||
override fun findInnerClass(name: Name) = innerClasses[name]
|
override fun findInnerClass(name: Name) = innerClasses[name]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -18,12 +18,15 @@ package org.jetbrains.kotlin.javac.wrappers.trees
|
|||||||
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.MapBasedJavaAnnotationOwner
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.buildLazyValueForMap
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import javax.tools.JavaFileObject
|
import javax.tools.JavaFileObject
|
||||||
|
|
||||||
class TreeBasedPackage(val name: String, val javac: JavacWrapper, val file: JavaFileObject) : JavaPackage {
|
class TreeBasedPackage(val name: String, val javac: JavacWrapper, val file: JavaFileObject) : JavaPackage, MapBasedJavaAnnotationOwner {
|
||||||
|
|
||||||
override val fqName: FqName
|
override val fqName: FqName
|
||||||
get() = FqName(name)
|
get() = FqName(name)
|
||||||
@@ -38,10 +41,15 @@ class TreeBasedPackage(val name: String, val javac: JavacWrapper, val file: Java
|
|||||||
override fun getClasses(nameFilter: (Name) -> Boolean) =
|
override fun getClasses(nameFilter: (Name) -> Boolean) =
|
||||||
javac.findClassesFromPackage(fqName).filter { nameFilter(it.fqName!!.shortName()) }
|
javac.findClassesFromPackage(fqName).filter { nameFilter(it.fqName!!.shortName()) }
|
||||||
|
|
||||||
|
override val annotations
|
||||||
|
get() = javac.getPackageAnnotationsFromSources(fqName)
|
||||||
|
|
||||||
|
override val annotationsByFqName: Map<FqName?, JavaAnnotation> by buildLazyValueForMap()
|
||||||
|
|
||||||
override fun equals(other: Any?) = (other as? TreeBasedPackage)?.name == name
|
override fun equals(other: Any?) = (other as? TreeBasedPackage)?.name == name
|
||||||
|
|
||||||
override fun hashCode() = name.hashCode()
|
override fun hashCode() = name.hashCode()
|
||||||
|
|
||||||
override fun toString() = name
|
override fun toString() = name
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package test;
|
||||||
|
|
||||||
|
public class A {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package test;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target(ElementType.PACKAGE)
|
||||||
|
public @interface Ann {
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@Ann
|
||||||
|
package test;
|
||||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
|||||||
import org.jetbrains.kotlin.preloading.ClassPreloadingUtils
|
import org.jetbrains.kotlin.preloading.ClassPreloadingUtils
|
||||||
import org.jetbrains.kotlin.preloading.Preloader
|
import org.jetbrains.kotlin.preloading.Preloader
|
||||||
import org.jetbrains.kotlin.utils.PathUtil
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
import org.junit.Assert
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -45,12 +46,29 @@ object MockLibraryUtil {
|
|||||||
sourcesPath: String,
|
sourcesPath: String,
|
||||||
jarName: String,
|
jarName: String,
|
||||||
addSources: Boolean = false,
|
addSources: Boolean = false,
|
||||||
|
allowKotlinSources: Boolean = true,
|
||||||
extraOptions: List<String> = emptyList(),
|
extraOptions: List<String> = emptyList(),
|
||||||
extraClasspath: List<String> = emptyList(),
|
extraClasspath: List<String> = emptyList(),
|
||||||
useJava9: Boolean = false
|
useJava9: Boolean = false
|
||||||
): File {
|
): File {
|
||||||
return compileLibraryToJar(sourcesPath, KotlinTestUtils.tmpDir("testLibrary-" + jarName), jarName, addSources,
|
return compileLibraryToJar(
|
||||||
extraOptions, extraClasspath, useJava9)
|
sourcesPath, KotlinTestUtils.tmpDir("testLibrary-" + jarName), jarName, addSources,allowKotlinSources, extraOptions, extraClasspath
|
||||||
|
, useJava9)}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun compileJavaFilesLibraryToJar(
|
||||||
|
sourcesPath: String,
|
||||||
|
jarName: String,
|
||||||
|
addSources: Boolean = false,
|
||||||
|
extraOptions: List<String> = emptyList(),
|
||||||
|
extraClasspath: List<String> = emptyList()
|
||||||
|
): File {
|
||||||
|
return compileJvmLibraryToJar(
|
||||||
|
sourcesPath, jarName, addSources,
|
||||||
|
allowKotlinSources = false,
|
||||||
|
extraClasspath = extraClasspath, extraOptions = extraOptions
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -60,6 +78,7 @@ object MockLibraryUtil {
|
|||||||
contentDir: File,
|
contentDir: File,
|
||||||
jarName: String,
|
jarName: String,
|
||||||
addSources: Boolean = false,
|
addSources: Boolean = false,
|
||||||
|
allowKotlinSources: Boolean = true,
|
||||||
extraOptions: List<String> = emptyList(),
|
extraOptions: List<String> = emptyList(),
|
||||||
extraClasspath: List<String> = emptyList(),
|
extraClasspath: List<String> = emptyList(),
|
||||||
useJava9: Boolean = false
|
useJava9: Boolean = false
|
||||||
@@ -69,6 +88,7 @@ object MockLibraryUtil {
|
|||||||
val srcFile = File(sourcesPath)
|
val srcFile = File(sourcesPath)
|
||||||
val kotlinFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), srcFile)
|
val kotlinFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), srcFile)
|
||||||
if (srcFile.isFile || kotlinFiles.isNotEmpty()) {
|
if (srcFile.isFile || kotlinFiles.isNotEmpty()) {
|
||||||
|
Assert.assertTrue("Only java files are expected", allowKotlinSources)
|
||||||
compileKotlin(sourcesPath, classesDir, extraOptions, *extraClasspath.toTypedArray())
|
compileKotlin(sourcesPath, classesDir, extraOptions, *extraClasspath.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.jvm.compiler
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||||
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||||
|
import org.jetbrains.kotlin.test.TestJdkKind
|
||||||
|
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class LoadJavaPackageAnnotationsTest : KtUsefulTestCase() {
|
||||||
|
companion object {
|
||||||
|
private val TEST_DATA_PATH = "compiler/testData/loadJavaPackageAnnotations/"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doTest(useJavac: Boolean, configurator: (CompilerConfiguration) -> Unit) {
|
||||||
|
val environment =
|
||||||
|
KotlinCoreEnvironment.createForTests(
|
||||||
|
myTestRootDisposable,
|
||||||
|
KotlinTestUtils.newConfiguration(
|
||||||
|
ConfigurationKind.ALL, TestJdkKind.FULL_JDK, KotlinTestUtils.getAnnotationsJar()
|
||||||
|
).also {
|
||||||
|
if (useJavac) {
|
||||||
|
it.put(JVMConfigurationKeys.USE_JAVAC, true)
|
||||||
|
}
|
||||||
|
configurator(it)
|
||||||
|
},
|
||||||
|
EnvironmentConfigFiles.JVM_CONFIG_FILES
|
||||||
|
).apply {
|
||||||
|
if (useJavac) {
|
||||||
|
registerJavac()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val moduleDescriptor = JvmResolveUtil.analyze(
|
||||||
|
environment
|
||||||
|
).moduleDescriptor
|
||||||
|
|
||||||
|
val packageFragmentDescriptor =
|
||||||
|
moduleDescriptor.getPackage(FqName("test")).fragments
|
||||||
|
.singleOrNull {
|
||||||
|
it.getMemberScope().getContributedClassifier(Name.identifier("A"), NoLookupLocation.FROM_TEST) != null
|
||||||
|
}.let { assertInstanceOf(it, LazyJavaPackageFragment::class.java) }
|
||||||
|
|
||||||
|
val annotation = packageFragmentDescriptor.getPackageAnnotations().findAnnotation(FqName("test.Ann"))
|
||||||
|
assertNotNull(annotation)
|
||||||
|
|
||||||
|
val singleAnnotation = packageFragmentDescriptor.getPackageAnnotations().singleOrNull()
|
||||||
|
assertNotNull(singleAnnotation)
|
||||||
|
|
||||||
|
val annotationFqName = singleAnnotation!!.type.constructor.declarationDescriptor?.fqNameSafe
|
||||||
|
|
||||||
|
assertEquals(FqName("test.Ann"), annotationFqName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAnnotationFromSource() {
|
||||||
|
doTest(useJavac = false) {
|
||||||
|
it.addJavaSourceRoots(listOf(File(TEST_DATA_PATH)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAnnotationFromSourceWithJavac() {
|
||||||
|
doTest(useJavac = true) {
|
||||||
|
it.addJavaSourceRoots(listOf(File(TEST_DATA_PATH)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAnnotationFromCompiledCode() {
|
||||||
|
val jar = prepareJar()
|
||||||
|
|
||||||
|
doTest(useJavac = false) {
|
||||||
|
it.addJvmClasspathRoot(jar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAnnotationFromCompiledCodeWithJavac() {
|
||||||
|
val jar = prepareJar()
|
||||||
|
|
||||||
|
doTest(useJavac = true) {
|
||||||
|
it.addJvmClasspathRoot(jar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareJar() =
|
||||||
|
MockLibraryUtil.compileJavaFilesLibraryToJar(TEST_DATA_PATH, "result.jar")
|
||||||
|
}
|
||||||
+6
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||||
|
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||||
@@ -48,6 +49,11 @@ class LazyJavaPackageFragment(
|
|||||||
onRecursiveCall = listOf()
|
onRecursiveCall = listOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val packageAnnotations = c.resolveAnnotations(jPackage)
|
||||||
|
|
||||||
|
// Test only method
|
||||||
|
fun getPackageAnnotations() = packageAnnotations
|
||||||
|
|
||||||
internal fun getSubPackageFqNames(): List<FqName> = subPackages()
|
internal fun getSubPackageFqNames(): List<FqName> = subPackages()
|
||||||
|
|
||||||
internal fun findClassifierByJavaClass(jClass: JavaClass): ClassDescriptor? = scope.javaScope.findClassifierByJavaClass(jClass)
|
internal fun findClassifierByJavaClass(jClass: JavaClass): ClassDescriptor? = scope.javaScope.findClassifierByJavaClass(jClass)
|
||||||
|
|||||||
+1
@@ -63,6 +63,7 @@ fun JavaAnnotationOwner.buildLazyValueForMap() = lazy {
|
|||||||
annotations.associateBy { it.classId?.asSingleFqName() }
|
annotations.associateBy { it.classId?.asSingleFqName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface JavaPackage : JavaElement, JavaAnnotationOwner {
|
||||||
val fqName: FqName
|
val fqName: FqName
|
||||||
val subPackages: Collection<JavaPackage>
|
val subPackages: Collection<JavaPackage>
|
||||||
|
|
||||||
|
|||||||
+9
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.load.java.structure.reflect
|
package org.jetbrains.kotlin.load.java.structure.reflect
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -33,6 +34,14 @@ class ReflectJavaPackage(override val fqName: FqName) : ReflectJavaElement(), Ja
|
|||||||
return listOf()
|
return listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support it if possible
|
||||||
|
override val annotations get() = emptyList<JavaAnnotation>()
|
||||||
|
|
||||||
|
override fun findAnnotation(fqName: FqName) = null
|
||||||
|
|
||||||
|
override val isDeprecatedInJavaDoc: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is ReflectJavaPackage && fqName == other.fqName
|
override fun equals(other: Any?) = other is ReflectJavaPackage && fqName == other.fqName
|
||||||
|
|
||||||
override fun hashCode() = fqName.hashCode()
|
override fun hashCode() = fqName.hashCode()
|
||||||
|
|||||||
Reference in New Issue
Block a user