org.checkerframework.checker.i18nformatter.I18nFormatterTransfer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java's type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.checker.i18nformatter;
import javax.lang.model.element.AnnotationMirror;
import org.checkerframework.checker.formatter.FormatterTreeUtil.Result;
import org.checkerframework.checker.i18nformatter.qual.I18nConversionCategory;
import org.checkerframework.checker.i18nformatter.qual.I18nInvalidFormat;
import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.framework.flow.CFAnalysis;
import org.checkerframework.framework.flow.CFStore;
import org.checkerframework.framework.flow.CFTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.javacutil.AnnotationBuilder;
/**
* The transfer function for the Internationalization Format String Checker.
*
* @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
*/
public class I18nFormatterTransfer extends CFTransfer {
public I18nFormatterTransfer(CFAnalysis analysis) {
super(analysis);
}
@Override
public TransferResult visitMethodInvocation(
MethodInvocationNode node, TransferInput in) {
I18nFormatterAnnotatedTypeFactory atypeFactory =
(I18nFormatterAnnotatedTypeFactory) analysis.getTypeFactory();
TransferResult result = super.visitMethodInvocation(node, in);
I18nFormatterTreeUtil tu = atypeFactory.treeUtil;
// If hasFormat is called, make sure that the format string is annotated correctly
if (tu.isHasFormatCall(node, atypeFactory)) {
CFStore thenStore = result.getRegularStore();
CFStore elseStore = thenStore.copy();
ConditionalTransferResult newResult =
new ConditionalTransferResult<>(result.getResultValue(), thenStore, elseStore);
Result cats = tu.getHasFormatCallCategories(node);
if (cats.value() == null) {
tu.failure(cats, "i18nformat.indirect.arguments");
} else {
JavaExpression firstParam = JavaExpression.fromNode(node.getArgument(0));
AnnotationMirror anno = atypeFactory.treeUtil.categoriesToFormatAnnotation(cats.value());
thenStore.insertValue(firstParam, anno);
}
return newResult;
}
// If isFormat is called, annotate the format string with I18nInvalidFormat
if (tu.isIsFormatCall(node, atypeFactory)) {
CFStore thenStore = result.getRegularStore();
CFStore elseStore = thenStore.copy();
ConditionalTransferResult newResult =
new ConditionalTransferResult<>(result.getResultValue(), thenStore, elseStore);
JavaExpression firstParam = JavaExpression.fromNode(node.getArgument(0));
AnnotationBuilder builder = new AnnotationBuilder(tu.processingEnv, I18nInvalidFormat.class);
// No need to set a value of @I18nInvalidFormat
builder.setValue("value", "");
elseStore.insertValue(firstParam, builder.build());
return newResult;
}
// @I18nMakeFormat that will be used to annotate ResourceBundle.getString() so that when the
// getString() method is called, this will check if the given key exist in the translation
// file and annotate the result string with the correct format annotation according to the
// corresponding key's value.
if (tu.isMakeFormatCall(node, atypeFactory)) {
Result cats = tu.makeFormatCallCategories(node, atypeFactory);
if (cats.value() == null) {
tu.failure(cats, "i18nformat.key.not.found");
} else {
AnnotationMirror anno = atypeFactory.treeUtil.categoriesToFormatAnnotation(cats.value());
CFValue newResultValue =
analysis.createSingleAnnotationValue(anno, result.getResultValue().getUnderlyingType());
return new RegularTransferResult<>(newResultValue, result.getRegularStore());
}
}
return result;
}
}