Added navigation to sources of builtin entities.

#KT-1069 fixed
This commit is contained in:
Evgeny Gerashchenko
2012-05-09 01:08:51 +04:00
parent 29a9fdde78
commit d6e3a392f6
4 changed files with 176 additions and 11 deletions
@@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import org.jetbrains.jet.util.slicedmap.Slices;
@@ -74,11 +73,6 @@ public class BindingContextUtils {
return element;
}
// TODO: Need to have a valid stubs for standard classes
if (referenceExpression != null && JetStandardClasses.getAllStandardClasses().contains(declarationDescriptor)) {
return referenceExpression.getContainingFile();
}
return null;
}
@@ -94,11 +88,6 @@ public class BindingContextUtils {
return elements;
}
// TODO: Need to have a valid stubs for standard classes
if (referenceExpression != null && JetStandardClasses.getAllStandardClasses().contains(declarationDescriptor)) {
return Lists.<PsiElement>newArrayList(referenceExpression.getContainingFile());
}
return Lists.newArrayList();
}
+3
View File
@@ -18,6 +18,9 @@
<component>
<implementation-class>org.jetbrains.jet.plugin.caches.JetCacheManager</implementation-class>
</component>
<component>
<implementation-class>org.jetbrains.jet.plugin.references.StandardLibraryReferenceResolver</implementation-class>
</component>
</project-components>
<actions>
@@ -110,6 +110,13 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
if (psiElement.size() > 1) {
return null;
}
if (psiElement.isEmpty()) {
PsiElement stdlibSymbol = myExpression.getProject().getComponent(StandardLibraryReferenceResolver.class)
.resolveStandardLibrarySymbol(bindingContext, myExpression);
if (stdlibSymbol != null) {
return stdlibSymbol;
}
}
Collection<? extends DeclarationDescriptor> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (declarationDescriptors != null) return null;
@@ -0,0 +1,166 @@
/*
* Copyright 2010-2012 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.jet.plugin.references;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
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.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.Collections;
import java.util.List;
public class StandardLibraryReferenceResolver extends AbstractProjectComponent {
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
private BindingContext bindingContext = null;
public StandardLibraryReferenceResolver(Project project) {
super(project);
}
@Override
public void initComponent() {
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
@Override
public void run() {
ensureInitialized();
}
});
}
private synchronized void ensureInitialized() {
if (bindingContext != null) {
return;
}
BindingTraceContext context = new BindingTraceContext();
NamespaceDescriptorImpl fakeRootNamespace = new NamespaceDescriptorImpl(new ModuleDescriptor("<fake_module>"),
Collections.<AnnotationDescriptor>emptyList(), "<root>");
NamespaceDescriptorImpl jetNamespace = new NamespaceDescriptorImpl(fakeRootNamespace,
Collections.<AnnotationDescriptor>emptyList(), "jet");
context.record(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, new FqName("jet"), jetNamespace);
WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, jetNamespace, RedeclarationHandler.THROW_EXCEPTION)
.setDebugName("Builtin classes scope");
scope.changeLockLevel(WritableScope.LockLevel.BOTH);
jetNamespace.initialize(scope);
TopDownAnalyzer.processStandardLibraryNamespace(myProject, context, scope, jetNamespace, getJetFiles("std"));
ClassDescriptor tuple0 = context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, new FqName("jet.Tuple0"));
assert tuple0 != null;
scope = new WritableScopeImpl(scope, jetNamespace, RedeclarationHandler.THROW_EXCEPTION).setDebugName("Builtin classes scope #2");
scope.changeLockLevel(WritableScope.LockLevel.BOTH);
scope.addClassifierAlias("Unit", tuple0);
jetNamespace.initialize(scope);
TopDownAnalyzer.processStandardLibraryNamespace(myProject, context, scope, jetNamespace, getJetFiles("jet"));
AnalyzingUtils.throwExceptionOnErrors(context.getBindingContext());
bindingContext = context.getBindingContext();
}
private List<JetFile> getJetFiles(String dir) {
String url = StandardLibraryReferenceResolver.class.getResource("/" + dir + "/").toString();
if (url.startsWith("jar:file:")) {
url = url.replace("jar:file:", "jar:/");
}
else if (url.startsWith("file:/")) {
url = url.replace("file:/", "file://");
}
else {
assert false;
}
VirtualFile vf = VirtualFileManager.getInstance().findFileByUrl(url);
assert vf != null;
PsiDirectory psiDirectory = PsiManager.getInstance(myProject).findDirectory(vf);
assert psiDirectory != null;
return ContainerUtil.mapNotNull(psiDirectory.getFiles(), new Function<PsiFile, JetFile>() {
@Override
public JetFile fun(PsiFile file) {
return file instanceof JetFile ? (JetFile) file : null;
}
});
}
@Nullable
private DeclarationDescriptor findCurrentDescriptor(@NotNull DeclarationDescriptor originalDescriptor) {
if (originalDescriptor instanceof ClassDescriptor) {
return bindingContext.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFQName(originalDescriptor).toSafe());
}
else if (originalDescriptor instanceof NamespaceDescriptor) {
return bindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, DescriptorUtils.getFQName(originalDescriptor).toSafe());
}
else {
DeclarationDescriptor parent = originalDescriptor.getContainingDeclaration();
if (parent == null) return null;
parent = findCurrentDescriptor(parent);
JetScope memberScope;
if (parent instanceof ClassDescriptor) {
memberScope = ((ClassDescriptor) parent).getDefaultType().getMemberScope();
}
else if (parent instanceof NamespaceDescriptor) {
memberScope = ((NamespaceDescriptor)parent).getMemberScope();
}
else {
return null;
}
String renderedOriginal = DescriptorRenderer.TEXT.render(originalDescriptor);
for (DeclarationDescriptor member : memberScope.getAllDescriptors()) {
if (renderedOriginal.equals(DescriptorRenderer.TEXT.render(member))) {
return member;
}
}
}
return null;
}
@Nullable
public PsiElement resolveStandardLibrarySymbol(@NotNull BindingContext originalContext, @Nullable JetReferenceExpression referenceExpression) {
ensureInitialized();
DeclarationDescriptor declarationDescriptor = BindingContextUtils.referenceToDescriptor(originalContext, referenceExpression);
if (declarationDescriptor != null) {
declarationDescriptor = declarationDescriptor.getOriginal();
declarationDescriptor = findCurrentDescriptor(declarationDescriptor);
if (declarationDescriptor != null) {
return BindingContextUtils.descriptorToDeclaration(bindingContext, declarationDescriptor);
}
}
return null;
}
}