edu.buaa.satla.analysis.util.SourceLocationMapper.java Source code

Java tutorial

Introduction

Here is the source code for edu.buaa.satla.analysis.util.SourceLocationMapper.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 edu.buaa.satla.analysis.util;

import java.util.Collections;
import java.util.Deque;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.eclipse.cdt.internal.core.parser.scanner.Token;
import org.sosy_lab.cpachecker.cfa.ast.FileLocation;
import org.sosy_lab.cpachecker.cfa.ast.c.CAstNode;
import org.sosy_lab.cpachecker.cfa.ast.c.CDeclaration;
import org.sosy_lab.cpachecker.cfa.ast.c.CExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpressionCollectingVisitor;
import org.sosy_lab.cpachecker.cfa.ast.c.CVariableDeclaration;
import org.sosy_lab.cpachecker.cfa.ast.c.FileLocationCollectingVisitor;
import org.sosy_lab.cpachecker.cfa.model.BlankEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.model.MultiEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CAssumeEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CDeclarationEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionCallEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionReturnEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionSummaryEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CReturnStatementEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CStatementEdge;

import com.google.common.base.Optional;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;

public class SourceLocationMapper {

    private static Map<String, Set<Integer>> variableRelatedTokens = Maps.newHashMap();
    private static Map<Integer, Token> tokenNumberToTokenMap = Maps.newHashMap();
    private static Map<Integer, Integer> tokenNumberToLineNumberMap = Maps.newHashMap();

    public static class OriginDescriptor implements Comparable<OriginDescriptor> {
        public final Optional<String> originFileName;
        public final int originLineNumber;

        public OriginDescriptor(Optional<String> pOriginFileName, int pOriginLineNumber) {
            this.originFileName = pOriginFileName;
            this.originLineNumber = pOriginLineNumber;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((originFileName == null) ? 0 : originFileName.hashCode());
            result = prime * result + originLineNumber;
            return result;
        }

        @Override
        public boolean equals(Object pObj) {
            if (!(pObj instanceof OriginDescriptor)) {
                return false;
            }
            return this.compareTo((OriginDescriptor) pObj) == 0;
        }

        @Override
        public int compareTo(OriginDescriptor that) {
            return ComparisonChain.start()
                    .compare(this.originFileName.orNull(), that.originFileName.orNull(),
                            Ordering.natural().nullsFirst())
                    .compare(this.originLineNumber, that.originLineNumber).result();
        }
    }

    public static Set<String> matchTokenNumbersToTokenStrings(final Set<Integer> tokenNumbers) {
        return Collections.emptySet();
    }

    public static void storeTokenInformation(final Token token, final int lineNumber, final int tokenNumber) {
        tokenNumberToTokenMap.put(tokenNumber, token);
        tokenNumberToLineNumberMap.put(tokenNumber, lineNumber);
    }

    private static void collectLine(final SortedSet<Integer> target, final FileLocation loc,
            boolean overApproximateTokens) {
        if (loc != null && !loc.equals(FileLocation.DUMMY)) {
            if (overApproximateTokens) {
                int lowerBound = loc.getStartingLineNumber();
                int upperBound = loc.getEndingLineNumber();
                if (target.size() > 0) {
                    lowerBound = Math.min(lowerBound, target.first());
                    upperBound = Math.max(upperBound, target.last());
                }
                for (int line = lowerBound; line <= upperBound; line++) {
                    target.add(line);
                }
            } else {
                target.add(loc.getStartingLineNumber());
            }
        }
    }

    public static Set<Integer> collectTokensFrom(CAstNode astNode, boolean overApproximateTokens) {
        final TreeSet<Integer> result = Sets.newTreeSet();
        Set<FileLocation> locs = collectFileLocationsFrom(astNode);

        for (FileLocation l : locs) {
            collectLine(result, l, overApproximateTokens);
        }

        return result;
    }

    public static class RowAndColumn implements Comparable<RowAndColumn> {
        public final int row;
        public final int column;

        public RowAndColumn(int row, int col) {
            this.row = row;
            this.column = col;
        }

        @Override
        public String toString() {
            return row + ":" + column;
        }

        @Override
        public int compareTo(RowAndColumn pO) {
            if ((pO.row == this.row) && (pO.column == this.column)) {
                return 0;
            } else {
                if (pO.row == this.row) {
                    if (pO.column > this.column) {
                        return 1;
                    } else {
                        return -1;
                    }
                } else if (pO.row > this.row) {
                    return 1;
                } else {
                    return -1;
                }
            }
        }

