diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AnnotationInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/AnnotationInsertHandler.java new file mode 100644 index 000000000000..6491ffba6db3 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AnnotationInsertHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.completion; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; + +/** +* @author peter +*/ +class AnnotationInsertHandler implements InsertHandler { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.AnnotationInsertHandler"); + static final AnnotationInsertHandler INSTANCE = new AnnotationInsertHandler(); + + @Override + public void handleInsert(InsertionContext context, JavaPsiClassReferenceElement item) { + JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER.handleInsert(context, item); + + PsiFile file = context.getFile(); + + 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 @ + ) + && isAtTokenNeeded(context)) { + int expectedOffsetForAtToken = elementAt.getTextRange().getStartOffset(); + context.getDocument().insertString(expectedOffsetForAtToken, "@"); + } + + if (JavaClassNameInsertHandler.shouldHaveAnnotationParameters(item.getObject())) { + JavaCompletionUtil.insertParentheses(context, item, false, true); + } + } + + private static boolean isAtTokenNeeded(InsertionContext myContext) { + HighlighterIterator iterator = ((EditorEx)myContext.getEditor()).getHighlighter().createIterator(myContext.getStartOffset()); + LOG.assertTrue(iterator.getTokenType() == JavaTokenType.IDENTIFIER); + iterator.retreat(); + if (iterator.getTokenType() == TokenType.WHITE_SPACE) iterator.retreat(); + return iterator.getTokenType() != JavaTokenType.AT && iterator.getTokenType() != JavaTokenType.DOT; + } + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index 0abd4231fac1..f18c789ea167 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -21,7 +21,6 @@ import com.intellij.codeInsight.template.SmartCompletionContextType; import com.intellij.codeInsight.template.impl.TemplateImpl; import com.intellij.codeInsight.template.impl.TemplateSettings; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.filters.getters.ClassLiteralGetter; import com.intellij.psi.filters.getters.ThisGetter; @@ -35,13 +34,10 @@ import org.jetbrains.annotations.Nullable; import java.util.Map; -import static com.intellij.patterns.PsiJavaPatterns.psiElement; - /** * @author peter */ public class BasicExpressionCompletionContributor { - public static final ElementPattern AFTER_DOT = psiElement().afterLeaf("."); private static void addKeyword(final Consumer result, final PsiElement element, final String s) { result.consume(createKeywordLookupItem(element, s)); @@ -67,7 +63,7 @@ public class BasicExpressionCompletionContributor { } - if (!AFTER_DOT.accepts(element)) { + if (!JavaCompletionData.AFTER_DOT.accepts(element)) { if (parameters.getParameters().getInvocationCount() <= 1) { new CollectionsUtilityMethodsProvider(parameters.getPosition(), parameters.getExpectedType(), diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index 3c103465b46d..067a4258b148 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -20,11 +20,7 @@ import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.PsiTypeLookupItem; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.highlighter.HighlighterIterator; import com.intellij.openapi.project.Project; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -33,11 +29,12 @@ import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import static com.intellij.patterns.PsiJavaPatterns.psiElement; + /** * @author peter */ class JavaClassNameInsertHandler implements InsertHandler { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaClassNameInsertHandler"); static final InsertHandler JAVA_CLASS_INSERT_HANDLER = new JavaClassNameInsertHandler(); @Override @@ -58,7 +55,6 @@ class JavaClassNameInsertHandler implements InsertHandler AFTER_DOT = psiElement().afterLeaf("."); + public static final ElementPattern AFTER_DOT = psiElement().afterLeaf("."); private static final LeftNeighbour INSTANCEOF_PLACE = new LeftNeighbour(new OrFilter( new ReferenceOnFilter(new ClassFilter(PsiVariable.class)), @@ -516,7 +515,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { addUnfinishedMethodTypeParameters(position, result); if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) && - !BasicExpressionCompletionContributor.AFTER_DOT.accepts(position) && + !AFTER_DOT.accepts(position) && !(position.getParent() instanceof PsiLiteralExpression)) { addExpectedTypeMembers(parameters, result, position); if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 591729fb88cd..ac7099363487 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -246,13 +246,13 @@ public class JavaSmartCompletionContributor extends CompletionContributor { @Override public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { final PsiElement element = parameters.getPosition(); - final ElementPattern leftNeighbor = PsiJavaPatterns.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withText(".")); + final ElementPattern leftNeighbor = JavaCompletionData.AFTER_DOT; final boolean needQualify = leftNeighbor.accepts(element); for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) { final PsiClass psiClass = PsiUtil.resolveClassInType(type); if (psiClass != null && psiClass.isAnnotationType()) { - final LookupItem item = JavaClassNameCompletionContributor.createClassLookupItem(psiClass, true); + final LookupItem item = AllClassesGetter.createLookupItem(psiClass, AnnotationInsertHandler.INSTANCE); if (needQualify) JavaCompletionUtil.qualify(item); result.addElement(item); } @@ -320,7 +320,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor { boolean quick, Consumer consumer) { PsiElement position = params.getPosition(); - if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) { + if (!JavaCompletionData.AFTER_DOT.accepts(position)) { for (ExpectedTypeInfo info : mergedInfos) { new JavaMembersGetter(info.getType(), params).addMembers(!quick, consumer); if (!info.getDefaultType().equals(info.getType())) { diff --git a/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-result.java b/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-result.java index f410038c7877..ded584ee78c4 100644 --- a/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-result.java +++ b/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-result.java @@ -2,7 +2,7 @@ String name(); } -@Column +@Column() @interface Annotation { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-source.java b/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-source.java index f53e0a206de2..99316491f82a 100644 --- a/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-source.java +++ b/java/java-tests/testData/codeInsight/completion/className/nameCompletion/java/Annotation-source.java @@ -2,7 +2,7 @@ String name(); } -Colu +@Colu @interface Annotation { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation.java b/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation.java new file mode 100644 index 000000000000..5a55cf898256 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation.java @@ -0,0 +1,8 @@ +public @interface Example { + + public static final String FOO = "foo", BAR = "bar"; + + String value(); +} + +@Example(Exam) \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation_after.java b/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation_after.java new file mode 100644 index 000000000000..9a552373f298 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/AnnotationClassFromWithinAnnotation_after.java @@ -0,0 +1,8 @@ +public @interface Example { + + public static final String FOO = "foo", BAR = "bar"; + + String value(); +} + +@Example(Example) \ 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 99e6434ed424..880e7b175c7a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1126,6 +1126,8 @@ class XInternalError {} assertFirstStringItems "XInternalError", "XInternalTimerServiceController" } + public void testAnnotationClassFromWithinAnnotation() { doTest() } + public void testStaticallyImportedFieldsTwice() { myFixture.addClass(""" class Foo {