/*
* Copyright (C) 2015 Matthias Heizmann (heizmann@informatik.uni-freiburg.de)
* Copyright (C) 2022 Dominik Klumpp (klumpp@informatik.uni-freiburg.de)
* Copyright (C) 2015-2022 University of Freiburg
*
* This file is part of the ULTIMATE ModelCheckerUtils Library.
*
* The ULTIMATE ModelCheckerUtils Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ULTIMATE ModelCheckerUtils Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ULTIMATE ModelCheckerUtils Library. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE ModelCheckerUtils Library, or any covered work, by linking
* or combining it with Eclipse RCP (or a modified version of Eclipse RCP),
* containing parts covered by the terms of the Eclipse Public License, the
* licensors of the ULTIMATE ModelCheckerUtils Library grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.hoaretriple;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.ModifiableGlobalsTable;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.ICallAction;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramOldVar;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicateCoverageChecker;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.IncrementalPlicationChecker.Validity;
class CallCheckHelper extends SdHoareTripleCheckHelper {
private static final String PRE_HIER_ERROR = "Unexpected hierarchical precondition for call action";
CallCheckHelper(final IPredicateCoverageChecker coverage, final IPredicate falsePredicate,
final IPredicate truePredicate, final HoareTripleCheckerStatisticsGenerator statistics,
final ModifiableGlobalsTable modifiableGlobals) {
super(coverage, falsePredicate, truePredicate, statistics, modifiableGlobals);
}
@Override
public Validity sdecToFalse(final IPredicate pre, final IPredicate preHier, final ICallAction call) {
assert preHier == null : PRE_HIER_ERROR;
// If the precondition is e.g. (distinct x |old(x)|) for some non-modifiable x, the triple is valid.
if (containsConflictingNonModifiableOldVars(call.getPrecedingProcedure(), pre)) {
return null;
}
// TODO: there could be a contradiction if the Call is not a simple call
// but interprocedural sequential composition
mStatistics.getSDtfsCounter().incCa();
return Validity.INVALID;
}
/**
* Returns true if p contains only non-old globals, or non-modifiable old variables.
*/
@Override
public boolean isInductiveSelfloop(final IPredicate pre, final IPredicate preHier, final ICallAction call,
final IPredicate post) {
assert preHier == null : PRE_HIER_ERROR;
if (pre != post) {
return false;
}
final String caller = call.getPrecedingProcedure();
for (final IProgramVar bv : pre.getVars()) {
// If pre contains a local variable, the triple might be invalid, as local variables could be modified
// (assigned or havoced) by the call.
if (!bv.isGlobal()) {
return false;
}
// Similarly, pre must also not contain any final old variables belonging to modifiable global variables, as
// such old variables could also be modified by the call.
if (bv.isOldvar() && mModifiableGlobals.isModifiable((IProgramOldVar) bv, caller)) {
return false;
}
}
// TODO Is this really enough? In particular, interprocedural compositions might assign global variables, right?
// TODO So wouldn't it be better to examine the assigned variables of the transition formula?
// TODO But do those contain ALL the modifications (params, local vars of caller and callee, old vars) ?
mStatistics.getSDsluCounter().incCa();
return true;
}
@Override
public Validity sdec(final IPredicate pre, final IPredicate preHier, final ICallAction call,
final IPredicate post) {
assert preHier == null : PRE_HIER_ERROR;
final var caller = call.getPrecedingProcedure();
final var callee = call.getSucceedingProcedure();
if (mModifiableGlobals.containsNonModifiableOldVars(pre, caller)
|| mModifiableGlobals.containsNonModifiableOldVars(post, callee)) {
return null;
}
if (!disjointFunctions(pre, post)) {
// If pre and post both refer to the same constant (or function), the triple could be valid.
return null;
}
for (final IProgramVar bv : post.getVars()) {
if (bv.isOldvar()) {
// If post contains old vars, e.g. post is (= x |old(x)|), the triple could be valid.
// Unlike other cases, here it does not matter whether x is modifiable or not.
return null;
} else if (bv.isGlobal() && pre.getVars().contains(bv)) {
return null;
}
}
// workaround see preHierIndependent()
final UnmodifiableTransFormula locVarAssignTf = call.getLocalVarsAssignment();
if (!varsDisjointFromOutVars(pre, locVarAssignTf)) {
return null;
}
// TODO: Matthias 7.10.2012 I hoped following would be sufficient. But this is not sufficient when constant
// assigned to invar, e.g. post is x!=0 and call is x_Out=1. Might be solved with dataflow map.
//
// 8.10.2012 consider also case where inVar is non-modifiable global which does not occur in pre, but in post
//
// if (!varSetDisjoint(pre.getVars(), locVarAssignTf.getInVars().keySet())
// && !varSetDisjoint(locVarAssignTf.getAssignedVars(), post.getVars())) {
// return false;
// }
//
// workaround for preceding problem
if (!varsDisjointFromOutVars(post, locVarAssignTf)) {
return null;
}
mStatistics.getSDsCounter().incCa();
return Validity.INVALID;
}
@Override
public Validity sdLazyEc(final IPredicate pre, final IPredicate preHier, final ICallAction call,
final IPredicate post) {
assert preHier == null : PRE_HIER_ERROR;
if (isOrIteFormula(post)) {
return sdec(pre, null, call, post);
}
final UnmodifiableTransFormula locVarAssignTf = call.getLocalVarsAssignment();
final boolean argumentsRestrictedByPre = !varsDisjointFromInVars(pre, locVarAssignTf);
for (final IProgramVar bv : post.getVars()) {
if (bv.isGlobal()) {
continue;
}
if (locVarAssignTf.getOutVars().keySet().contains(bv)) {
if (argumentsRestrictedByPre) {
continue;
}
}
mStatistics.getSdLazyCounter().incCa();
return Validity.INVALID;
}
return null;
}
}