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 87c535193f7..492008697b4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -347,6 +347,20 @@ public class JetPsiUtil { return null; } + public static boolean isFirstPartInQualified(@NotNull JetSimpleNameExpression nameExpression) { + @SuppressWarnings("unchecked") JetUserType userType = PsiTreeUtil.getParentOfType(nameExpression, JetUserType.class, true, JetDeclaration.class); + if (userType != null) { + return PsiTreeUtil.isAncestor(userType.getFirstChild(), nameExpression, false); + } + + @SuppressWarnings("unchecked") JetQualifiedExpression qualifiedExpression = PsiTreeUtil.getParentOfType(nameExpression, JetQualifiedExpression.class, true, JetDeclaration.class); + if (qualifiedExpression != null) { + return PsiTreeUtil.isAncestor(qualifiedExpression.getFirstChild(), nameExpression, false); + } + + return true; + } + public static boolean isVoidType(@Nullable JetTypeReference typeReference) { if (typeReference == null) { return false; diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java index a1616c15acc..f7fdff14d7b 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java @@ -46,6 +46,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.Visibilities; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; @@ -96,8 +97,11 @@ public class ImportClassAndFunFix extends JetHintAction ResolveSession resolveSession = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile((JetFile) element.getContainingFile()); List result = Lists.newArrayList(); - result.addAll(getClassNames(referenceName, (JetFile) file, resolveSession)); - result.addAll(getJetTopLevelFunctions(referenceName, element, resolveSession, file.getProject())); + if (!isSuppressedTopLevelImportInPosition(element)) { + result.addAll(getClassNames(referenceName, (JetFile) file, resolveSession)); + result.addAll(getJetTopLevelFunctions(referenceName, element, resolveSession, file.getProject())); + } + result.addAll(getJetExtensionFunctions(referenceName, element, resolveSession, file.getProject())); return Collections2.filter(result, new Predicate() { @@ -109,6 +113,10 @@ public class ImportClassAndFunFix extends JetHintAction }); } + private static boolean isSuppressedTopLevelImportInPosition(@NotNull JetSimpleNameExpression element) { + return element.isImportDirectiveExpression() || !JetPsiUtil.isFirstPartInQualified(element); + } + private static Collection getJetTopLevelFunctions( @NotNull String referenceName, @NotNull JetSimpleNameExpression expression, diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt new file mode 100644 index 00000000000..ca9b31c4496 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.after.kt @@ -0,0 +1,10 @@ +// "Import" "true" +// ERROR: Unresolved reference: Some + +package testing + +import some.Some + +fun testing() { + Some.test() +} diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt new file mode 100644 index 00000000000..721957f11fc --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: Some + +package testing + +fun testing() { + Some.test() +} diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.data.Sample.kt b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.data.Sample.kt new file mode 100644 index 00000000000..944e1c7d7ac --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.data.Sample.kt @@ -0,0 +1,8 @@ +package some + +public class Some { + class object { + public fun test() { + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInUserType.after.kt b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.after.kt new file mode 100644 index 00000000000..50b103cf9f0 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.after.kt @@ -0,0 +1,7 @@ +// "Import" "true" +// ERROR: Unresolved reference: Some +package testing + +import some.Some + +class TestClass: Some.InnerInSome() \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.Main.kt b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.Main.kt new file mode 100644 index 00000000000..72b4d7ed41d --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.Main.kt @@ -0,0 +1,5 @@ +// "Import" "true" +// ERROR: Unresolved reference: Some +package testing + +class TestClass: Some.InnerInSome() \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.data.Sample.kt b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.data.Sample.kt new file mode 100644 index 00000000000..a99e62abb55 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importInFirstPartInUserType.before.data.Sample.kt @@ -0,0 +1,7 @@ +package some + +public class Some { + public open class InnerInSome { + + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.after.kt b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.after.kt new file mode 100644 index 00000000000..87756e6c90a --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.after.kt @@ -0,0 +1,8 @@ +// "Import" "false" +// ERROR: Unresolved reference: externalFun + +package testing + +fun some() { + testing.externalFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.Main.kt b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.Main.kt new file mode 100644 index 00000000000..87756e6c90a --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.Main.kt @@ -0,0 +1,8 @@ +// "Import" "false" +// ERROR: Unresolved reference: externalFun + +package testing + +fun some() { + testing.externalFun() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.data.Sample.kt b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.data.Sample.kt new file mode 100644 index 00000000000..a5f87d89639 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.data.Sample.kt @@ -0,0 +1,4 @@ +package some + +fun externalFun() { +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInImports.after.kt b/idea/testData/quickfix/autoImports/noImportInImports.after.kt new file mode 100644 index 00000000000..5c3faf9e4a8 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInImports.after.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +import testing.SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInImports.before.Main.kt b/idea/testData/quickfix/autoImports/noImportInImports.before.Main.kt new file mode 100644 index 00000000000..5c3faf9e4a8 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInImports.before.Main.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +import testing.SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInImports.before.data.Sample.kt b/idea/testData/quickfix/autoImports/noImportInImports.before.data.Sample.kt new file mode 100644 index 00000000000..e4df00781fe --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInImports.before.data.Sample.kt @@ -0,0 +1,4 @@ +package some + +public class SomeTest + diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.after.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.after.kt new file mode 100644 index 00000000000..9cd3ed822ca --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.after.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +val x = some.SomeTest() diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.Main.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.Main.kt new file mode 100644 index 00000000000..c5fe6af4f30 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.Main.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +val x = testing.SomeTest() diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.data.Sample.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.data.Sample.kt new file mode 100644 index 00000000000..30dac46a1f2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedExpressionNotFirst.before.data.Sample.kt @@ -0,0 +1,3 @@ +package some + +public class SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt new file mode 100644 index 00000000000..65e523502af --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.after.kt @@ -0,0 +1,7 @@ +// "Import" "false" +// ACTION: Change to constructor invocation +// ERROR: Unresolved reference: SomeTest + +package testing + +class Some: testing.SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt new file mode 100644 index 00000000000..65e523502af --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.Main.kt @@ -0,0 +1,7 @@ +// "Import" "false" +// ACTION: Change to constructor invocation +// ERROR: Unresolved reference: SomeTest + +package testing + +class Some: testing.SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.data.Sample.kt b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.data.Sample.kt new file mode 100644 index 00000000000..30dac46a1f2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInQualifiedUserTypeNotFirst.before.data.Sample.kt @@ -0,0 +1,3 @@ +package some + +public class SomeTest \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.after.kt b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.after.kt new file mode 100644 index 00000000000..0075eebc5e2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.after.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +val x = testing?.SomeTest() \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.Main.kt b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.Main.kt new file mode 100644 index 00000000000..0075eebc5e2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.Main.kt @@ -0,0 +1,6 @@ +// "Import" "false" +// ERROR: Unresolved reference: SomeTest + +package testing + +val x = testing?.SomeTest() \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.data.Sample.kt b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.data.Sample.kt new file mode 100644 index 00000000000..30dac46a1f2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/noImportInSafeQualifiedExpressionNotFirst.before.data.Sample.kt @@ -0,0 +1,3 @@ +package some + +public class SomeTest \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/AutoImportFixTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/AutoImportFixTest.java index 920f5a9e83d..ce210d79b1f 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/AutoImportFixTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/AutoImportFixTest.java @@ -38,10 +38,38 @@ public class AutoImportFixTest extends JetQuickFixMultiFileTest { doTest(); } + public void testImportInFirstPartInQualifiedExpression() throws Exception { + doTest(); + } + + public void testImportInFirstPartInUserType() throws Exception { + doTest(); + } + + public void testNoImportForFunInQualifiedNotFirst() throws Exception { + doTest(); + } + public void testNoImportForPrivateClass() throws Exception { doTest(); } + public void testNoImportInImports() throws Exception { + doTest(); + } + + public void testNoImportInQualifiedExpressionNotFirst() throws Exception { + doTest(); + } + + public void testNoImportInQualifiedUserTypeNotFirst() throws Exception { + doTest(); + } + + public void testNoImportInSafeQualifiedExpressionNotFirst() throws Exception { + doTest(); + } + @Override protected String getCheckFileName() { return getTestName(true) + ".after.kt"; diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixMultiFileTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixMultiFileTest.java index a7c2a17c890..231ced9e1f0 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixMultiFileTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixMultiFileTest.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.plugin.quickfix; +import com.google.common.collect.Sets; import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; @@ -26,11 +27,13 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Pair; import com.intellij.util.ui.UIUtil; import junit.framework.ComparisonFailure; +import org.jetbrains.jet.InTextDirectivesUtils; import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; /** * @author Nikolay Krasko @@ -41,6 +44,14 @@ public abstract class JetQuickFixMultiFileTest extends DaemonAnalyzerTestCase { return false; } + private static List getActionsTexts(List availableActions) { + List texts = new ArrayList(); + for (IntentionAction intentionAction : availableActions) { + texts.add(intentionAction.getText()); + } + return texts; + } + public void doTest() throws Exception { configureByFiles(null, getTestFileNames().toArray(new String[1])); @@ -69,20 +80,27 @@ public abstract class JetQuickFixMultiFileTest extends DaemonAnalyzerTestCase { @SuppressWarnings({"HardCodedStringLiteral"}) public void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath) throws Exception { - IntentionAction action = LightQuickFixTestCase.findActionWithText(getAvailableActions(), text); + List availableActions = getAvailableActions(); + IntentionAction action = LightQuickFixTestCase.findActionWithText(availableActions, text); + if (action == null) { if (actionShouldBeAvailable) { - List actions = getAvailableActions(); - List texts = new ArrayList(); - for (IntentionAction intentionAction : actions) { - texts.add(intentionAction.getText()); - } + List texts = getActionsTexts(availableActions); Collection infos = doHighlighting(); fail("Action with text '" + text + "' is not available in test " + testFullPath + "\n" + "Available actions (" + texts.size() + "): " + texts + "\n" + - actions + "\n" + + availableActions + "\n" + "Infos:" + infos); } + else { + Set validActions = Sets.newHashSet(InTextDirectivesUtils.findLinesWithPrefixRemoved("// ACTION:", getFile().getText())); + for (IntentionAction availableAction : availableActions) { + if (!validActions.contains(availableAction.getText())) { + fail(String.format("Unexpected action available at current position: %s. Use // ACTION: directive", + availableAction.getText())); + } + } + } } else { if (!actionShouldBeAvailable) { diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java index 5cffe1ce9db..c0d9b3fd0d1 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java @@ -25,6 +25,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.apache.commons.lang.SystemUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.InTextDirectivesUtils; import org.jetbrains.jet.JetTestCaseBuilder; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.diagnostics.Diagnostic; @@ -34,7 +35,6 @@ import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.plugin.highlighter.IdeErrorMessages; import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade; import org.jetbrains.jet.testing.ConfigRuntimeUtil; -import org.jetbrains.jet.InTextDirectivesUtils; import java.io.File; import java.io.FilenameFilter; @@ -132,8 +132,6 @@ public class JetQuickFixTest extends LightQuickFixTestCase { if (diagnostics.size() != 0) { List expectedErrorStrings = InTextDirectivesUtils.findLinesWithPrefixRemoved("// ERROR:", getFile().getText()); - System.out.println(getFile().getText()); - Collection expectedErrors = new HashSet(expectedErrorStrings); StringBuilder builder = new StringBuilder();