Support reading annotations on java 9 module on sources and binaries

This commit is contained in:
Victor Petukhov
2021-04-07 17:09:29 +03:00
parent 24685ee9d6
commit bc5e92033b
18 changed files with 140 additions and 43 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isValidJavaFqName import org.jetbrains.kotlin.name.isValidJavaFqName
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
@@ -52,7 +53,8 @@ class ClasspathRootsResolver(
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?, private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
private val javaModuleFinder: CliJavaModuleFinder, private val javaModuleFinder: CliJavaModuleFinder,
private val requireStdlibModule: Boolean, private val requireStdlibModule: Boolean,
private val outputDirectory: VirtualFile? private val outputDirectory: VirtualFile?,
private val javaFileManager: KotlinCliJavaFileManager
) { ) {
val javaModuleGraph = JavaModuleGraph(javaModuleFinder) val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
@@ -160,7 +162,7 @@ class ClasspathRootsResolver(
} }
if (moduleInfoFile != null) { if (moduleInfoFile != null) {
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null val moduleInfo = JavaModuleInfo.read(moduleInfoFile, javaFileManager) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile) return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
} }
@@ -35,6 +35,10 @@ class CliVirtualFileFinder(
override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? = override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class") findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
override fun findSourceOrBinaryVirtualFile(classId: ClassId) =
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
?: findSourceClass(classId, classId.relativeClassName.asString() + ".java")
override fun findMetadata(classId: ClassId): InputStream? { override fun findMetadata(classId: ClassId): InputStream? {
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" } assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" }
@@ -61,8 +65,11 @@ class CliVirtualFileFinder(
return findBinaryClass(classId, BuiltInSerializerProtocol.getBuiltInsFileName(packageFqName))?.inputStream return findBinaryClass(classId, BuiltInSerializerProtocol.getBuiltInsFileName(packageFqName))?.inputStream
} }
private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? = private fun findClass(classId: ClassId, fileName: String, rootType: Set<JavaRoot.RootType>) =
index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ -> index.findClass(classId, acceptedRootTypes = rootType) { dir, _ ->
dir.findChild(fileName)?.takeIf(VirtualFile::isValid) dir.findChild(fileName)?.takeIf(VirtualFile::isValid)
}?.takeIf { it in scope } }?.takeIf { it in scope }
private fun findBinaryClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlyBinary)
private fun findSourceClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlySource)
} }
@@ -82,7 +82,9 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap() private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
private val signatureParsingComponent = BinaryClassSignatureParser() private val signatureParsingComponent = BinaryClassSignatureParser()
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope) fun findClass(classId: ClassId, searchScope: GlobalSearchScope) = findClass(JavaClassFinder.Request(classId), searchScope)
override fun findClass(classId: ClassId): JavaClass? = findClass(JavaClassFinder.Request(classId), allScope)
override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? { override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? {
val (classId, classFileContentFromRequest, outerClassFromRequest) = request val (classId, classFileContentFromRequest, outerClassFromRequest) = request
@@ -110,7 +112,7 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray() val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray()
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
val resolver = ClassifierResolutionContext { findClass(it, allScope) } val resolver = ClassifierResolutionContext { findClass(it) }
BinaryJavaClass( BinaryJavaClass(
virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent, virtualFile, classId.asSingleFqName(), resolver, signatureParsingComponent,
@@ -190,11 +190,16 @@ class KotlinCoreEnvironment private constructor(
sourceFiles.sortBy { it.virtualFile.path } sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME) val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL) val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path -> val javaModuleFinder = CliJavaModuleFinder(
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR) jdkHome?.path?.let { path ->
}) jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager
)
val outputDirectory = val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory() configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
@@ -207,7 +212,8 @@ class KotlinCoreEnvironment private constructor(
this::contentRootToVirtualFile, this::contentRootToVirtualFile,
javaModuleFinder, javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE), !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile) outputDirectory?.let(this::findLocalFile),
javaFileManager
) )
val (initialRoots, javaModules) = val (initialRoots, javaModules) =
@@ -231,7 +237,7 @@ class KotlinCoreEnvironment private constructor(
updateClasspathFromRootsIndex(this) updateClasspathFromRootsIndex(this)
} }
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize( javaFileManager.initialize(
rootsIndex, rootsIndex,
packagePartProviders, packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots), SingleJavaFileRootsIndex(singleJavaFileRoots),
@@ -240,7 +246,7 @@ class KotlinCoreEnvironment private constructor(
project.registerService( project.registerService(
JavaModuleResolver::class.java, JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList()) CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
) )
val finderFactory = CliVirtualFileFinderFactory(rootsIndex) val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
@@ -78,10 +78,7 @@ import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.extensions.* import org.jetbrains.kotlin.extensions.*
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
@@ -193,11 +190,16 @@ class KotlinCoreEnvironment private constructor(
sourceFiles.sortBy { it.virtualFile.path } sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME) val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL) val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path -> val javaModuleFinder = CliJavaModuleFinder(
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR) jdkHome?.path?.let { path ->
}) jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager
)
val outputDirectory = val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory() configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
@@ -210,7 +212,8 @@ class KotlinCoreEnvironment private constructor(
this::contentRootToVirtualFile, this::contentRootToVirtualFile,
javaModuleFinder, javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE), !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile) outputDirectory?.let(this::findLocalFile),
javaFileManager
) )
val (initialRoots, javaModules) = val (initialRoots, javaModules) =
@@ -234,7 +237,7 @@ class KotlinCoreEnvironment private constructor(
updateClasspathFromRootsIndex(this) updateClasspathFromRootsIndex(this)
} }
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize( javaFileManager.initialize(
rootsIndex, rootsIndex,
packagePartProviders, packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots), SingleJavaFileRootsIndex(singleJavaFileRoots),
@@ -243,7 +246,7 @@ class KotlinCoreEnvironment private constructor(
project.registerService( project.registerService(
JavaModuleResolver::class.java, JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList()) CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
) )
val finderFactory = CliVirtualFileFinderFactory(rootsIndex) val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
@@ -45,6 +45,7 @@ data class JavaRoot(val file: VirtualFile, val type: RootType, val prefixFqName:
companion object RootTypes { companion object RootTypes {
val OnlyBinary: Set<RootType> = EnumSet.of(RootType.BINARY) val OnlyBinary: Set<RootType> = EnumSet.of(RootType.BINARY)
val OnlySource: Set<RootType> = EnumSet.of(RootType.SOURCE)
val SourceAndBinary: Set<RootType> = EnumSet.of(RootType.BINARY, RootType.SOURCE) val SourceAndBinary: Set<RootType> = EnumSet.of(RootType.BINARY, RootType.SOURCE)
} }
} }
@@ -18,11 +18,12 @@ package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder { class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?, val javaFileManager: KotlinCliJavaFileManager) : JavaModuleFinder {
private val modulesRoot = jrtFileSystemRoot?.findChild("modules") private val modulesRoot = jrtFileSystemRoot?.findChild("modules")
private val userModules = linkedMapOf<String, JavaModule>() private val userModules = linkedMapOf<String, JavaModule>()
@@ -41,7 +42,7 @@ class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? { private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
val moduleInfo = JavaModuleInfo.read(file) ?: return null val moduleInfo = JavaModuleInfo.read(file, javaFileManager) ?: return null
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file) return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
} }
} }
@@ -18,10 +18,14 @@ package org.jetbrains.kotlin.cli.jvm.modules
import com.intellij.ide.highlighter.JavaClassFileType import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.ide.highlighter.JavaFileType import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
@@ -29,7 +33,8 @@ import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
class CliJavaModuleResolver( class CliJavaModuleResolver(
private val moduleGraph: JavaModuleGraph, private val moduleGraph: JavaModuleGraph,
private val userModules: List<JavaModule>, private val userModules: List<JavaModule>,
private val systemModules: List<JavaModule.Explicit> private val systemModules: List<JavaModule.Explicit>,
private val project: Project
) : JavaModuleResolver { ) : JavaModuleResolver {
init { init {
assert(userModules.count(JavaModule::isSourceModule) <= 1) { assert(userModules.count(JavaModule::isSourceModule) <= 1) {
@@ -37,6 +42,13 @@ class CliJavaModuleResolver(
} }
} }
private val virtualFileFinder by lazy { VirtualFileFinder.getInstance(project) }
override fun getModuleAnnotations(classId: ClassId): List<JavaAnnotation>? {
val virtualFile = virtualFileFinder.findSourceOrBinaryVirtualFile(classId) ?: return null
return (findJavaModule(virtualFile) as? JavaModule.Explicit)?.moduleInfo?.annotations
}
private val sourceModule: JavaModule? = userModules.firstOrNull(JavaModule::isSourceModule) private val sourceModule: JavaModule? = userModules.firstOrNull(JavaModule::isSourceModule)
private fun findJavaModule(file: VirtualFile): JavaModule? { private fun findJavaModule(file: VirtualFile): JavaModule? {
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFil
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
@@ -147,6 +148,7 @@ fun StorageComponentContainer.configureJavaSpecificComponents(
typeEnhancementImprovementsInStrictMode = languageVersionSettings.supportsFeature(LanguageFeature.TypeEnhancementImprovementsInStrictMode) typeEnhancementImprovementsInStrictMode = languageVersionSettings.supportsFeature(LanguageFeature.TypeEnhancementImprovementsInStrictMode)
) )
) )
useInstance(JavaModuleResolver.getInstance(moduleContext.project))
useImpl<FilesByFacadeFqNameIndexer>() useImpl<FilesByFacadeFqNameIndexer>()
useImpl<JvmDiagnosticComponents>() useImpl<JvmDiagnosticComponents>()
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.utils.sure
abstract class VirtualFileFinder : KotlinClassFinder { abstract class VirtualFileFinder : KotlinClassFinder {
abstract fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? abstract fun findVirtualFileWithHeader(classId: ClassId): VirtualFile?
abstract fun findSourceOrBinaryVirtualFile(classId: ClassId): VirtualFile?
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? { override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
val file = findVirtualFileWithHeader(classId) ?: return null val file = findVirtualFileWithHeader(classId) ?: return null
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file) return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
@@ -19,19 +19,24 @@ package org.jetbrains.kotlin.resolve.jvm.modules
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import com.intellij.psi.PsiModifier import com.intellij.psi.PsiModifier
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationImpl
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaAnnotation
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext
import org.jetbrains.kotlin.load.java.structure.impl.convert
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.kotlin.utils.compact import org.jetbrains.kotlin.utils.compact
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
import org.jetbrains.org.objectweb.asm.ModuleVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_TRANSITIVE import org.jetbrains.org.objectweb.asm.Opcodes.ACC_TRANSITIVE
import java.io.IOException import java.io.IOException
class JavaModuleInfo( class JavaModuleInfo(
val moduleName: String, val moduleName: String,
val requires: List<Requires>, val requires: List<Requires>,
val exports: List<Exports> val exports: List<Exports>,
val annotations: List<JavaAnnotation>
) { ) {
data class Requires(val moduleName: String, val isTransitive: Boolean) data class Requires(val moduleName: String, val isTransitive: Boolean)
@@ -51,15 +56,20 @@ class JavaModuleInfo(
statement.packageName?.let { packageName -> statement.packageName?.let { packageName ->
Exports(FqName(packageName), statement.moduleNames) Exports(FqName(packageName), statement.moduleNames)
} }
} },
psiJavaModule.annotations.convert(::JavaAnnotationImpl)
) )
fun read(file: VirtualFile): JavaModuleInfo? { fun read(file: VirtualFile, javaFileManager: KotlinCliJavaFileManager): JavaModuleInfo? {
val contents = try { file.contentsToByteArray() } catch (e: IOException) { return null } val contents = try {
file.contentsToByteArray()
} catch (e: IOException) {
return null
}
var moduleName: String? = null var moduleName: String? = null
val requires = arrayListOf<Requires>() val requires = arrayListOf<Requires>()
val exports = arrayListOf<Exports>() val exports = arrayListOf<Exports>()
val annotations = arrayListOf<JavaAnnotation>()
try { try {
ClassReader(contents).accept(object : ClassVisitor(Opcodes.API_VERSION) { ClassReader(contents).accept(object : ClassVisitor(Opcodes.API_VERSION) {
@@ -77,6 +87,21 @@ class JavaModuleInfo(
} }
} }
} }
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
if (descriptor == null) return null
val (annotation, visitor) = BinaryJavaAnnotation.createAnnotationAndVisitor(
descriptor,
ClassifierResolutionContext(javaFileManager::findClass),
BinaryClassSignatureParser(),
isFreshlySupportedTypeUseAnnotation = true
)
annotations.add(annotation)
return visitor
}
}, ClassReader.SKIP_DEBUG or ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES) }, ClassReader.SKIP_DEBUG or ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES)
} catch (e: Exception) { } catch (e: Exception) {
throw IllegalStateException( throw IllegalStateException(
@@ -86,9 +111,7 @@ class JavaModuleInfo(
) )
} }
return if (moduleName != null) return moduleName?.let { JavaModuleInfo(it, requires.compact(), exports.compact(), annotations) }
JavaModuleInfo(moduleName!!, requires.compact(), exports.compact())
else null
} }
} }
} }
@@ -19,9 +19,10 @@ package org.jetbrains.kotlin.resolve.jvm.modules
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.load.java.lazy.JavaModuleAnnotationsProvider
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
interface JavaModuleResolver { interface JavaModuleResolver : JavaModuleAnnotationsProvider {
fun checkAccessibility(fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?): AccessError? fun checkAccessibility(fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?): AccessError?
sealed class AccessError { sealed class AccessError {
@@ -31,7 +32,6 @@ interface JavaModuleResolver {
} }
companion object SERVICE { companion object SERVICE {
fun getInstance(project: Project): JavaModuleResolver = fun getInstance(project: Project): JavaModuleResolver = ServiceManager.getService(project, JavaModuleResolver::class.java)
ServiceManager.getService(project, JavaModuleResolver::class.java)
} }
} }
@@ -20,9 +20,11 @@ import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass 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.FqName
interface KotlinCliJavaFileManager : JavaFileManager { interface KotlinCliJavaFileManager : JavaFileManager {
fun findClass(classId: ClassId): JavaClass?
fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass?
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
} }
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.load.java.lazy
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.name.ClassId
interface JavaModuleAnnotationsProvider {
fun getModuleAnnotations(classId: ClassId): List<JavaAnnotation>?
}
@@ -65,6 +65,7 @@ class JavaResolverComponents(
val settings: JavaResolverSettings, val settings: JavaResolverSettings,
val kotlinTypeChecker: NewKotlinTypeChecker, val kotlinTypeChecker: NewKotlinTypeChecker,
val javaTypeEnhancementState: JavaTypeEnhancementState, val javaTypeEnhancementState: JavaTypeEnhancementState,
val javaModuleResolver: JavaModuleAnnotationsProvider,
val syntheticPartsProvider: SyntheticJavaPartsProvider = SyntheticJavaPartsProvider.EMPTY val syntheticPartsProvider: SyntheticJavaPartsProvider = SyntheticJavaPartsProvider.EMPTY
) { ) {
fun replace( fun replace(
@@ -75,8 +76,7 @@ class JavaResolverComponents(
javaPropertyInitializerEvaluator, samConversionResolver, sourceElementFactory, javaPropertyInitializerEvaluator, samConversionResolver, sourceElementFactory,
moduleClassResolver, packagePartProvider, supertypeLoopChecker, lookupTracker, module, reflectionTypes, moduleClassResolver, packagePartProvider, supertypeLoopChecker, lookupTracker, module, reflectionTypes,
annotationTypeQualifierResolver, signatureEnhancement, javaClassesTracker, settings, annotationTypeQualifierResolver, signatureEnhancement, javaClassesTracker, settings,
kotlinTypeChecker, kotlinTypeChecker, javaTypeEnhancementState, javaModuleResolver
javaTypeEnhancementState
) )
} }
@@ -31,9 +31,11 @@ import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluato
import org.jetbrains.kotlin.load.java.components.JavaResolverCache import org.jetbrains.kotlin.load.java.components.JavaResolverCache
import org.jetbrains.kotlin.load.java.components.SignaturePropagator import org.jetbrains.kotlin.load.java.components.SignaturePropagator
import org.jetbrains.kotlin.load.java.lazy.* import org.jetbrains.kotlin.load.java.lazy.*
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImpl import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImpl
@@ -119,7 +121,10 @@ fun makeLazyJavaPackageFragmentFromClassLoaderProvider(
singleModuleClassResolver, packagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module, singleModuleClassResolver, packagePartProvider, SupertypeLoopChecker.EMPTY, LookupTracker.DO_NOTHING, module,
ReflectionTypes(module, notFoundClasses), annotationTypeQualifierResolver, ReflectionTypes(module, notFoundClasses), annotationTypeQualifierResolver,
SignatureEnhancement(annotationTypeQualifierResolver, JavaTypeEnhancementState.DISABLED_JSR_305, JavaTypeEnhancement(JavaResolverSettings.Default)), SignatureEnhancement(annotationTypeQualifierResolver, JavaTypeEnhancementState.DISABLED_JSR_305, JavaTypeEnhancement(JavaResolverSettings.Default)),
JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default, javaTypeEnhancementState JavaClassesTracker.Default, JavaResolverSettings.Default, NewKotlinTypeChecker.Default, javaTypeEnhancementState,
object : JavaModuleAnnotationsProvider {
override fun getModuleAnnotations(classId: ClassId): List<JavaAnnotation>? = null
}
) )
return LazyJavaPackageFragmentProvider(javaResolverComponents) return LazyJavaPackageFragmentProvider(javaResolverComponents)
@@ -10,10 +10,24 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaModule import com.intellij.psi.PsiJavaModule
import com.intellij.psi.impl.light.LightJavaModule import com.intellij.psi.impl.light.LightJavaModule
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationImpl
import org.jetbrains.kotlin.load.java.structure.impl.convert
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
class IdeJavaModuleResolver(private val project: Project) : JavaModuleResolver { class IdeJavaModuleResolver(private val project: Project) : JavaModuleResolver {
private val virtualFileFinder by lazy { VirtualFileFinder.getInstance(project) }
override fun getModuleAnnotations(classId: ClassId): List<JavaAnnotation>? {
val virtualFile = virtualFileFinder.findVirtualFileWithHeader(classId) ?: return null
return findJavaModule(virtualFile)?.annotations?.convert(::JavaAnnotationImpl)
}
private fun findJavaModule(file: VirtualFile): PsiJavaModule? = ModuleHighlightUtil2.getModuleDescriptor(file, project) private fun findJavaModule(file: VirtualFile): PsiJavaModule? = ModuleHighlightUtil2.getModuleDescriptor(file, project)
override fun checkAccessibility( override fun checkAccessibility(
@@ -32,6 +32,8 @@ class IDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileFi
override fun findBuiltInsData(packageFqName: FqName): InputStream? = override fun findBuiltInsData(packageFqName: FqName): InputStream? =
findVirtualFileWithHeader(packageFqName, KotlinBuiltInsMetadataIndex.KEY)?.inputStream findVirtualFileWithHeader(packageFqName, KotlinBuiltInsMetadataIndex.KEY)?.inputStream
override fun findSourceOrBinaryVirtualFile(classId: ClassId) = findVirtualFileWithHeader(classId)
init { init {
if (scope != GlobalSearchScope.EMPTY_SCOPE && scope.project == null) { if (scope != GlobalSearchScope.EMPTY_SCOPE && scope.project == null) {
LOG.warn("Scope with null project $scope") LOG.warn("Scope with null project $scope")