void TraceViewerDialog::visit(TraceSymbolicBranch *node) { // This printer only works for straight-line traces, so we require branches that one side is alwyas "capped" // by a TraceUnexplored node immediately. ExpressionPrinter printer; node->getSymbolicCondition()->accept(&printer); if(isImmediatelyUnexplored(node->getFalseBranch())){ // Took 'true' branch. mNodeList->addItem(QString("Branch: Condition: %1; Took true branch; Symbolic").arg(printer.getResult().data())); node->getTrueBranch()->accept(this); } else if(isImmediatelyUnexplored(node->getTrueBranch())){ // Took 'false' branch. mNodeList->addItem(QString("Branch: Condition: %1; Took false branch; Symbolic").arg(printer.getResult().data())); node->getFalseBranch()->accept(this); } else { // Invalid branch node Log::fatal("Trace Display: reached an invalid branch node."); exit(1); } }
void DepthFirstSearch::visit(TraceConcreteBranch *node) { // Concrete branches are basically ignored by this search. // If there are unexplored nodes as children of a concrete branch, then we ignore them and only search through children of symbolic branches. if(isImmediatelyUnexplored(node->getFalseBranch()) && isImmediatelyUnexplored(node->getTrueBranch())){ Log::fatal("Reached a branch where both branches are unexplored during search."); exit(1); }else if(isImmediatelyUnexplored(node->getFalseBranch())){ // Then we treat this node as a pass-through to the 'true' subtree node->getTrueBranch()->accept(this); }else if(isImmediatelyUnexplored(node->getTrueBranch())){ // Then we treat this node as a pass-through to the 'false' subtree node->getFalseBranch()->accept(this); }else{ // Both branches are explored, so we must search each in turn. mParentStack.push(SavedPosition(node, mCurrentDepth, mCurrentPC, mCurrentDomConstraints)); //mCurrentDepth++; // Do not increase depth for concrete branches. mPreviousParent = node; mPreviousDirection = false; // We are always taking the false branch to begin with. node->getFalseBranch()->accept(this); } }
void DepthFirstSearch::markNodeMissed() { // This method can only be called once we have started a search. assert(mIsPreviousRun); // Replace the current node with TraceUnexploredMissed. if(mPreviousDirection){ // Replace the true branch of mPreviousParent. assert(isImmediatelyUnexplored(mPreviousParent->getTrueBranch())); mPreviousParent->setTrueBranch(TraceUnexploredMissed::getInstance()); }else{ // Replace the false branch of mPreviousParent. assert(isImmediatelyUnexplored(mPreviousParent->getFalseBranch())); mPreviousParent->setFalseBranch(TraceUnexploredMissed::getInstance()); } }
/** * Selects an unexplored node from the tree to be explored next. * Calculates the constraint [hopefully] leading to the unexplored node it has chosen. * Returns true if an unexplored node was found (then the constraint can be retrieved with getTargetPC()) * and false when we reached the end of the tree. * N.B. in this case there may still be unexplored areas in the following cases: * * They were lower than the current search depth in the tree. * * They were skipped (i.e. the first attempt to explore them failed). * * A previously skipped node was explored "accidentally" by a later run. * * TODO: I think this mehtod assumes there will be at least one branch above any unexplored node. * This means we should only run it on a tree containing at least one trace for now. */ bool DepthFirstSearch::chooseNextTarget() { TraceNodePtr current; // Check if we are starting a new search or continuing an old one. if(mIsPreviousRun){ // Continue the search. // Check if the left/right (according to mPreviousDirection) child of mPreviousParent is still unexplored. // If so, skip it and search for the next unexplored node. // If not, we want to search the newly revealed area before continuing. // ASSUMPTION: if the true/false child of a branch eventually terminates in unexplored (without further branching) then it is immediately unexplored. if(mPreviousDirection){ // We are interested in the 'true' branch of mPreviousParent. current = mPreviousParent->getTrueBranch(); }else{ // We are interested in the 'false' branch of mPreviousParent. current = mPreviousParent->getFalseBranch(); } // The depth, PC, etc. are all already set from the previous call. if(isImmediatelyUnexplored(current)){ // Then the previous run did not reach the intended target. // Use the same method as continueFromLeaf() to jump to the next node to be searched. // If the parent stack is empty here, then we have reached the end of the search. if(mParentStack.empty()){ mFoundTarget = false; return deepenRestartAndChoose(); }else{ current = nextAfterLeaf(); } } }else{ // Strat a new search. current = mTree; } // Call the visitor to continue the search. current->accept(this); // Future runs should continue wherever we left off. mIsPreviousRun = true; // The visitor will set its own "output" in mCurrentPC. // This function returns whether we reached the end of the iteration or not. if(mFoundTarget) { mPreviousPassFoundTarget = true; return true; } else { // Attempt to increase the depth limit and restart, if possible. return deepenRestartAndChoose(); } }
void TraceViewerDialog::visit(TraceConcreteBranch *node) { // This printer only works for straight-line traces, so we require branches that one side is alwyas "capped" // by a TraceUnexplored node immediately. if(isImmediatelyUnexplored(node->getFalseBranch())){ // Took 'true' branch. mNodeList->addItem("Branch: Took true branch;"); node->getTrueBranch()->accept(this); } else if(isImmediatelyUnexplored(node->getTrueBranch())){ // Took 'false' branch. mNodeList->addItem("Branch: Took false branch;"); node->getFalseBranch()->accept(this); } else { // Invalid branch node Log::fatal("Trace Display: reached an invalid branch node."); exit(1); } }
bool DepthFirstSearch::overUnexploredNode() { // This method can only be called once we have started a search. assert(mIsPreviousRun); // Use mPreviousParent and mPreviousDirection to find the "current" node again, as in chooseNextTarget(). TraceNodePtr current; if(mPreviousDirection){ current = mPreviousParent->getTrueBranch(); }else{ current = mPreviousParent->getFalseBranch(); } return isImmediatelyUnexplored(current); }