Merge remote-tracking branch 'origin/master'

This commit is contained in:
svtk
2012-01-13 13:28:35 +04:00
142 changed files with 2456 additions and 1299 deletions
+2
View File
@@ -13,6 +13,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="IDEA 10.x" jdkType="IDEA JDK" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -21,6 +22,7 @@
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" />
<orderEntry type="module" module-name="compiler-tests" />
<orderEntry type="module" module-name="jet.as.java.psi" />
</component>
</module>
@@ -0,0 +1,2 @@
#parse("File Header.java")
@@ -0,0 +1,14 @@
<html>
<body>
<table border="0" cellpadding="2" cellspacing="0" style="border-collapse: collapse">
<tr>
<td colspan="3">
<font face="verdana" size="-1">
This is a built-in template used by <b>IDEA</b> each time you create a
Kotlin file
</font>
</td>
</tr>
</table>
</body>
</html>
+9 -2
View File
@@ -14,6 +14,10 @@
</project-components>
<actions>
<action id="Kotlin.NewFile" class="org.jetbrains.jet.plugin.actions.NewKotlinFileAction">
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFromTemplate"/>
</action>
<action id="ShowJetExpressionType" class="org.jetbrains.jet.plugin.actions.ShowExpressionTypeAction"
text="Show Expression Type">
<keyboard-shortcut keymap="$default" first-keystroke="control shift Q"/>
@@ -32,6 +36,9 @@
</actions>
<extensions defaultExtensionNs="com.intellij">
<internalFileTemplate name="Kotlin File"/>
<fileTypeFactory implementation="org.jetbrains.jet.plugin.JetFileFactory"/>
<lang.syntaxHighlighterFactory key="jet" implementationClass="org.jetbrains.jet.plugin.JetSyntaxHighlighterFactory"/>
<lang.braceMatcher language="jet" implementationClass="org.jetbrains.jet.plugin.JetPairMatcher"/>
@@ -59,8 +66,8 @@
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
<java.elementFinder implementation="org.jetbrains.jet.plugin.java.JavaElementFinder"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.plugin.java.JetCodeBlockModificationListener"/>
<java.elementFinder implementation="org.jetbrains.jet.asJava.JavaElementFinder"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.asJava.JetCodeBlockModificationListener"/>
<toolWindow id="CodeWindow"
factoryClass="org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow$Factory"
@@ -1,6 +1,7 @@
package org.jetbrains.jet.plugin;
import com.intellij.ide.IconProvider;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
@@ -16,9 +17,13 @@ import javax.swing.*;
*/
public class JetIconProvider extends IconProvider {
public static final Icon ICON_FOR_OBJECT = PlatformIcons.ANONYMOUS_CLASS_ICON;
public static final Icon KOTLIN_ICON = IconLoader.getIcon("/org/jetbrains/jet/plugin/icons/kotlin16x16.png");
@Override
public Icon getIcon(@NotNull PsiElement psiElement, int flags) {
if (psiElement instanceof JetFile) {
return KOTLIN_ICON;
}
if (psiElement instanceof JetNamespaceHeader) {
return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? PlatformIcons.PACKAGE_OPEN_ICON : PlatformIcons.PACKAGE_ICON;
}
@@ -0,0 +1,22 @@
package org.jetbrains.jet.plugin.actions;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.actions.CreateFromTemplateAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import org.jetbrains.jet.plugin.JetIconProvider;
/**
* @author Nikolay Krasko
*/
public class NewKotlinFileAction extends CreateFromTemplateAction {
public NewKotlinFileAction() {
super(FileTemplateManager.getInstance().getInternalTemplate("Kotlin File"));
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setIcon(JetIconProvider.KOTLIN_ICON);
}
}
@@ -64,7 +64,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
if (element instanceof JetNamedFunction) {
JetNamedFunction jetFunction = (JetNamedFunction) element;
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, jetFunction);
final NamedFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, jetFunction);
if (functionDescriptor == null) return null;
final Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors();
Icon icon = isMember(functionDescriptor) ? (overriddenFunctions.isEmpty() ? PlatformIcons.METHOD_ICON : OVERRIDING_FUNCTION) : PlatformIcons.FUNCTION_ICON;
@@ -182,7 +182,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
);
}
private boolean isMember(@NotNull FunctionDescriptor functionDescriptor) {
private boolean isMember(@NotNull NamedFunctionDescriptor functionDescriptor) {
return functionDescriptor.getContainingDeclaration().getOriginal() instanceof ClassifierDescriptor;
}
@@ -54,8 +54,8 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns
}
for (DescriptorClassMember selectedElement : selectedElements) {
final DeclarationDescriptor descriptor = selectedElement.getDescriptor();
if (descriptor instanceof FunctionDescriptor) {
JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor);
if (descriptor instanceof NamedFunctionDescriptor) {
JetElement target = overrideFunction(project, (NamedFunctionDescriptor) descriptor);
body.addBefore(target, body.getRBrace());
}
else if (descriptor instanceof PropertyDescriptor) {
@@ -84,7 +84,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns
return JetPsiFactory.createProperty(project, bodyBuilder.toString());
}
private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) {
private static JetElement overrideFunction(Project project, NamedFunctionDescriptor descriptor) {
StringBuilder bodyBuilder = new StringBuilder("override fun ");
bodyBuilder.append(descriptor.getName());
bodyBuilder.append("(");
@@ -1,122 +0,0 @@
/*
* @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);
}
}
@@ -1,212 +0,0 @@
/*
* @author max
*/
package org.jetbrains.jet.plugin.java;
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.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.*;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.plugin.JetFileType;
import java.util.*;
public class JavaElementFinder extends PsiElementFinder {
private final Project project;
private final PsiManager psiManager;
private WeakHashMap<GlobalSearchScope, List<JetFile>> jetFiles = new WeakHashMap<GlobalSearchScope, List<JetFile>>();
public JavaElementFinder(Project project) {
this.project = project;
psiManager = PsiManager.getInstance(project);
// Monitoring for files instead of collecting them each time
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() {
@Override
public void fileCreated(VirtualFileEvent event) {
invalidateJetFilesCache();
}
@Override
public void fileDeleted(VirtualFileEvent event) {
invalidateJetFilesCache();
}
@Override
public void fileMoved(VirtualFileMoveEvent event) {
invalidateJetFilesCache();
}
@Override
public void fileCopied(VirtualFileCopyEvent event) {
invalidateJetFilesCache();
}
});
}
@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<JetFile> filesInScope = collectProjectJetFiles(project, scope);
for (JetFile file : filesInScope) {
final String packageName = JetPsiUtil.getFQName(file);
if (packageName != null && qualifiedName.startsWith(packageName)) {
if (qualifiedName.equals(fqn(packageName, JvmAbi.PACKAGE_CLASS))) {
answer.add(new JetLightClass(psiManager, file, qualifiedName));
}
else {
for (JetDeclaration declaration : file.getDeclarations()) {
scanClasses(answer, declaration, qualifiedName, packageName, file);
}
}
}
}
return answer.toArray(new PsiClass[answer.size()]);
}
private void scanClasses(List<PsiClass> answer, JetDeclaration declaration, String qualifiedName, String containerFqn, JetFile file) {
if (declaration instanceof JetClassOrObject) {
String localName = getLocalName(declaration);
if (localName != null) {
String fqn = fqn(containerFqn, localName);
if (qualifiedName.equals(fqn)) {
answer.add(new JetLightClass(psiManager, file, qualifiedName));
}
else {
for (JetDeclaration child : ((JetClassOrObject) declaration).getDeclarations()) {
scanClasses(answer, child, qualifiedName, fqn, file);
}
}
}
}
else if (declaration instanceof JetClassObject) {
scanClasses(answer, ((JetClassObject) declaration).getObjectDeclaration(), qualifiedName, containerFqn, file);
}
}
private static String getLocalName(JetDeclaration declaration) {
String given = declaration.getName();
if (given != null) return given;
if (declaration instanceof JetObjectDeclaration) {
return JetTypeMapper.getLocalNameForObject((JetObjectDeclaration) declaration);
}
return null;
}
@Override
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
Set<String> answer = new HashSet<String>();
String packageFQN = psiPackage.getQualifiedName();
for (JetFile psiFile : collectProjectJetFiles(project, GlobalSearchScope.allScope(project))) {
if (packageFQN.equals(JetPsiUtil.getFQName(psiFile))) {
answer.add(JvmAbi.PACKAGE_CLASS);
for (JetDeclaration declaration : psiFile.getDeclarations()) {
if (declaration instanceof JetClassOrObject) {
answer.add(getLocalName(declaration));
}
}
}
}
return answer;
}
private static String fqn(String packageName, String className) {
if (StringUtil.isEmpty(packageName)) return className;
return packageName + "." + className;
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName) {
final List<JetFile> psiFiles = collectProjectJetFiles(project, GlobalSearchScope.allScope(project));
for (JetFile psiFile : psiFiles) {
if (qualifiedName.equals(JetPsiUtil.getFQName(psiFile))) {
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<JetFile> filesInScope = collectProjectJetFiles(project, scope);
String packageFQN = psiPackage.getQualifiedName();
for (JetFile file : filesInScope) {
if (packageFQN.equals(JetPsiUtil.getFQName(file))) {
answer.add(new JetLightClass(psiManager, file, fqn(packageFQN, JvmAbi.PACKAGE_CLASS)));
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetClassOrObject) {
answer.add(new JetLightClass(psiManager, file, fqn(packageFQN, getLocalName(declaration))));
}
}
}
}
return answer.toArray(new PsiClass[answer.size()]);
}
private synchronized void invalidateJetFilesCache() {
jetFiles.clear();
}
private synchronized List<JetFile> collectProjectJetFiles(final Project project, @NotNull final GlobalSearchScope scope) {
List<JetFile> cachedFiles = jetFiles.get(scope);
if (cachedFiles == null) {
final List<JetFile> answer = new ArrayList<JetFile>();
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
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((JetFile) psiFile);
}
}
}
});
cachedFiles = answer;
jetFiles.put(scope, answer);
}
return cachedFiles;
}
}
@@ -1,112 +0,0 @@
/*
* @author max
*/
package org.jetbrains.jet.plugin.java;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiModificationTrackerImpl;
import com.intellij.psi.impl.PsiTreeChangeEventImpl;
import com.intellij.psi.impl.PsiTreeChangePreprocessor;
import com.intellij.psi.util.PsiModificationTracker;
import org.jetbrains.jet.lang.psi.JetBlockExpression;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetFile;
public class JetCodeBlockModificationListener implements PsiTreeChangePreprocessor {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jet.plugin.java.JetCodeBlockModificationListener");
private final PsiModificationTrackerImpl myModificationTracker;
public JetCodeBlockModificationListener(final PsiModificationTracker modificationTracker) {
myModificationTracker = (PsiModificationTrackerImpl) modificationTracker;
}
@Override
public void treeChanged(final PsiTreeChangeEventImpl event) {
switch (event.getCode()) {
case BEFORE_CHILDREN_CHANGE:
case BEFORE_PROPERTY_CHANGE:
case BEFORE_CHILD_MOVEMENT:
case BEFORE_CHILD_REPLACEMENT:
case BEFORE_CHILD_ADDITION:
case BEFORE_CHILD_REMOVAL:
break;
case CHILD_ADDED:
case CHILD_REMOVED:
case CHILD_REPLACED:
processChange(event.getParent(), event.getOldChild(), event.getChild());
break;
case CHILDREN_CHANGED:
// general childrenChanged() event after each change
if (!event.isGenericChildrenChange()) {
processChange(event.getParent(), event.getParent(), null);
}
break;
case CHILD_MOVED:
case PROPERTY_CHANGED:
myModificationTracker.incCounter();
break;
default:
LOG.error("Unknown code:" + event.getCode());
break;
}
}
private void processChange(final PsiElement parent, final PsiElement child1, final PsiElement child2) {
try {
if (!isInsideCodeBlock(parent)) {
if (parent != null && parent.getContainingFile() instanceof JetFile) {
myModificationTracker.incCounter();
}
else {
myModificationTracker.incOutOfCodeBlockModificationCounter();
}
return;
}
if (containsClassesInside(child1) || child2 != child1 && containsClassesInside(child2)) {
myModificationTracker.incCounter();
}
} catch (PsiInvalidElementAccessException e) {
myModificationTracker.incCounter(); // Shall not happen actually, just a pre-release paranoia
}
}
private static boolean containsClassesInside(final PsiElement element) {
if (element == null) return false;
if (element instanceof PsiClass) return true;
PsiElement child = element.getFirstChild();
while (child != null) {
if (containsClassesInside(child)) return true;
child = child.getNextSibling();
}
return false;
}
private static boolean isInsideCodeBlock(PsiElement element) {
if (element instanceof PsiFileSystemItem) {
return false;
}
if (element == null || element.getParent() == null) return true;
PsiElement parent = element;
while (true) {
if (parent instanceof PsiFile || parent instanceof PsiDirectory || parent == null) {
return false;
}
if (parent instanceof JetClass) return false; // anonymous or local class
if (parent instanceof JetBlockExpression) {
return true;
}
parent = parent.getParent();
}
}
}
@@ -1,178 +0,0 @@
/*
* @author max
*/
package org.jetbrains.jet.plugin.java;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
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.impl.light.AbstractLightClass;
import com.intellij.psi.stubs.PsiClassHolderFileStub;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
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.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.resolve.java.JetJavaMirrorMarker;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.Collections;
import java.util.List;
public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMarker {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jet.plugin.java.JetLightClass");
private final static Key<CachedValue<PsiJavaFileStub>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
private final JetFile file;
private final String qualifiedName;
private PsiClass delegate;
public JetLightClass(PsiManager manager, JetFile file, String qualifiedName) {
super(manager, JetLanguage.INSTANCE);
this.file = file;
this.qualifiedName = qualifiedName;
}
@Override
public String getName() {
int idx = qualifiedName.lastIndexOf('.');
return idx > 0 ? qualifiedName.substring(idx + 1) : qualifiedName;
}
@Override
public PsiElement copy() {
return new JetLightClass(getManager(), file, qualifiedName);
}
@Override
public PsiFile getContainingFile() {
return file;
}
@Override
public PsiClass getDelegate() {
if (delegate == null) {
delegate = findClass(qualifiedName, getStub());
if (delegate == null) {
delegate = findClass(qualifiedName, getStub());
}
}
return delegate;
}
private static PsiClass findClass(String fqn, StubElement<?> stub) {
if (stub instanceof PsiClassStub && Comparing.equal(fqn, ((PsiClassStub) stub).getQualifiedName())) {
return (PsiClass) stub.getPsi();
}
for (StubElement child : stub.getChildrenStubs()) {
PsiClass answer = findClass(fqn, child);
if (answer != null) return answer;
}
return null;
}
@Override
public String getQualifiedName() {
return qualifiedName;
}
private PsiJavaFileStub getStub() {
CachedValue<PsiJavaFileStub> answer = file.getUserData(JAVA_API_STUB);
if (answer == null) {
answer = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<PsiJavaFileStub>() {
@Override
public Result<PsiJavaFileStub> compute() {
return Result.create(calcStub(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
}, false);
file.putUserData(JAVA_API_STUB, answer);
}
return answer.getValue();
}
private PsiJavaFileStub calcStub() {
final PsiJavaFileStubImpl answer = new PsiJavaFileStubImpl(JetPsiUtil.getFQName(file), true);
final Project project = getProject();
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(JetFile namespace) {
PsiManager manager = PsiManager.getInstance(project);
stubStack.push(answer);
answer.setPsiFactory(new ClsWrapperStubPsiFactory());
final ClsFileImpl fakeFile = new ClsFileImpl((PsiManagerImpl) manager, new ClassFileViewProvider(manager, file.getVirtualFile())) {
@NotNull
@Override
public PsiClassHolderFileStub getStub() {
return answer;
}
};
fakeFile.setPhysical(false);
answer.setPsi(fakeFile);
try {
super.generateNamespace(namespace);
}
finally {
final StubElement pop = stubStack.pop();
if (pop != answer) {
LOG.error("Unbalanced stack operations: " + pop);
}
}
}
};
List<JetFile> files = Collections.singletonList(file);
final BindingContext context = AnalyzerFacade.shallowAnalyzeFiles(files);
state.compileCorrectFiles(context, files);
state.getFactory().files();
return answer;
}
@Override
public boolean isEquivalentTo(PsiElement another) {
return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName());
}
}
@@ -1,99 +0,0 @@
/*
* @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.jetbrains.jet.lang.resolve.java.JvmAbi;
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(JvmAbi.PACKAGE_CLASS) || name.endsWith("/" + JvmAbi.PACKAGE_CLASS)) {
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;
}
}
@@ -11,9 +11,9 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.ArrayList;
import java.util.Collection;
import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
@@ -83,6 +83,8 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
}
Collection<? extends DeclarationDescriptor> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (declarationDescriptors != null) return null;
// TODO: Need a better resolution for intrinsic function (KT-975)
return file;
}
@@ -91,15 +93,19 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
Collection<? extends DeclarationDescriptor> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (declarationDescriptors == null) return ResolveResult.EMPTY_ARRAY;
ResolveResult[] results = new ResolveResult[declarationDescriptors.size()];
int i = 0;
ArrayList<ResolveResult> results = new ArrayList<ResolveResult>(declarationDescriptors.size());
for (DeclarationDescriptor descriptor : declarationDescriptors) {
PsiElement element = bindingContext.get(DESCRIPTOR_TO_DECLARATION, descriptor);
if (element != null) {
results[i] = new PsiElementResolveResult(element, true);
i++;
if (element == null) {
// TODO: Need a better resolution for intrinsic function (KT-975)
element = file;
}
results.add(new PsiElementResolveResult(element, true));
}
return results;
return results.toArray(new ResolveResult[results.size()]);
}
}
@@ -6,8 +6,16 @@ import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.util.Function;
import com.intellij.util.PsiIconUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import javax.swing.*;
import java.util.ArrayList;
@@ -19,8 +27,17 @@ import java.util.List;
public class JetStructureViewElement implements StructureViewTreeElement {
private final NavigatablePsiElement myElement;
public JetStructureViewElement(NavigatablePsiElement element) {
// For file context will be updated after each construction
// For other tree sub-elements it's immutable.
private BindingContext context;
public JetStructureViewElement(NavigatablePsiElement element, BindingContext context) {
myElement = element;
this.context = context;
}
public JetStructureViewElement(JetFile fileElement) {
myElement = fileElement;
}
@Override
@@ -48,13 +65,29 @@ public class JetStructureViewElement implements StructureViewTreeElement {
return new ItemPresentation() {
@Override
public String getPresentableText() {
String name = myElement.getName();
if (StringUtil.isEmpty(name)) {
String text = "";
// Try to find text in correspondent descriptor
// if (myElement instanceof JetDeclaration) {
// JetDeclaration declaration = (JetDeclaration) myElement;
// final DeclarationDescriptor descriptor =
// context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
//
// if (descriptor != null) {
// text = getDescriptorTreeText(descriptor);
// }
// }
if (StringUtil.isEmpty(text)) {
text = myElement.getName();
}
if (StringUtil.isEmpty(text)) {
if (myElement instanceof JetClassInitializer) {
return "<class initializer>";
}
}
return name;
return text;
}
@Override
@@ -64,20 +97,26 @@ public class JetStructureViewElement implements StructureViewTreeElement {
@Override
public Icon getIcon(boolean open) {
return myElement.isValid()
? PsiIconUtil.getProvidersIcon(myElement, open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED)
: null;
if (myElement.isValid()) {
return PsiIconUtil.getProvidersIcon(
myElement,
open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED);
}
return null;
}
};
}
@Override
public TreeElement[] getChildren() {
if (myElement instanceof JetFile) {
return new TreeElement[] { new JetStructureViewElement(myElement) };
}
else if (myElement instanceof JetFile) {
return wrapDeclarations(((JetFile) myElement).getDeclarations());
final JetFile jetFile = (JetFile) myElement;
// TODO: Understand why it significantly reduce responsibility of IDEA during typing
// context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile);
return wrapDeclarations(jetFile.getDeclarations());
}
else if (myElement instanceof JetClass) {
JetClass jetClass = (JetClass) myElement;
@@ -89,19 +128,68 @@ public class JetStructureViewElement implements StructureViewTreeElement {
}
declarations.addAll(jetClass.getDeclarations());
return wrapDeclarations(declarations);
}
else if (myElement instanceof JetClassOrObject) {
return wrapDeclarations(((JetClassOrObject) myElement).getDeclarations());
}
return new TreeElement[0];
}
private static TreeElement[] wrapDeclarations(List<JetDeclaration> declarations) {
private TreeElement[] wrapDeclarations(List<JetDeclaration> declarations) {
TreeElement[] result = new TreeElement[declarations.size()];
for (int i = 0; i < declarations.size(); i++) {
result[i] = new JetStructureViewElement(declarations.get(i));
result[i] = new JetStructureViewElement(declarations.get(i), context);
}
return result;
}
public static String getDescriptorTreeText(@NotNull DeclarationDescriptor descriptor) {
StringBuilder textBuilder;
if (descriptor instanceof FunctionDescriptor) {
textBuilder = new StringBuilder();
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
ReceiverDescriptor receiver = functionDescriptor.getReceiverParameter();
if (receiver.exists()) {
textBuilder.append(DescriptorRenderer.TEXT.renderType(receiver.getType())).append(".");
}
textBuilder.append(functionDescriptor.getName());
String parametersString = StringUtil.join(
functionDescriptor.getValueParameters(),
new Function<ValueParameterDescriptor, String>() {
@Override
public String fun(ValueParameterDescriptor valueParameterDescriptor) {
return valueParameterDescriptor.getName() + ":" +
DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType());
}
},
",");
textBuilder.append("(").append(parametersString).append(")");
JetType returnType = functionDescriptor.getReturnType();
textBuilder.append(":").append(DescriptorRenderer.TEXT.renderType(returnType));
}
else if (descriptor instanceof VariableDescriptor) {
JetType outType = ((VariableDescriptor) descriptor).getOutType();
textBuilder = new StringBuilder(descriptor.getName());
textBuilder.append(":").append(DescriptorRenderer.TEXT.renderType(outType));
}
else if (descriptor instanceof ClassDescriptor) {
textBuilder = new StringBuilder(descriptor.getName());
textBuilder
.append(" (")
.append(DescriptorUtils.getFQName(descriptor.getContainingDeclaration()))
.append(")");
}
else {
return DescriptorRenderer.TEXT.render(descriptor);
}
return textBuilder.toString();
}
}
@@ -6,6 +6,7 @@ import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
import com.intellij.lang.PsiStructureViewFactory;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
/**
* @author yole
@@ -13,12 +14,18 @@ import org.jetbrains.annotations.NotNull;
public class JetStructureViewFactory implements PsiStructureViewFactory {
@Override
public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
return new TreeBasedStructureViewBuilder() {
@NotNull
@Override
public StructureViewModel createStructureViewModel() {
return new JetStructureViewModel(psiFile);
}
};
if (psiFile instanceof JetFile) {
final JetFile file = (JetFile) psiFile;
return new TreeBasedStructureViewBuilder() {
@NotNull
@Override
public StructureViewModel createStructureViewModel() {
return new JetStructureViewModel(file);
}
};
}
return null;
}
}
@@ -1,16 +1,16 @@
package org.jetbrains.jet.plugin.structureView;
import com.intellij.ide.structureView.StructureViewModelBase;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFile;
/**
* @author yole
*/
public class JetStructureViewModel extends StructureViewModelBase {
public JetStructureViewModel(@NotNull PsiFile psiFile) {
super(psiFile, new JetStructureViewElement(psiFile));
public JetStructureViewModel(@NotNull JetFile jetFile) {
super(jetFile, new JetStructureViewElement(jetFile));
withSuitableClasses(JetDeclaration.class);
}
}
+8
View File
@@ -0,0 +1,8 @@
package ctrl_click
fun IntArray(vararg content : Int) : IntArray = content
fun <T> array(vararg t : T) : Array<T> = t
fun main(args : ArrayList<String>) {
var a = <caret>IntArray(array(1, 2, 3))
}
@@ -0,0 +1,89 @@
package org.jetbrains.jet.resolve;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.PsiReference;
import com.intellij.psi.ResolveResult;
import com.intellij.testFramework.LightCodeInsightTestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetTestCaseBuilder;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
/**
* @author Nikolay Krasko
*/
public class ResolveBaseTest extends LightCodeInsightTestCase {
private final String myPath;
private final String myName;
protected ResolveBaseTest(@NotNull String path, @NotNull String name) {
myPath = path;
myName = name;
// Set name explicitly because otherwise there will be "TestCase.fName cannot be null"
setName("testResolve");
}
@Override
protected Sdk getProjectJDK() {
return PluginTestCaseBase.jdkFromIdeaHome();
}
@Override
protected String getTestDataPath() {
return new File(PluginTestCaseBase.getTestDataPathBase(), myPath).getPath() +
File.separator;
}
@NotNull
@Override
public String getName() {
return "test" + myName;
}
public void testResolve() throws Exception {
doTest();
}
// TODO: Currently this test is only for KT-763 bug - it should be extended to framework for testing references
protected void doTest() throws Exception {
final String testName = getTestName(false);
configureByFile(testName + ".kt");
final PsiReference psiReference =
getFile().findReferenceAt(getEditor().getCaretModel().getOffset());
assertTrue(psiReference instanceof PsiPolyVariantReference);
final PsiPolyVariantReference variantReference = (PsiPolyVariantReference) psiReference;
final ResolveResult[] results = variantReference.multiResolve(true);
for (ResolveResult result : results) {
assertNotNull(result);
}
}
@NotNull
public static TestSuite suite() {
TestSuite suite = new TestSuite();
JetTestCaseBuilder.appendTestsInDirectory(
PluginTestCaseBase.getTestDataPathBase(), "/resolve/", false,
JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
@NotNull
@Override
public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) {
return new ResolveBaseTest(dataPath, name);
}
}, suite);
return suite;
}
}