org.sosy_lab.cpachecker.util.CFAUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.CFAUtils.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.cpachecker.util;

import static com.google.common.base.Preconditions.*;
import static com.google.common.base.Predicates.not;

import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;

import org.sosy_lab.common.collect.Collections3;
import org.sosy_lab.cpachecker.cfa.ast.AbstractSimpleDeclaration;
import org.sosy_lab.cpachecker.cfa.model.AssumeEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdgeType;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.core.ShutdownNotifier;
import org.sosy_lab.cpachecker.util.CFATraversal.DefaultCFAVisitor;
import org.sosy_lab.cpachecker.util.CFATraversal.TraversalProcess;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.UnmodifiableIterator;

public class CFAUtils {

    /**
     * Return an {@link Iterable} that contains all entering edges of a given CFANode,
     * including the summary edge if the node as one.
     */
    public static FluentIterable<CFAEdge> allEnteringEdges(final CFANode node) {
        checkNotNull(node);
        return new FluentIterable<CFAEdge>() {

            @Override
            public Iterator<CFAEdge> iterator() {
                return new UnmodifiableIterator<CFAEdge>() {

                    // the index of the next edge (-1 means the summary edge)
                    private int i = (node.getEnteringSummaryEdge() != null) ? -1 : 0;

                    @Override
                    public boolean hasNext() {
                        return i < node.getNumEnteringEdges();
                    }

                    @Override
                    public CFAEdge next() {
                        if (i == -1) {
                            i = 0;
                            return node.getEnteringSummaryEdge();
                        }
                        return node.getEnteringEdge(i++);
                    }
                };
            }
        };
    }

    /**
     * Return an {@link Iterable} that contains the entering edges of a given CFANode,
     * excluding the summary edge.
     */
    public static FluentIterable<CFAEdge> enteringEdges(final CFANode node) {
        checkNotNull(node);
        return new FluentIterable<CFAEdge>() {

            @Override
            public Iterator<CFAEdge> iterator() {
                return new UnmodifiableIterator<CFAEdge>() {

                    // the index of the next edge
                    private int i = 0;

                    @Override
                    public boolean hasNext() {
                        return i < node.getNumEnteringEdges();
                    }

                    @Override
                    public CFAEdge next() {
                        return node.getEnteringEdge(i++);
                    }
                };
            }
        };
    }

    /**
     * Return an {@link Iterable} that contains all leaving edges of a given CFANode,
     * including the summary edge if the node as one.
     */
    public static FluentIterable<CFAEdge> allLeavingEdges(final CFANode node) {
        checkNotNull(node);
        return new FluentIterable<CFAEdge>() {

            @Override
            public Iterator<CFAEdge> iterator() {
                return new UnmodifiableIterator<CFAEdge>() {

                    // the index of the next edge (-1 means the summary edge)
                    private int i = (node.getLeavingSummaryEdge() != null) ? -1 : 0;

                    @Override
                    public boolean hasNext() {
                        return i < node.getNumLeavingEdges();
                    }

                    @Override
                    public CFAEdge next() {
                        if (i == -1) {
                            i = 0;
                            return node.getLeavingSummaryEdge();
                        }
                        return node.getLeavingEdge(i++);
                    }
                };
            }
        };
    }

    /**
     * Return an {@link Iterable} that contains the leaving edges of a given CFANode,
     * excluding the summary edge.
     */
    public static FluentIterable<CFAEdge> leavingEdges(final CFANode node) {
        checkNotNull(node);
        return new FluentIterable<CFAEdge>() {

            @Override
            public Iterator<CFAEdge> iterator() {
                return new UnmodifiableIterator<CFAEdge>() {

                    // the index of the next edge
                    private int i = 0;

                    @Override
                    public boolean hasNext() {
                        return i < node.getNumLeavingEdges();
                    }

                    @Override
                    public CFAEdge next() {
                        return node.getLeavingEdge(i++);
                    }
                };
            }
        };
    }

    public static final Function<CFAEdge, CFANode> TO_PREDECESSOR = new Function<CFAEdge, CFANode>() {
        @Override
        public CFANode apply(CFAEdge pInput) {
            return pInput.getPredecessor();
        }
    };

    public static final Function<CFAEdge, CFANode> TO_SUCCESSOR = new Function<CFAEdge, CFANode>() {
        @Override
        public CFANode apply(CFAEdge pInput) {
            return pInput.getSuccessor();
        }
    };

    /**
     * Return an {@link Iterable} that contains the predecessor nodes of a given CFANode,
     * excluding the one reachable via the summary edge (if there is one).
     */
    public static FluentIterable<CFANode> predecessorsOf(final CFANode node) {
        return enteringEdges(node).transform(TO_PREDECESSOR);
    }

    /**
     * Return an {@link Iterable} that contains all the predecessor nodes of a given CFANode,
     * including the one reachable via the summary edge (if there is one).
     */
    public static FluentIterable<CFANode> allPredecessorsOf(final CFANode node) {
        return allEnteringEdges(node).transform(TO_PREDECESSOR);
    }

    /**
     * Return an {@link Iterable} that contains the successor nodes of a given CFANode,
     * excluding the one reachable via the summary edge (if there is one).
     */
    public static FluentIterable<CFANode> successorsOf(final CFANode node) {
        return leavingEdges(node).transform(TO_SUCCESSOR);
    }

    /**
     * Return an {@link Iterable} that contains all the successor nodes of a given CFANode,
     * including the one reachable via the summary edge (if there is one).
     */
    public static FluentIterable<CFANode> allSuccessorsOf(final CFANode node) {
        return allLeavingEdges(node).transform(TO_SUCCESSOR);
    }