        @Override
        public int hashCode() {
            return 31 * (31 + column) + row;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof RowAndColumn)) {
                return false;
            }
            RowAndColumn other = (RowAndColumn) obj;
            return row == other.row && column == other.column;
        }
    }

    public static synchronized Set<RowAndColumn> collectRowsAndColsFrom(CAstNode astNode,
            boolean overApproximateTokens) {
        final TreeSet<RowAndColumn> result = Sets.newTreeSet();
        Set<FileLocation> locs = collectFileLocationsFrom(astNode);

        for (FileLocation l : locs) {
            RowAndColumn rc = new RowAndColumn(l.getStartingLineNumber(), l.getNodeOffset());
            result.add(rc);
        }

        return result;
    }

    public static synchronized Set<FileLocation> collectFileLocationsFrom(CAstNode astNode) {
        final FileLocationCollectingVisitor visitor = new FileLocationCollectingVisitor();
        return astNode.accept(visitor);
    }

    public static synchronized Set<CAstNode> getAstNodesFromCfaEdge(CFAEdge pEdge) {
        final Set<CAstNode> result = Sets.newHashSet();
        final Deque<CFAEdge> edges = Queues.newArrayDeque();

        edges.add(pEdge);

        while (!edges.isEmpty()) {
            CFAEdge edge = edges.pop();

            switch (edge.getEdgeType()) {
            case MultiEdge:
                edges.addAll(((MultiEdge) edge).getEdges());
                break;
            case AssumeEdge:
                result.add(((CAssumeEdge) edge).getExpression());
                break;
            case CallToReturnEdge:
                CFunctionSummaryEdge fnSumEdge = (CFunctionSummaryEdge) edge;
                result.add(fnSumEdge.getExpression());
                break;
            case DeclarationEdge:
                result.add(((CDeclarationEdge) edge).getDeclaration());
                break;
            case FunctionCallEdge:
                if (edge.getPredecessor().getLeavingSummaryEdge() != null) {
                    edges.add(edge.getPredecessor().getLeavingSummaryEdge());
                }
                result.addAll(((CFunctionCallEdge) edge).getArguments());
                break;
            case FunctionReturnEdge:
                break;
            case ReturnStatementEdge:
                CReturnStatementEdge retStmt = (CReturnStatementEdge) edge;
                if (retStmt.getRawAST().isPresent()) {
                    result.add(retStmt.getRawAST().get());
                }

                if (retStmt.getExpression().isPresent()) {
                    result.add(retStmt.getExpression().get());
                }
                break;
            case StatementEdge:
                result.add(((CStatementEdge) edge).getStatement());
                break;
            }
        }

        return result;
    }

    public static synchronized Set<FileLocation> getFileLocationsFromCfaEdge(CFAEdge pEdge) {
        final Set<FileLocation> result = Sets.newHashSet();

        final Set<CAstNode> astNodes = getAstNodesFromCfaEdge(pEdge);
        for (CAstNode n : astNodes) {
            result.addAll(collectFileLocationsFrom(n));
        }

        result.add(pEdge.getFileLocation());

        return result;
    }

    public static synchronized Set<RowAndColumn> getRowsAndColsFromCFAEdge(CFAEdge pEdge,
            boolean overApproximateTokens) {
        final TreeSet<RowAndColumn> result = Sets.newTreeSet();
        final Set<CAstNode> astNodes = getAstNodesFromCfaEdge(pEdge);

        for (CAstNode n : astNodes) {
            result.addAll(collectRowsAndColsFrom(n, overApproximateTokens));
        }

        RowAndColumn rc = new RowAndColumn(pEdge.getFileLocation().getStartingLineNumber(),
                pEdge.getFileLocation().getNodeOffset());
        result.add(rc);

        return result;
    }

    public static synchronized Set<Integer> getAbsoluteTokensFromCFAEdge(CFAEdge pEdge,
            boolean overApproximateTokens) {
        final TreeSet<Integer> result = Sets.newTreeSet();
        final Deque<CFAEdge> edges = Queues.newArrayDeque();
        final Deque<CAstNode> astNodes = Queues.newArrayDeque();

        if (overApproximateTokens) {
            Set<String> variables = getEdgeVariableNames(pEdge);
            for (String variable : variables) {
                if (variable.contains("__CPA")) {
                    Set<Integer> tokens = variableRelatedTokens.get(variable);
                    if (tokens != null) {
                        result.addAll(tokens);
                    } else {
                        result.addAll(Collections.<Integer>emptySet());
                    }
                }
            }
        }

        edges.add(pEdge);

        while (!edges.isEmpty()) {
            CFAEdge edge = edges.pop();
            CFANode startNode = edge.getPredecessor();

            if (overApproximateTokens) {
                result.add(edge.getLineNumber());
            }

            switch (edge.getEdgeType()) {
            case MultiEdge:
                edges.addAll(((MultiEdge) edge).getEdges());
                break;
            case AssumeEdge:
                if (overApproximateTokens) {
                    result.add(edge.getFileLocation().getEndingLineNumber());

                    // Assumes of a while loop should also include the while token
                    for (CFAEdge e : CFAUtils.enteringEdges(startNode)) {
                        if (e instanceof BlankEdge) {
                            result.add(e.getLineNumber());
                        }
                    }
                }
                CAssumeEdge assumeEdge = ((CAssumeEdge) edge);
                astNodes.add(assumeEdge.getExpression());
                break;
            case CallToReturnEdge:
                CFunctionSummaryEdge fnSumEdge = (CFunctionSummaryEdge) edge;
                result.add(fnSumEdge.getLineNumber());
                astNodes.add(fnSumEdge.getExpression());
                break;
            case DeclarationEdge:
                CDeclaration decl = ((CDeclarationEdge) edge).getDeclaration();
                collectLine(result, decl.getFileLocation(), overApproximateTokens);
                if (decl instanceof CVariableDeclaration) {
                    CVariableDeclaration varDecl = (CVariableDeclaration) decl;
                    if (varDecl.getInitializer() != null) {
                        result.addAll(collectTokensFrom(varDecl.getInitializer(), overApproximateTokens));
                    }
                }
                break;
            case FunctionCallEdge:
                if (edge.getPredecessor().getLeavingSummaryEdge() != null) {
                    edges.add(edge.getPredecessor().getLeavingSummaryEdge());
                }
                result.add(((CFunctionCallEdge) edge).getLineNumber());
                astNodes.addAll(((CFunctionCallEdge) edge).getArguments());
                break;
            case FunctionReturnEdge:
                result.add(((CFunctionReturnEdge) edge).getLineNumber());
                break;
            case ReturnStatementEdge:
                result.add(((CReturnStatementEdge) edge).getLineNumber());
                Optional<CExpression> expr = ((CReturnStatementEdge) edge).getExpression();
                if (expr.isPresent()) {
                    astNodes.add(expr.get());
                }
                break;
            case StatementEdge:
                result.addAll(collectTokensFrom(((CStatementEdge) edge).getStatement(), overApproximateTokens));
                break;
            }

            while (!astNodes.isEmpty()) {
                CAstNode node = astNodes.pop();
                result.addAll(collectTokensFrom(node, overApproximateTokens));
            }
        }

        return result;
    }

    public static synchronized void getKnownToEdge(CFAEdge edge) {
        Set<String> variables = getEdgeVariableNames(edge);
        Set<Integer> tokens = getAbsoluteTokensFromCFAEdge(edge, true);

        // Store for each variable the related tokens
        for (String variable : variables) {
            Set<Integer> variableTokens = variableRelatedTokens.get(variable);
            if (variableTokens == null) {
                variableTokens = Sets.newTreeSet();
                variableRelatedTokens.put(variable, variableTokens);
            }
            variableTokens.addAll(tokens);
        }
    }

    public static Set<String> getEdgeVariableNames(CFAEdge subject) {
        CIdExpressionCollectingVisitor visitor = new CIdExpressionCollectingVisitor();

        final Set<String> result = Sets.newHashSet();
        final Set<CIdExpression> idExs = Sets.newHashSet();
        final Deque<CFAEdge> edges = Queues.newArrayDeque();

        edges.add(subject);

        while (!edges.isEmpty()) {
            CFAEdge edge = edges.pop();

            switch (edge.getEdgeType()) {
            case MultiEdge:
                edges.addAll(((MultiEdge) edge).getEdges());
                break;
            case AssumeEdge:
                CAssumeEdge assumeEdge = ((CAssumeEdge) edge);
                idExs.addAll(assumeEdge.getExpression().accept(visitor));
                break;
            case CallToReturnEdge:
                CFunctionSummaryEdge fnSumEdge = (CFunctionSummaryEdge) edge;
                idExs.addAll(fnSumEdge.getExpression().accept(visitor));
                break;
            case DeclarationEdge:
                CDeclaration decl = ((CDeclarationEdge) edge).getDeclaration();
                if (decl instanceof CVariableDeclaration) {
                    CVariableDeclaration varDecl = (CVariableDeclaration) decl;
                    result.add(varDecl.getQualifiedName());
                    if (varDecl.getInitializer() != null) {
                        idExs.addAll(varDecl.getInitializer().accept(visitor));
                    }
                }
                break;
            case FunctionCallEdge:
                CFunctionCallEdge callEdge = (CFunctionCallEdge) edge;
                for (CExpression e : callEdge.getArguments()) {
                    idExs.addAll(e.accept(visitor));
                }
                break;
            case FunctionReturnEdge:
                break;
            case ReturnStatementEdge:
                Optional<CExpression> expr = ((CReturnStatementEdge) edge).getExpression();
                if (expr.isPresent()) {
                    idExs.addAll(expr.get().accept(visitor));
                }
                break;
            case StatementEdge:
                idExs.addAll(((CStatementEdge) edge).getStatement().accept(visitor));
                break;
            }
        }

        for (CIdExpression e : idExs) {
            if (e.getDeclaration() != null) {
                result.add(e.getDeclaration().getQualifiedName());
            }
        }

        return result;
    }

}