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:
@@ -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()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// "Import" "true"
|
||||||
|
// ERROR: Unresolved reference: Some
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
fun testing() {
|
||||||
|
<caret>Some.test()
|
||||||
|
}
|
||||||
+8
@@ -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()
|
||||||
|
}
|
||||||
+4
@@ -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()
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Import" "false"
|
||||||
|
// ERROR: Unresolved reference: SomeTest
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
val x = testing.<caret>SomeTest()
|
||||||
+3
@@ -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
|
||||||
+3
@@ -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()
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Import" "false"
|
||||||
|
// ERROR: Unresolved reference: SomeTest
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
val x = testing?.<caret>SomeTest()
|
||||||
+3
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user