private static String buildAnnotationText(PsiAnnotation annotation) { final StringBuilder out = new StringBuilder("@"); final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); assert nameReferenceElement != null; out.append(nameReferenceElement.getText()); final PsiAnnotationParameterList parameterList = annotation.getParameterList(); final PsiNameValuePair[] attributes = parameterList.getAttributes(); if (attributes.length == 0) { return out.toString(); } out.append('('); if (attributes.length == 1) { final PsiNameValuePair attribute = attributes[0]; @NonNls final String name = attribute.getName(); if (name != null && !PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name)) { out.append(name).append('='); } buildAttributeValueText(attribute.getValue(), out); } else { for (int i = 0; i < attributes.length; i++) { final PsiNameValuePair attribute = attributes[i]; if (i > 0) { out.append(','); } out.append(attribute.getName()).append('='); buildAttributeValueText(attribute.getValue(), out); } } out.append(')'); return out.toString(); }
private static boolean containsError(PsiAnnotation annotation) { final PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) { return true; } final PsiClass aClass = (PsiClass) nameRef.resolve(); if (aClass == null || !aClass.isAnnotationType()) { return true; } final Set<String> names = new HashSet<String>(); final PsiAnnotationParameterList annotationParameterList = annotation.getParameterList(); if (PsiUtilCore.hasErrorElementChild(annotationParameterList)) { return true; } final PsiNameValuePair[] attributes = annotationParameterList.getAttributes(); for (PsiNameValuePair attribute : attributes) { final PsiReference reference = attribute.getReference(); if (reference == null) { return true; } final PsiMethod method = (PsiMethod) reference.resolve(); if (method == null) { return true; } final PsiAnnotationMemberValue value = attribute.getValue(); if (value == null || PsiUtilCore.hasErrorElementChild(value)) { return true; } if (value instanceof PsiAnnotation && containsError((PsiAnnotation) value)) { return true; } if (!hasCorrectType(value, method.getReturnType())) { return true; } final String name = attribute.getName(); if (!names.add(name != null ? name : PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME)) { return true; } } for (PsiMethod method : aClass.getMethods()) { if (!(method instanceof PsiAnnotationMethod)) { continue; } final PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod) method; if (annotationMethod.getDefaultValue() == null && !names.contains(annotationMethod.getName())) { return true; // missing a required argument } } return false; }
private static boolean processAnnotationAttributes( @Nullable Map<String, Object> annotationAttributeValues, @NotNull PsiAnnotation annotation) { if (annotationAttributeValues != null) { final PsiAnnotationParameterList parameterList = annotation.getParameterList(); final PsiNameValuePair[] attributes = parameterList.getAttributes(); for (PsiNameValuePair attribute : attributes) { final String name = attribute.getName(); if (annotationAttributeValues.containsKey(name)) { annotationAttributeValues.put(name, attribute.getValue()); } } } return true; }
@Override @NotNull public PsiAnnotationParameterList getParameterList() { synchronized (lock) { if (myParameterList == null) { final PsiAnnotationStub stub = getStub(); final CompositeElement mirror = stub.getTreeElement(); final PsiAnnotationParameterList paramList = (PsiAnnotationParameterList) mirror.findChildByRoleAsPsiElement(ChildRole.PARAMETER_LIST); myParameterList = new ClsAnnotationParameterListImpl(this, paramList.getAttributes()); } return myParameterList; } }
@Nullable private static HighlightInfo checkDuplicateAttribute(PsiNameValuePair pair) { PsiAnnotationParameterList annotation = (PsiAnnotationParameterList) pair.getParent(); PsiNameValuePair[] attributes = annotation.getAttributes(); for (PsiNameValuePair attribute : attributes) { if (attribute == pair) break; String name = pair.getName(); if (Comparing.equal(attribute.getName(), name)) { String description = JavaErrorMessages.message( "annotation.duplicate.attribute", name == null ? PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME : name); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(pair) .descriptionAndTooltip(description) .create(); } } return null; }
@Override public List<PsiLiteralExpression> getTargets() { final List<PsiLiteralExpression> result = new ArrayList<PsiLiteralExpression>(); if (mySuppressedExpression != null) { result.add(mySuppressedExpression); return result; } final PsiAnnotationParameterList list = myTarget.getParameterList(); final PsiNameValuePair[] attributes = list.getAttributes(); for (PsiNameValuePair attribute : attributes) { final PsiAnnotationMemberValue value = attribute.getValue(); if (value instanceof PsiArrayInitializerMemberValue) { final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue) value).getInitializers(); for (PsiAnnotationMemberValue initializer : initializers) { if (initializer instanceof PsiLiteralExpression) { result.add((PsiLiteralExpression) initializer); } } } } return result; }
@Override public void visitAnnotation(PsiAnnotation annotation) { super.visitAnnotation(annotation); final PsiAnnotationParameterList parameterList = annotation.getParameterList(); final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); if (nameReferenceElement == null) { return; } final PsiNameValuePair[] attributes = parameterList.getAttributes(); final PsiElement[] annotationChildren = annotation.getChildren(); if (annotationChildren.length >= 2 && annotationChildren[1] instanceof PsiWhiteSpace && !containsError(annotation)) { registerError(annotationChildren[1], Boolean.TRUE); } if (attributes.length == 0) { if (parameterList.getChildren().length > 0 && !containsError(annotation)) { registerError(parameterList, ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } else if (attributes.length == 1) { final PsiNameValuePair attribute = attributes[0]; final PsiIdentifier identifier = attribute.getNameIdentifier(); final PsiAnnotationMemberValue attributeValue = attribute.getValue(); if (identifier != null && attributeValue != null) { @NonNls final String name = attribute.getName(); if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name) && !containsError(annotation)) { registerErrorAtOffset( attribute, 0, attributeValue.getStartOffsetInParent(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } if (!(attributeValue instanceof PsiArrayInitializerMemberValue)) { return; } final PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue) attributeValue; final PsiAnnotationMemberValue[] initializers = arrayValue.getInitializers(); if (initializers.length != 1) { return; } if (!containsError(annotation)) { registerError( arrayValue.getFirstChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); registerError( arrayValue.getLastChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } else if (attributes.length > 1) { for (PsiNameValuePair attribute : attributes) { final PsiAnnotationMemberValue value = attribute.getValue(); if (!(value instanceof PsiArrayInitializerMemberValue)) { continue; } final PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue) value; final PsiAnnotationMemberValue[] initializers = arrayValue.getInitializers(); if (initializers.length != 1) { continue; } if (!containsError(annotation)) { registerError( arrayValue.getFirstChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); registerError( arrayValue.getLastChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } } }
private static void completeAnnotationAttributeName( CompletionResultSet result, PsiElement insertedElement, CompletionParameters parameters) { PsiNameValuePair pair = PsiTreeUtil.getParentOfType(insertedElement, PsiNameValuePair.class); PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList) pair.getParent(); PsiAnnotation anno = (PsiAnnotation) parameterList.getParent(); boolean showClasses = psiElement().afterLeaf("(").accepts(insertedElement); PsiClass annoClass = null; final PsiJavaCodeReferenceElement referenceElement = anno.getNameReferenceElement(); if (referenceElement != null) { final PsiElement element = referenceElement.resolve(); if (element instanceof PsiClass) { annoClass = (PsiClass) element; if (annoClass.findMethodsByName("value", false).length == 0) { showClasses = false; } } } if (showClasses && insertedElement.getParent() instanceof PsiReferenceExpression) { final Set<LookupElement> set = JavaCompletionUtil.processJavaReference( insertedElement, (PsiJavaReference) insertedElement.getParent(), new ElementExtractorFilter(createAnnotationFilter(insertedElement)), JavaCompletionProcessor.Options.DEFAULT_OPTIONS, result.getPrefixMatcher(), parameters); for (final LookupElement element : set) { result.addElement(element); } addAllClasses(parameters, result, new InheritorsHolder(insertedElement, result)); } if (annoClass != null) { final PsiNameValuePair[] existingPairs = parameterList.getAttributes(); methods: for (PsiMethod method : annoClass.getMethods()) { if (!(method instanceof PsiAnnotationMethod)) continue; final String attrName = method.getName(); for (PsiNameValuePair existingAttr : existingPairs) { if (PsiTreeUtil.isAncestor(existingAttr, insertedElement, false)) break; if (Comparing.equal(existingAttr.getName(), attrName) || PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(attrName) && existingAttr.getName() == null) continue methods; } LookupElementBuilder element = LookupElementBuilder.createWithIcon(method) .withInsertHandler( new InsertHandler<LookupElement>() { @Override public void handleInsert(InsertionContext context, LookupElement item) { final Editor editor = context.getEditor(); TailType.EQ.processTail(editor, editor.getCaretModel().getOffset()); context.setAddCompletionChar(false); context.commitDocument(); PsiAnnotationParameterList paramList = PsiTreeUtil.findElementOfClassAtOffset( context.getFile(), context.getStartOffset(), PsiAnnotationParameterList.class, false); if (paramList != null && paramList.getAttributes().length > 0 && paramList.getAttributes()[0].getName() == null) { int valueOffset = paramList.getAttributes()[0].getTextRange().getStartOffset(); context .getDocument() .insertString( valueOffset, PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME); TailType.EQ.processTail( editor, valueOffset + PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.length()); } } }); PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod) method).getDefaultValue(); if (defaultValue != null) { Object constant = JavaPsiFacade.getInstance(method.getProject()) .getConstantEvaluationHelper() .computeConstantExpression(defaultValue); if (constant != null) { element = element.withTailText( " default " + (constant instanceof String ? "\"" + constant + "\"" : constant), true); } } result.addElement(element); } } }