use of org.checkerframework.framework.util.Contract in project checker-framework by typetools.
the class BaseTypeVisitor method parseAndLocalizeContracts.
/**
* Localizes some contracts -- that is, viewpoint-adapts them to some method body, according to
* the value of {@link #methodTree}.
*
* <p>The input is a set of {@link Contract}s, each of which contains an expression string and an
* annotation. In a {@link Contract}, Java expressions are exactly as written in source code, not
* standardized or viewpoint-adapted.
*
* <p>The output is a set of pairs of {@link JavaExpression} (parsed expression string) and
* standardized annotation (with respect to the path of {@link #methodTree}. This method discards
* any contract whose expression cannot be parsed into a JavaExpression.
*
* @param contractSet a set of contracts
* @param methodType the type of the method that the contracts are for
* @return pairs of (expression, AnnotationMirror), which are localized contracts
*/
private Set<Pair<JavaExpression, AnnotationMirror>> parseAndLocalizeContracts(Set<? extends Contract> contractSet, AnnotatedExecutableType methodType) {
if (contractSet.isEmpty()) {
return Collections.emptySet();
}
// This is the path to a place where the contract is being used, which might or might not be
// where the contract was defined. For example, methodTree might be an overriding
// definition, and the contract might be for a superclass.
MethodTree methodTree = this.methodTree;
StringToJavaExpression stringToJavaExpr = expression -> {
JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, methodType.getElement(), checker);
// viewpoint-adapt it to methodTree.
return javaExpr.atMethodBody(methodTree);
};
Set<Pair<JavaExpression, AnnotationMirror>> result = new HashSet<>(contractSet.size());
for (Contract p : contractSet) {
String expressionString = p.expressionString;
AnnotationMirror annotation = p.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, methodTree);
JavaExpression exprJe;
try {
// TODO: currently, these expressions are parsed many times.
// This could be optimized to store the result the first time.
// (same for other annotations)
exprJe = stringToJavaExpr.toJavaExpression(expressionString);
} catch (JavaExpressionParseException e) {
// report errors here
checker.report(methodTree, e.getDiagMessage());
continue;
}
result.add(Pair.of(exprJe, annotation));
}
return result;
}
use of org.checkerframework.framework.util.Contract in project checker-framework by typetools.
the class CFAbstractTransfer method processPostconditionsAndConditionalPostconditions.
/**
* Add information from the postconditions and conditional postconditions of a method to the
* stores after an invocation.
*
* @param invocationNode a method call
* @param invocationTree the tree for the method call
* @param thenStore the "then" store; is side-effected by this method
* @param elseStore the "else" store; is side-effected by this method
* @param postconditions the postconditions
*/
private void processPostconditionsAndConditionalPostconditions(MethodInvocationNode invocationNode, Tree invocationTree, S thenStore, S elseStore, Set<? extends Contract> postconditions) {
StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodInvocation(stringExpr, invocationNode, analysis.checker);
for (Contract p : postconditions) {
// Viewpoint-adapt to the method use (the call site).
AnnotationMirror anno = p.viewpointAdaptDependentTypeAnnotation(analysis.atypeFactory, stringToJavaExpr, /*errorTree=*/
null);
String expressionString = p.expressionString;
try {
JavaExpression je = stringToJavaExpr.toJavaExpression(expressionString);
// are removed from the store before this method is called.
if (p.kind == Contract.Kind.CONDITIONALPOSTCONDITION) {
if (((ConditionalPostcondition) p).resultValue) {
thenStore.insertOrRefinePermitNondeterministic(je, anno);
} else {
elseStore.insertOrRefinePermitNondeterministic(je, anno);
}
} else {
thenStore.insertOrRefinePermitNondeterministic(je, anno);
}
} catch (JavaExpressionParseException e) {
// report errors here
if (e.isFlowParseError()) {
Object[] args = new Object[e.args.length + 1];
args[0] = ElementUtils.getSimpleSignature(TreeUtils.elementFromUse(invocationNode.getTree()));
System.arraycopy(e.args, 0, args, 1, e.args.length);
analysis.checker.reportError(invocationTree, "flowexpr.parse.error.postcondition", args);
} else {
analysis.checker.report(invocationTree, e.getDiagMessage());
}
}
}
}
use of org.checkerframework.framework.util.Contract in project checker-framework by typetools.
the class BaseTypeVisitor method checkPreconditions.
/**
* Checks that all the given {@code preconditions} hold true immediately prior to the method
* invocation or variable access at {@code tree}.
*
* @param tree the method invocation; immediately prior to it, the preconditions must hold true
* @param preconditions the preconditions to be checked
*/
protected void checkPreconditions(MethodInvocationTree tree, Set<Precondition> preconditions) {
// TODO: Remove this check and investigate the root cause.
if (preconditions.isEmpty()) {
return;
}
StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodInvocation(stringExpr, tree, checker);
for (Contract c : preconditions) {
Precondition p = (Precondition) c;
String expressionString = p.expressionString;
AnnotationMirror anno = c.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, tree);
JavaExpression exprJe;
try {
exprJe = StringToJavaExpression.atMethodInvocation(expressionString, tree, checker);
} catch (JavaExpressionParseException e) {
// report errors here
checker.report(tree, e.getDiagMessage());
return;
}
CFAbstractStore<?, ?> store = atypeFactory.getStoreBefore(tree);
CFAbstractValue<?> value = null;
if (CFAbstractStore.canInsertJavaExpression(exprJe)) {
value = store.getValue(exprJe);
}
AnnotationMirror inferredAnno = null;
if (value != null) {
QualifierHierarchy hierarchy = atypeFactory.getQualifierHierarchy();
Set<AnnotationMirror> annos = value.getAnnotations();
inferredAnno = hierarchy.findAnnotationInSameHierarchy(annos, anno);
}
if (!checkContract(exprJe, anno, inferredAnno, store)) {
if (exprJe != null) {
expressionString = exprJe.toString();
}
checker.reportError(tree, "contracts.precondition", tree.getMethodSelect().toString(), contractExpressionAndType(expressionString, inferredAnno), contractExpressionAndType(expressionString, anno));
}
}
}
use of org.checkerframework.framework.util.Contract in project checker-framework by typetools.
the class BaseTypeVisitor method checkContractsAtMethodDeclaration.
/**
* Check the contracts written on a method declaration. Ensures that the postconditions hold on
* exit, and that the contracts are well-formed.
*
* @param methodTree the method declaration
* @param methodElement the method element
* @param formalParamNames the formal parameter names
* @param abstractMethod whether the method is abstract
*/
private void checkContractsAtMethodDeclaration(MethodTree methodTree, ExecutableElement methodElement, List<String> formalParamNames, boolean abstractMethod) {
Set<Contract> contracts = atypeFactory.getContractsFromMethod().getContracts(methodElement);
if (contracts.isEmpty()) {
return;
}
StringToJavaExpression stringToJavaExpr = stringExpr -> StringToJavaExpression.atMethodBody(stringExpr, methodTree, checker);
for (Contract contract : contracts) {
String expressionString = contract.expressionString;
AnnotationMirror annotation = contract.viewpointAdaptDependentTypeAnnotation(atypeFactory, stringToJavaExpr, methodTree);
JavaExpression exprJe;
try {
exprJe = StringToJavaExpression.atMethodBody(expressionString, methodTree, checker);
} catch (JavaExpressionParseException e) {
DiagMessage diagMessage = e.getDiagMessage();
if (diagMessage.getMessageKey().equals("flowexpr.parse.error")) {
String s = String.format("'%s' in the %s %s on the declaration of method '%s': ", expressionString, contract.kind.errorKey, contract.contractAnnotation.getAnnotationType().asElement().getSimpleName(), methodTree.getName().toString());
checker.reportError(methodTree, "flowexpr.parse.error", s + diagMessage.getArgs()[0]);
} else {
checker.report(methodTree, e.getDiagMessage());
}
continue;
}
if (!CFAbstractStore.canInsertJavaExpression(exprJe)) {
checker.reportError(methodTree, "flowexpr.parse.error", expressionString);
continue;
}
if (!abstractMethod && contract.kind != Contract.Kind.PRECONDITION) {
switch(contract.kind) {
case POSTCONDITION:
checkPostcondition(methodTree, annotation, exprJe);
break;
case CONDITIONALPOSTCONDITION:
checkConditionalPostcondition(methodTree, annotation, exprJe, ((ConditionalPostcondition) contract).resultValue);
break;
default:
throw new BugInCF("Impossible: " + contract.kind);
}
}
if (formalParamNames != null && formalParamNames.contains(expressionString)) {
String locationOfExpression = contract.kind.errorKey + " " + contract.contractAnnotation.getAnnotationType().asElement().getSimpleName() + " on the declaration";
checker.reportWarning(methodTree, "expression.parameter.name.shadows.field", locationOfExpression, methodTree.getName().toString(), expressionString, expressionString, formalParamNames.indexOf(expressionString) + 1);
}
checkParametersAreEffectivelyFinal(methodTree, exprJe);
}
}
Aggregations