| 45 | import static pascal.taie.analysis.graph.icfg.ICFGBuilder.getCFGOf; |
| 46 | |
| 47 | class DefaultICFG extends AbstractICFG<JMethod, Stmt> { |
| 48 | |
| 49 | private static final Logger logger = LogManager.getLogger(DefaultICFG.class); |
| 50 | |
| 51 | private final MultiMap<Stmt, ICFGEdge<Stmt>> inEdges = Maps.newMultiMap(); |
| 52 | |
| 53 | private final MultiMap<Stmt, ICFGEdge<Stmt>> outEdges = Maps.newMultiMap(); |
| 54 | |
| 55 | private final Map<Stmt, CFG<Stmt>> stmtToCFG = Maps.newLinkedHashMap(); |
| 56 | |
| 57 | DefaultICFG(CallGraph<Stmt, JMethod> callGraph) { |
| 58 | super(callGraph); |
| 59 | build(callGraph); |
| 60 | } |
| 61 | |
| 62 | private void build(CallGraph<Stmt, JMethod> callGraph) { |
| 63 | callGraph.forEach(method -> { |
| 64 | CFG<Stmt> cfg = getCFGOf(method); |
| 65 | if (cfg == null) { |
| 66 | logger.warn("CFG of {} is absent, try to fix this" + |
| 67 | " by adding option: -scope REACHABLE", method); |
| 68 | return; |
| 69 | } |
| 70 | cfg.forEach(stmt -> { |
| 71 | stmtToCFG.put(stmt, cfg); |
| 72 | cfg.getOutEdgesOf(stmt).forEach(edge -> { |
| 73 | ICFGEdge<Stmt> local = isCallSite(stmt) ? |
| 74 | new CallToReturnEdge<>(edge) : |
| 75 | new NormalEdge<>(edge); |
| 76 | outEdges.put(stmt, local); |
| 77 | inEdges.put(edge.target(), local); |
| 78 | }); |
| 79 | if (isCallSite(stmt)) { |
| 80 | getCalleesOf(stmt).forEach(callee -> { |
| 81 | if (getCFGOf(callee) == null) { |
| 82 | logger.warn("CFG of {} is missing", callee); |
| 83 | return; |
| 84 | } |
| 85 | // Add call edges |
| 86 | Stmt entry = getEntryOf(callee); |
| 87 | CallEdge<Stmt> call = new CallEdge<>(stmt, entry, callee); |
| 88 | outEdges.put(stmt, call); |
| 89 | inEdges.put(entry, call); |
| 90 | // Add return edges |
| 91 | Stmt exit = getExitOf(callee); |
| 92 | Set<Var> retVars = Sets.newHybridSet(); |
| 93 | Set<ClassType> exceptions = Sets.newHybridSet(); |
| 94 | // The exit node of CFG is mock, thus it is not |
| 95 | // a real return or excepting Stmt. We need to |
| 96 | // collect return and exception information from |
| 97 | // the real return and excepting Stmts, and attach |
| 98 | // them to the ReturnEdge. |
| 99 | getCFGOf(callee).getInEdgesOf(exit).forEach(retEdge -> { |
| 100 | if (retEdge.getKind() == CFGEdge.Kind.RETURN) { |
| 101 | Return ret = (Return) retEdge.source(); |
| 102 | if (ret.getValue() != null) { |
| 103 | retVars.add(ret.getValue()); |
| 104 | } |
nothing calls this directly
no test coverage detected