diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index 3e13df602b5a..d10cce47486d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -83,7 +83,7 @@ class ConstructorInsertHandler implements InsertHandler JAVA_CLASS_INSERT_HANDLER = new InsertHandler() { public void handleInsert(final InsertionContext context, final JavaPsiClassReferenceElement item) { - context.setAddCompletionChar(false); + final char c = context.getCompletionChar(); + + if (c != '.' && c != ' ' && c != '#') { + context.setAddCompletionChar(false); + } + int offset = context.getTailOffset() - 1; final PsiFile file = context.getFile(); if (PsiTreeUtil.findElementOfClassAtOffset(file, offset, PsiImportStatementBase.class, false) != null) { @@ -70,14 +76,16 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { PsiElement position = file.findElementAt(offset); PsiClass psiClass = item.getObject(); + final Project project = context.getProject(); + final boolean annotation = DefaultInsertHandler.insertingAnnotation(context, item); - if (context.getCompletionChar() == '#') { + final Editor editor = context.getEditor(); + if (c == '#') { context.setLaterRunnable(new Runnable() { public void run() { - new CodeCompletionHandlerBase(CompletionType.BASIC).invoke(context.getProject(), context.getEditor(), file); + new CodeCompletionHandlerBase(CompletionType.BASIC).invoke(project, editor, file); } }); - TailType.insertChar(context.getEditor(), context.getTailOffset(), '#'); } if (position != null) { @@ -90,11 +98,31 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } if (completingRawConstructor(context, item) && !JavaCompletionUtil.hasAccessibleInnerClass(psiClass, file)) { - ConstructorInsertHandler.insertParentheses(context, item, psiClass); - DefaultInsertHandler.addImportForItem(context.getFile(), context.getStartOffset(), item); - } else { - new DefaultInsertHandler().handleInsert(context, item); + if (ConstructorInsertHandler.insertParentheses(context, item, psiClass)) { + AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null); + } } + else if (DefaultInsertHandler.insertingAnnotationWithParameters(context, item)) { + JavaCompletionUtil.insertParentheses(context, item, false, true); + AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null); + } + DefaultInsertHandler.addImportForItem(context.getFile(), context.getStartOffset(), item); + + if (annotation) { + // Check if someone inserts annotation class that require @ + PsiElement elementAt = file.findElementAt(context.getStartOffset()); + final PsiElement parentElement = elementAt != null ? elementAt.getParent():null; + + if (elementAt instanceof PsiIdentifier && + (PsiTreeUtil.getParentOfType(elementAt, PsiAnnotationParameterList.class) != null || + parentElement instanceof PsiErrorElement && parentElement.getParent() instanceof PsiJavaFile // top level annotation without @ + ) + && DefaultInsertHandler.isAtTokenNeeded(context)) { + int expectedOffsetForAtToken = elementAt.getTextRange().getStartOffset(); + context.getDocument().insertString(expectedOffsetForAtToken, "@"); + } + } + } private boolean completingRawConstructor(InsertionContext context, JavaPsiClassReferenceElement item) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab.java new file mode 100644 index 000000000000..723d66f49d22 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab.java @@ -0,0 +1,16 @@ +public class TestClass { + + public TestClass create() { + final int value = 1; + return new XxTexCompXxx(value); + } +} + +class Xxx { + private Xxx(String x) { + } + + class Yyy { + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java new file mode 100644 index 000000000000..28d5cebdbd75 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/ClassNameWithInnersTab_after.java @@ -0,0 +1,16 @@ +public class TestClass { + + public TestClass create() { + final int value = 1; + return new Xxx(value); + } +} + +class Xxx { + private Xxx(String x) { + } + + class Yyy { + + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 3c50f548fe4e..02c591b8df3d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -741,6 +741,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { checkResult(); } + public void testClassNameWithInnersTab() throws Throwable { + configure() + myFixture.type '\t' + checkResult(); + } + public void testRightShift() throws Throwable { configure() assertStringItems("myField1", "myField2");