BuiltInsReferenceResolver: J2K
This commit is contained in:
+149
-175
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user