[JSR308] Checkers Framework Instability
Chester Chen
CChen at ascentmedia.com
Fri Dec 19 12:39:06 EST 2008
Mahmood,
Thanks for the follow-up. You are probably right that I haven't use Checker Framework
correctly.
> Does PanguProcessor or ResourceBundleProcessor extend SourceChecker?
> In the stacktrace you provided, it seems that you implemented your own
>processor. You should be careful about that.
The ResourceBundleProcessor extends PanguProcessor, which doesn't extends SourceChecker.
I have used PanguProcessor is my base processor which used for many other processings,
in most cases, I am dealing with Elements, so things are pretty easy.
Its only ResourceBundleProcessor I need to processing local variable annotation and need
to deal with Tree nodes.
I don't want to change the whole structure just for this.
I simply instantiated AnnotatedTypeFactory by factory = new AnnotatedTypeFactory(env, null, treePath.getCompilationUnit());
this probably incorrect way of using it.
>>As we discussed earlier, typical annotation processors do not get all
>>the necessary type information from the compiler, especially type
>>information regarding local variables. SourceChecker.process()
>>(SourceChecker.attribute() to be exact) performs some magic calls to
>>the compiler to get the type information by starting an "attribution"
>>phase.
>>If you're processor doesn't invoke the attribution phase, many methods
>>in AnnotatedTypeFactory (and the rest of the framework) would fail.
That probably explained why there are so many exceptions.
>>If you want to rely on type information (instead of what I sampled
>>earlier), I highly recommend using SourceChecker.
I am back to your original prototyped approach now, and it works fine.
I was hoping there a more type-safe way approach instead of having to know the inner structure
of the annotation.Something similar to Element APIs
Something like
@Override
public R visitVariable(VariableTree tree, P p) {
ErrorMessage errMessage= tree.getAnnoation(tree, ErrorMessage.class);
if (errMessage == null)
return null;
//continue to use errMessage
....
return super.visitVariable(tree, null);
}
Or
@Override
public R visitVariable(VariableTree tree, P p) {
ErrorMessage errMessage= AnnotationUtis.getAnnoation(tree, ErrorMessage.class);
if (errMessage == null)
return null;
//continue to use errMessage
....
return super.visitVariable(tree, null);
}
Here is what I got based on the approach your originally suggested, it works fine:
@Override
public R visitVariable(VariableTree tree, P p) {
AnnotationData annotation= getErrorMessageAnnotations(tree);
if (annotation == null) return null;
ExpressionTree initializer =tree.getInitializer();
String errorCode = "EC_0";
if (initializer != null)
errorCode = initializer.toString();
//record error code and message for later processing
addErrorCode(errorCode, annotation);
return super.visitVariable(tree, null);
}
private AnnotationData getErrorMessageAnnotations(VariableTree node) {
if (node == null) return null;
ModifiersTree modifiers = node.getModifiers();
List<? extends AnnotationTree> annotationNodes = modifiers.getAnnotations();
if (annotationNodes == null || annotationNodes.isEmpty()) return null;
List<AnnotationData> dataList = AnnotationUtils.getAnnotations(ErrorMessage.class, annotationNodes);
if (dataList.isEmpty()) return null;
//Since I know there is only one Annotation if any
return dataList.get(0);
}
IN AnnotationUtils.java
/**
* The method convert the AnnotationTree to AnnoationData Structure.
* There does not seem an convenient way to convert Tree node to Element.
* So we use AnnoatationData to perform this convertion.
*
* @param annotationType --The Class of the Annoation Type (Declaration)
* @param annotationNodes -- The AnnoationTree Nodes
* @return Array of the AnnoationData matches to the give Annotation Type, if none return empty List
*
*/
public static List<AnnotationData> getAnnotations(Class annotationType, List<? extends AnnotationTree> annotationNodes) {
if (annotationNodes == null || annotationNodes.isEmpty())
return new ArrayList<AnnotationData>(0);
List<AnnotationData> results = new ArrayList<AnnotationData>(annotationNodes.size());
for (AnnotationTree at : annotationNodes) {
if (! at.getAnnotationType().toString().equals(annotationType.getSimpleName()) )
continue;
AnnotationData data = new AnnotationData(annotationType.getSimpleName());
Method[] methods = annotationType.getDeclaredMethods();
for (Method m : methods) {
boolean methodFound = false;
List<? extends ExpressionTree> args = at.getArguments();
for (ExpressionTree t : args) {
if (t instanceof AssignmentTree) {
AssignmentTree value = (AssignmentTree) t;
if (value.getVariable().toString().equals(m.getName())) {
methodFound = true;
data.mValues.put(m.getName(), value.getExpression().toString());
}
}
else
System.out.println("AnnotationUtils.getAnnotations t is not Assignement, but a: " + t.getClass().getName());
}
if (!methodFound)
data.mValues.put(m.getName(), m.getDefaultValue());
}
results.add(data);
}
**
* Data Structure used to transfer annotation from AST Tree node
* to this data Structure
*/
public class AnnotationData {
public String mName;
//key = methodName, value = annoation argument values
public Map<String, Object> mValues;
public AnnotationData(String annotationClassName) {
mName = annotationClassName;
mValues = new HashMap<String, Object>();
}
}
-----Original Message-----
From: Mahmood Ali [mailto:mahmood at MIT.EDU]
Sent: Fri 12/19/2008 9:12 AM
To: Chester Chen
Cc: JSR 308 (Annotations) mailing list
Subject: Checkers Framework Instability
Greetings Chester,
I apologize for not following the thread more closely. I will go over
the emails soon.
> In general, the Checker framework seems not very stable for me, or
> simply my incorrect-use of the Checker's code.
> There are several NullPointer Exceptions.
My initial guess is that the environment isn't initialized properly.
I would recommend that you run the processor with assertions enabled.
Does PanguProcessor or ResourceBundleProcessor extend SourceChecker?
In the stacktrace you provided, it seems that you implemented your own
processor. You should be careful about that.
As we discussed earlier, typical annotation processors do not get all
the necessary type information from the compiler, especially type
information regarding local variables. SourceChecker.process()
(SourceChecker.attribute() to be exact) performs some magic calls to
the compiler to get the type information by starting an "attribution"
phase.
If you're processor doesn't invoke the attribution phase, many methods
in AnnotatedTypeFactory (and the rest of the framework) would fail.
If you want to rely on type information (instead of what I sampled
earlier), I highly recommend using SourceChecker.
Regards,
Mahmood
-------------- next part --------------
An HTML attachment was scrubbed...
URL: https://lists.csail.mit.edu/pipermail/jsr308/attachments/20081219/f37910bd/attachment.htm
More information about the JSR308
mailing list