Merge branch 'master' of git+ssh://git.labs.intellij.net/jet

This commit is contained in:
James Strachan
2012-02-08 11:50:27 +00:00
15 changed files with 149 additions and 65 deletions
@@ -1,41 +0,0 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.util.QualifiedNamesUtil;
/**
* @author Nikolay Krasko
*/
public final class DescriptorsUtils {
private DescriptorsUtils() {
}
public static String getFQName(@NotNull NamespaceDescriptor namespaceDescriptor) {
NamespaceDescriptor tempNamespace = namespaceDescriptor;
String fqn = tempNamespace.getName();
while (tempNamespace.getContainingDeclaration() instanceof NamespaceDescriptor) {
tempNamespace = (NamespaceDescriptor) tempNamespace.getContainingDeclaration();
assert tempNamespace != null;
fqn = tempNamespace.getName() + "." + fqn;
}
return fqn;
}
public static String getFQName(@NotNull NamedFunctionDescriptor functionDescriptor) {
if (functionDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
final String namespaceFQN = getFQName((NamespaceDescriptor) functionDescriptor.getContainingDeclaration());
return QualifiedNamesUtil.combine(namespaceFQN, functionDescriptor.getName());
}
throw new IllegalArgumentException("Currently supported only for top level functions");
}
public static boolean isTopLevelFunction(@NotNull NamedFunctionDescriptor functionDescriptor) {
return functionDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
}
}
@@ -138,6 +138,17 @@ public class JetPsiUtil {
return jetClass.getName();
}
@Nullable @JetElement.IfNotParsed
public static String getImportPath(JetImportDirective importDirective) {
final JetExpression importedReference = importDirective.getImportedReference();
if (importedReference == null) {
return null;
}
final String text = importedReference.getText();
return text.replaceAll(" ", "") + (importDirective.isAllUnder() ? ".*" : "");
}
private static String makeFQName(String prefix, JetClassOrObject jetClass) {
return ((prefix == null || prefix.length() == 0) ? "" : prefix + ".") + jetClass.getName();
}
@@ -1,23 +1,16 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.psi.JetObjectDeclarationName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
@@ -175,6 +168,10 @@ public class DescriptorUtils {
return descriptor.getName();
}
public static boolean isTopLevelFunction(@NotNull NamedFunctionDescriptor functionDescriptor) {
return functionDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
}
@Nullable
public static <D extends DeclarationDescriptor> D getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class<D> aClass) {
return getParentOfType(descriptor, aClass, true);
@@ -100,4 +100,19 @@ public final class QualifiedNamesUtil {
return null;
}
/**
* Check that given fqn could be imported with import.
*
* @param importPath path from the import. Could contain .* part
* @param fqn
* @return
*/
public static boolean isImported(@NotNull String importPath, @NotNull String fqn) {
if (importPath.endsWith("*")) {
return withoutLastSegment(importPath).equals(withoutLastSegment(fqn));
}
return importPath.equals(fqn);
}
}
@@ -4,14 +4,18 @@ import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.DescriptorsUtils;
import org.jetbrains.jet.lang.descriptors.NamedFunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.plugin.completion.JetLookupObject;
import org.jetbrains.jet.plugin.quickfix.ImportClassHelper;
@@ -38,7 +42,10 @@ public class JetFunctionInsertHandler implements InsertHandler<LookupElement> {
int startOffset = context.getStartOffset();
PsiElement element = context.getFile().findElementAt(startOffset);
if (element == null) return;
if (element == null) {
return;
}
int lookupStringLength = item.getLookupString().length();
int endOffset = startOffset + lookupStringLength;
Document document = context.getDocument();
@@ -63,22 +70,43 @@ public class JetFunctionInsertHandler implements InsertHandler<LookupElement> {
PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument());
// Should be done after all string insertions and document commitment.
addImport(context, item);
}
private static void addImport(InsertionContext context, LookupElement item) {
if (context.getFile() instanceof JetFile && item.getObject() instanceof JetLookupObject) {
final DeclarationDescriptor descriptor = ((JetLookupObject) item.getObject()).getDescriptor();
if (descriptor instanceof NamedFunctionDescriptor) {
private static void addImport(final InsertionContext context, final @NotNull LookupElement item) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
int startOffset = context.getStartOffset();
PsiElement element = context.getFile().findElementAt(startOffset);
if (element == null) {
return;
}
JetFile file = (JetFile) context.getFile();
NamedFunctionDescriptor functionDescriptor = (NamedFunctionDescriptor) descriptor;
// No auto import for qualified expressions
if (PsiTreeUtil.getParentOfType(element, JetQualifiedExpression.class) != null) {
return;
}
if (DescriptorsUtils.isTopLevelFunction(functionDescriptor)) {
ImportClassHelper.addImportDirective(DescriptorsUtils.getFQName(functionDescriptor), file);
if (context.getFile() instanceof JetFile && item.getObject() instanceof JetLookupObject) {
final DeclarationDescriptor descriptor = ((JetLookupObject) item.getObject()).getDescriptor();
if (descriptor instanceof NamedFunctionDescriptor) {
final JetFile file = (JetFile) context.getFile();
NamedFunctionDescriptor functionDescriptor = (NamedFunctionDescriptor) descriptor;
final String fqn = DescriptorUtils.getFQName(functionDescriptor);
if (DescriptorUtils.isTopLevelFunction(functionDescriptor)) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
ImportClassHelper.addImportDirective(fqn, file);
}
});
}
}
}
}
}
});
}
}
@@ -52,10 +52,11 @@ public class ImportClassHelper {
JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importString);
if (!importDirectives.isEmpty()) {
// Check if import is already present
for (JetImportDirective directive : importDirectives) {
if (directive.getText().endsWith(importString) || directive.getText().endsWith(importString + ";")) {
String importPath = JetPsiUtil.getImportPath(directive);
if (importPath != null && QualifiedNamesUtil.isImported(importPath, importString)) {
return;
}
}
@@ -0,0 +1,7 @@
package some
import jettesting.*
fun other() {
data.topLevelFu<caret>
}
@@ -0,0 +1,4 @@
package jettesting.data
fun topLevelFunction() {
}
@@ -0,0 +1,7 @@
package some
import jettesting.*
fun other() {
data.topLevelFunction()
}
@@ -0,0 +1,6 @@
package some
import jettesting.data.*;
fun otherfun() {
}
@@ -0,0 +1,6 @@
package some
import jettesting.data.*;
fun otherfun() {
}
@@ -0,0 +1,6 @@
package some
import jettesting . data .*;
fun otherfun() {
}
@@ -0,0 +1,6 @@
package some
import jettesting . data .*;
fun otherfun() {
}
@@ -14,6 +14,10 @@ public class CompletionMultifileHandlerTest extends CompletionTestCase {
doTest();
}
public void testTopLevelFunctionInQualifiedExpr() {
doTest();
}
public void doTest() {
String fileName = getTestName(false);
try {
@@ -0,0 +1,27 @@
package org.jetbrains.jet.plugin.quickfix;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
/**
* @author Nikolay Krasko
*/
public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase {
public void testDoNotImportIfGeneralExist() {
configureByFile(getTestName(false) + ".kt");
ImportClassHelper.addImportDirective("jettesting.data.testFunction", (JetFile) getFile());
checkResultByFile(getTestName(false) + ".kt.after");
}
public void testDoNotImportIfGeneralSpaceExist() {
configureByFile(getTestName(false) + ".kt");
ImportClassHelper.addImportDirective("jettesting.data.testFunction", (JetFile) getFile());
checkResultByFile(getTestName(false) + ".kt.after");
}
@Override
protected String getTestDataPath() {
return PluginTestCaseBase.getTestDataPathBase() + "/quickfix/importHelper/";
}
}