diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java index d513b80f588b..9b45d139d5ff 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCharFilter.java @@ -42,7 +42,7 @@ public class JavaCharFilter extends CharFilter { return psiElement != null && psiElement.getParent() instanceof PsiLiteralExpression; } - public static boolean isNonImportedClassEntered(LookupImpl lookup) { + public static boolean isNonImportedClassEntered(LookupImpl lookup, boolean orPackage) { if (lookup.isSelectionTouched() || !lookup.isCompletion()) return false; CompletionProcess process = CompletionService.getCompletionService().getCurrentCompletion(); @@ -66,6 +66,10 @@ public class JavaCharFilter extends CharFilter { } } + if (orPackage && prefix.length() > 1 && JavaPsiFacade.getInstance(file.getProject()).findPackage(prefix) != null) { + return true; + } + return false; } @@ -117,7 +121,8 @@ public class JavaCharFilter extends CharFilter { return Result.HIDE_LOOKUP; } - if ((c == '[' || c == '<' || c == '.' || c == ' ' || c == '(') && isNonImportedClassEntered((LookupImpl)lookup)) { + if ((c == '[' || c == '<' || c == '.' || c == ' ' || c == '(') && + isNonImportedClassEntered((LookupImpl)lookup, c == '.')) { return Result.HIDE_LOOKUP; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java index 185e62caa2c5..f7d604d8fd67 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyReferenceCharFilter.java @@ -20,14 +20,16 @@ import com.intellij.codeInsight.lookup.CharFilter; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.patterns.StandardPatterns; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrConditionalExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; + +import static com.intellij.patterns.PsiJavaPatterns.psiElement; /** * @author ilyas @@ -45,7 +47,8 @@ public class GroovyReferenceCharFilter extends CharFilter { return Result.ADD_TO_PREFIX; } - if ((c == '[' || c == '<' || c == '.' || c == ' ' || c == '(') && JavaCharFilter.isNonImportedClassEntered((LookupImpl)lookup)) { + if ((c == '[' || c == '<' || c == '.' || c == ' ' || c == '(') && + JavaCharFilter.isNonImportedClassEntered((LookupImpl)lookup, c == '.')) { return Result.HIDE_LOOKUP; } @@ -58,12 +61,16 @@ public class GroovyReferenceCharFilter extends CharFilter { if (c == ':') { PsiFile file = lookup.getPsiFile(); PsiDocumentManager.getInstance(file.getProject()).commitDocument(lookup.getEditor().getDocument()); - PsiElement element = lookup.getPsiElement(); - if (PsiTreeUtil.getParentOfType(element, GrCaseLabel.class) != null || - PsiTreeUtil.getParentOfType(element, GrConditionalExpression.class) != null || - PsiTreeUtil.getParentOfType(element, GrArgumentList.class) != null || - PsiTreeUtil.getParentOfType(element, GrListOrMap.class) != null - ) { + PsiElement element = file.findElementAt(Math.max(caret - 1, 0)); + if (psiElement().withParent( + psiElement(GrReferenceExpression.class).withParent( + StandardPatterns.or(psiElement(GrCaseLabel.class), + psiElement(GrConditionalExpression.class)))).accepts(element)) { + return Result.SELECT_ITEM_AND_FINISH_LOOKUP; + } + if (item.getObject() instanceof NamedArgumentDescriptor && + (MapArgumentCompletionProvider.IN_ARGUMENT_LIST_OF_CALL.accepts(element) || + MapArgumentCompletionProvider.IN_LABEL.accepts(element))) { return Result.SELECT_ITEM_AND_FINISH_LOOKUP; } return Result.HIDE_LOOKUP; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java index 84b6b2808589..e69a65085b31 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java @@ -51,20 +51,19 @@ import static org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor.Pr */ class MapArgumentCompletionProvider extends CompletionProvider { + public static final ElementPattern IN_ARGUMENT_LIST_OF_CALL = psiElement().withParent(psiElement(GrReferenceExpression.class).withParent( + StandardPatterns.or(psiElement(GrArgumentList.class), psiElement(GrListOrMap.class))) + ); + public static final ElementPattern IN_LABEL = psiElement(GroovyTokenTypes.mIDENT).withParent(GrArgumentLabel.class); + private MapArgumentCompletionProvider() { } public static void register(CompletionContributor contributor) { MapArgumentCompletionProvider instance = new MapArgumentCompletionProvider(); - ElementPattern inArgumentListOfCall = psiElement().withParent(psiElement(GrReferenceExpression.class).withParent( - StandardPatterns.or(psiElement(GrArgumentList.class), psiElement(GrListOrMap.class))) - ); - - ElementPattern inLabel = psiElement(GroovyTokenTypes.mIDENT).withParent(GrArgumentLabel.class); - - contributor.extend(CompletionType.BASIC, inArgumentListOfCall, instance); - contributor.extend(CompletionType.BASIC, inLabel, instance); + contributor.extend(CompletionType.BASIC, IN_ARGUMENT_LIST_OF_CALL, instance); + contributor.extend(CompletionType.BASIC, IN_LABEL, instance); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index cba609eeb069..2e4f31e52201 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -463,19 +463,23 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { final GrExpression right = expression.getRightOperand(); final IElementType opType = expression.getOperationTokenType(); - final FakeInstruction binaryEnd = - opType == GroovyTokenTypes.mLAND || opType == GroovyTokenTypes.mLOR ? new FakeInstruction(myInstructionNumber++) : null; - + InstructionImpl start = myHead; left.accept(this); - if (binaryEnd != null && myHead != null) { - addEdge(myHead, binaryEnd); + + if (right != null) { + if (opType == GroovyTokenTypes.mLOR) { + addPendingEdge(expression, myHead); + myHead = start; + + myNegate = !myNegate; + left.accept(this); + myNegate = !myNegate; + } + + right.accept(this); } - if (right != null) right.accept(this); - visitCall(expression); - - if (binaryEnd != null) addNode(binaryEnd); } /** diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy index e47e50a569e7..03f99f1c3f9c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyAutoPopupTest.groovy @@ -232,4 +232,23 @@ class GroovyAutoPopupTest extends CompletionAutoPopupTestCase { assert myFixture.file.text == 'FIS:' } + public void testEnteringNamedArg() { + myFixture.configureByText 'a.groovy', 'foo()' + type 'has:' + myFixture.checkResult 'foo(has:)' + } + + public void testEnteringMapKey() { + myFixture.configureByText 'a.groovy', '[]' + type 'has:' + myFixture.checkResult '[has:]' + } + + public void testTypingFqn() { + CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE + myFixture.configureByText 'a.groovy', '' + type 'java.' + myFixture.checkResult 'java.' + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 058d28cc9305..b610ce6fc158 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -111,6 +111,9 @@ public class GroovyCompletionTest extends GroovyCompletionTestBase { doBasicTest(); } + public void testInstanceofHelpsDetermineTypeInBinaryAnd() throws Throwable { doBasicTest() } + public void testInstanceofHelpsDetermineTypeInBinaryOr() throws Throwable { doBasicTest() } + public void testNotInstanceofDoesntHelpDetermineType() throws Throwable { myFixture.testCompletion(getTestName(false) + ".groovy", getTestName(false) + ".groovy"); } diff --git a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd.groovy b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd.groovy new file mode 100644 index 000000000000..54162e5aa5b1 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd.groovy @@ -0,0 +1,7 @@ +public class Parent { + + def foo(o) { + return o instanceof String && o.subst + } + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd_after.groovy b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd_after.groovy new file mode 100644 index 000000000000..55e3f521edb1 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryAnd_after.groovy @@ -0,0 +1,7 @@ +public class Parent { + + def foo(o) { + return o instanceof String && o.substring() + } + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr.groovy b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr.groovy new file mode 100644 index 000000000000..1e8ef025bd1d --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr.groovy @@ -0,0 +1,7 @@ +public class Parent { + + def foo(o) { + return !(o instanceof String) || o.subst + } + +} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr_after.groovy b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr_after.groovy new file mode 100644 index 000000000000..f46c3fbbf144 --- /dev/null +++ b/plugins/groovy/testdata/groovy/completion/InstanceofHelpsDetermineTypeInBinaryOr_after.groovy @@ -0,0 +1,7 @@ +public class Parent { + + def foo(o) { + return !(o instanceof String) || o.substring() + } + +} \ No newline at end of file