package de.plushnikov.intellij.plugin.util; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiAnnotation; import com.intellij.psi.PsiAnnotationMemberValue; import com.intellij.psi.PsiArrayInitializerMemberValue; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClassObjectAccessExpression; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiEnumConstant; import com.intellij.psi.PsiField; import com.intellij.psi.PsiLiteralExpression; import com.intellij.psi.PsiModifierList; import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiReferenceExpression; import com.intellij.psi.PsiType; import com.intellij.psi.PsiTypeElement; import com.intellij.psi.PsiVariable; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.regex.Pattern; /** * Some util methods for annotation processing * * @author peichhorn * @author Plushnikov Michail */ public class PsiAnnotationUtil { @NotNull public static PsiAnnotation createPsiAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull Class<? extends Annotation> annotationClass) { return createPsiAnnotation(psiModifierListOwner, annotationClass, ""); } @NotNull public static PsiAnnotation createPsiAnnotation(@NotNull PsiModifierListOwner psiModifierListOwner, @NotNull Class<? extends Annotation> annotationClass, @Nullable String value) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiModifierListOwner.getProject()); final PsiClass psiClass = PsiTreeUtil.getParentOfType(psiModifierListOwner, PsiClass.class); final String valueString = StringUtil.isNotEmpty(value) ? "(" + value + ")" : ""; return elementFactory.createAnnotationFromText("@" + annotationClass.getName() + valueString, psiClass); } @NotNull public static <T> Collection<T> getAnnotationValues(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter, @NotNull Class<T> asClass) { Collection<T> result = Collections.emptyList(); PsiAnnotationMemberValue attributeValue = psiAnnotation.findAttributeValue(parameter); if (attributeValue instanceof PsiArrayInitializerMemberValue) { final PsiAnnotationMemberValue[] memberValues = ((PsiArrayInitializerMemberValue) attributeValue).getInitializers(); result = new ArrayList<T>(memberValues.length); for (PsiAnnotationMemberValue memberValue : memberValues) { T value = resolveElementValue(memberValue, asClass); if (null != value) { result.add(value); } } } else if (null != attributeValue) { T value = resolveElementValue(attributeValue, asClass); if (null != value) { result = Collections.singletonList(value); } } return result; } public static boolean hasDeclaredProperty(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter) { return null != psiAnnotation.findDeclaredAttributeValue(parameter); } public static boolean getBooleanAnnotationValue(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter, boolean defaultValue) { PsiAnnotationMemberValue attrValue = psiAnnotation.findAttributeValue(parameter); final Boolean result = null != attrValue ? resolveElementValue(attrValue, Boolean.class) : null; return result == null ? defaultValue : result; } public static String getStringAnnotationValue(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter) { PsiAnnotationMemberValue attrValue = psiAnnotation.findAttributeValue(parameter); return null != attrValue ? resolveElementValue(attrValue, String.class) : null; } @Nullable private static <T> T resolveElementValue(@NotNull PsiElement psiElement, @NotNull Class<T> asClass) { T value = null; if (psiElement instanceof PsiReferenceExpression) { final PsiElement resolved = ((PsiReferenceExpression) psiElement).resolve(); if (resolved instanceof PsiEnumConstant) { final PsiEnumConstant psiEnumConstant = (PsiEnumConstant) resolved; //Enums are supported as VALUE-Strings only if (asClass.isAssignableFrom(String.class)) { value = (T) psiEnumConstant.getName(); } } else if (resolved instanceof PsiVariable) { final PsiVariable psiVariable = (PsiVariable) resolved; Object elementValue = psiVariable.computeConstantValue(); if (null != elementValue && asClass.isAssignableFrom(elementValue.getClass())) { value = (T) elementValue; } } } else if (psiElement instanceof PsiLiteralExpression) { Object elementValue = ((PsiLiteralExpression) psiElement).getValue(); if (null != elementValue && asClass.isAssignableFrom(elementValue.getClass())) { value = (T) elementValue; } } else if (psiElement instanceof PsiClassObjectAccessExpression) { PsiTypeElement elementValue = ((PsiClassObjectAccessExpression) psiElement).getOperand(); //Enums are supported as VALUE-Strings only if (asClass.isAssignableFrom(PsiType.class)) { value = (T) elementValue.getType(); } } else if (psiElement instanceof PsiAnnotation) { if (asClass.isAssignableFrom(PsiAnnotation.class)) { value = (T) psiElement; } } return value; } @Nullable public static Boolean getDeclaredBooleanAnnotationValue(@NotNull PsiAnnotation psiAnnotation, @NotNull String parameter) { PsiAnnotationMemberValue attributeValue = psiAnnotation.findDeclaredAttributeValue(parameter); Object constValue = null; if (null != attributeValue) { final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(psiAnnotation.getProject()); constValue = javaPsiFacade.getConstantEvaluationHelper().computeConstantExpression(attributeValue); } return constValue instanceof Boolean ? (Boolean) constValue : null; } @NotNull public static Collection<String> collectAnnotationsToCopy(@NotNull PsiField psiField, final Pattern... patterns) { Collection<String> annotationsToCopy = new ArrayList<String>(); PsiModifierList modifierList = psiField.getModifierList(); if (null != modifierList) { for (PsiAnnotation psiAnnotation : modifierList.getAnnotations()) { final String annotationName = PsiAnnotationSearchUtil.getSimpleNameOf(psiAnnotation); for (Pattern pattern : patterns) { if (pattern.matcher(annotationName).matches()) { annotationsToCopy.add(psiAnnotation.getQualifiedName()); } } } } return annotationsToCopy; } }