From e8ffaa28f3597cc507ad72c74e8ce778df0608ed Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 8 Feb 2012 12:53:56 +0400 Subject: [PATCH 1/2] Don't add import after insertion function with fqn --- .../lang/descriptors/DescriptorsUtils.java | 41 --------------- .../jet/lang/resolve/DescriptorUtils.java | 17 +++--- .../handlers/JetFunctionInsertHandler.java | 52 ++++++++++++++----- .../TopLevelFunctionInQualifiedExpr-1.kt | 7 +++ .../TopLevelFunctionInQualifiedExpr-2.kt | 4 ++ .../TopLevelFunctionInQualifiedExpr.kt.after | 7 +++ .../CompletionMultifileHandlerTest.java | 4 ++ 7 files changed, 69 insertions(+), 63 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DescriptorsUtils.java create mode 100644 idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-1.kt create mode 100644 idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-2.kt create mode 100644 idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr.kt.after diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DescriptorsUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DescriptorsUtils.java deleted file mode 100644 index f28f1ec954c..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/DescriptorsUtils.java +++ /dev/null @@ -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; - } -} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 31e995218d6..51a0b9b2e2f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -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 getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class aClass) { return getParentOfType(descriptor, aClass, true); diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java index c3840eb2675..b7a5e8ed21c 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java @@ -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 { 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 { 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); + } + }); + } + } } } - } + }); } } diff --git a/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-1.kt b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-1.kt new file mode 100644 index 00000000000..62ef681718e --- /dev/null +++ b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-1.kt @@ -0,0 +1,7 @@ +package some + +import jettesting.* + +fun other() { + data.topLevelFu +} diff --git a/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-2.kt b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-2.kt new file mode 100644 index 00000000000..39c9b80f455 --- /dev/null +++ b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr-2.kt @@ -0,0 +1,4 @@ +package jettesting.data + +fun topLevelFunction() { +} \ No newline at end of file diff --git a/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr.kt.after b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr.kt.after new file mode 100644 index 00000000000..d3905ced711 --- /dev/null +++ b/idea/testData/completion/handlers/multifile/TopLevelFunctionInQualifiedExpr.kt.after @@ -0,0 +1,7 @@ +package some + +import jettesting.* + +fun other() { + data.topLevelFunction() +} diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java index e192c85ba5f..2257967233d 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java @@ -14,6 +14,10 @@ public class CompletionMultifileHandlerTest extends CompletionTestCase { doTest(); } + public void testTopLevelFunctionInQualifiedExpr() { + doTest(); + } + public void doTest() { String fileName = getTestName(false); try { From 01e71cbd5990b10f794cfc76cab53597f0532b4a Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 8 Feb 2012 15:27:41 +0400 Subject: [PATCH 2/2] Don't add import if there's general import with .* exist --- .../jetbrains/jet/lang/psi/JetPsiUtil.java | 11 ++++++++ .../jet/util/QualifiedNamesUtil.java | 15 +++++++++++ .../plugin/quickfix/ImportClassHelper.java | 5 ++-- .../importHelper/DoNotImportIfGeneralExist.kt | 6 +++++ .../DoNotImportIfGeneralExist.kt.after | 6 +++++ .../DoNotImportIfGeneralSpaceExist.kt | 6 +++++ .../DoNotImportIfGeneralSpaceExist.kt.after | 6 +++++ .../quickfix/ImportClassHelperTest.java | 27 +++++++++++++++++++ 8 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt create mode 100644 idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt.after create mode 100644 idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt create mode 100644 idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt.after create mode 100644 idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 3f1121d9a19..800cd647185 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -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(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java b/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java index db62e45c1d3..8d263ec272d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java @@ -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); + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java index 98b30a5375f..19c202ec5ab 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java @@ -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; } } diff --git a/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt new file mode 100644 index 00000000000..f7e6dce4946 --- /dev/null +++ b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt @@ -0,0 +1,6 @@ +package some + +import jettesting.data.*; + +fun otherfun() { +} diff --git a/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt.after b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt.after new file mode 100644 index 00000000000..f7e6dce4946 --- /dev/null +++ b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralExist.kt.after @@ -0,0 +1,6 @@ +package some + +import jettesting.data.*; + +fun otherfun() { +} diff --git a/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt new file mode 100644 index 00000000000..963032725e6 --- /dev/null +++ b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt @@ -0,0 +1,6 @@ +package some + +import jettesting . data .*; + +fun otherfun() { +} diff --git a/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt.after b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt.after new file mode 100644 index 00000000000..963032725e6 --- /dev/null +++ b/idea/testData/quickfix/importHelper/DoNotImportIfGeneralSpaceExist.kt.after @@ -0,0 +1,6 @@ +package some + +import jettesting . data .*; + +fun otherfun() { +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java new file mode 100644 index 00000000000..a1212528ed4 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/ImportClassHelperTest.java @@ -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/"; + } +}