[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