Introduce experimental -Xuse-javac compilation mode

In this mode, javac AST and Symbol files are used during
Kotlin compilation instead of PSI / binary stuff.
Later, they are reused for Java file compilation.
javac in this mode is integrated into kotlinc.
This commit is contained in:
baratynskiy
2017-04-05 13:11:26 +03:00
committed by Mikhail Glukhikh
parent c9a04fe1e2
commit 5eea3b6569
217 changed files with 6537 additions and 565 deletions
+1
View File
@@ -64,6 +64,7 @@
<module fileurl="file://$PROJECT_DIR$/compiler/ir/ir.tree/ir.tree.iml" filepath="$PROJECT_DIR$/compiler/ir/ir.tree/ir.tree.iml" group="compiler/ir" />
<module fileurl="file://$PROJECT_DIR$/j2k/j2k.iml" filepath="$PROJECT_DIR$/j2k/j2k.iml" group="j2k" />
<module fileurl="file://$PROJECT_DIR$/plugins/java-model-wrappers/java-model-wrappers.iml" filepath="$PROJECT_DIR$/plugins/java-model-wrappers/java-model-wrappers.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/compiler/javac-wrapper/javac-wrapper.iml" filepath="$PROJECT_DIR$/compiler/javac-wrapper/javac-wrapper.iml" group="compiler" />
<module fileurl="file://$PROJECT_DIR$/jps-plugin/jps-plugin.iml" filepath="$PROJECT_DIR$/jps-plugin/jps-plugin.iml" group="ide/jps" />
<module fileurl="file://$PROJECT_DIR$/jps-plugin/jps-tests/jps-tests.iml" filepath="$PROJECT_DIR$/jps-plugin/jps-tests/jps-tests.iml" group="ide/jps" />
<module fileurl="file://$PROJECT_DIR$/js/js.ast/js.ast.iml" filepath="$PROJECT_DIR$/js/js.ast/js.ast.iml" group="compiler/js" />
+7
View File
@@ -22,6 +22,9 @@
<property name="javax.inject.jar" value="${basedir}/lib/javax.inject.jar"/>
<property name="gradle.logging.level" value=""/>
<property environment="env"/>
<property name="tools.jar" value="${env.JDK_18}/lib/tools.jar"/>
<property name="java.target" value="1.8"/>
<property name="java.target.1.6" value="1.6"/>
@@ -56,6 +59,7 @@
<file file="${bootstrap.script.runtime}"/>
<fileset dir="${idea.sdk}" includes="core/*.jar"/>
<pathelement location="${protobuf.jar}"/>
<pathelement location="${tools.jar}"/>
<fileset dir="${basedir}/lib" includes="**/*.jar"/>
<fileset dir="${dependencies}" includes="jansi.jar"/>
@@ -85,6 +89,7 @@
<include name="compiler/ir/ir.psi2ir/src"/>
<include name="compiler/ir/ir.tree/src"/>
<include name="compiler/builtins-serializer/src"/>
<include name="compiler/javac-wrapper/src"/>
<include name="compiler/cli/src"/>
<include name="compiler/cli/cli-common/src"/>
<include name="compiler/conditional-preprocessor/src/"/>
@@ -140,6 +145,7 @@
<include name="plugin-api/**"/>
<include name="annotation-collector/**"/>
<include name="builtins-serializer/**"/>
<include name="javac-wrapper/**"/>
<include name="js.ast/**"/>
<include name="js.translator/**"/>
<include name="js.frontend/**"/>
@@ -235,6 +241,7 @@
<fileset dir="compiler/ir/ir.psi2ir/src"/>
<fileset dir="compiler/ir/ir.tree/src"/>
<fileset dir="compiler/builtins-serializer/src"/>
<fileset dir="compiler/javac-wrapper/src"/>
<fileset dir="compiler/cli/src"/>
<fileset dir="compiler/cli/cli-common/src"/>
<fileset dir="compiler/conditional-preprocessor/src"/>
@@ -137,6 +137,16 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
)
public String[] scriptResolverEnvironment;
// Javac options
@Argument(value = "-Xuse-javac", description = "Use javac for Java source and class files analysis")
public boolean useJavac;
@Argument(
value = "-Xjavac-arguments",
valueDescription = "<option[,]>",
description = "Java compiler arguments")
public String[] javacArguments;
// Paths to output directories for friend modules.
public String[] friendPaths;
+1
View File
@@ -23,5 +23,6 @@
<orderEntry type="module" module-name="annotation-collector" />
<orderEntry type="module" module-name="builtins-serializer" />
<orderEntry type="module" module-name="frontend.script" />
<orderEntry type="module" module-name="javac-wrapper" />
</component>
</module>
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.PluginCliOptionProcessingException
import org.jetbrains.kotlin.compiler.plugin.cliPluginUsageString
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
@@ -158,6 +159,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val environment = createEnvironmentWithScriptingSupport(rootDisposable, configuration, arguments, messageCollector)
?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
KotlinToJVMBytecodeCompiler.compileModules(environment, directory)
}
else if (arguments.script) {
@@ -183,6 +188,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val environment = createEnvironmentWithScriptingSupport(rootDisposable, configuration, arguments, messageCollector)
?: return COMPILATION_ERROR
registerJavacIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
if (environment.getSourceFiles().isEmpty()) {
if (arguments.version) {
return OK
@@ -192,6 +201,10 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment)
compileJavaFilesIfNeeded(environment, arguments).let {
if (!it) return COMPILATION_ERROR
}
}
if (arguments.reportPerf) {
@@ -211,6 +224,23 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
}
}
private fun registerJavacIfNeeded(environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments): Boolean {
if (arguments.useJavac) {
environment.configuration.put(JVMConfigurationKeys.USE_JAVAC, true)
return environment.registerJavac(arguments = arguments.javacArguments)
}
return true
}
private fun compileJavaFilesIfNeeded(environment: KotlinCoreEnvironment,
arguments: K2JVMCompilerArguments): Boolean {
if (arguments.useJavac) {
return JavacWrapper.getInstance(environment.project).use { it.compile() }
}
return true
}
private fun createEnvironmentWithScriptingSupport(rootDisposable: Disposable,
configuration: CompilerConfiguration,
@@ -25,6 +25,7 @@ import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreJavaFileManager
import com.intellij.core.JavaCoreApplicationEnvironment
import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.lang.MetaLanguage
import com.intellij.lang.java.JavaParserDefinition
@@ -70,10 +71,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesDynamicCompoundIndex
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
@@ -89,6 +87,7 @@ import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.extensions.PreprocessedVirtualFileFactoryExtension
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.javac.JavacWrapperRegistrar
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
@@ -219,6 +218,28 @@ class KotlinCoreEnvironment private constructor(
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
}
private val VirtualFile.javaFiles: List<VirtualFile>
get() = mutableListOf<VirtualFile>().apply {
VfsUtilCore.processFilesRecursively(this@javaFiles) { file ->
if (file.fileType == JavaFileType.INSTANCE) {
add(file)
}
true
}
}
private val allJavaFiles: List<File>
get() = configuration.javaSourceRoots
.mapNotNull(this::findLocalDirectory)
.flatMap { it.javaFiles }
.map { File(it.canonicalPath) }
fun registerJavac(javaFiles: List<File> = allJavaFiles,
kotlinFiles: List<KtFile> = sourceFiles,
arguments: Array<String>? = null): Boolean {
return JavacWrapperRegistrar.registerJavac(this, javaFiles, kotlinFiles, arguments)
}
private val applicationEnvironment: CoreApplicationEnvironment
get() = projectEnvironment.environment
@@ -327,6 +348,10 @@ class KotlinCoreEnvironment private constructor(
}
}
fun findLocalFile(path: String) = applicationEnvironment.localFileSystem.findFileByPath(path)
fun findJarFile(path: String) = applicationEnvironment.jarFileSystem.findFileByPath(path)
private fun findLocalDirectory(root: JvmContentRoot): VirtualFile? {
val path = root.file
val localFile = findLocalDirectory(path.absolutePath)
@@ -33,8 +33,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
@@ -52,6 +51,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.addKotlinSourceRoots
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.modules.TargetId
@@ -164,6 +164,22 @@ object KotlinToJVMBytecodeCompiler {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
writeOutput(state.configuration, state.factory, null)
}
if (projectConfiguration.getBoolean(JVMConfigurationKeys.USE_JAVAC)) {
val singleModule = chunk.singleOrNull()
if (singleModule != null) {
return JavacWrapper.getInstance(environment.project).use {
it.compile(File(singleModule.getOutputDirectory()))
}
}
else {
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let {
it.report(WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files")
}
JavacWrapper.getInstance(environment.project).close()
}
}
return true
}
finally {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.cli.jvm.config
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.ContentRoot
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.KotlinSourceRoot
import java.io.File
data class JvmClasspathRoot(override val file: File): JvmContentRoot
@@ -46,3 +47,10 @@ val CompilerConfiguration.jvmClasspathRoots: List<File>
@JvmOverloads fun CompilerConfiguration.addJavaSourceRoots(files: List<File>, packagePrefix: String? = null): Unit =
files.forEach { addJavaSourceRoot(it, packagePrefix) }
val CompilerConfiguration.javaSourceRoots: Set<String>
get() = get(JVMConfigurationKeys.CONTENT_ROOTS)
?.mapNotNullTo(hashSetOf<String>()) {
(it as? KotlinSourceRoot)?.path ?: (it as? JavaSourceRoot)?.file?.path
}
.orEmpty()
+5
View File
@@ -57,6 +57,7 @@ messages/**)
-libraryjars '<bootstrap.runtime>'
-libraryjars '<bootstrap.reflect>'
-libraryjars '<bootstrap.script.runtime>'
-libraryjars '<tools.jar>'
-dontoptimize
-dontobfuscate
@@ -199,3 +200,7 @@ messages/**)
# for building kotlin-build-common-test
-keep class org.jetbrains.kotlin.build.SerializationUtilsKt { *; }
# for tools.jar
-keep class com.sun.tools.javac.** { *; }
-keep class com.sun.source.** { *; }
+1
View File
@@ -11,5 +11,6 @@
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
<orderEntry type="module" module-name="descriptor.loader.java" exported="" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="javac-wrapper" />
</component>
</module>
@@ -113,4 +113,8 @@ public class JVMConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> USE_FAST_CLASS_FILES_READING =
CompilerConfigurationKey.create("use fast class files reading implementation [experimental]");
public static final CompilerConfigurationKey<Boolean> USE_JAVAC =
CompilerConfigurationKey.create("use javac");
}
@@ -19,6 +19,9 @@ package org.jetbrains.kotlin.frontend.java.di
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.JvmBuiltInsPackageFragmentProvider
import org.jetbrains.kotlin.javac.components.JavacBasedClassFinder
import org.jetbrains.kotlin.javac.components.StubJavaResolverCache
import org.jetbrains.kotlin.javac.components.JavacBasedSourceElementFactory
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -48,7 +51,8 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
private fun StorageComponentContainer.configureJavaTopDownAnalysis(
moduleContentScope: GlobalSearchScope,
project: Project,
lookupTracker: LookupTracker
lookupTracker: LookupTracker,
useJavac: Boolean
) {
useInstance(moduleContentScope)
useInstance(lookupTracker)
@@ -60,17 +64,23 @@ private fun StorageComponentContainer.configureJavaTopDownAnalysis(
useInstance(VirtualFileFinderFactory.getInstance(project).create(moduleContentScope))
useImpl<AnnotationResolverImpl>()
if (useJavac) {
useImpl<JavacBasedClassFinder>()
useImpl<StubJavaResolverCache>()
useImpl<JavacBasedSourceElementFactory>()
} else {
useImpl<JavaClassFinderImpl>()
useImpl<LazyResolveBasedCache>()
useImpl<JavaSourceElementFactoryImpl>()
}
useImpl<JavaClassFinderImpl>()
useImpl<JavaPropertyInitializerEvaluatorImpl>()
useImpl<AnnotationResolverImpl>()
useImpl<SignaturePropagatorImpl>()
useImpl<LazyResolveBasedCache>()
useImpl<TraceBasedErrorReporter>()
useImpl<PsiBasedExternalAnnotationResolver>()
useImpl<JavaPropertyInitializerEvaluatorImpl>()
useInstance(SamWithReceiverResolver())
useImpl<SamConversionResolverImpl>()
useImpl<JavaSourceElementFactoryImpl>()
useInstance(InternalFlexibleTypeTransformer)
useImpl<CompilerDeserializationConfiguration>()
@@ -88,10 +98,11 @@ fun createContainerForLazyResolveWithJava(
jvmTarget: JvmTarget,
languageVersionSettings: LanguageVersionSettings,
useBuiltInsProvider: Boolean,
useLazyResolve: Boolean
useLazyResolve: Boolean,
useJavac: Boolean = false
): StorageComponentContainer = createContainer("LazyResolveWithJava", JvmPlatform) {
configureModule(moduleContext, JvmPlatform, jvmTarget, bindingTrace)
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, lookupTracker)
configureJavaTopDownAnalysis(moduleContentScope, moduleContext.project, lookupTracker, useJavac)
useInstance(packagePartProvider)
useInstance(moduleClassResolver)
@@ -110,7 +121,10 @@ fun createContainerForLazyResolveWithJava(
useImpl<LazyResolveToken>()
}
}.apply {
get<JavaClassFinderImpl>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
if (useJavac)
get<JavacBasedClassFinder>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
else
get<JavaClassFinderImpl>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
}
@@ -123,11 +137,12 @@ fun createContainerForTopDownAnalyzerForJvm(
packagePartProvider: PackagePartProvider,
moduleClassResolver: ModuleClassResolver,
jvmTarget: JvmTarget,
languageVersionSettings: LanguageVersionSettings
languageVersionSettings: LanguageVersionSettings,
useJavac: Boolean = false
): ComponentProvider = createContainerForLazyResolveWithJava(
moduleContext, bindingTrace, declarationProviderFactory, moduleContentScope, moduleClassResolver,
CompilerEnvironment, lookupTracker, packagePartProvider, jvmTarget, languageVersionSettings,
useBuiltInsProvider = true, useLazyResolve = false
useBuiltInsProvider = true, useLazyResolve = false, useJavac = useJavac
)
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.frontend.java.di.createContainerForTopDownAnalyzerFo
import org.jetbrains.kotlin.frontend.java.di.initJvmBuiltInsForTopDownAnalysis
import org.jetbrains.kotlin.frontend.java.di.initialize
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.javac.MockKotlinClassifier
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
@@ -61,6 +62,7 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedClass
import java.util.*
object TopDownAnalyzerFacadeForJVM {
@@ -143,6 +145,8 @@ object TopDownAnalyzerFacadeForJVM {
}
else null
val useJavac = configuration.getBoolean(JVMConfigurationKeys.USE_JAVAC)
val dependencyModule = if (separateModules) {
val dependenciesContext = ContextForNewModule(
moduleContext, Name.special("<dependencies of ${configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)}>"),
@@ -154,7 +158,7 @@ object TopDownAnalyzerFacadeForJVM {
val dependenciesContainer = createContainerForTopDownAnalyzerForJvm(
dependenciesContext, trace, DeclarationProviderFactory.EMPTY, dependencyScope, lookupTracker,
packagePartProvider(dependencyScope), moduleClassResolver, jvmTarget, languageVersionSettings
packagePartProvider(dependencyScope), moduleClassResolver, jvmTarget, languageVersionSettings, useJavac
)
StorageComponentContainerContributor.getInstances(project).forEach { it.onContainerComposed(dependenciesContainer, null) }
@@ -181,7 +185,7 @@ object TopDownAnalyzerFacadeForJVM {
// TODO: get rid of duplicate invocation of CodeAnalyzerInitializer#initialize, or refactor CliLightClassGenerationSupport
val container = createContainerForTopDownAnalyzerForJvm(
moduleContext, trace, declarationProviderFactory(storageManager, files), sourceScope, lookupTracker,
partProvider, moduleClassResolver, jvmTarget, languageVersionSettings
partProvider, moduleClassResolver, jvmTarget, languageVersionSettings, useJavac
).apply {
initJvmBuiltInsForTopDownAnalysis()
(partProvider as? IncrementalPackagePartProvider)?.deserializationConfiguration = get<DeserializationConfiguration>()
@@ -243,7 +247,8 @@ object TopDownAnalyzerFacadeForJVM {
lateinit var sourceCodeResolver: JavaDescriptorResolver
override fun resolveClass(javaClass: JavaClass): ClassDescriptor? {
val resolver = if (javaClass is JavaClassImpl && javaClass.psi.containingFile.virtualFile in sourceScope)
val resolver = if (javaClass is JavaClassImpl && javaClass.psi.containingFile.virtualFile in sourceScope
|| javaClass is TreeBasedClass || javaClass is MockKotlinClassifier)
sourceCodeResolver
else
compiledCodeResolver
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="module" module-name="descriptor.loader.java" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../ideaSDK/lib/openapi.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="intellij-core" level="project" />
<orderEntry type="library" name="javax.inject" level="project" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="cli" />
</component>
</module>
@@ -0,0 +1,65 @@
/*
* 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
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Log
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import java.io.PrintWriter
import java.io.Writer
class JavacLogger(context: Context,
errorWriter: PrintWriter,
warningWriter: PrintWriter,
infoWriter: PrintWriter) : Log(context, errorWriter, warningWriter, infoWriter) {
init {
context.put(Log.outKey, infoWriter)
}
override fun printLines(kind: WriterKind, message: String, vararg args: Any?) {}
companion object {
fun preRegister(context: Context, messageCollector: MessageCollector) {
context.put(Log.logKey, Context.Factory<Log> {
JavacLogger(it,
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.ERROR)),
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.WARNING)),
PrintWriter(MessageCollectorAdapter(messageCollector, CompilerMessageSeverity.INFO)))
})
}
}
}
private class MessageCollectorAdapter(private val messageCollector: MessageCollector,
private val severity: CompilerMessageSeverity) : Writer() {
override fun write(buffer: CharArray, offset: Int, length: Int) {
if (length == 1 && buffer[0] == '\n') return
messageCollector.report(severity, String(buffer, offset, length))
}
override fun flush() {
(messageCollector as? GroupingMessageCollector)?.flush()
}
override fun close() = flush()
}
@@ -0,0 +1,40 @@
/*
* 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
import com.sun.tools.javac.util.Options
import java.util.regex.Pattern
object JavacOptionsMapper {
fun map(options: Options, arguments: List<String>) {
arguments.forEach { options.putOption(it) }
}
private val optionPattern = Pattern.compile("\\s+")
private fun Options.putOption(option: String) =
option.split(optionPattern)
.filter { it.isNotEmpty() }
.let { arg ->
when(arg.size) {
1 -> put(arg[0], arg[0])
2 -> put(arg[0], arg[1])
}
}
}
@@ -0,0 +1,330 @@
/*
* 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
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.CommonClassNames
import com.intellij.psi.search.EverythingGlobalScope
import com.intellij.psi.search.GlobalSearchScope
import com.sun.source.tree.CompilationUnitTree
import com.sun.source.util.TreePath
import com.sun.tools.javac.api.JavacTrees
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.code.Symbol
import com.sun.tools.javac.code.Symtab
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.jvm.ClassReader
import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.model.JavacElements
import com.sun.tools.javac.model.JavacTypes
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.List as JavacList
import com.sun.tools.javac.util.Names
import com.sun.tools.javac.util.Options
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.config.JVMConfigurationKeys
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.load.java.structure.JavaClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isSubpackageOf
import org.jetbrains.kotlin.name.parentOrNull
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedClass
import org.jetbrains.kotlin.javac.wrappers.trees.TreeBasedPackage
import org.jetbrains.kotlin.javac.wrappers.trees.TreePathResolverCache
import org.jetbrains.kotlin.javac.wrappers.trees.computeClassId
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
import org.jetbrains.kotlin.load.java.structure.JavaPackage
import org.jetbrains.kotlin.name.ClassId
import java.io.Closeable
import java.io.File
import javax.lang.model.element.Element
import javax.lang.model.type.TypeMirror
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
import javax.tools.StandardLocation
class JavacWrapper(javaFiles: Collection<File>,
kotlinFiles: Collection<KtFile>,
arguments: Array<String>?,
private val environment: KotlinCoreEnvironment) : Closeable {
companion object {
fun getInstance(project: Project): JavacWrapper = ServiceManager.getService(project, JavacWrapper::class.java)
}
private fun createCommonClassifierType(fqName: String) =
findClassInSymbols(fqName)?.let {
SymbolBasedClassifierType(it.element.asType(), this)
}
val JAVA_LANG_OBJECT by lazy {
createCommonClassifierType(CommonClassNames.JAVA_LANG_OBJECT)
}
val JAVA_LANG_ENUM by lazy {
createCommonClassifierType(CommonClassNames.JAVA_LANG_ENUM)
}
val JAVA_LANG_ANNOTATION_ANNOTATION by lazy {
createCommonClassifierType(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION)
}
private val messageCollector = environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]
private val context = Context()
init {
messageCollector?.let { JavacLogger.preRegister(context, it) }
arguments?.toList()?.let { JavacOptionsMapper.map(Options.instance(context), it) }
}
private val javac = object : JavaCompiler(context) {
override fun parseFiles(files: Iterable<JavaFileObject>?) = compilationUnits
}
private val fileManager = context[JavaFileManager::class.java] as JavacFileManager
init {
// use rt.jar instead of lib/ct.sym
fileManager.setSymbolFileEnabled(false)
fileManager.setLocation(StandardLocation.CLASS_PATH, environment.configuration.jvmClasspathRoots)
}
private val names = Names.instance(context)
private val symbols = Symtab.instance(context)
private val trees = JavacTrees.instance(context)
private val elements = JavacElements.instance(context)
private val types = JavacTypes.instance(context)
private val fileObjects = fileManager.getJavaFileObjectsFromFiles(javaFiles).toJavacList()
private val compilationUnits: JavacList<JCTree.JCCompilationUnit> = fileObjects.map(javac::parse).toJavacList()
private val javaClasses = compilationUnits
.flatMap { unit ->
unit.typeDecls.flatMap { classDecl ->
TreeBasedClass(classDecl as JCTree.JCClassDecl,
trees.getPath(unit, classDecl),
this,
unit.sourceFile).withInnerClasses()
}
}
.associateBy(JavaClass::fqName)
private val javaClassesAssociatedByClassId =
javaClasses.values.associateBy { it.computeClassId() }
private val javaPackages = compilationUnits
.mapNotNullTo(hashSetOf()) { unit ->
unit.packageName?.toString()?.let { packageName ->
TreeBasedPackage(packageName, this, unit.sourcefile)
}
}
.associateBy(TreeBasedPackage::fqName)
private val kotlinClassifiersCache = KotlinClassifiersCache(kotlinFiles, this)
private val treePathResolverCache = TreePathResolverCache(this)
private val symbolBasedClassesCache = hashMapOf<String, SymbolBasedClass?>()
private val symbolBasedPackagesCache = hashMapOf<String, SymbolBasedPackage?>()
fun compile(outDir: File? = null): Boolean = with(javac) {
if (errorCount() > 0) return false
fileManager.setClassPathForCompilation(outDir)
messageCollector?.report(CompilerMessageSeverity.INFO,
"Compiling Java sources")
compile(fileObjects)
errorCount() == 0
}
override fun close() {
fileManager.close()
javac.close()
}
fun findClass(fqName: FqName, scope: GlobalSearchScope = EverythingGlobalScope()): JavaClass? {
javaClasses[fqName]?.let { javaClass ->
javaClass.virtualFile?.let { if (it in scope) return javaClass }
}
findClassInSymbols(fqName.asString())?.let { javaClass ->
javaClass.virtualFile?.let { if (it in scope) return javaClass }
}
return null
}
fun findClass(classId: ClassId, scope: GlobalSearchScope = EverythingGlobalScope()): JavaClass? {
javaClassesAssociatedByClassId[classId]?.let { javaClass ->
javaClass.virtualFile?.let { if (it in scope) return javaClass }
}
findPackageInSymbols(classId.packageFqName.asString())?.let {
(it.element as Symbol.PackageSymbol).findClass(classId.relativeClassName.asString())?.let { javaClass ->
javaClass.virtualFile?.let { file ->
if (file in scope) return javaClass
}
}
}
return null
}
fun findPackage(fqName: FqName, scope: GlobalSearchScope): JavaPackage? {
javaPackages[fqName]?.let { javaPackage ->
javaPackage.virtualFile?.let { file ->
if (file in scope) return javaPackage
}
}
return findPackageInSymbols(fqName.asString())
}
fun findSubPackages(fqName: FqName): List<JavaPackage> =
symbols.packages
.filterKeys { it.toString().startsWith("$fqName.") }
.map { SymbolBasedPackage(it.value, this) } +
javaPackages
.filterKeys { it.isSubpackageOf(fqName) && it != fqName }
.map { it.value }
fun findClassesFromPackage(fqName: FqName): List<JavaClass> =
javaClasses
.filterKeys { it?.parentOrNull() == fqName }
.flatMap { it.value.withInnerClasses() } +
elements.getPackageElement(fqName.asString())
?.members()
?.elements
?.filterIsInstance(Symbol.ClassSymbol::class.java)
?.map { SymbolBasedClass(it, this, it.classfile) }
.orEmpty()
fun knownClassNamesInPackage(fqName: FqName): Set<String> =
javaClasses.filterKeys { it?.parentOrNull() == fqName }
.mapTo(hashSetOf()) { it.value.name.asString() } +
elements.getPackageElement(fqName.asString())
?.members_field
?.elements
?.filterIsInstance<Symbol.ClassSymbol>()
?.map { it.name.toString() }
.orEmpty()
fun getTreePath(tree: JCTree, compilationUnit: CompilationUnitTree): TreePath =
trees.getPath(compilationUnit, tree)
fun getKotlinClassifier(fqName: FqName): JavaClass? =
kotlinClassifiersCache.getKotlinClassifier(fqName)
fun isDeprecated(element: Element) = elements.isDeprecated(element)
fun isDeprecated(typeMirror: TypeMirror) = isDeprecated(types.asElement(typeMirror))
fun resolve(treePath: TreePath): JavaClassifier? =
treePathResolverCache.resolve(treePath)
fun toVirtualFile(javaFileObject: JavaFileObject): VirtualFile? =
javaFileObject.toUri().let { uri ->
if (uri.scheme == "jar") {
environment.findJarFile(uri.schemeSpecificPart.substring("file:".length))
}
else {
environment.findLocalFile(uri.schemeSpecificPart)
}
}
private inline fun <reified T> Iterable<T>.toJavacList() = JavacList.from(this)
private fun findClassInSymbols(fqName: String): SymbolBasedClass? {
if (symbolBasedClassesCache.containsKey(fqName)) return symbolBasedClassesCache[fqName]
elements.getTypeElement(fqName)?.let { symbol ->
SymbolBasedClass(symbol, this, symbol.classfile)
}.let { symbolBasedClass ->
symbolBasedClassesCache[fqName] = symbolBasedClass
return symbolBasedClass
}
}
private fun findPackageInSymbols(fqName: String): SymbolBasedPackage? {
if (symbolBasedPackagesCache.containsKey(fqName)) return symbolBasedPackagesCache[fqName]
elements.getPackageElement(fqName)?.let { symbol ->
SymbolBasedPackage(symbol, this)
}.let { symbolBasedPackage ->
symbolBasedPackagesCache[fqName] = symbolBasedPackage
return symbolBasedPackage
}
}
private fun JavacFileManager.setClassPathForCompilation(outDir: File?) = apply {
(outDir ?: environment.configuration[JVMConfigurationKeys.OUTPUT_DIRECTORY])?.let { outputDir ->
outputDir.mkdirs()
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, listOf(outputDir))
}
val reader = ClassReader.instance(context)
val names = Names.instance(context)
val outDirName = getLocation(StandardLocation.CLASS_OUTPUT)?.firstOrNull()?.path ?: ""
list(StandardLocation.CLASS_OUTPUT, "", setOf(JavaFileObject.Kind.CLASS), true)
.forEach { fileObject ->
val fqName = fileObject.name
.substringAfter(outDirName)
.substringBefore(".class")
.replace(File.separator, ".")
.let { className ->
if (className.startsWith(".")) className.substring(1) else className
}.let(names::fromString)
symbols.classes[fqName]?.let { symbols.classes[fqName] = null }
val symbol = reader.enterClass(fqName, fileObject)
(elements.getPackageOf(symbol) as? Symbol.PackageSymbol)?.let { packageSymbol ->
packageSymbol.members_field.enter(symbol)
packageSymbol.flags_field = packageSymbol.flags_field or Flags.EXISTS.toLong()
}
}
}
private fun TreeBasedClass.withInnerClasses(): List<TreeBasedClass> =
listOf(this) + innerClasses.values.flatMap { it.withInnerClasses() }
private fun Symbol.PackageSymbol.findClass(name: String): SymbolBasedClass? {
val nameParts = name.replace("$", ".").split(".")
var symbol = members_field.getElementsByName(names.fromString(nameParts.first()))
?.firstOrNull() as? Symbol.ClassSymbol ?: return null
if (nameParts.size > 1) {
symbol.complete()
for (it in nameParts.drop(1)) {
symbol = symbol.members_field?.getElementsByName(names.fromString(it))?.firstOrNull() as? Symbol.ClassSymbol ?: return null
symbol.complete()
}
}
return symbol?.let { SymbolBasedClass(it, this@JavacWrapper, it.classfile) }
}
}
@@ -0,0 +1,49 @@
/*
* 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
import com.intellij.mock.MockProject
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
object JavacWrapperRegistrar {
private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
fun registerJavac(environment: KotlinCoreEnvironment,
javaFiles: List<File>,
kotlinFiles: List<KtFile>,
arguments: Array<String>?): Boolean {
try {
Class.forName(JAVAC_CONTEXT_CLASS)
} catch (e: ClassNotFoundException) {
environment.configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]
?.report(CompilerMessageSeverity.STRONG_WARNING,
"'$JAVAC_CONTEXT_CLASS' class can't be found ('tools.jar' is not found). ")
return false
}
(environment.project as MockProject).registerService(JavacWrapper::class.java,
JavacWrapper(javaFiles, kotlinFiles, arguments, environment))
return true
}
}
@@ -0,0 +1,255 @@
/*
* 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
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.javac.wrappers.trees.find
import org.jetbrains.kotlin.javac.wrappers.trees.findInner
import org.jetbrains.kotlin.javac.wrappers.trees.tryToResolveByFqName
import org.jetbrains.kotlin.javac.wrappers.trees.tryToResolveInJavaLang
class KotlinClassifiersCache(sourceFiles: Collection<KtFile>,
private val javac: JavacWrapper) {
private val kotlinClasses: Map<FqName?, KtClassOrObject?> = sourceFiles.flatMap { ktFile ->
ktFile.collectDescendantsOfType<KtClassOrObject>().map { it.fqName to it } +
(ktFile.javaFileFacadeFqName to null)
}.toMap()
private val classifiers = hashMapOf<FqName, JavaClass>()
fun getKotlinClassifier(fqName: FqName) = classifiers[fqName] ?: createClassifier(fqName)
private fun createClassifier(fqName: FqName): JavaClass? {
if (!kotlinClasses.containsKey(fqName)) return null
val kotlinClassifier = kotlinClasses[fqName] ?: return null
return MockKotlinClassifier(fqName,
kotlinClassifier,
kotlinClassifier.typeParameters.isNotEmpty(),
javac)
.apply { classifiers[fqName] = this }
}
}
class MockKotlinClassifier(override val fqName: FqName,
private val classOrObject: KtClassOrObject,
val hasTypeParameters: Boolean,
private val javac: JavacWrapper) : JavaClass {
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() = throw UnsupportedOperationException("Should not be called")
override val typeParameters: List<JavaTypeParameter>
get() = throw UnsupportedOperationException("Should not be called")
override val supertypes: Collection<JavaClassifierType>
get() = classOrObject.superTypeListEntries
.mapNotNull { superTypeListEntry ->
val userType = superTypeListEntry.typeAsUserType
arrayListOf<String>().apply {
userType?.referencedName?.let { add(it) }
var qualifier = userType?.qualifier
while (qualifier != null) {
qualifier.referencedName?.let { add(it) }
qualifier = qualifier.qualifier
}
}.reversed().joinToString(separator = ".") { it }
}
.mapNotNull { resolveSupertype(it, classOrObject, javac) }
.map { MockKotlinClassifierType(it) }
val innerClasses: Collection<JavaClass>
get() = classOrObject.declarations.filterIsInstance<KtClassOrObject>()
.mapNotNull { nestedClassOrObject ->
nestedClassOrObject.fqName?.let {
javac.getKotlinClassifier(it)
}
}
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 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 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 findAnnotation(fqName: FqName) =
throw UnsupportedOperationException("Should not be called")
override val innerClassNames
get() = innerClasses.map(JavaClass::name)
override fun findInnerClass(name: Name) =
innerClasses.find { it.name == name }
}
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")
}
private fun resolveSupertype(name: String,
classOrObject: KtClassOrObject,
javac: JavacWrapper): JavaClass? {
val nameParts = name.split(".")
val ktFile = classOrObject.containingKtFile
tryToResolveInner(name, classOrObject, javac, nameParts)?.let { return it }
ktFile.tryToResolvePackageClass(name, javac, nameParts)?.let { return it }
tryToResolveByFqName(name, javac)?.let { return it }
ktFile.tryToResolveSingleTypeImport(name, javac, nameParts)?.let { return it }
ktFile.tryToResolveTypeImportOnDemand(name, javac, nameParts)?.let { return it }
tryToResolveInJavaLang(name, javac)?.let { return it }
return null
}
private fun tryToResolveInner(name: String,
classOrObject: KtClassOrObject,
javac: JavacWrapper,
nameParts: List<String>) =
classOrObject.containingClassOrObject?.let { containingClass ->
containingClass.fqName?.let {
javac.findClass(it) ?: javac.getKotlinClassifier(it)
}
}?.findInner(name, javac, nameParts)
private fun KtFile.tryToResolvePackageClass(name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()): JavaClass? {
if (nameParts.size > 1) {
return find(FqName("${packageFqName.asString()}.${nameParts.first()}"), javac, nameParts)
}
else {
return javac.findClass(FqName("${packageFqName.asString()}.$name"))
?: javac.getKotlinClassifier(FqName("${packageFqName.asString()}.$name"))
}
}
private fun KtFile.tryToResolveSingleTypeImport(name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()): JavaClass? {
if (nameParts.size > 1) {
val foundImports = importDirectives.filter { it.text.endsWith(".${nameParts.first()}") }
foundImports.forEach { importDirective ->
importDirective.importedFqName?.let { importedFqName ->
find(importedFqName, javac, nameParts)?.let { importedClass ->
return importedClass
}
}
}
return null
}
else {
return importDirectives.find { importDirective ->
importDirective.text.endsWith(".$name")
}?.let { importDirective ->
importDirective.importedFqName?.let { fqName ->
javac.findClass(fqName) ?: javac.getKotlinClassifier(fqName)
}
}
}
}
private fun KtFile.tryToResolveTypeImportOnDemand(name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()): JavaClass? {
val packagesWithAsterisk = importDirectives.filter { it.text.endsWith("*") }
if (nameParts.size > 1) {
packagesWithAsterisk.forEach { importDirective ->
find(FqName("${importDirective.importedFqName?.asString()}.${nameParts.first()}"),
javac,
nameParts)?.let { return it }
}
return null
}
else {
packagesWithAsterisk.forEach { importDirective ->
val fqName = "${importDirective.importedFqName?.asString()}.$name".let(::FqName)
javac.findClass(fqName)?.let { return it } ?: javac.getKotlinClassifier(fqName)?.let { return it }
}
return null
}
}
@@ -0,0 +1,41 @@
/*
* 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.components
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.AbstractJavaClassFinder
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
class JavacBasedClassFinder : AbstractJavaClassFinder() {
private lateinit var javac: JavacWrapper
override fun initialize(trace: BindingTrace, codeAnalyzer: KotlinCodeAnalyzer) {
javac = JavacWrapper.getInstance(project)
super.initialize(trace, codeAnalyzer)
}
override fun findClass(classId: ClassId) = javac.findClass(classId, javaSearchScope)
override fun findPackage(fqName: FqName) = javac.findPackage(fqName, javaSearchScope)
override fun knownClassNamesInPackage(packageFqName: FqName) = javac.knownClassNamesInPackage(packageFqName)
}
@@ -0,0 +1,26 @@
/*
* 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.components
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.JavaElement
class JavacBasedSourceElement(override val javaElement: JavaElement) : JavaSourceElement {
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
}
@@ -0,0 +1,26 @@
/*
* 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.components
import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
import org.jetbrains.kotlin.load.java.structure.JavaElement
class JavacBasedSourceElementFactory : JavaSourceElementFactory {
override fun source(javaElement: JavaElement) = JavacBasedSourceElement(javaElement)
}
@@ -0,0 +1,40 @@
/*
* 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.components
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.load.java.components.AbstractJavaResolverCache
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaElement
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
class StubJavaResolverCache(resolveSession: ResolveSession) : AbstractJavaResolverCache(resolveSession) {
override fun recordMethod(method: JavaMethod, descriptor: SimpleFunctionDescriptor) {}
override fun recordConstructor(element: JavaElement, descriptor: ConstructorDescriptor) {}
override fun recordField(field: JavaField, descriptor: PropertyDescriptor) {}
override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) {}
}
@@ -0,0 +1,46 @@
/*
* 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.wrappers.symbols
import com.sun.tools.javac.code.Symbol
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
import org.jetbrains.kotlin.load.java.structure.JavaElement
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.TypeElement
open class SymbolBasedAnnotation(
val annotationMirror: AnnotationMirror,
val javac: JavacWrapper
) : JavaElement, JavaAnnotation {
override val arguments: Collection<JavaAnnotationArgument>
get() = annotationMirror.elementValues.map { (key, value) ->
SymbolBasedAnnotationArgument.create(value.value, Name.identifier(key.simpleName.toString()), javac)
}
override val classId: ClassId?
get() = (annotationMirror.annotationType.asElement() as? TypeElement)?.computeClassId()
override fun resolve() = with(annotationMirror.annotationType.asElement() as Symbol.ClassSymbol) {
SymbolBasedClass(this, javac, classfile)
}
}
@@ -0,0 +1,121 @@
/*
* 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.wrappers.symbols
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.CommonClassNames
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.ElementKind
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
import javax.lang.model.element.VariableElement
import javax.lang.model.type.NoType
import javax.lang.model.type.TypeKind
import javax.tools.JavaFileObject
class SymbolBasedClass(
element: TypeElement,
javac: JavacWrapper,
val file: JavaFileObject?
) : SymbolBasedClassifier<TypeElement>(element, javac), VirtualFileBoundJavaClass {
override val name: Name
get() = Name.identifier(element.simpleName.toString())
override val isAbstract: Boolean
get() = element.isAbstract
override val isStatic: Boolean
get() = element.isStatic
override val isFinal: Boolean
get() = element.isFinal
override val visibility: Visibility
get() = element.getVisibility()
override val typeParameters: List<JavaTypeParameter>
get() = element.typeParameters.map { SymbolBasedTypeParameter(it, javac) }
override val fqName: FqName
get() = FqName(element.qualifiedName.toString())
override val supertypes: Collection<JavaClassifierType>
get() = element.interfaces.toMutableList()
.apply {
element.superclass.takeIf { it !is NoType }?.let(this::add)
}
.mapTo(arrayListOf()) { SymbolBasedClassifierType(it, javac) }
.apply {
if (isEmpty() && element.qualifiedName.toString() != CommonClassNames.JAVA_LANG_OBJECT) {
javac.JAVA_LANG_OBJECT?.let { add(it) }
}
}
val innerClasses: Map<Name, JavaClass>
get() = element.enclosedElements
.filterIsInstance(TypeElement::class.java)
.map { SymbolBasedClass(it, javac, file) }
.associateBy(JavaClass::name)
override val outerClass: JavaClass?
get() = element.enclosingElement?.let {
if (it.asType().kind != TypeKind.DECLARED) null else SymbolBasedClass(it as TypeElement, javac, file)
}
override val isInterface: Boolean
get() = element.kind == ElementKind.INTERFACE
override val isAnnotationType: Boolean
get() = element.kind == ElementKind.ANNOTATION_TYPE
override val isEnum: Boolean
get() = element.kind == ElementKind.ENUM
override val lightClassOriginKind: LightClassOriginKind?
get() = null
override val methods: Collection<JavaMethod>
get() = element.enclosedElements
.filter { it.kind == ElementKind.METHOD }
.map { SymbolBasedMethod(it as ExecutableElement, javac) }
override val fields: Collection<JavaField>
get() = element.enclosedElements
.filter { it.kind.isField && Name.isValidIdentifier(it.simpleName.toString()) }
.map { SymbolBasedField(it as VariableElement, javac) }
override val constructors: Collection<JavaConstructor>
get() = element.enclosedElements
.filter { it.kind == ElementKind.CONSTRUCTOR }
.map { SymbolBasedConstructor(it as ExecutableElement, javac) }
override val innerClassNames: Collection<Name>
get() = innerClasses.keys
override val virtualFile: VirtualFile? by lazy {
file?.let { javac.toVirtualFile(it) }
}
override fun findInnerClass(name: Name) = innerClasses[name]
}
@@ -0,0 +1,39 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
import org.jetbrains.kotlin.name.FqName
import javax.lang.model.element.Element
abstract class SymbolBasedClassifier<out T : Element>(
element: T,
javac: JavacWrapper
) : SymbolBasedElement<T>(element, javac), JavaClassifier, JavaAnnotationOwner {
override val annotations: Collection<JavaAnnotation>
get() = element.annotationMirrors.map { SymbolBasedAnnotation(it, javac) }
override fun findAnnotation(fqName: FqName) = element.findAnnotation(fqName, javac)
override val isDeprecatedInJavaDoc: Boolean
get() = javac.isDeprecated(element)
}
@@ -0,0 +1,36 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import javax.lang.model.element.ExecutableElement
class SymbolBasedConstructor(
element: ExecutableElement,
javac: JavacWrapper
) : SymbolBasedMember<ExecutableElement>(element, javac), JavaConstructor {
override val typeParameters: List<JavaTypeParameter>
get() = element.typeParameters.map { SymbolBasedTypeParameter(it, javac) }
override val valueParameters: List<JavaValueParameter>
get() = element.valueParameters(javac)
}
@@ -0,0 +1,34 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaElement
import javax.lang.model.element.Element
open class SymbolBasedElement<out T : Element>(
val element: T,
val javac: JavacWrapper
) : JavaElement {
override fun equals(other: Any?) = (other as? SymbolBasedElement<*>)?.element == element
override fun hashCode() = element.hashCode()
override fun toString() = element.simpleName.toString()
}
@@ -0,0 +1,47 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaType
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
import javax.lang.model.element.VariableElement
import javax.lang.model.type.DeclaredType
class SymbolBasedField(
element: VariableElement,
javac: JavacWrapper
) : SymbolBasedMember<VariableElement>(element, javac), JavaField {
override val isEnumEntry: Boolean
get() = element.kind == ElementKind.ENUM_CONSTANT
override val type: JavaType
get() = SymbolBasedType.create(element.asType(), javac)
override val initializerValue: Any?
get() = element.constantValue
override val hasConstantNotNullInitializer: Boolean
get() = element.constantValue != null && element.asType().let {
it.kind.isPrimitive ||
((it as? DeclaredType)?.asElement() as? TypeElement)?.qualifiedName?.toString() == "java.lang.String"
}
}
@@ -0,0 +1,62 @@
/*
* 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.wrappers.symbols
import com.sun.tools.javac.code.Symbol
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.Element
abstract class SymbolBasedMember<out T : Element>(
element: T,
javac: JavacWrapper
) : SymbolBasedElement<T>(element, javac), JavaMember {
override val containingClass: JavaClass
get() = with(element.enclosingElement as Symbol.ClassSymbol) {
SymbolBasedClass(this, javac, classfile)
}
override val annotations: Collection<JavaAnnotation>
get() = element.annotationMirrors.map { SymbolBasedAnnotation(it, javac) }
override fun findAnnotation(fqName: FqName) = element.findAnnotation(fqName, javac)
override val visibility: Visibility
get() = element.getVisibility()
override val name: Name
get() = Name.identifier(element.simpleName.toString())
override val isDeprecatedInJavaDoc: Boolean
get() = javac.isDeprecated(element)
override val isAbstract: Boolean
get() = element.isAbstract
override val isStatic: Boolean
get() = element.isStatic
override val isFinal: Boolean
get() = element.isFinal
}
@@ -0,0 +1,40 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import javax.lang.model.element.ExecutableElement
class SymbolBasedMethod(
element: ExecutableElement,
javac: JavacWrapper
) : SymbolBasedMember<ExecutableElement>(element, javac), JavaMethod {
override val typeParameters: List<JavaTypeParameter>
get() = element.typeParameters.map { SymbolBasedTypeParameter(it, javac) }
override val valueParameters: List<JavaValueParameter>
get() = element.valueParameters(javac)
override val returnType: JavaType
get() = SymbolBasedType.create(element.returnType, javac)
override val hasAnnotationParameterDefaultValue: Boolean
get() = element.defaultValue != null
}
@@ -0,0 +1,41 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaPackage
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.PackageElement
class SymbolBasedPackage(
element: PackageElement,
javac: JavacWrapper
) : SymbolBasedElement<PackageElement>(element, javac), JavaPackage {
override val fqName: FqName
get() = FqName(element.qualifiedName.toString())
override val subPackages: Collection<JavaPackage>
get() = javac.findSubPackages(FqName(element.qualifiedName.toString()))
override fun getClasses(nameFilter: (Name) -> Boolean) =
javac.findClassesFromPackage(fqName).filter { nameFilter(it.name) }
override fun toString() = element.qualifiedName.toString()
}
@@ -0,0 +1,36 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.TypeParameterElement
class SymbolBasedTypeParameter(
element: TypeParameterElement,
javac: JavacWrapper
) : SymbolBasedClassifier<TypeParameterElement>(element, javac), JavaTypeParameter {
override val name: Name
get() = Name.identifier(element.simpleName.toString())
override val upperBounds: Collection<JavaClassifierType>
get() = element.bounds.map { SymbolBasedClassifierType(it, javac) }
}
@@ -0,0 +1,49 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.VariableElement
class SymbolBasedValueParameter(
element: VariableElement,
private val elementName : String,
override val isVararg : Boolean,
javac: JavacWrapper
) : SymbolBasedElement<VariableElement>(element, javac), JavaValueParameter {
override val annotations: Collection<JavaAnnotation>
get() = element.annotationMirrors.map { SymbolBasedAnnotation(it, javac) }
override fun findAnnotation(fqName: FqName) =
element.findAnnotation(fqName, javac)
override val isDeprecatedInJavaDoc: Boolean
get() = javac.isDeprecated(element)
override val name: Name
get() = Name.identifier(elementName)
override val type: JavaType
get() = SymbolBasedType.create(element.asType(), javac)
}
@@ -0,0 +1,93 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.AnnotationMirror
import javax.lang.model.element.AnnotationValue
import javax.lang.model.element.VariableElement
import javax.lang.model.type.TypeMirror
sealed class SymbolBasedAnnotationArgument(
override val name: Name,
val javac: JavacWrapper
) : JavaAnnotationArgument, JavaElement {
companion object {
fun create(value: Any, name: Name, javac: JavacWrapper): JavaAnnotationArgument = when (value) {
is AnnotationMirror -> SymbolBasedAnnotationAsAnnotationArgument(value, name, javac)
is VariableElement -> SymbolBasedReferenceAnnotationArgument(value, javac)
is TypeMirror -> SymbolBasedClassObjectAnnotationArgument(value, name, javac)
is Collection<*> -> arrayAnnotationArguments(value, name, javac)
is AnnotationValue -> create(value.value, name, javac)
else -> SymbolBasedLiteralAnnotationArgument(value, name, javac)
}
private fun arrayAnnotationArguments(values: Collection<*>, name: Name, javac: JavacWrapper): JavaArrayAnnotationArgument =
values.map { if (it is Collection<*>) arrayAnnotationArguments(it, name, javac) else create(it!!, name, javac) }
.let { argumentList -> SymbolBasedArrayAnnotationArgument(argumentList, name, javac) }
}
}
class SymbolBasedAnnotationAsAnnotationArgument(
val mirror: AnnotationMirror,
name: Name,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation() = SymbolBasedAnnotation(mirror, javac)
}
class SymbolBasedReferenceAnnotationArgument(
val element: VariableElement,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(Name.identifier(element.simpleName.toString()), javac), JavaEnumValueAnnotationArgument {
override fun resolve() = SymbolBasedField(element, javac)
}
class SymbolBasedClassObjectAnnotationArgument(
val type: TypeMirror,
name : Name,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaClassObjectAnnotationArgument {
override fun getReferencedType() = SymbolBasedType.create(type, javac)
}
class SymbolBasedArrayAnnotationArgument(
val args : List<JavaAnnotationArgument>,
name : Name,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaArrayAnnotationArgument {
override fun getElements() = args
}
class SymbolBasedLiteralAnnotationArgument(
override val value : Any,
name : Name,
javac: JavacWrapper
) : SymbolBasedAnnotationArgument(name, javac), JavaLiteralAnnotationArgument
@@ -0,0 +1,131 @@
/*
* 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.wrappers.symbols
import com.sun.tools.javac.code.Symbol
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import javax.lang.model.element.TypeElement
import javax.lang.model.element.TypeParameterElement
import javax.lang.model.type.*
sealed class SymbolBasedType<out T : TypeMirror>(
val typeMirror: T,
val javac: JavacWrapper
) : JavaType, JavaAnnotationOwner {
companion object {
fun <T : TypeMirror> create(t: T, javac: JavacWrapper) = when {
t.kind.isPrimitive || t.kind == TypeKind.VOID -> SymbolBasedPrimitiveType(t, javac)
t.kind == TypeKind.DECLARED || t.kind == TypeKind.TYPEVAR -> SymbolBasedClassifierType(t, javac)
t.kind == TypeKind.WILDCARD -> SymbolBasedWildcardType(t as WildcardType, javac)
t.kind == TypeKind.ARRAY -> SymbolBasedArrayType(t as ArrayType, javac)
else -> throw UnsupportedOperationException("Unsupported type: $t")
}
}
override val annotations: Collection<JavaAnnotation>
get() = typeMirror.annotationMirrors.map { SymbolBasedAnnotation(it, javac) }
override val isDeprecatedInJavaDoc: Boolean
get() = javac.isDeprecated(typeMirror)
override fun findAnnotation(fqName: FqName) = typeMirror.findAnnotation(fqName, javac)
override fun equals(other: Any?) = (other as? SymbolBasedType<*>)?.typeMirror == typeMirror
override fun hashCode() = typeMirror.hashCode()
override fun toString() = typeMirror.toString()
}
class SymbolBasedPrimitiveType(
typeMirror: TypeMirror,
javac: JavacWrapper
) : SymbolBasedType<TypeMirror>(typeMirror, javac), JavaPrimitiveType {
override val type: PrimitiveType?
get() = if (typeMirror.kind == TypeKind.VOID) null else JvmPrimitiveType.get(typeMirror.toString()).primitiveType
}
class SymbolBasedClassifierType<out T : TypeMirror>(
typeMirror: T,
javac: JavacWrapper
) : SymbolBasedType<T>(typeMirror, javac), JavaClassifierType {
override val classifier: JavaClassifier?
get() = when (typeMirror.kind) {
TypeKind.DECLARED -> ((typeMirror as DeclaredType).asElement() as Symbol.ClassSymbol).let { symbol ->
SymbolBasedClass(symbol, javac, symbol.classfile)
}
TypeKind.TYPEVAR -> SymbolBasedTypeParameter((typeMirror as TypeVariable).asElement() as TypeParameterElement, javac)
else -> null
}
override val typeArguments: List<JavaType>
get() = if (typeMirror.kind == TypeKind.DECLARED) {
(typeMirror as DeclaredType).typeArguments.map { create(it, javac) }
}
else {
emptyList()
}
override val isRaw: Boolean
get() = when {
typeMirror !is DeclaredType -> false
(typeMirror.asElement() as TypeElement).typeParameters.isEmpty() -> false
else -> typeMirror.typeArguments.isEmpty()
}
override val classifierQualifiedName: String
get() = typeMirror.toString()
override val presentableText: String
get() = typeMirror.toString()
}
class SymbolBasedWildcardType(
typeMirror: WildcardType,
javac: JavacWrapper
) : SymbolBasedType<WildcardType>(typeMirror, javac), JavaWildcardType {
override val bound: JavaType?
get() {
val boundMirror = typeMirror.extendsBound ?: typeMirror.superBound
return boundMirror?.let { create(it, javac) }
}
override val isExtends: Boolean
get() = typeMirror.extendsBound != null
}
class SymbolBasedArrayType(
typeMirror: ArrayType,
javac: JavacWrapper
) : SymbolBasedType<ArrayType>(typeMirror, javac), JavaArrayType {
override val componentType: JavaType
get() = create(typeMirror.componentType, javac)
}
@@ -0,0 +1,74 @@
/*
* 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.wrappers.symbols
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.lang.model.AnnotatedConstruct
import javax.lang.model.element.*
internal val Element.isAbstract: Boolean
get() = modifiers.contains(Modifier.ABSTRACT)
internal val Element.isStatic: Boolean
get() = modifiers.contains(Modifier.STATIC)
internal val Element.isFinal: Boolean
get() = modifiers.contains(Modifier.FINAL)
internal fun Element.getVisibility(): Visibility = when {
Modifier.PUBLIC in modifiers -> Visibilities.PUBLIC
Modifier.PRIVATE in modifiers -> Visibilities.PRIVATE
Modifier.PROTECTED in modifiers -> {
if (Modifier.STATIC in modifiers) {
JavaVisibilities.PROTECTED_STATIC_VISIBILITY
}
else {
JavaVisibilities.PROTECTED_AND_PACKAGE
}
}
else -> JavaVisibilities.PACKAGE_VISIBILITY
}
internal fun TypeElement.computeClassId(): ClassId? {
if (enclosingElement.kind != ElementKind.PACKAGE) {
val parentClassId = (enclosingElement as TypeElement).computeClassId() ?: return null
return parentClassId.createNestedClassId(Name.identifier(simpleName.toString()))
}
return ClassId.topLevel(FqName(qualifiedName.toString()))
}
internal fun ExecutableElement.valueParameters(javac: JavacWrapper): List<JavaValueParameter> =
parameters.mapIndexed { index, parameter ->
SymbolBasedValueParameter(parameter,
parameter.simpleName.toString(),
index == parameters.lastIndex && isVarArgs,
javac)
}
internal fun AnnotatedConstruct.findAnnotation(fqName: FqName,
javac: JavacWrapper) =
annotationMirrors.find {
(it.annotationType.asElement() as TypeElement).qualifiedName.toString() == fqName.asString()
}?.let { SymbolBasedAnnotation(it, javac) }
@@ -0,0 +1,46 @@
/*
* 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.wrappers.trees
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.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaElement
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
class TreeBasedAnnotation(
val annotation: JCTree.JCAnnotation,
val treePath: TreePath,
val javac: JavacWrapper
) : JavaElement, JavaAnnotation {
override val arguments: Collection<JavaAnnotationArgument>
get() = annotation.arguments.map { TreeBasedAnnotationArgument(Name.identifier(it.toString())) }
override val classId: ClassId?
get() = resolve()?.computeClassId()
override fun resolve() =
javac.resolve(TreePath.getPath(treePath.compilationUnit, annotation.annotationType)) as? JavaClass
}
class TreeBasedAnnotationArgument(override val name: Name) : JavaAnnotationArgument, JavaElement
@@ -0,0 +1,153 @@
/*
* 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.wrappers.trees
import com.intellij.openapi.vfs.VirtualFile
import com.sun.source.tree.Tree
import com.sun.source.util.TreePath
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.TreeInfo
import org.jetbrains.kotlin.descriptors.Visibilities.PUBLIC
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.tools.JavaFileObject
class TreeBasedClass(
tree: JCTree.JCClassDecl,
treePath: TreePath,
javac: JavacWrapper,
val file: JavaFileObject
) : TreeBasedElement<JCTree.JCClassDecl>(tree, treePath, javac), JavaClass {
override val name: Name
get() = Name.identifier(tree.simpleName.toString())
override val annotations: Collection<JavaAnnotation> by lazy {
tree.annotations().map { annotation -> TreeBasedAnnotation(annotation, treePath, javac) }
}
override fun findAnnotation(fqName: FqName) =
annotations.find { it.classId?.asSingleFqName() == fqName }
override val isDeprecatedInJavaDoc: Boolean
get() = false
override val isAbstract: Boolean
get() = tree.modifiers.isAbstract || (isAnnotationType && methods.any { it.isAbstract })
override val isStatic: Boolean
get() = (outerClass?.isInterface ?: false) || tree.modifiers.isStatic
override val isFinal: Boolean
get() = tree.modifiers.isFinal
override val visibility: Visibility
get() = if (outerClass?.isInterface ?: false) PUBLIC else tree.modifiers.visibility
override val typeParameters: List<JavaTypeParameter>
get() = tree.typeParameters.map { parameter ->
TreeBasedTypeParameter(parameter, TreePath(treePath, parameter), javac)
}
override val fqName: FqName =
treePath.reversed()
.filterIsInstance<JCTree.JCClassDecl>()
.joinToString(
separator = ".",
prefix = "${treePath.compilationUnit.packageName}.",
transform = JCTree.JCClassDecl::name
)
.let(::FqName)
override val supertypes: Collection<JavaClassifierType>
get() = arrayListOf<JavaClassifierType>().apply {
fun JCTree.mapToJavaClassifierType() = when {
this is JCTree.JCTypeApply -> TreeBasedGenericClassifierType(this, TreePath(treePath, this), javac)
this is JCTree.JCExpression -> TreeBasedNonGenericClassifierType(this, TreePath(treePath, this), javac)
else -> null
}
if (isEnum) {
javac.JAVA_LANG_ENUM?.let(this::add)
} else if (isAnnotationType) {
javac.JAVA_LANG_ANNOTATION_ANNOTATION?.let(this::add)
}
tree.implementing?.mapNotNull { it.mapToJavaClassifierType() }?.let(this::addAll)
tree.extending?.let { it.mapToJavaClassifierType()?.let(this::add) }
if (isEmpty()) {
javac.JAVA_LANG_OBJECT?.let(this::add)
}
}
val innerClasses: Map<Name, TreeBasedClass> by lazy {
tree.members
.filterIsInstance(JCTree.JCClassDecl::class.java)
.map { TreeBasedClass(it, TreePath(treePath, it), javac, file) }
.associateBy(JavaClass::name)
}
override val outerClass: JavaClass? by lazy {
(treePath.parentPath.leaf as? JCTree.JCClassDecl)?.let { classDecl ->
TreeBasedClass(classDecl, treePath.parentPath, javac, file)
}
}
override val isInterface: Boolean
get() = tree.modifiers.flags and Flags.INTERFACE.toLong() != 0L
override val isAnnotationType: Boolean
get() = tree.modifiers.flags and Flags.ANNOTATION.toLong() != 0L
override val isEnum: Boolean
get() = tree.modifiers.flags and Flags.ENUM.toLong() != 0L
override val lightClassOriginKind: LightClassOriginKind?
get() = null
override val methods: Collection<JavaMethod>
get() = tree.members
.filter { it.kind == Tree.Kind.METHOD && !TreeInfo.isConstructor(it) }
.map { TreeBasedMethod(it as JCTree.JCMethodDecl, TreePath(treePath, it), this, javac) }
override val fields: Collection<JavaField>
get() = tree.members
.filterIsInstance(JCTree.JCVariableDecl::class.java)
.map { TreeBasedField(it, TreePath(treePath, it), this, javac) }
override val constructors: Collection<JavaConstructor>
get() = tree.members
.filter { member -> TreeInfo.isConstructor(member) }
.map { constructor ->
TreeBasedConstructor(constructor as JCTree.JCMethodDecl, TreePath(treePath, constructor), this, javac)
}
override val innerClassNames: Collection<Name>
get() = innerClasses.keys
val virtualFile: VirtualFile? by lazy {
javac.toVirtualFile(file)
}
override fun findInnerClass(name: Name) = innerClasses[name]
}
@@ -0,0 +1,57 @@
/*
* 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.wrappers.trees
import com.sun.source.util.TreePath
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.Name
class TreeBasedConstructor(
tree: JCTree.JCMethodDecl,
treePath: TreePath,
containingClass: JavaClass,
javac: JavacWrapper
) : TreeBasedMember<JCTree.JCMethodDecl>(tree, treePath, containingClass, javac), JavaConstructor {
override val name: Name
get() = Name.identifier(tree.name.toString())
override val isAbstract: Boolean
get() = false
override val isStatic: Boolean
get() = false
override val isFinal: Boolean
get() = true
override val visibility: Visibility
get() = tree.modifiers.visibility
override val typeParameters: List<JavaTypeParameter>
get() = tree.typeParameters.map { TreeBasedTypeParameter(it, TreePath(treePath, it), javac) }
override val valueParameters: List<JavaValueParameter>
get() = tree.parameters.map { TreeBasedValueParameter(it, TreePath(treePath, it), javac) }
}
@@ -0,0 +1,36 @@
/*
* 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.wrappers.trees
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.JavaElement
abstract class TreeBasedElement<out T : JCTree>(
val tree: T,
val treePath: TreePath,
val javac: JavacWrapper
) : JavaElement {
override fun equals(other: Any?) = (other as? TreeBasedElement<*>)?.tree == tree
override fun hashCode() = tree.hashCode()
override fun toString() = tree.toString()
}
@@ -0,0 +1,76 @@
/*
* 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.wrappers.trees
import com.sun.source.util.TreePath
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
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.load.java.structure.JavaType
import org.jetbrains.kotlin.name.Name
class TreeBasedField(
tree: JCTree.JCVariableDecl,
treePath: TreePath,
containingClass: JavaClass,
javac: JavacWrapper
) : TreeBasedMember<JCTree.JCVariableDecl>(tree, treePath, containingClass, javac), JavaField {
override val name: Name
get() = Name.identifier(tree.name.toString())
override val isAbstract: Boolean
get() = tree.modifiers.isAbstract
override val isStatic: Boolean
get() = containingClass.isInterface || tree.modifiers.isStatic
override val isFinal: Boolean
get() = containingClass.isInterface || tree.modifiers.isFinal
override val visibility: Visibility
get() = if (containingClass.isInterface) Visibilities.PUBLIC else tree.modifiers.visibility
override val isEnumEntry: Boolean
get() = tree.modifiers.flags and Flags.ENUM.toLong() != 0L
override val type: JavaType
get() = TreeBasedType.create(tree.getType(), treePath, javac)
override val initializerValue: Any?
get() = tree.init?.let { initExpr ->
if (hasConstantNotNullInitializer && initExpr is JCTree.JCLiteral) {
initExpr.value
} else {
null
}
}
override val hasConstantNotNullInitializer: Boolean
get() = tree.init?.let {
val type = this.type
isFinal && ((type is TreeBasedPrimitiveType) ||
(type is TreeBasedNonGenericClassifierType &&
type.classifierQualifiedName == "java.lang.String"))
} ?: false
}
@@ -0,0 +1,44 @@
/*
* 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.wrappers.trees
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.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.name.FqName
abstract class TreeBasedMember<out T : JCTree>(
tree: T,
treePath: TreePath,
override val containingClass: JavaClass,
javac: JavacWrapper
) : TreeBasedElement<T>(tree, treePath, javac), JavaMember {
override val isDeprecatedInJavaDoc: Boolean
get() = false
override val annotations: Collection<JavaAnnotation> by lazy {
tree.annotations().map { TreeBasedAnnotation(it, treePath, javac) }
}
override fun findAnnotation(fqName: FqName) =
annotations.find { it.classId?.asSingleFqName() == fqName }
}
@@ -0,0 +1,60 @@
/*
* 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.wrappers.trees
import com.sun.source.util.TreePath
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
class TreeBasedMethod(
tree: JCTree.JCMethodDecl,
treePath: TreePath,
containingClass: JavaClass,
javac: JavacWrapper
) : TreeBasedMember<JCTree.JCMethodDecl>(tree, treePath, containingClass, javac), JavaMethod {
override val name: Name
get() = Name.identifier(tree.name.toString())
override val isAbstract: Boolean
get() = (containingClass.isInterface && !tree.modifiers.hasDefaultModifier) || tree.modifiers.isAbstract
override val isStatic: Boolean
get() = tree.modifiers.isStatic
override val isFinal: Boolean
get() = tree.modifiers.isFinal
override val visibility: Visibility
get() = if (containingClass.isInterface) Visibilities.PUBLIC else tree.modifiers.visibility
override val typeParameters: List<JavaTypeParameter>
get() = tree.typeParameters.map { TreeBasedTypeParameter(it, TreePath(treePath, it), javac) }
override val valueParameters: List<JavaValueParameter>
get() = tree.parameters.map { TreeBasedValueParameter(it, TreePath(treePath, it), javac) }
override val returnType: JavaType
get() = TreeBasedType.create(tree.returnType, treePath, javac)
override val hasAnnotationParameterDefaultValue: Boolean
get() = tree.defaultValue != null
}
@@ -0,0 +1,47 @@
/*
* 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.wrappers.trees
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaPackage
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import javax.tools.JavaFileObject
class TreeBasedPackage(val name: String, val javac: JavacWrapper, val file: JavaFileObject) : JavaPackage {
override val fqName: FqName
get() = FqName(name)
override val subPackages: Collection<JavaPackage>
get() = javac.findSubPackages(fqName)
val virtualFile: VirtualFile? by lazy {
javac.toVirtualFile(file)
}
override fun getClasses(nameFilter: (Name) -> Boolean) =
javac.findClassesFromPackage(fqName).filter { nameFilter(it.fqName!!.shortName()) }
override fun equals(other: Any?) = (other as? TreeBasedPackage)?.name == name
override fun hashCode() = name.hashCode()
override fun toString() = name
}
@@ -0,0 +1,56 @@
/*
* 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.wrappers.trees
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.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class TreeBasedTypeParameter(
tree: JCTree.JCTypeParameter,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedElement<JCTree.JCTypeParameter>(tree, treePath, javac), JavaTypeParameter {
override val name: Name
get() = Name.identifier(tree.name.toString())
override val annotations: Collection<JavaAnnotation> by lazy {
tree.annotations().map { TreeBasedAnnotation(it, treePath, javac) }
}
override fun findAnnotation(fqName: FqName) =
annotations.firstOrNull { it.classId?.asSingleFqName() == fqName }
override val isDeprecatedInJavaDoc: Boolean
get() = false
override val upperBounds: Collection<JavaClassifierType>
get() = tree.bounds.map {
when (it) {
is JCTree.JCTypeApply -> TreeBasedGenericClassifierType(it, TreePath(treePath, it), javac)
is JCTree.JCIdent -> TreeBasedNonGenericClassifierType(it, TreePath(treePath, it), javac)
else -> null
}
}.filterNotNull()
}
@@ -0,0 +1,53 @@
/*
* 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.wrappers.trees
import com.sun.source.util.TreePath
import com.sun.tools.javac.code.Flags
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class TreeBasedValueParameter(
tree: JCTree.JCVariableDecl,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedElement<JCTree.JCVariableDecl>(tree, treePath, javac), JavaValueParameter {
override val annotations: Collection<JavaAnnotation> by lazy {
tree.annotations().map { TreeBasedAnnotation(it, treePath, javac) }
}
override fun findAnnotation(fqName: FqName) =
annotations.find { it.classId?.asSingleFqName() == fqName }
override val isDeprecatedInJavaDoc: Boolean
get() = false
override val name: Name
get() = Name.identifier(tree.name.toString())
override val type: JavaType
get() = TreeBasedType.create(tree.getType(), treePath, javac)
override val isVararg: Boolean
get() = tree.modifiers.flags and Flags.VARARGS != 0L
}
@@ -0,0 +1,193 @@
/*
* 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.wrappers.trees
import com.sun.source.tree.Tree
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.JavaClassifier
import org.jetbrains.kotlin.name.FqName
class TreePathResolverCache(private val javac: JavacWrapper) {
private val cache = hashMapOf<Tree, JavaClassifier?>()
fun resolve(treePath: TreePath): JavaClassifier? = with(treePath) {
if (cache.containsKey(leaf)) return cache[leaf]
return tryToGetClassifier().apply { cache[leaf] = this }
}
private fun TreePath.tryToGetClassifier(): JavaClassifier? {
val name = leaf.toString().substringBefore("<").substringAfter("@")
val nameParts = name.split(".")
with(compilationUnit as JCTree.JCCompilationUnit) {
tryToResolveInner(name, javac, nameParts)?.let { return it }
tryToResolvePackageClass(name, javac, nameParts)?.let { return it }
tryToResolveByFqName(name, javac)?.let { return it }
tryToResolveSingleTypeImport(name, javac, nameParts)?.let { return it }
tryToResolveTypeImportOnDemand(name, javac, nameParts)?.let { return it }
tryToResolveInJavaLang(name, javac)?.let { return it }
}
return tryToResolveTypeParameter(javac)
}
private fun TreePath.tryToResolveInner(
name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()
): JavaClass? = findEnclosingClasses(javac)?.forEach { javaClass ->
javaClass.findInner(name, javac, nameParts)?.let { inner -> return inner }
}.let { return null }
private fun TreePath.findEnclosingClasses(javac: JavacWrapper) =
filterIsInstance<JCTree.JCClassDecl>()
.filter { it.extending != leaf && !it.implementing.contains(leaf) }
.reversed()
.joinToString(separator = ".", prefix = "${compilationUnit.packageName}.") { it.simpleName }
.let { javac.findClass(FqName(it)) }
?.let {
arrayListOf(it).apply {
var enclosingClass = it.outerClass
while (enclosingClass != null) {
add(enclosingClass)
enclosingClass = enclosingClass.outerClass
}
}
}
private fun JCTree.JCCompilationUnit.tryToResolveSingleTypeImport(
name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()
): JavaClass? {
nameParts.size.takeIf { it > 1 }?.let {
imports.filter { it.qualifiedIdentifier.toString().endsWith(".${nameParts.first()}") }
.forEach { import ->
find(FqName("${import.qualifiedIdentifier}"), javac, nameParts)?.let { javaClass ->
return javaClass
}
}
.let { return null }
}
return imports
.find { it.qualifiedIdentifier.toString().endsWith(".$name") }
?.let { import ->
FqName(import.qualifiedIdentifier.toString()).let { fqName ->
javac.findClass(fqName) ?: javac.getKotlinClassifier(fqName)
}
}
}
private fun JCTree.JCCompilationUnit.tryToResolvePackageClass(
name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()
): JavaClass? {
return nameParts.size.takeIf { it > 1 }?.let {
find(FqName("$packageName.${nameParts.first()}"), javac, nameParts)
}
?: javac.findClass(FqName("$packageName.$name"))
?: javac.getKotlinClassifier(FqName("$packageName.$name"))
}
private fun JCTree.JCCompilationUnit.tryToResolveTypeImportOnDemand(
name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()
): JavaClass? {
with(imports.filter { it.qualifiedIdentifier.toString().endsWith("*") }) {
nameParts.size.takeIf { it > 1 }
?.let {
forEach { pack ->
find(FqName("${pack.qualifiedIdentifier.toString().substringBefore("*")}${nameParts.first()}"),
javac,
nameParts)?.let { return it }
}.let { return null }
}
this.forEach {
val fqName = "${it.qualifiedIdentifier.toString().substringBefore("*")}$name".let(::FqName)
(javac.findClass(fqName) ?: javac.getKotlinClassifier(fqName))?.let { return it }
}.let { return null }
}
}
private fun TreePath.tryToResolveTypeParameter(javac: JavacWrapper) =
flatMap {
when (it) {
is JCTree.JCClassDecl -> it.typarams
is JCTree.JCMethodDecl -> it.typarams
else -> emptyList<JCTree.JCTypeParameter>()
}
}
.find { it.toString().substringBefore(" ") == leaf.toString() }
?.let {
TreeBasedTypeParameter(it,
javac.getTreePath(it, compilationUnit),
javac)
}
}
fun JavaClass.findInner(name: String,
javac: JavacWrapper,
nameParts: List<String> = emptyList()) : JavaClass? {
nameParts.size.takeIf { it > 1 }?.let {
return find(FqName("${fqName!!.asString()}.${nameParts[0]}"), javac, nameParts)
}
if (name == this.fqName?.shortName()?.asString()) return this
with(FqName("${fqName!!.asString()}.$name")) {
javac.findClass(this)?.let { return it }
javac.getKotlinClassifier(this)?.let { return it }
}
supertypes.mapNotNull { it.classifier as? JavaClass }
.forEach { javaClass ->
javaClass.findInner(name, javac)?.let { inner -> return inner }
}.let { return null }
}
fun tryToResolveByFqName(name: String,
javac: JavacWrapper) = with(FqName(name)) {
javac.findClass(this) ?: javac.getKotlinClassifier(this)
}
fun tryToResolveInJavaLang(name: String,
javac: JavacWrapper) = javac.findClass(FqName("java.lang.$name"))
fun find(fqName: FqName,
javac: JavacWrapper,
nameParts: List<String>): JavaClass? {
val initial = with(fqName) {
javac.findClass(this)
?: javac.getKotlinClassifier(this)
?: return null
}
nameParts.drop(1).fold(initial) {
javaClass, namePart -> javaClass.findInner(namePart, javac) ?: return null
}.let { return it }
}
@@ -0,0 +1,159 @@
/*
* 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.wrappers.trees
import com.sun.source.util.TreePath
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.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import javax.lang.model.type.TypeKind
abstract class TreeBasedType<out T : JCTree>(
val tree: T,
val treePath: TreePath,
val javac: JavacWrapper
) : JavaType, JavaAnnotationOwner {
companion object {
fun <Type : JCTree> create(tree: Type, treePath: TreePath, javac: JavacWrapper) = when (tree) {
is JCTree.JCPrimitiveTypeTree -> TreeBasedPrimitiveType(tree, TreePath(treePath, tree), javac)
is JCTree.JCArrayTypeTree -> TreeBasedArrayType(tree, TreePath(treePath, tree), javac)
is JCTree.JCWildcard -> TreeBasedWildcardType(tree, TreePath(treePath, tree), javac)
is JCTree.JCTypeApply -> TreeBasedGenericClassifierType(tree, TreePath(treePath, tree), javac)
is JCTree.JCExpression -> TreeBasedNonGenericClassifierType(tree, TreePath(treePath, tree), javac)
else -> throw UnsupportedOperationException("Unsupported type: $tree")
}
}
override val annotations: Collection<JavaAnnotation>
get() = emptyList()
override val isDeprecatedInJavaDoc: Boolean
get() = false
override fun findAnnotation(fqName: FqName) = annotations.find { it.classId?.asSingleFqName() == fqName }
override fun equals(other: Any?) = (other as? TreeBasedType<*>)?.tree == tree
override fun hashCode() = tree.hashCode()
override fun toString() = tree.toString()
}
class TreeBasedPrimitiveType(
tree: JCTree.JCPrimitiveTypeTree,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedType<JCTree.JCPrimitiveTypeTree>(tree, treePath, javac), JavaPrimitiveType {
override val type: PrimitiveType?
get() = if (tree.primitiveTypeKind == TypeKind.VOID) {
null
}
else {
JvmPrimitiveType.get(tree.toString()).primitiveType
}
}
class TreeBasedArrayType(
tree: JCTree.JCArrayTypeTree,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedType<JCTree.JCArrayTypeTree>(tree, treePath, javac), JavaArrayType {
override val componentType: JavaType
get() = create(tree.elemtype, treePath, javac)
}
class TreeBasedWildcardType(
tree: JCTree.JCWildcard,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedType<JCTree.JCWildcard>(tree, treePath, javac), JavaWildcardType {
override val bound: JavaType?
get() = tree.bound?.let { create(it, treePath, javac) }
override val isExtends: Boolean
get() = tree.kind.kind == BoundKind.EXTENDS
}
sealed class TreeBasedClassifierType<out T : JCTree>(
tree: T,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedType<T>(tree, treePath, javac), JavaClassifierType {
override val classifier: JavaClassifier?
get() = javac.resolve(treePath)
override val classifierQualifiedName: String
get() = (classifier as? JavaClass)?.fqName?.asString() ?: treePath.leaf.toString()
override val presentableText: String
get() = classifierQualifiedName
private val typeParameter: JCTree.JCTypeParameter?
get() = treePath.flatMap {
when (it) {
is JCTree.JCClassDecl -> it.typarams
is JCTree.JCMethodDecl -> it.typarams
else -> emptyList<JCTree.JCTypeParameter>()
}
}
.find { it.toString().substringBefore(" ") == treePath.leaf.toString() }
}
class TreeBasedNonGenericClassifierType(
tree: JCTree.JCExpression,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedClassifierType<JCTree.JCExpression>(tree, treePath, javac) {
override val typeArguments: List<JavaType>
get() = emptyList()
override val isRaw: Boolean
get() = (classifier as? MockKotlinClassifier)?.hasTypeParameters
?: (classifier as? JavaClass)?.typeParameters?.isNotEmpty()
?: false
}
class TreeBasedGenericClassifierType(
tree: JCTree.JCTypeApply,
treePath: TreePath,
javac: JavacWrapper
) : TreeBasedClassifierType<JCTree.JCTypeApply>(tree, treePath, javac) {
override val typeArguments: List<JavaType>
get() = tree.arguments.map { create(it, treePath, javac) }
override val isRaw: Boolean
get() = false
}
@@ -0,0 +1,61 @@
/*
* 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.wrappers.trees
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.name.ClassId
import javax.lang.model.element.Modifier
internal val JCTree.JCModifiers.isAbstract: Boolean
get() = Modifier.ABSTRACT in getFlags()
internal val JCTree.JCModifiers.isFinal: Boolean
get() = Modifier.FINAL in getFlags()
internal val JCTree.JCModifiers.isStatic: Boolean
get() = Modifier.STATIC in getFlags()
internal val JCTree.JCModifiers.hasDefaultModifier: Boolean
get() = Modifier.DEFAULT in getFlags()
internal val JCTree.JCModifiers.visibility: Visibility
get() = getFlags().let {
when {
Modifier.PUBLIC in it -> Visibilities.PUBLIC
Modifier.PRIVATE in it -> Visibilities.PRIVATE
Modifier.PROTECTED in it -> {
if (Modifier.STATIC in it) JavaVisibilities.PROTECTED_STATIC_VISIBILITY
else JavaVisibilities.PROTECTED_AND_PACKAGE
}
else -> JavaVisibilities.PACKAGE_VISIBILITY
}
}
internal fun JCTree.annotations(): Collection<JCTree.JCAnnotation> = when (this) {
is JCTree.JCMethodDecl -> mods?.annotations
is JCTree.JCClassDecl -> mods?.annotations
is JCTree.JCVariableDecl -> mods?.annotations
is JCTree.JCTypeParameter -> annotations
else -> null
} ?: emptyList<JCTree.JCAnnotation>()
fun JavaClass.computeClassId(): ClassId? =
outerClass?.computeClassId()?.createNestedClassId(name) ?: fqName?.let { ClassId.topLevel(it) }
+2
View File
@@ -14,6 +14,8 @@ where advanced options include:
Load definitions of built-in declarations from module dependencies, instead of from the compiler
-Xscript-resolver-environment=<key=value[,]>
Script resolver environment in key-value pairs (the value could be quoted and escaped)
-Xuse-javac Use javac for Java source and class files analysis
-Xjavac-arguments=<option[,]> Java compiler arguments
-Xno-inline Disable method inlining
-Xrepeat=<count> Repeat compilation (for performance analysis)
-Xskip-metadata-version-check Load classes with bad metadata version anyway (incl. pre-release classes)
+1 -1
View File
@@ -1,4 +1,4 @@
package test
// extra parameter is to preserve generic signature
fun anyany(a: Any, ignore: java.util.List<String>) = a
fun anyany(a: kotlin.Any, ignore: java.util.List<String>) = a
+1 -1
View File
@@ -1,3 +1,3 @@
package test
fun lll(a: Int) = a
fun lll(a: kotlin.Int) = a
@@ -1,4 +1,4 @@
package test
// extra parameter is to make sure generic signature is not erased
fun doNothing(array: IntArray, ignore: java.util.List<String>) = array
fun doNothing(array: kotlin.IntArray, ignore: java.util.List<String>) = array
@@ -0,0 +1,7 @@
package test;
public abstract class AbstractClass {
public abstract void implementMe();
}
@@ -0,0 +1,7 @@
package test
class AbstractClassImpl : AbstractClass() {
override fun implementMe() {}
}
@@ -0,0 +1,11 @@
package test
public abstract class AbstractClass {
public constructor AbstractClass()
public abstract fun implementMe(): kotlin.Unit
}
public final class AbstractClassImpl : test.AbstractClass {
public constructor AbstractClassImpl()
public open fun implementMe(): kotlin.Unit
}
@@ -0,0 +1,12 @@
package test;
public enum AbstractEnum {
ONE {
@Override
String getString() { return null; }
};
abstract String getString();
}
@@ -0,0 +1,3 @@
package test
fun useEnum() = AbstractEnum.ONE.getString()
@@ -0,0 +1,22 @@
package test
public fun useEnum(): kotlin.String!
public abstract enum class AbstractEnum : kotlin.Enum<test.AbstractEnum!> {
enum entry ONE
private constructor AbstractEnum()
public final /*fake_override*/ val name: kotlin.String
public final /*fake_override*/ val ordinal: kotlin.Int
protected final /*fake_override*/ fun clone(): kotlin.Any
public final /*fake_override*/ fun compareTo(/*0*/ test.AbstractEnum!): kotlin.Int
protected/*protected and package*/ final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.AbstractEnum!>!
public/*package*/ abstract fun getString(): kotlin.String!
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ kotlin.String): test.AbstractEnum
public open fun valueOf(/*0*/ kotlin.String!): test.AbstractEnum!
public open fun values(): kotlin.Array<(out) test.AbstractEnum!>!
public final /*synthesized*/ fun values(): kotlin.Array<test.AbstractEnum>
}
@@ -0,0 +1,12 @@
package test;
import java.lang.annotation.*;
@Target(value=ElementType.TYPE)
public @interface AnnotationWithArguments {
String name();
String arg() default "default";
}
@@ -0,0 +1,7 @@
package test
@AnnotationWithArguments(name="withDefault")
class ClassWithDefault
@AnnotationWithArguments(name="withoutDefault", arg="non")
class ClassWithoutDefault
@@ -0,0 +1,15 @@
package test
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FILE}) public final annotation class AnnotationWithArguments : kotlin.Annotation {
public constructor AnnotationWithArguments(/*0*/ kotlin.String, /*1*/ kotlin.String = ...)
public final val arg: kotlin.String
public final val name: kotlin.String
}
@test.AnnotationWithArguments(name = "withDefault") public final class ClassWithDefault {
public constructor ClassWithDefault()
}
@test.AnnotationWithArguments(arg = "non", name = "withoutDefault") public final class ClassWithoutDefault {
public constructor ClassWithoutDefault()
}
@@ -0,0 +1,9 @@
package test;
public @interface AnnotationWithField {
String text();
int ANSWER = 42;
}
@@ -0,0 +1,4 @@
package test
@AnnotationWithField(text="desc")
class SomeClass
@@ -0,0 +1,13 @@
package test
public final annotation class AnnotationWithField : kotlin.Annotation {
public constructor AnnotationWithField(/*0*/ kotlin.String)
public final val text: kotlin.String
// Static members
public const final val ANSWER: kotlin.Int
}
@test.AnnotationWithField(text = "desc") public final class SomeClass {
public constructor SomeClass()
}
@@ -0,0 +1,9 @@
package test;
import java.util.*;
public class AsteriskInImport {
public static List<String> getStrings() { return null; }
}
@@ -0,0 +1,3 @@
package test
fun getStrings() = AsteriskInImport.getStrings()
@@ -0,0 +1,10 @@
package test
public fun getStrings(): kotlin.collections.(Mutable)List<kotlin.String!>!
public open class AsteriskInImport {
public constructor AsteriskInImport()
// Static members
public open fun getStrings(): kotlin.collections.(Mutable)List<kotlin.String!>!
}
@@ -0,0 +1,7 @@
package test;
import test2.*;
public class CheckKotlinStub {
public KotlinStub getKotlinStub() { return null; }
}
@@ -0,0 +1,7 @@
package test2
import test.*
class KotlinStub
fun checkKotlinStub() = CheckKotlinStub().getKotlinStub()
@@ -0,0 +1,6 @@
package test
public open class CheckKotlinStub {
public constructor CheckKotlinStub()
public open fun getKotlinStub(): test2.KotlinStub!
}
@@ -0,0 +1,10 @@
package test;
import org.jetbrains.annotations.NotNull;
public class CheckNotNull {
@NotNull
public String returnNotNull() { return "42"; }
}
@@ -0,0 +1,3 @@
package test
fun notNullable(): String = CheckNotNull().returnNotNull()
@@ -0,0 +1,8 @@
package test
public fun notNullable(): kotlin.String
public open class CheckNotNull {
public constructor CheckNotNull()
@org.jetbrains.annotations.NotNull public open fun returnNotNull(): kotlin.String
}
+11
View File
@@ -0,0 +1,11 @@
package test;
public class Class {
private final String str;
public Class(String str) {
this.str = str;
}
}
+3
View File
@@ -0,0 +1,3 @@
package test
fun useClass() = Class("Hello")
+8
View File
@@ -0,0 +1,8 @@
package test
public fun useClass(): test.Class
public open class Class {
public constructor Class(/*0*/ kotlin.String!)
private final val str: kotlin.String!
}
@@ -0,0 +1,9 @@
package test;
public class ClassWithNestedEnum {
public enum NestedEnum {
ONE, TWO, THREE;
}
}
@@ -0,0 +1,3 @@
package test
fun test() = ClassWithNestedEnum.NestedEnum.ONE
@@ -0,0 +1,29 @@
package test
public fun test(): test.ClassWithNestedEnum.NestedEnum
public open class ClassWithNestedEnum {
public constructor ClassWithNestedEnum()
public final enum class NestedEnum : kotlin.Enum<test.ClassWithNestedEnum.NestedEnum!> {
enum entry ONE
enum entry TWO
enum entry THREE
private constructor NestedEnum()
public final /*fake_override*/ val name: kotlin.String
public final /*fake_override*/ val ordinal: kotlin.Int
protected final /*fake_override*/ fun clone(): kotlin.Any
public final /*fake_override*/ fun compareTo(/*0*/ test.ClassWithNestedEnum.NestedEnum!): kotlin.Int
protected/*protected and package*/ final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.ClassWithNestedEnum.NestedEnum!>!
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ kotlin.String): test.ClassWithNestedEnum.NestedEnum
public open fun valueOf(/*0*/ kotlin.String!): test.ClassWithNestedEnum.NestedEnum!
public open fun values(): kotlin.Array<(out) test.ClassWithNestedEnum.NestedEnum!>!
public final /*synthesized*/ fun values(): kotlin.Array<test.ClassWithNestedEnum.NestedEnum>
}
}
@@ -0,0 +1,7 @@
package test;
public class ClassWithTypeParameter<T extends KotlinInterface> {
public ClassWithTypeParameter(T kotlinInterface) {}
}
@@ -0,0 +1,15 @@
package test
interface KotlinInterface
class Impl1 : KotlinInterface
class Impl2 : KotlinInterface
class Impl3 : KotlinInterface
fun getProducer1() = Impl1().let(::ClassWithTypeParameter)
fun getProducer2() = Impl2().let(::ClassWithTypeParameter)
fun getProducer3() = Impl3().let(::ClassWithTypeParameter)
@@ -0,0 +1,24 @@
package test
public fun getProducer1(): test.ClassWithTypeParameter<test.Impl1>
public fun getProducer2(): test.ClassWithTypeParameter<test.Impl2>
public fun getProducer3(): test.ClassWithTypeParameter<test.Impl3>
public open class ClassWithTypeParameter</*0*/ T : test.KotlinInterface!> {
public constructor ClassWithTypeParameter</*0*/ T : test.KotlinInterface!>(/*0*/ T!)
}
public final class Impl1 : test.KotlinInterface {
public constructor Impl1()
}
public final class Impl2 : test.KotlinInterface {
public constructor Impl2()
}
public final class Impl3 : test.KotlinInterface {
public constructor Impl3()
}
public interface KotlinInterface {
}
@@ -0,0 +1,13 @@
package test;
public class CyclicDependencies {
public KotlinClass useKotlinClass() {
return new KotlinClass().getKotlinClass();
}
public KotlinClass2 useKotlinClass2(KotlinClass kotlinClass) {
return new KotlinClass2();
}
}
@@ -0,0 +1,13 @@
package test
class KotlinClass {
fun getKotlinClass() = KotlinClass()
}
class KotlinClass2 {
val str = "HELLO"
}
fun useJavaClass() = CyclicDependencies().apply {
useKotlinClass().let { useKotlinClass2(it) }
}.let { it.useKotlinClass2(it.useKotlinClass()) }
@@ -0,0 +1,19 @@
package test
public fun useJavaClass(): test.KotlinClass2!
public open class CyclicDependencies {
public constructor CyclicDependencies()
public open fun useKotlinClass(): test.KotlinClass!
public open fun useKotlinClass2(/*0*/ test.KotlinClass!): test.KotlinClass2!
}
public final class KotlinClass {
public constructor KotlinClass()
public final fun getKotlinClass(): test.KotlinClass
}
public final class KotlinClass2 {
public constructor KotlinClass2()
public final val str: kotlin.String
}
@@ -0,0 +1,11 @@
package test;
public class DefaultModifier implements WithDefault {
}
interface WithDefault {
default String getString() { return "str"; }
}
@@ -0,0 +1,3 @@
package test
fun useDefaultMethod() = DefaultModifier().getString()
@@ -0,0 +1,12 @@
package test
public fun useDefaultMethod(): kotlin.String!
public open class DefaultModifier : test.WithDefault {
public constructor DefaultModifier()
public open /*fake_override*/ fun getString(): kotlin.String!
}
public/*package*/ interface WithDefault {
public open fun getString(): kotlin.String!
}
@@ -0,0 +1,22 @@
package test;
class InterfaceImpl implements Interface {
interface BuilderImpl extends Interface.Builder {
@Override
Builder setKind(Kind kind);
}
Builder getBuilder() { return null; }
}
interface Interface {
enum Kind { DECLARATION; }
interface Builder {
Builder setKind(Kind kind);
}
}
@@ -0,0 +1,7 @@
package test
private class Impl : InterfaceImpl() {
private fun kind(kind: Interface.Kind) = getBuilder().setKind(kind)
}
@@ -0,0 +1,41 @@
package test
private final class Impl : test.InterfaceImpl {
public constructor Impl()
public/*package*/ open /*fake_override*/ fun getBuilder(): test.Interface.Builder!
private final fun kind(/*0*/ test.Interface.Kind): test.Interface.Builder!
}
public/*package*/ interface Interface {
public interface Builder {
public abstract fun setKind(/*0*/ test.Interface.Kind!): test.Interface.Builder!
}
public final enum class Kind : kotlin.Enum<test.Interface.Kind!> {
enum entry DECLARATION
private constructor Kind()
public final /*fake_override*/ val name: kotlin.String
public final /*fake_override*/ val ordinal: kotlin.Int
protected final /*fake_override*/ fun clone(): kotlin.Any
public final /*fake_override*/ fun compareTo(/*0*/ test.Interface.Kind!): kotlin.Int
protected/*protected and package*/ final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.Interface.Kind!>!
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ kotlin.String): test.Interface.Kind
public open fun valueOf(/*0*/ kotlin.String!): test.Interface.Kind!
public open fun values(): kotlin.Array<(out) test.Interface.Kind!>!
public final /*synthesized*/ fun values(): kotlin.Array<test.Interface.Kind>
}
}
public/*package*/ open class InterfaceImpl : test.Interface {
public/*package*/ constructor InterfaceImpl()
public/*package*/ open fun getBuilder(): test.Interface.Builder!
public/*package*/ interface BuilderImpl : test.Interface.Builder {
public abstract fun setKind(/*0*/ test.Interface.Kind!): test.Interface.Builder!
}
}
+5
View File
@@ -0,0 +1,5 @@
package test;
public enum Enum {
NORTH, SOUTH, WEST, EAST;
}
+8
View File
@@ -0,0 +1,8 @@
package test
fun checkEnum(e: Enum) = when(e) {
Enum.SOUTH -> println(1)
Enum.NORTH -> println(2)
Enum.WEST -> println(3)
Enum.EAST -> println(42)
}
+27
View File
@@ -0,0 +1,27 @@
package test
public fun checkEnum(/*0*/ test.Enum): kotlin.Unit
public final enum class Enum : kotlin.Enum<test.Enum!> {
enum entry NORTH
enum entry SOUTH
enum entry WEST
enum entry EAST
private constructor Enum()
public final /*fake_override*/ val name: kotlin.String
public final /*fake_override*/ val ordinal: kotlin.Int
protected final /*fake_override*/ fun clone(): kotlin.Any
public final /*fake_override*/ fun compareTo(/*0*/ test.Enum!): kotlin.Int
protected/*protected and package*/ final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.Enum!>!
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ kotlin.String): test.Enum
public open fun valueOf(/*0*/ kotlin.String!): test.Enum!
public open fun values(): kotlin.Array<(out) test.Enum!>!
public final /*synthesized*/ fun values(): kotlin.Array<test.Enum>
}
@@ -0,0 +1,5 @@
package test;
public enum EnumName {
FIRST, SECOND;
}
@@ -0,0 +1,3 @@
package test
fun func(enum: EnumName) = enum.name
+23
View File
@@ -0,0 +1,23 @@
package test
public fun func(/*0*/ test.EnumName): kotlin.String
public final enum class EnumName : kotlin.Enum<test.EnumName!> {
enum entry FIRST
enum entry SECOND
private constructor EnumName()
public final /*fake_override*/ val name: kotlin.String
public final /*fake_override*/ val ordinal: kotlin.Int
protected final /*fake_override*/ fun clone(): kotlin.Any
public final /*fake_override*/ fun compareTo(/*0*/ test.EnumName!): kotlin.Int
protected/*protected and package*/ final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<test.EnumName!>!
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ kotlin.String): test.EnumName
public open fun valueOf(/*0*/ kotlin.String!): test.EnumName!
public open fun values(): kotlin.Array<(out) test.EnumName!>!
public final /*synthesized*/ fun values(): kotlin.Array<test.EnumName>
}
@@ -0,0 +1,25 @@
package test;
public class Inheritance extends AbstractInheritance { }
abstract class AbstractInheritance implements Interface {
@Override public int getAnswer() { return 42; }
}
interface Interface extends I {
@Override
int getAnswer();
}
interface I {
int getAnswer();
}
interface I2 extends I {
@Override
int getAnswer();
}

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