From 5825a4a6be1461548d1b7bbc5007c8623cb1ab2a Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 12 Oct 2016 13:25:43 +0300 Subject: [PATCH] verbose diagnostics for incomplete annotation error --- .../AnnotationInvocationHandler.java | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationInvocationHandler.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationInvocationHandler.java index c30b3153383a..66fb8a3f2b23 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationInvocationHandler.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationInvocationHandler.java @@ -15,11 +15,11 @@ */ package com.intellij.codeInsight; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.PsiAnnotation; -import com.intellij.psi.PsiAnnotationMemberValue; -import com.intellij.psi.PsiNameValuePair; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.*; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; import java.lang.annotation.IncompleteAnnotationException; @@ -50,9 +50,12 @@ class AnnotationInvocationHandler implements InvocationHandler { } // Handle annotation member accessors - PsiAnnotationMemberValue value = myAnnotation.findAttributeValue(member); + Pair pair = attributeValueOrError(myAnnotation, member); + PsiAnnotationMemberValue value = pair.first; + if (value == null) { - throw new IncompleteAnnotationException(type, member+". (Unable to find attribute in '"+myAnnotation.getText()+"')"); + String error = pair.second; + throw new IncompleteAnnotationException(type, member+". (Unable to find attribute in '"+myAnnotation.getText()+"': " + error + ")"); } Object result = JavaPsiFacade.getInstance(myAnnotation.getProject()).getConstantEvaluationHelper().computeConstantExpression(value); @@ -65,6 +68,38 @@ class AnnotationInvocationHandler implements InvocationHandler { return result; } + @NotNull + private static Pair attributeValueOrError(@NotNull PsiAnnotation annotation, @Nullable @NonNls String attributeName) { + PsiNameValuePair attribute = AnnotationUtil.findDeclaredAttribute(annotation, attributeName); + final PsiAnnotationMemberValue value = attribute == null ? null : attribute.getValue(); + if (value != null) return Pair.create(value, null); + + if (attributeName == null) attributeName = "value"; + final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement(); + if (referenceElement == null) { + return Pair.create(null, "no reference found in "+annotation.getText()); + } + PsiElement resolved = referenceElement.resolve(); + if (resolved == null) { + return Pair.create(null, "can't resolve reference '"+referenceElement.getText()+"'"); + } + PsiClass psiClass; + if (!(resolved instanceof PsiClass) || !(psiClass = (PsiClass)resolved).isAnnotationType()) { + return Pair.create(null, "reference '"+referenceElement.getText()+"' resolved to "+resolved+" ("+resolved.getClass()+") instead of enum"); + } + PsiMethod[] methods = psiClass.findMethodsByName(attributeName, false); + for (PsiMethod method : methods) { + if (method instanceof PsiAnnotationMethod) { + PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod)method).getDefaultValue(); + if (defaultValue != null) { + return Pair.create(defaultValue, null); + } + return Pair.create(null, "method has no value nor default value: "+method.getText()); + } + } + return Pair.create(null, "method '"+attributeName+"' not found in "+psiClass.getQualifiedName()+" among methods "+Arrays.asList(psiClass.getMethods())); + } + /** * Implementation of dynamicProxy.toString() */