J2K CliLightClassGenerationSupport: autoconvert

This commit is contained in:
Pavel V. Talanov
2015-09-08 16:38:49 +03:00
parent 8ded5e97ef
commit 0c884f10ee
@@ -14,285 +14,237 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.cli.jvm.compiler; package org.jetbrains.kotlin.cli.jvm.compiler
import com.google.common.base.Predicate; import com.google.common.base.Predicate
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager; import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiSearchScopeUtil; import com.intellij.psi.search.PsiSearchScopeUtil
import com.intellij.util.Function; import com.intellij.util.Function
import com.intellij.util.SmartList; import com.intellij.util.SmartList
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.asJava.KotlinLightClassForExplicitDeclaration
import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.asJava.KotlinLightClassForFacade
import org.jetbrains.kotlin.asJava.KotlinLightClassForExplicitDeclaration; import org.jetbrains.kotlin.asJava.LightClassConstructionContext
import org.jetbrains.kotlin.asJava.KotlinLightClassForFacade; import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.LightClassConstructionContext; import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor; import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer; import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils; import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.utils.*
import org.jetbrains.kotlin.util.slicedMap.WritableSlice; import java.util.Collections
import org.jetbrains.kotlin.utils.UtilsPackage;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* This class solves the problem of interdependency between analyzing Kotlin code and generating JetLightClasses * This class solves the problem of interdependency between analyzing Kotlin code and generating JetLightClasses
*
* Consider the following example: * Consider the following example:
*
* KClass.kt refers to JClass.java and vice versa * KClass.kt refers to JClass.java and vice versa
*
* To analyze KClass.kt we need to load descriptors from JClass.java, and to do that we need a JetLightClass instance for KClass, * To analyze KClass.kt we need to load descriptors from JClass.java, and to do that we need a JetLightClass instance for KClass,
* which can only be constructed when the structure of KClass is known. * which can only be constructed when the structure of KClass is known.
*
* To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses * To mitigate this, CliLightClassGenerationSupport hold a trace that is shared between the analyzer and JetLightClasses
*/ */
public class CliLightClassGenerationSupport extends LightClassGenerationSupport implements CodeAnalyzerInitializer { public class CliLightClassGenerationSupport(project: Project) : LightClassGenerationSupport(), CodeAnalyzerInitializer {
private final PsiManager psiManager; private val psiManager: PsiManager
private BindingContext bindingContext = null; private var bindingContext: BindingContext? = null
private ModuleDescriptor module = null; private var module: ModuleDescriptor? = null
public CliLightClassGenerationSupport(@NotNull Project project) { init {
this.psiManager = PsiManager.getInstance(project); this.psiManager = PsiManager.getInstance(project)
} }
@Override override fun initialize(trace: BindingTrace, module: ModuleDescriptor, analyzer: KotlinCodeAnalyzer?) {
public void initialize(@NotNull BindingTrace trace, @NotNull ModuleDescriptor module, @Nullable KotlinCodeAnalyzer analyzer) { this.bindingContext = trace.bindingContext
this.bindingContext = trace.getBindingContext(); this.module = module
this.module = module;
if (!(trace instanceof CliBindingTrace)) { if (trace !is CliBindingTrace) {
throw new IllegalArgumentException("Shared trace is expected to be subclass of " + CliBindingTrace.class.getSimpleName() + " class"); throw IllegalArgumentException("Shared trace is expected to be subclass of " + javaClass<CliBindingTrace>().simpleName + " class")
} }
((CliBindingTrace) trace).setKotlinCodeAnalyzer(analyzer); trace.setKotlinCodeAnalyzer(analyzer)
} }
@NotNull private fun getBindingContext(): BindingContext {
private BindingContext getBindingContext() { assert(bindingContext != null, "Call initialize() first")
assert bindingContext != null : "Call initialize() first"; return bindingContext
return bindingContext;
} }
@NotNull private fun getModule(): ModuleDescriptor {
private ModuleDescriptor getModule() { assert(module != null, "Call initialize() first")
assert module != null : "Call initialize() first"; return module
return module;
} }
@NotNull override fun getContextForPackage(files: Collection<JetFile>): LightClassConstructionContext {
@Override return getContext()
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
return getContext();
} }
@NotNull override fun getContextForClassOrObject(classOrObject: JetClassOrObject): LightClassConstructionContext {
@Override return getContext()
public LightClassConstructionContext getContextForClassOrObject(@NotNull JetClassOrObject classOrObject) {
return getContext();
} }
@NotNull private fun getContext(): LightClassConstructionContext {
private LightClassConstructionContext getContext() { return LightClassConstructionContext(bindingContext, getModule())
return new LightClassConstructionContext(bindingContext, getModule());
} }
@NotNull override fun findClassOrObjectDeclarations(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
@Override val classDescriptors = ResolveSessionUtils.getClassDescriptorsByFqName(getModule(), fqName)
public Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull final GlobalSearchScope searchScope) {
Collection<ClassDescriptor> classDescriptors = ResolveSessionUtils.getClassDescriptorsByFqName(getModule(), fqName);
return ContainerUtil.mapNotNull(classDescriptors, new Function<ClassDescriptor, JetClassOrObject>() { return ContainerUtil.mapNotNull(classDescriptors, object : Function<ClassDescriptor, JetClassOrObject> {
@Override override fun `fun`(descriptor: ClassDescriptor): JetClassOrObject? {
public JetClassOrObject fun(ClassDescriptor descriptor) { val element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor)
PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor); if (element is JetClassOrObject && PsiSearchScopeUtil.isInScope(searchScope, element)) {
if (element instanceof JetClassOrObject && PsiSearchScopeUtil.isInScope(searchScope, element)) { return element
return (JetClassOrObject) element;
} }
return null; return null
} }
}); })
} }
@NotNull override fun findFilesForPackage(fqName: FqName, searchScope: GlobalSearchScope): Collection<JetFile> {
@Override val files = getBindingContext().get(BindingContext.PACKAGE_TO_FILES, fqName)
public Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull final GlobalSearchScope searchScope) {
Collection<JetFile> files = getBindingContext().get(BindingContext.PACKAGE_TO_FILES, fqName);
if (files != null) { if (files != null) {
return Collections2.filter(files, new Predicate<JetFile>() { return Collections2.filter(files, object : Predicate<JetFile> {
@Override override fun apply(input: JetFile?): Boolean {
public boolean apply(JetFile input) { return PsiSearchScopeUtil.isInScope(searchScope, input)
return PsiSearchScopeUtil.isInScope(searchScope, input);
} }
}); })
} }
return Collections.emptyList(); return emptyList()
} }
@NotNull override fun findClassOrObjectDeclarationsInPackage(
@Override packageFqName: FqName, searchScope: GlobalSearchScope): Collection<JetClassOrObject> {
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage( val files = findFilesForPackage(packageFqName, searchScope)
@NotNull FqName packageFqName, @NotNull GlobalSearchScope searchScope val result = SmartList<JetClassOrObject>()
) { for (file in files) {
Collection<JetFile> files = findFilesForPackage(packageFqName, searchScope); for (declaration in file.declarations) {
List<JetClassOrObject> result = new SmartList<JetClassOrObject>(); if (declaration is JetClassOrObject) {
for (JetFile file : files) { result.add(declaration)
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetClassOrObject) {
result.add((JetClassOrObject) declaration);
} }
} }
} }
return result; return result
} }
@Override override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean {
public boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope) { return !getModule().getPackage(fqName).isEmpty()
return !getModule().getPackage(fqName).isEmpty();
} }
@NotNull override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> {
@Override val packageView = getModule().getPackage(fqn)
public Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope) { val members = packageView.memberScope.getDescriptors(DescriptorKindFilter.PACKAGES, JetScope.ALL_NAME_FILTER)
PackageViewDescriptor packageView = getModule().getPackage(fqn); return ContainerUtil.mapNotNull(members, object : Function<DeclarationDescriptor, FqName> {
Collection<DeclarationDescriptor> members = packageView.getMemberScope().getDescriptors(DescriptorKindFilter.PACKAGES, JetScope.ALL_NAME_FILTER); override fun `fun`(member: DeclarationDescriptor): FqName? {
return ContainerUtil.mapNotNull(members, new Function<DeclarationDescriptor, FqName>() { if (member is PackageViewDescriptor) {
@Override return member.fqName
public FqName fun(DeclarationDescriptor member) {
if (member instanceof PackageViewDescriptor) {
return ((PackageViewDescriptor) member).getFqName();
} }
return null; return null
} }
}); })
} }
@Nullable override fun getPsiClass(classOrObject: JetClassOrObject): PsiClass? {
@Override return KotlinLightClassForExplicitDeclaration.create(psiManager, classOrObject)
public PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject) {
return KotlinLightClassForExplicitDeclaration.Companion.create(psiManager, classOrObject);
} }
@NotNull override fun getPackageClasses(packageFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
@Override val filesInPackage = findFilesForPackage(packageFqName, scope)
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
Collection<JetFile> filesInPackage = findFilesForPackage(packageFqName, scope);
List<JetFile> filesWithCallables = PackagePartClassUtils.getFilesWithCallables(filesInPackage); val filesWithCallables = PackagePartClassUtils.getFilesWithCallables(filesInPackage)
if (filesWithCallables.isEmpty()) return Collections.emptyList(); if (filesWithCallables.isEmpty()) return emptyList()
//noinspection RedundantTypeArguments //noinspection RedundantTypeArguments
return UtilsPackage.<PsiClass>emptyOrSingletonList( return emptyOrSingletonList<PsiClass>(
KotlinLightClassForFacade.Factory.createForPackageFacade(psiManager, packageFqName, scope, filesWithCallables)); KotlinLightClassForFacade.createForPackageFacade(psiManager, packageFqName, scope, filesWithCallables))
} }
@Nullable override fun resolveClassToDescriptor(classOrObject: JetClassOrObject): ClassDescriptor? {
@Override return bindingContext!!.get(BindingContext.CLASS, classOrObject)
public ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject) {
return bindingContext.get(BindingContext.CLASS, classOrObject);
} }
@NotNull override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
@Override val filesForFacade = findFilesForFacade(facadeFqName, scope)
public Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) { if (filesForFacade.isEmpty()) return emptyList()
Collection<JetFile> filesForFacade = findFilesForFacade(facadeFqName, scope);
if (filesForFacade.isEmpty()) return Collections.emptyList();
//noinspection RedundantTypeArguments //noinspection RedundantTypeArguments
return UtilsPackage.<PsiClass>emptyOrSingletonList( return emptyOrSingletonList<PsiClass>(
KotlinLightClassForFacade.Factory.createForFacade(psiManager, facadeFqName, scope, filesForFacade)); KotlinLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade))
} }
@NotNull override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection<JetFile> {
@Override
public Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
// TODO We need a way to plug some platform-dependent stuff into LazyTopDownAnalyzer. // TODO We need a way to plug some platform-dependent stuff into LazyTopDownAnalyzer.
// It already performs some ad hoc stuff for packages->files mapping, anyway. // It already performs some ad hoc stuff for packages->files mapping, anyway.
Collection<JetFile> filesInPackage = findFilesForPackage(facadeFqName.parent(), scope); val filesInPackage = findFilesForPackage(facadeFqName.parent(), scope)
return PackagePartClassUtils.getFilesForPart(facadeFqName, filesInPackage); return PackagePartClassUtils.getFilesForPart(facadeFqName, filesInPackage)
} }
@NotNull override fun getContextForFacade(files: Collection<JetFile>): LightClassConstructionContext {
@Override return getContext()
public LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files) {
return getContext();
} }
@NotNull override fun createTrace(): BindingTraceContext {
@Override return NoScopeRecordCliBindingTrace()
public BindingTraceContext createTrace() {
return new NoScopeRecordCliBindingTrace();
} }
public static class NoScopeRecordCliBindingTrace extends CliBindingTrace { public class NoScopeRecordCliBindingTrace : CliBindingTrace() {
@Override override fun <K, V> record(slice: WritableSlice<K, V>, key: K, value: V) {
public <K, V> void record(WritableSlice<K, V> slice, K key, V value) { if (slice === BindingContext.RESOLUTION_SCOPE || slice === BindingContext.TYPE_RESOLUTION_SCOPE || slice === BindingContext.LEXICAL_SCOPE) {
if (slice == BindingContext.RESOLUTION_SCOPE || slice == BindingContext.TYPE_RESOLUTION_SCOPE
|| slice == BindingContext.LEXICAL_SCOPE) {
// In the compiler there's no need to keep scopes // In the compiler there's no need to keep scopes
return; return
} }
super.record(slice, key, value); super.record(slice, key, value)
} }
@Override override fun toString(): String {
public String toString() { return javaClass<NoScopeRecordCliBindingTrace>().name
return NoScopeRecordCliBindingTrace.class.getName();
} }
} }
public static class CliBindingTrace extends BindingTraceContext { public open class CliBindingTrace
private KotlinCodeAnalyzer kotlinCodeAnalyzer; TestOnly
constructor() : BindingTraceContext() {
private var kotlinCodeAnalyzer: KotlinCodeAnalyzer? = null
@TestOnly override fun toString(): String {
public CliBindingTrace() { return javaClass<CliBindingTrace>().name
} }
@Override public fun setKotlinCodeAnalyzer(kotlinCodeAnalyzer: KotlinCodeAnalyzer) {
public String toString() { this.kotlinCodeAnalyzer = kotlinCodeAnalyzer
return CliBindingTrace.class.getName();
} }
public void setKotlinCodeAnalyzer(KotlinCodeAnalyzer kotlinCodeAnalyzer) { override fun <K, V> get(slice: ReadOnlySlice<K, V>, key: K): V? {
this.kotlinCodeAnalyzer = kotlinCodeAnalyzer; val value = super.get(slice, key)
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
V value = super.get(slice, key);
if (value == null) { if (value == null) {
if (BindingContext.FUNCTION == slice || BindingContext.VARIABLE == slice) { if (BindingContext.FUNCTION === slice || BindingContext.VARIABLE === slice) {
if (key instanceof JetDeclaration) { if (key is JetDeclaration) {
JetDeclaration jetDeclaration = (JetDeclaration) key; if (!JetPsiUtil.isLocal(key)) {
if (!JetPsiUtil.isLocal(jetDeclaration)) { kotlinCodeAnalyzer!!.resolveToDescriptor(key)
kotlinCodeAnalyzer.resolveToDescriptor(jetDeclaration); return super.get(slice, key)
return super.get(slice, key);
} }
} }
} }
} }
return value; return value
} }
} }
} }