KT-3133 Editor suggest to specify the package when it already has specified

Do not suggest imports in imports and in qualified names
 #KT-3133 Fixed
This commit is contained in:
Nikolay Krasko
2012-12-06 13:52:14 +04:00
parent 1092164684
commit c224b6441d
26 changed files with 206 additions and 12 deletions
@@ -347,6 +347,20 @@ public class JetPsiUtil {
return null; 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) { public static boolean isVoidType(@Nullable JetTypeReference typeReference) {
if (typeReference == null) { if (typeReference == null) {
return false; return false;
@@ -46,6 +46,7 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Visibilities; import org.jetbrains.jet.lang.descriptors.Visibilities;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.psi.JetFile; 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.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
@@ -96,8 +97,11 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
ResolveSession resolveSession = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile((JetFile) element.getContainingFile()); ResolveSession resolveSession = WholeProjectAnalyzerFacade.getLazyResolveSessionForFile((JetFile) element.getContainingFile());
List<FqName> result = Lists.newArrayList(); List<FqName> result = Lists.newArrayList();
result.addAll(getClassNames(referenceName, (JetFile) file, resolveSession)); if (!isSuppressedTopLevelImportInPosition(element)) {
result.addAll(getJetTopLevelFunctions(referenceName, element, resolveSession, file.getProject())); result.addAll(getClassNames(referenceName, (JetFile) file, resolveSession));
result.addAll(getJetTopLevelFunctions(referenceName, element, resolveSession, file.getProject()));
}
result.addAll(getJetExtensionFunctions(referenceName, element, resolveSession, file.getProject())); result.addAll(getJetExtensionFunctions(referenceName, element, resolveSession, file.getProject()));
return Collections2.filter(result, new Predicate<FqName>() { return Collections2.filter(result, new Predicate<FqName>() {
@@ -109,6 +113,10 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
}); });
} }
private static boolean isSuppressedTopLevelImportInPosition(@NotNull JetSimpleNameExpression element) {
return element.isImportDirectiveExpression() || !JetPsiUtil.isFirstPartInQualified(element);
}
private static Collection<FqName> getJetTopLevelFunctions( private static Collection<FqName> getJetTopLevelFunctions(
@NotNull String referenceName, @NotNull String referenceName,
@NotNull JetSimpleNameExpression expression, @NotNull JetSimpleNameExpression expression,
@@ -0,0 +1,10 @@
// "Import" "true"
// ERROR: Unresolved reference: Some
package testing
import some.Some
fun testing() {
<caret>Some.test()
}
@@ -0,0 +1,8 @@
// "Import" "true"
// ERROR: Unresolved reference: Some
package testing
fun testing() {
<caret>Some.test()
}
@@ -0,0 +1,8 @@
package some
public class Some {
class object {
public fun test() {
}
}
}
@@ -0,0 +1,7 @@
// "Import" "true"
// ERROR: Unresolved reference: Some
package testing
import some.Some
class TestClass: <caret>Some.InnerInSome()
@@ -0,0 +1,5 @@
// "Import" "true"
// ERROR: Unresolved reference: Some
package testing
class TestClass: <caret>Some.InnerInSome()
@@ -0,0 +1,7 @@
package some
public class Some {
public open class InnerInSome {
}
}
@@ -0,0 +1,8 @@
// "Import" "false"
// ERROR: Unresolved reference: externalFun
package testing
fun some() {
testing.<caret>externalFun()
}
@@ -0,0 +1,8 @@
// "Import" "false"
// ERROR: Unresolved reference: externalFun
package testing
fun some() {
testing.<caret>externalFun()
}
@@ -0,0 +1,4 @@
package some
fun externalFun() {
}
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
import testing.<caret>SomeTest
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
import testing.<caret>SomeTest
@@ -0,0 +1,4 @@
package some
public class SomeTest
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
val x = some.<caret>SomeTest()
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
val x = testing.<caret>SomeTest()
@@ -0,0 +1,3 @@
package some
public class SomeTest
@@ -0,0 +1,7 @@
// "Import" "false"
// ACTION: Change to constructor invocation
// ERROR: Unresolved reference: SomeTest
package testing
class Some: testing.<caret>SomeTest
@@ -0,0 +1,7 @@
// "Import" "false"
// ACTION: Change to constructor invocation
// ERROR: Unresolved reference: SomeTest
package testing
class Some: testing.<caret>SomeTest
@@ -0,0 +1,3 @@
package some
public class SomeTest
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
val x = testing?.<caret>SomeTest()
@@ -0,0 +1,6 @@
// "Import" "false"
// ERROR: Unresolved reference: SomeTest
package testing
val x = testing?.<caret>SomeTest()
@@ -0,0 +1,3 @@
package some
public class SomeTest
@@ -38,10 +38,38 @@ public class AutoImportFixTest extends JetQuickFixMultiFileTest {
doTest(); doTest();
} }
public void testImportInFirstPartInQualifiedExpression() throws Exception {
doTest();
}
public void testImportInFirstPartInUserType() throws Exception {
doTest();
}
public void testNoImportForFunInQualifiedNotFirst() throws Exception {
doTest();
}
public void testNoImportForPrivateClass() throws Exception { public void testNoImportForPrivateClass() throws Exception {
doTest(); 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 @Override
protected String getCheckFileName() { protected String getCheckFileName() {
return getTestName(true) + ".after.kt"; return getTestName(true) + ".after.kt";
@@ -16,6 +16,7 @@
package org.jetbrains.jet.plugin.quickfix; package org.jetbrains.jet.plugin.quickfix;
import com.google.common.collect.Sets;
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; 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.openapi.util.Pair;
import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.UIUtil;
import junit.framework.ComparisonFailure; import junit.framework.ComparisonFailure;
import org.jetbrains.jet.InTextDirectivesUtils;
import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author Nikolay Krasko * @author Nikolay Krasko
@@ -41,6 +44,14 @@ public abstract class JetQuickFixMultiFileTest extends DaemonAnalyzerTestCase {
return false; return false;
} }
private static List<String> getActionsTexts(List<IntentionAction> availableActions) {
List<String> texts = new ArrayList<String>();
for (IntentionAction intentionAction : availableActions) {
texts.add(intentionAction.getText());
}
return texts;
}
public void doTest() throws Exception { public void doTest() throws Exception {
configureByFiles(null, getTestFileNames().toArray(new String[1])); configureByFiles(null, getTestFileNames().toArray(new String[1]));
@@ -69,20 +80,27 @@ public abstract class JetQuickFixMultiFileTest extends DaemonAnalyzerTestCase {
@SuppressWarnings({"HardCodedStringLiteral"}) @SuppressWarnings({"HardCodedStringLiteral"})
public void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath) public void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath)
throws Exception { throws Exception {
IntentionAction action = LightQuickFixTestCase.findActionWithText(getAvailableActions(), text); List<IntentionAction> availableActions = getAvailableActions();
IntentionAction action = LightQuickFixTestCase.findActionWithText(availableActions, text);
if (action == null) { if (action == null) {
if (actionShouldBeAvailable) { if (actionShouldBeAvailable) {
List<IntentionAction> actions = getAvailableActions(); List<String> texts = getActionsTexts(availableActions);
List<String> texts = new ArrayList<String>();
for (IntentionAction intentionAction : actions) {
texts.add(intentionAction.getText());
}
Collection<HighlightInfo> infos = doHighlighting(); Collection<HighlightInfo> infos = doHighlighting();
fail("Action with text '" + text + "' is not available in test " + testFullPath + "\n" + fail("Action with text '" + text + "' is not available in test " + testFullPath + "\n" +
"Available actions (" + texts.size() + "): " + texts + "\n" + "Available actions (" + texts.size() + "): " + texts + "\n" +
actions + "\n" + availableActions + "\n" +
"Infos:" + infos); "Infos:" + infos);
} }
else {
Set<String> 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 { else {
if (!actionShouldBeAvailable) { if (!actionShouldBeAvailable) {
@@ -25,6 +25,7 @@ import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.apache.commons.lang.SystemUtils; import org.apache.commons.lang.SystemUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.InTextDirectivesUtils;
import org.jetbrains.jet.JetTestCaseBuilder; import org.jetbrains.jet.JetTestCaseBuilder;
import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.lang.diagnostics.Diagnostic; 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.highlighter.IdeErrorMessages;
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.testing.ConfigRuntimeUtil; import org.jetbrains.jet.testing.ConfigRuntimeUtil;
import org.jetbrains.jet.InTextDirectivesUtils;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
@@ -132,8 +132,6 @@ public class JetQuickFixTest extends LightQuickFixTestCase {
if (diagnostics.size() != 0) { if (diagnostics.size() != 0) {
List<String> expectedErrorStrings = InTextDirectivesUtils.findLinesWithPrefixRemoved("// ERROR:", getFile().getText()); List<String> expectedErrorStrings = InTextDirectivesUtils.findLinesWithPrefixRemoved("// ERROR:", getFile().getText());
System.out.println(getFile().getText());
Collection<String> expectedErrors = new HashSet<String>(expectedErrorStrings); Collection<String> expectedErrors = new HashSet<String>(expectedErrorStrings);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();