Check printf at compile-time
Monday, March 16th, 2009
Since the introduction of #printf in Java 1.5, I always wished to check my format strings and their arguments at compile-time.
Now, it can be done.
The following compiler-plugin checks format string and format arguments of any call to #printf and #format. Of course, checking is limited to format-strings known at compile time.
Just put printf.jar in your classpath (works with javac only!)
javac -classpath printf.jar Example.java
Since there are numerous #printf and #format methods in the Java API, any method with one of said names and with parameters of type String and Object[] is checked. (A cleaner solution would use a @Printf annotation to mark these methods. Alas, I cannot touch the Java API just like that.)
The above plugin works with javac only. Why? Annotation processing is done before type attribution and thus type information is not available to a JSR 269 plugin. However, checking the type of format arguments cannot be done without type information. Thus, what I do is to manually invoke the compiler’s type attribution phase. This is done using the internal Attr component as follows.
import com.sun.tools.javac.comp.Attr;
@SupportedAnnotationTypes("*")
public class Printf extends AbstractProcessor {
private Attr attr;
public synchronized void init(ProcessingEnvironment processingEnv) {
attr = Attr.instance(((JavacProcessingEnvironment) processingEnv).getContext());
...
}
public boolean process(Set annotations, RoundEnvironment roundEnv) {
for (Element each: roundEnv.getRootElements()) {
if (each.getKind() == ElementKind.CLASS) {
attr.attribClass(null, (ClassSymbol) each);
...
}
}
}
...
PS, type information is discarded after each annotation processor round. It is thus safe to apply type manipulating changes to the AST from within an annotation processor, since after the plugins have been run, type information is re-attributed again from scratch.
For the full sources, please refer to /Sources/b/Printf on the SCG repository.
Have fun!