    public static final Function<CFANode, String> GET_FUNCTION = new Function<CFANode, String>() {
        @Override
        public String apply(CFANode pInput) {
            return pInput.getFunctionName();
        }
    };

    /**
     * A comparator for comparing {@link CFANode}s by their node numbers.
     */
    public static final Comparator<CFANode> NODE_NUMBER_COMPARATOR = new Comparator<CFANode>() {
        @Override
        public int compare(CFANode pO1, CFANode pO2) {
            return Integer.compare(pO1.getNodeNumber(), pO2.getNodeNumber());
        }
    };

    /**
     * Returns a predicate for CFA edges with the given edge type.
     * The predicate is not null safe.
     *
     * @param pEdgeType the edge type matched on.
     */
    public static Predicate<CFAEdge> edgeHasType(final CFAEdgeType pType) {
        checkNotNull(pType);
        return new Predicate<CFAEdge>() {

            @Override
            public boolean apply(CFAEdge pInput) {
                return pInput.getEdgeType() == pType;
            }

        };
    }

    /**
     * Returns the other AssumeEdge (with the negated condition)
     * of a given AssumeEdge.
     */
    public static AssumeEdge getComplimentaryAssumeEdge(AssumeEdge edge) {
        checkArgument(edge.getPredecessor().getNumLeavingEdges() == 2);
        return (AssumeEdge) Iterables.getOnlyElement(
                CFAUtils.leavingEdges(edge.getPredecessor()).filter(not(Predicates.<CFAEdge>equalTo(edge))));
    }

    /**
     * Checks if a path from the source to the target exists, using the given
     * function to obtain the edges leaving a node.
     *
     * @param pSource the search start node.
     * @param pTarget the target.
     * @param pGetLeavingEdges the function used to obtain leaving edges and thus
     * the successors of a node.
     * @param pShutdownNotifier the shutdown notifier to be checked.
     *
     * @return {@code true} if a path from the source to the target exists,
     * {@code false} otherwise.
     *
     * @throws InterruptedException if a shutdown has been requested by the given
     * shutdown notifier.
     */
    public static boolean existsPath(CFANode pSource, CFANode pTarget,
            Function<CFANode, Iterable<CFAEdge>> pGetLeavingEdges, ShutdownNotifier pShutdownNotifier)
            throws InterruptedException {
        Set<CFANode> visited = new HashSet<>();
        Queue<CFANode> waitlist = new ArrayDeque<>();
        waitlist.offer(pSource);
        while (!waitlist.isEmpty()) {
            pShutdownNotifier.shutdownIfNecessary();
            CFANode current = waitlist.poll();
            if (current.equals(pTarget)) {
                return true;
            }
            if (visited.add(current)) {
                for (CFAEdge leavingEdge : pGetLeavingEdges.apply(current)) {
                    CFANode succ = leavingEdge.getSuccessor();
                    waitlist.offer(succ);
                }
            }
        }
        return false;
    }

    /**
     * This Visitor searches for backwards edges in the CFA, if some backwards edges
     * were found can be obtained by calling the method hasBackwardsEdges()
     */
    private static class FindBackwardsEdgesVisitor extends DefaultCFAVisitor {

        private boolean hasBackwardsEdges = false;

        @Override
        public TraversalProcess visitNode(CFANode pNode) {

            if (pNode.getNumLeavingEdges() == 0) {
                return TraversalProcess.CONTINUE;
            } else if (pNode.getNumLeavingEdges() == 1 && pNode.getLeavingEdge(0).getSuccessor()
                    .getReversePostorderId() >= pNode.getReversePostorderId()) {

                hasBackwardsEdges = true;
                return TraversalProcess.ABORT;
            } else if (pNode.getNumLeavingEdges() == 2 && (pNode.getLeavingEdge(0).getSuccessor()
                    .getReversePostorderId() >= pNode.getReversePostorderId()
                    || pNode.getLeavingEdge(1).getSuccessor().getReversePostorderId() >= pNode
                            .getReversePostorderId())) {
                hasBackwardsEdges = true;
                return TraversalProcess.ABORT;
            } else if (pNode.getNumLeavingEdges() > 2) {
                throw new AssertionError("forgotten case in traversing cfa with more than 2 leaving edges");
            } else {
                return TraversalProcess.CONTINUE;
            }
        }

        public boolean hasBackwardsEdges() {
            return hasBackwardsEdges;
        }
    }

    /**
     * Searches for backwards edges from a given starting node
     * @param actNode The node where the search is started
     * @return indicates if a backwards edge was found
     */
    static boolean hasBackWardsEdges(CFANode rootNode) {
        FindBackwardsEdgesVisitor visitor = new FindBackwardsEdgesVisitor();

        CFATraversal.dfs().ignoreSummaryEdges().traverseOnce(rootNode, visitor);

        return visitor.hasBackwardsEdges();
    }

    /**
     * This method allows to select from a set of variables
     * all local variables from a given function.
     * This requires that the given set contains the qualified names of each variable
     * as returned by {@link AbstractSimpleDeclaration#getQualifiedName()}.
     *
     * @param variables Set of qualified names of variables.
     * @param function A function name.
     * @return A subset of "variables".
     */
    public static SortedSet<String> filterVariablesOfFunction(SortedSet<String> variables, String function) {
        // TODO: Currently the format of the qualified name is not defined.
        // In theory, frontends could use different formats.
        // The best would be to eliminate all uses of this method
        // (code should not use Strings, but for example AIdExpressions).
        // For now, we just assume all variables are named as
        // {@link org.sosy_lab.cpachecker.cfa.parser.eclipse.c.FunctionScope#createQualifiedName(String, String)}
        // produces them.
        String prefix = checkNotNull(function) + "::";
        return Collections3.subSetWithPrefix(variables, prefix);
    }
}