Resolve Kotlin from Java, first drop.
This commit is contained in:
@@ -56,5 +56,7 @@
|
||||
<debugger.positionManagerFactory implementation="org.jetbrains.jet.plugin.debugger.JetPositionManagerFactory"/>
|
||||
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler"/>
|
||||
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
|
||||
|
||||
<java.elementFinder implementation="org.jetbrains.jet.plugin.java.JavaElementFinder"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.plugin.java;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.compiled.ClsClassImpl;
|
||||
import com.intellij.psi.impl.compiled.ClsEnumConstantImpl;
|
||||
import com.intellij.psi.impl.compiled.ClsFieldImpl;
|
||||
import com.intellij.psi.impl.compiled.ClsMethodImpl;
|
||||
import com.intellij.psi.impl.java.stubs.*;
|
||||
import com.intellij.psi.stubs.StubBase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class ClsWrapperStubPsiFactory extends StubPsiFactory {
|
||||
public static final Key<PsiElement> ORIGIN_ELEMENT = Key.create("ORIGIN_ELEMENT");
|
||||
private final StubPsiFactory delegate = new ClsStubPsiFactory();
|
||||
|
||||
@Override
|
||||
public PsiClass createClass(PsiClassStub stub) {
|
||||
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
|
||||
if (origin == null) return delegate.createClass(stub);
|
||||
|
||||
return new ClsClassImpl(stub) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
return origin;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiAnnotation createAnnotation(PsiAnnotationStub stub) {
|
||||
return delegate.createAnnotation(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiClassInitializer createClassInitializer(PsiClassInitializerStub stub) {
|
||||
return delegate.createClassInitializer(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiReferenceList createClassReferenceList(PsiClassReferenceListStub stub) {
|
||||
return delegate.createClassReferenceList(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiField createField(PsiFieldStub stub) {
|
||||
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
|
||||
if (origin == null) return delegate.createField(stub);
|
||||
if (stub.isEnumConstant()) {
|
||||
return new ClsEnumConstantImpl(stub) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
return origin;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
return new ClsFieldImpl(stub) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
return origin;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiImportList createImportList(PsiImportListStub stub) {
|
||||
return delegate.createImportList(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiImportStatementBase createImportStatement(PsiImportStatementStub stub) {
|
||||
return delegate.createImportStatement(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiMethod createMethod(PsiMethodStub stub) {
|
||||
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
|
||||
if (origin == null) return delegate.createMethod(stub);
|
||||
|
||||
return new ClsMethodImpl(stub) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement getNavigationElement() {
|
||||
return origin;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiModifierList createModifierList(PsiModifierListStub stub) {
|
||||
return delegate.createModifierList(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiParameter createParameter(PsiParameterStub stub) {
|
||||
return delegate.createParameter(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiParameterList createParameterList(PsiParameterListStub stub) {
|
||||
return delegate.createParameterList(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiTypeParameter createTypeParameter(PsiTypeParameterStub stub) {
|
||||
return delegate.createTypeParameter(stub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiTypeParameterList createTypeParameterList(PsiTypeParameterListStub stub) {
|
||||
return delegate.createTypeParameterList(stub);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.plugin.java;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.intellij.openapi.compiler.ex.CompilerPathsEx;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiManagerImpl;
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
||||
import com.intellij.psi.impl.file.PsiPackageImpl;
|
||||
import com.intellij.psi.impl.java.stubs.PsiClassStub;
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.PsiClassHolderFileStub;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.ClassBuilder;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactory;
|
||||
import org.jetbrains.jet.codegen.GenerationState;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaElementFinder extends PsiElementFinder {
|
||||
private final Project project;
|
||||
|
||||
public JavaElementFinder(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
private final static Key<PsiJavaFileStub> JAVA_API_STUB = Key.create("JAVA_API_STUB");
|
||||
|
||||
@Override
|
||||
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||
final PsiClass[] allClasses = findClasses(qualifiedName, scope);
|
||||
return allClasses.length > 0 ? allClasses[0] : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||
// Backend searches for java.lang.String. Will fail with SOE if continue
|
||||
if (qualifiedName.startsWith("java.")) return PsiClass.EMPTY_ARRAY;
|
||||
|
||||
List<PsiClass> answer = new SmartList<PsiClass>();
|
||||
final List<PsiFile> filesInScope = ensureUpToDate(scope);
|
||||
for (PsiFile file : filesInScope) {
|
||||
final PsiJavaFileStub stub = file.getUserData(JAVA_API_STUB);
|
||||
if (stub == null) continue;
|
||||
|
||||
final String packageName = stub.getPackageName();
|
||||
if (packageName != null && qualifiedName.startsWith(packageName)) {
|
||||
collectClasses(answer, qualifiedName, stub);
|
||||
}
|
||||
}
|
||||
return answer.toArray(new PsiClass[answer.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
||||
final List<PsiFile> psiFiles = collectProjectFiles(project, GlobalSearchScope.allScope(project));
|
||||
|
||||
for (PsiFile psiFile : psiFiles) {
|
||||
if (psiFile instanceof JetFile) {
|
||||
if (qualifiedName.equals(((JetFile) psiFile).getRootNamespace().getFQName())) {
|
||||
return new PsiPackageImpl(psiFile.getManager(), qualifiedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
||||
List<PsiClass> answer = new SmartList<PsiClass>();
|
||||
final List<PsiFile> filesInScope = ensureUpToDate(scope);
|
||||
final String qualifiedName = psiPackage.getQualifiedName();
|
||||
for (PsiFile file : filesInScope) {
|
||||
final PsiJavaFileStub stub = file.getUserData(JAVA_API_STUB);
|
||||
if (stub == null) continue;
|
||||
|
||||
if (Comparing.equal(qualifiedName, stub.getPackageName())) {
|
||||
for (StubElement child : stub.getChildrenStubs()) {
|
||||
if (child instanceof PsiClassStub) {
|
||||
answer.add((PsiClass) child.getPsi());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return answer.toArray(new PsiClass[answer.size()]);
|
||||
}
|
||||
|
||||
private static void collectClasses(List<PsiClass> answer, String qualifiedName, StubElement<?> stub) {
|
||||
if (stub instanceof PsiClassStub && qualifiedName.equals(((PsiClassStub) stub).getQualifiedName())) {
|
||||
answer.add((PsiClass) stub.getPsi());
|
||||
}
|
||||
|
||||
for (StubElement child : stub.getChildrenStubs()) {
|
||||
collectClasses(answer, qualifiedName, child);
|
||||
}
|
||||
}
|
||||
|
||||
private List<PsiFile> ensureUpToDate(GlobalSearchScope scope) {
|
||||
final Stack<StubElement> stubStack = new Stack<StubElement>();
|
||||
|
||||
final ClassBuilderFactory builderFactory = new ClassBuilderFactory() {
|
||||
@Override
|
||||
public ClassBuilder newClassBuilder() {
|
||||
return new StubClassBuilder(stubStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asText(ClassBuilder builder) {
|
||||
throw new UnsupportedOperationException("asText is not implemented"); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes(ClassBuilder builder) {
|
||||
throw new UnsupportedOperationException("asBytes is not implemented"); // TODO
|
||||
}
|
||||
};
|
||||
|
||||
final GenerationState state = new GenerationState(project, builderFactory) {
|
||||
@Override
|
||||
protected void generateNamespace(JetNamespace namespace) {
|
||||
final PsiJavaFileStubImpl fileStub = new PsiJavaFileStubImpl(namespace.getFQName(), true);
|
||||
PsiManager manager = PsiManager.getInstance(project);
|
||||
stubStack.push(fileStub);
|
||||
|
||||
final PsiFile file = namespace.getContainingFile();
|
||||
file.putUserData(JAVA_API_STUB, fileStub);
|
||||
fileStub.setPsiFactory(new ClsWrapperStubPsiFactory());
|
||||
final ClsFileImpl fakeFile = new ClsFileImpl((PsiManagerImpl) manager, new ClassFileViewProvider(manager, file.getVirtualFile())) {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassHolderFileStub getStub() {
|
||||
return fileStub;
|
||||
}
|
||||
};
|
||||
|
||||
fakeFile.setPhysical(false);
|
||||
fileStub.setPsi(fakeFile);
|
||||
|
||||
try {
|
||||
super.generateNamespace(namespace);
|
||||
}
|
||||
finally {
|
||||
final StubElement pop = stubStack.pop();
|
||||
assert pop == fileStub : "Unbalanced stack operations";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final List<PsiFile> psiFiles = collectProjectFiles(project, scope);
|
||||
|
||||
Collection<PsiFile> dirty = Collections2.filter(psiFiles, new Predicate<PsiFile>() {
|
||||
@Override
|
||||
public boolean apply(PsiFile psiFile) {
|
||||
return psiFile.getUserData(JAVA_API_STUB) == null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (dirty.size() > 0) {
|
||||
final BindingContext context = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).shallowAnalyzeFiles(dirty);
|
||||
state.compileCorrectNamespaces(context, AnalyzingUtils.collectRootNamespaces(dirty));
|
||||
state.getFactory().files();
|
||||
}
|
||||
|
||||
return psiFiles;
|
||||
}
|
||||
|
||||
private static List<PsiFile> collectProjectFiles(final Project project, @NotNull final GlobalSearchScope scope) {
|
||||
final List<PsiFile> answer = new ArrayList<PsiFile>();
|
||||
|
||||
|
||||
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
|
||||
final PsiManager psiManager = PsiManager.getInstance(project);
|
||||
|
||||
VirtualFile[] contentRoots = ProjectRootManager.getInstance(project).getContentRoots();
|
||||
CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() {
|
||||
@Override
|
||||
protected void acceptFile(VirtualFile file, String fileRoot, String filePath) {
|
||||
final FileType fileType = fileTypeManager.getFileTypeByFile(file);
|
||||
if (fileType != JetFileType.INSTANCE) return;
|
||||
|
||||
if (scope.accept(file)) {
|
||||
final PsiFile psiFile = psiManager.findFile(file);
|
||||
if (psiFile instanceof JetFile) {
|
||||
answer.add(psiFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package org.jetbrains.jet.plugin.java;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.compiled.InnerClassSourceStrategy;
|
||||
import com.intellij.psi.impl.compiled.StubBuildingVisitor;
|
||||
import com.intellij.psi.stubs.StubBase;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.ClassBuilder;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StubClassBuilder extends ClassBuilder {
|
||||
private static final InnerClassSourceStrategy<Object> EMPTY_STRATEGY = new InnerClassSourceStrategy<Object>() {
|
||||
@Override
|
||||
public Object findInnerClass(String s, Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassReader readerForInnerClass(Object o) {
|
||||
throw new UnsupportedOperationException("Shall not be called!");
|
||||
}
|
||||
};
|
||||
private final StubElement parent;
|
||||
private StubBuildingVisitor v;
|
||||
private final Stack<StubElement> parentStack;
|
||||
private boolean isNamespace = false;
|
||||
|
||||
public StubClassBuilder(Stack<StubElement> parentStack) {
|
||||
this.parentStack = parentStack;
|
||||
this.parent = parentStack.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassVisitor getVisitor() {
|
||||
assert v != null : "Called before class is defined";
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defineClass(PsiElement origin, int version, int access, String name, @Nullable String signature, String superName, String[] interfaces) {
|
||||
assert v == null : "defineClass() called twice?";
|
||||
v = new StubBuildingVisitor<Object>(null, EMPTY_STRATEGY, parent, access);
|
||||
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces);
|
||||
if (name.equals("namespace") || name.endsWith("/namespace")) {
|
||||
isNamespace = true;
|
||||
}
|
||||
else {
|
||||
parentStack.push(v.getResult());
|
||||
}
|
||||
|
||||
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor newMethod(@Nullable PsiElement origin, int access, String name, String desc, @Nullable String signature, @Nullable String[] exceptions) {
|
||||
final MethodVisitor answer = super.newMethod(origin, access, name, desc, signature, exceptions);
|
||||
markLastChild(origin);
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor newField(@Nullable PsiElement origin, int access, String name, String desc, @Nullable String signature, @Nullable Object value) {
|
||||
final FieldVisitor answer = super.newField(origin, access, name, desc, signature, value);
|
||||
markLastChild(origin);
|
||||
return answer;
|
||||
}
|
||||
|
||||
private void markLastChild(PsiElement origin) {
|
||||
final List children = v.getResult().getChildrenStubs();
|
||||
StubBase last = (StubBase) children.get(children.size() - 1);
|
||||
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
if (!isNamespace) {
|
||||
final StubElement pop = parentStack.pop();
|
||||
assert pop == v.getResult();
|
||||
}
|
||||
super.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateCode() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user