package org.checkerframework.checker.formatter; import javax.lang.model.element.AnnotationMirror; import org.checkerframework.checker.formatter.FormatterTreeUtil.Result; import org.checkerframework.checker.formatter.qual.ConversionCategory; 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.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.framework.flow.CFValue; public class FormatterTransfer extends CFTransfer { public FormatterTransfer(CFAnalysis analysis) { super(analysis); } /** * Makes it so that the {@link FormatUtil#asFormat} method returns a correctly annotated String. */ @Override public TransferResult<CFValue, CFStore> visitMethodInvocation( MethodInvocationNode node, TransferInput<CFValue, CFStore> in) { FormatterAnnotatedTypeFactory atypeFactory = (FormatterAnnotatedTypeFactory) analysis.getTypeFactory(); TransferResult<CFValue, CFStore> result = super.visitMethodInvocation(node, in); FormatterTreeUtil tu = atypeFactory.treeUtil; if (tu.isAsFormatCall(node, atypeFactory)) { Result<ConversionCategory[]> cats = tu.asFormatCallCategories(node); if (cats.value() == null) { tu.failure(cats, "format.asformat.indirect.arguments"); } else { AnnotationMirror anno = atypeFactory.treeUtil.categoriesToFormatAnnotation(cats.value()); CFValue newResultValue = analysis.createSingleAnnotationValue( anno, result.getResultValue().getUnderlyingType()); return new RegularTransferResult<>(newResultValue, result.getRegularStore()); } } return result; } }