IDEA-163986 Code complete second default array argument in annotation

This commit is contained in:
peter
2017-05-09 14:37:54 +02:00
parent c7d41b6576
commit 2461a8751c
4 changed files with 70 additions and 0 deletions
@@ -37,9 +37,12 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author yole
*/
@@ -181,9 +184,64 @@ public class JavaTypedHandler extends TypedHandlerDelegate {
return Result.STOP;
}
}
else if (c == ',' && handleAnnotationParameter(project, editor, file)) {
return Result.STOP;
}
return Result.CONTINUE;
}
private static boolean handleAnnotationParameter(Project project, @NotNull Editor editor, @NotNull PsiFile file) {
int caret = editor.getCaretModel().getOffset();
if (mightBeInsideDefaultAnnotationAttribute(editor, caret - 2)) {
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiAnnotation anno = PsiTreeUtil.findElementOfClassAtOffset(file, caret, PsiAnnotation.class, false);
PsiNameValuePair attr = anno == null ? null : getTheOnlyDefaultAttribute(anno);
if (attr != null && hasDefaultArrayMethod(anno) && !(attr.getValue() instanceof PsiArrayInitializerMemberValue)) {
editor.getDocument().insertString(caret, "}");
editor.getDocument().insertString(attr.getTextRange().getStartOffset(), "{");
return true;
}
}
return false;
}
@Nullable private static PsiNameValuePair getTheOnlyDefaultAttribute(@NotNull PsiAnnotation anno) {
List<PsiNameValuePair> attributes = ContainerUtil.findAll(anno.getParameterList().getAttributes(), a -> !a.getTextRange().isEmpty());
return attributes.size() == 1 && attributes.get(0).getNameIdentifier() == null ? attributes.get(0) : null;
}
private static boolean hasDefaultArrayMethod(@NotNull PsiAnnotation anno) {
PsiJavaCodeReferenceElement nameRef = anno.getNameReferenceElement();
PsiElement annoClass = nameRef == null ? null : nameRef.resolve();
if (annoClass instanceof PsiClass) {
PsiMethod[] methods = ((PsiClass)annoClass).getMethods();
return methods.length == 1 && PsiUtil.isAnnotationMethod(methods[0]) &&
PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(methods[0].getName()) &&
methods[0].getReturnType() instanceof PsiArrayType;
}
return false;
}
private static boolean mightBeInsideDefaultAnnotationAttribute(@NotNull Editor editor, int offset) {
HighlighterIterator iterator = ((EditorEx)editor).getHighlighter().createIterator(offset);
int parenCount = 0;
while (!iterator.atEnd()) {
IElementType tokenType = iterator.getTokenType();
if (tokenType == JavaTokenType.AT) {
return true;
}
if (tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE ||
tokenType == JavaTokenType.EQ || tokenType == JavaTokenType.SEMICOLON || tokenType == JavaTokenType.COMMA) {
return false;
}
if (tokenType == JavaTokenType.LPARENTH && ++parenCount > 1) {
return false;
}
iterator.retreat();
}
return false;
}
private static boolean handleSemicolon(Editor editor, FileType fileType) {
if (fileType != StdFileTypes.JAVA) return false;
int offset = editor.getCaretModel().getOffset();
@@ -0,0 +1,4 @@
public @interface Category {
Class<?>[] value();
}
@Category({Foo.class,<caret>})
@@ -0,0 +1,4 @@
public @interface Category {
Class<?>[] value();
}
@Category(Foo.class<caret>)
@@ -110,6 +110,10 @@ public class JavaTypingTest extends LightPlatformCodeInsightFixtureTestCase {
doTest(';');
}
public void testCommaAfterDefaultAnnotationArgumentWhenArrayIsExpected() {
doTest(',');
}
private void doTest(char c) {
myFixture.configureByFile(getTestName(true) + "_before.java");
myFixture.type(c);