BuiltInsReferenceResolver: J2K

This commit is contained in:
Dmitry Jemerov
2015-07-30 17:26:26 +02:00
parent 13a8f86049
commit 79bbb820bd
3 changed files with 151 additions and 177 deletions
@@ -14,138 +14,113 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.references;
package org.jetbrains.kotlin.idea.references
import com.google.common.collect.Sets;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.asJava.LightClassUtil;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.context.ContextPackage;
import org.jetbrains.kotlin.context.MutableModuleContext;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.frontend.di.DiPackage;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingTraceContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.TargetPlatform;
import org.jetbrains.kotlin.resolve.lazy.ResolveSession;
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.types.DynamicTypesSettings;
import org.jetbrains.kotlin.utils.UtilsPackage;
import com.google.common.collect.Sets
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.AbstractProjectComponent
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.StartupManager
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.util.Function
import com.intellij.util.PathUtil
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.context.*
import org.jetbrains.kotlin.context.MutableModuleContext
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.frontend.di.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.types.DynamicTypesSettings
import org.jetbrains.kotlin.utils.*
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.io.File
import java.net.MalformedURLException
import java.net.URL
import java.util.HashSet
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassId;
import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies;
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
public class BuiltInsReferenceResolver extends AbstractProjectComponent {
private static final File BUILT_INS_COMPILABLE_SRC_DIR =
new File("core/builtins/src", KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString());
public class BuiltInsReferenceResolver(project: Project) : AbstractProjectComponent(project) {
private volatile ModuleDescriptor moduleDescriptor;
private volatile Set<JetFile> builtInsSources;
private volatile PackageFragmentDescriptor builtinsPackageFragment;
volatile private var moduleDescriptor: ModuleDescriptor? = null
volatile public var builtInsSources: Set<JetFile>? = null
private set
volatile private var builtinsPackageFragment: PackageFragmentDescriptor? = null
public BuiltInsReferenceResolver(Project project) {
super(project);
}
@Override
public void initComponent() {
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
@Override
public void run() {
initialize();
override fun initComponent() {
StartupManager.getInstance(myProject).registerPostStartupActivity(object : Runnable {
override fun run() {
initialize()
}
});
})
}
@TestOnly
public Set<JetFile> getBuiltInsSources() {
return builtInsSources;
}
private fun initialize() {
assert(moduleDescriptor == null, "Attempt to initialize twice")
private void initialize() {
assert moduleDescriptor == null : "Attempt to initialize twice";
val jetBuiltInsFiles = getJetBuiltInsFiles()
final Set<JetFile> jetBuiltInsFiles = getJetBuiltInsFiles();
val initializeRunnable = object : Runnable {
override fun run() {
val newModuleContext = ContextForNewModule(myProject, Name.special("<built-ins resolver module>"), ModuleParameters.Empty)
newModuleContext.setDependencies(newModuleContext.module)
final Runnable initializeRunnable = new Runnable() {
@Override
public void run() {
MutableModuleContext newModuleContext = ContextPackage
.ContextForNewModule(myProject, Name.special("<built-ins resolver module>"), ModuleParameters.Empty.INSTANCE$);
newModuleContext.setDependencies(newModuleContext.getModule());
val declarationFactory = FileBasedDeclarationProviderFactory(newModuleContext.storageManager, jetBuiltInsFiles)
FileBasedDeclarationProviderFactory declarationFactory =
new FileBasedDeclarationProviderFactory(newModuleContext.getStorageManager(), jetBuiltInsFiles);
val resolveSession = createLazyResolveSession(
newModuleContext,
declarationFactory, BindingTraceContext(),
TargetPlatform.Default)
ResolveSession resolveSession =
DiPackage.createLazyResolveSession(
newModuleContext,
declarationFactory, new BindingTraceContext(),
TargetPlatform.Default.INSTANCE$
);
newModuleContext.initializeModuleContents(resolveSession.getPackageFragmentProvider());
newModuleContext.initializeModuleContents(resolveSession.getPackageFragmentProvider())
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// Use lazy initialization in tests
resolveSession.forceResolveAll();
resolveSession.forceResolveAll()
}
PackageViewDescriptor packageView = newModuleContext.getModule().getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME);
List<PackageFragmentDescriptor> fragments = packageView.getFragments();
val packageView = newModuleContext.module.getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
val fragments = packageView.fragments
BuiltInsReferenceResolver.this.moduleDescriptor = newModuleContext.getModule();
builtinsPackageFragment = KotlinPackage.single(fragments);
builtInsSources = Sets.newHashSet(jetBuiltInsFiles);
this@BuiltInsReferenceResolver.moduleDescriptor = newModuleContext.module
builtinsPackageFragment = fragments.single()
builtInsSources = Sets.newHashSet(jetBuiltInsFiles)
}
};
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
initializeRunnable.run();
initializeRunnable.run()
}
else {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(initializeRunnable);
ApplicationManager.getApplication().executeOnPooledThread(object : Runnable {
override fun run() {
ApplicationManager.getApplication().runReadAction(initializeRunnable)
}
});
})
}
}
@NotNull
private Set<JetFile> getJetBuiltInsFiles() {
Set<JetFile> builtIns = getBuiltInSourceFiles(LightClassUtil.getBuiltInsDirUrl());
private fun getJetBuiltInsFiles(): Set<JetFile> {
val builtIns = getBuiltInSourceFiles(LightClassUtil.getBuiltInsDirUrl())
if (ApplicationManager.getApplication().isUnitTestMode()) {
// In production, the above URL is enough as it contains sources for both native and compilable built-ins
@@ -153,116 +128,115 @@ public class BuiltInsReferenceResolver extends AbstractProjectComponent {
// But in tests, sources of built-ins are not added to the classpath automatically, so we manually specify URLs for both:
// LightClassUtil.getBuiltInsDirUrl() does so for native built-ins and the code below for compilable built-ins
try {
builtIns.addAll(getBuiltInSourceFiles(BUILT_INS_COMPILABLE_SRC_DIR.toURI().toURL()));
builtIns.addAll(getBuiltInSourceFiles(BUILT_INS_COMPILABLE_SRC_DIR.toURI().toURL()))
}
catch (MalformedURLException e) {
throw UtilsPackage.rethrow(e);
catch (e: MalformedURLException) {
throw rethrow(e)
}
}
return builtIns;
return builtIns
}
@NotNull
private Set<JetFile> getBuiltInSourceFiles(@NotNull URL url) {
String fromUrl = VfsUtilCore.convertFromUrl(url);
VirtualFile vf = VirtualFileManager.getInstance().findFileByUrl(fromUrl);
assert vf != null : "Virtual file not found by URL: " + url;
private fun getBuiltInSourceFiles(url: URL): MutableSet<JetFile> {
val fromUrl = VfsUtilCore.convertFromUrl(url)
val vf = VirtualFileManager.getInstance().findFileByUrl(fromUrl)
assert(vf != null) { "Virtual file not found by URL: $url" }
// Refreshing VFS: in case the plugin jar was updated, the caches may hold the old value
vf.getChildren();
vf.refresh(false, true);
PathUtil.getLocalFile(vf).refresh(false, true);
vf!!.getChildren()
vf.refresh(false, true)
PathUtil.getLocalFile(vf).refresh(false, true)
PsiDirectory psiDirectory = PsiManager.getInstance(myProject).findDirectory(vf);
assert psiDirectory != null : "No PsiDirectory for " + vf;
return new HashSet<JetFile>(ContainerUtil.mapNotNull(psiDirectory.getFiles(), new Function<PsiFile, JetFile>() {
@Override
public JetFile fun(PsiFile file) {
return file instanceof JetFile ? (JetFile) file : null;
val psiDirectory = PsiManager.getInstance(myProject).findDirectory(vf)
assert(psiDirectory != null) { "No PsiDirectory for $vf" }
return HashSet(ContainerUtil.mapNotNull(psiDirectory!!.getFiles(), object : Function<PsiFile, JetFile> {
override fun `fun`(file: PsiFile): JetFile? {
return if (file is JetFile) file else null
}
}));
}))
}
@Nullable
private DeclarationDescriptor findCurrentDescriptorForMember(@NotNull MemberDescriptor originalDescriptor) {
if (!isFromBuiltinModule(originalDescriptor)) return null;
private fun findCurrentDescriptorForMember(originalDescriptor: MemberDescriptor): DeclarationDescriptor? {
if (!isFromBuiltinModule(originalDescriptor)) return null
DeclarationDescriptor containingDeclaration = findCurrentDescriptor(originalDescriptor.getContainingDeclaration());
JetScope memberScope = getMemberScope(containingDeclaration);
if (memberScope == null) return null;
val containingDeclaration = findCurrentDescriptor(originalDescriptor.getContainingDeclaration())
val memberScope = getMemberScope(containingDeclaration) ?: return null
String renderedOriginal = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(originalDescriptor);
Collection<? extends DeclarationDescriptor> descriptors;
if (originalDescriptor instanceof ConstructorDescriptor && containingDeclaration instanceof ClassDescriptor) {
descriptors = ((ClassDescriptor) containingDeclaration).getConstructors();
val renderedOriginal = DescriptorRenderer.FQ_NAMES_IN_TYPES.render(originalDescriptor)
val descriptors: Collection<DeclarationDescriptor>
if (originalDescriptor is ConstructorDescriptor && containingDeclaration is ClassDescriptor) {
descriptors = containingDeclaration.getConstructors()
}
else {
descriptors = memberScope.getAllDescriptors();
descriptors = memberScope.getAllDescriptors()
}
for (DeclarationDescriptor member : descriptors) {
if (renderedOriginal.equals(DescriptorRenderer.FQ_NAMES_IN_TYPES.render(member))) {
return member;
for (member in descriptors) {
if (renderedOriginal == DescriptorRenderer.FQ_NAMES_IN_TYPES.render(member)) {
return member
}
}
return null;
return null
}
@Nullable
private DeclarationDescriptor findCurrentDescriptor(@NotNull DeclarationDescriptor originalDescriptor) {
if (originalDescriptor instanceof ClassDescriptor) {
return isFromBuiltinModule(originalDescriptor)
? findClassAcrossModuleDependencies(moduleDescriptor, getClassId((ClassDescriptor) originalDescriptor))
: null;
private fun findCurrentDescriptor(originalDescriptor: DeclarationDescriptor): DeclarationDescriptor? {
if (originalDescriptor is ClassDescriptor) {
return if (isFromBuiltinModule(originalDescriptor))
moduleDescriptor!!.findClassAcrossModuleDependencies(originalDescriptor.classId)
else
null
}
else if (originalDescriptor instanceof PackageFragmentDescriptor) {
return isFromBuiltinModule(originalDescriptor)
&& KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.equals(((PackageFragmentDescriptor) originalDescriptor).getFqName())
? builtinsPackageFragment
: null;
else if (originalDescriptor is PackageFragmentDescriptor) {
return if (isFromBuiltinModule(originalDescriptor) && KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME == originalDescriptor.fqName)
builtinsPackageFragment
else
null
}
else if (originalDescriptor instanceof MemberDescriptor) {
return findCurrentDescriptorForMember((MemberDescriptor) originalDescriptor);
else if (originalDescriptor is MemberDescriptor) {
return findCurrentDescriptorForMember(originalDescriptor)
}
else {
return null;
return null
}
}
private static boolean isFromBuiltinModule(@NotNull DeclarationDescriptor originalDescriptor) {
// TODO This is optimization only
// It should be rewritten by checking declarationDescriptor.getSource(), when the latter returns something non-trivial for builtins.
return KotlinBuiltIns.getInstance().getBuiltInsModule() == DescriptorUtils.getContainingModule(originalDescriptor);
}
@Nullable
public PsiElement resolveBuiltInSymbol(@NotNull DeclarationDescriptor declarationDescriptor) {
public fun resolveBuiltInSymbol(declarationDescriptor: DeclarationDescriptor): PsiElement? {
if (moduleDescriptor == null) {
return null;
return null
}
DeclarationDescriptor descriptor = findCurrentDescriptor(declarationDescriptor);
val descriptor = findCurrentDescriptor(declarationDescriptor)
if (descriptor != null) {
return DescriptorToSourceUtils.getSourceFromDescriptor(descriptor);
return DescriptorToSourceUtils.getSourceFromDescriptor(descriptor)
}
return null;
return null
}
public static boolean isFromBuiltIns(@NotNull PsiElement element) {
//noinspection SuspiciousMethodCalls
return element.getProject().getComponent(BuiltInsReferenceResolver.class).builtInsSources.contains(element.getContainingFile());
}
companion object {
private val BUILT_INS_COMPILABLE_SRC_DIR = File("core/builtins/src", KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString())
@Nullable
private static JetScope getMemberScope(@Nullable DeclarationDescriptor parent) {
if (parent instanceof ClassDescriptor) {
return ((ClassDescriptor) parent).getDefaultType().getMemberScope();
private fun isFromBuiltinModule(originalDescriptor: DeclarationDescriptor): Boolean {
// TODO This is optimization only
// It should be rewritten by checking declarationDescriptor.getSource(), when the latter returns something non-trivial for builtins.
return KotlinBuiltIns.getInstance().getBuiltInsModule() == DescriptorUtils.getContainingModule(originalDescriptor)
}
else if (parent instanceof PackageFragmentDescriptor) {
return ((PackageFragmentDescriptor) parent).getMemberScope();
public fun isFromBuiltIns(element: PsiElement): Boolean {
//noinspection SuspiciousMethodCalls
return element.getProject().getComponent(javaClass<BuiltInsReferenceResolver>())!!.builtInsSources!!.contains(element.getContainingFile())
}
else {
return null;
private fun getMemberScope(parent: DeclarationDescriptor?): JetScope? {
if (parent is ClassDescriptor) {
return parent.getDefaultType().getMemberScope()
}
else if (parent is PackageFragmentDescriptor) {
return parent.getMemberScope()
}
else {
return null
}
}
}
}
@@ -89,7 +89,7 @@ public class QuickFixUtil {
}
public static boolean canModifyElement(@NotNull PsiElement element) {
return element.isWritable() && !BuiltInsReferenceResolver.isFromBuiltIns(element);
return element.isWritable() && !BuiltInsReferenceResolver.Companion.isFromBuiltIns(element);
}
@Nullable
@@ -80,7 +80,7 @@ public fun closeAndDeleteProject(): Unit =
ApplicationManager.getApplication().runWriteAction() { LightPlatformTestCase.closeAndDeleteProject() }
public fun unInvalidateBuiltins(project: Project, runnable: RunnableWithException) {
val builtInsSources = project.getComponent<org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver>(javaClass<BuiltInsReferenceResolver>())!!.getBuiltInsSources()
val builtInsSources = project.getComponent<org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver>(javaClass<BuiltInsReferenceResolver>())!!.builtInsSources!!
runnable.run()