/** * Returns true if the constraint is associated with the given FromElement. * * @param constraint the constraint in question * @param fromElement the FromElement to check * @return true if associated */ public static boolean isRelatedTo(Constraint constraint, FromElement fromElement) { if (isAssociatedWith(constraint, fromElement)) { return true; } // also want to find out if this is referred to in a Contains or Subquery // constraint that is associated with another fromElement. if (constraint instanceof ContainsConstraint) { if (fromElement == ((ContainsConstraint) constraint).getQueryClass()) { return true; } } else if (constraint instanceof SubqueryConstraint) { if (fromElement == ((SubqueryConstraint) constraint).getQuery()) { return true; } } else if (constraint instanceof SimpleConstraint) { SimpleConstraint sc = (SimpleConstraint) constraint; Set<QueryField> qFields = getQueryFields(sc.getArg1()); qFields.addAll(getQueryFields(sc.getArg2())); for (QueryField qf : qFields) { if (fromElement == qf.getFromElement()) { return true; } } } return false; }
/** * Returns true if the given constraint is related to no FromElement. This should only return true * if c is a SimpleConstraint that only references constants. * * @param c the constraint to examine * @return true if constraint is not associated with a FromElement */ public static boolean isRelatedToNothing(Constraint c) { if (c instanceof SimpleConstraint) { SimpleConstraint sc = (SimpleConstraint) c; Set<QueryField> fields = getQueryFields(sc.getArg1()); fields.addAll(getQueryFields(sc.getArg2())); if (fields.size() == 0) { return true; } } return false; }
@Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('[').append('\n'); for (BaseConstraint bc : getBaseConstraints()) { sb.append('{').append(bc.getSubVar()).append("} \u2286 "); sb.append(bc.getSuperVar()).append('\n'); } for (SimpleConstraint bc : getSimpleConstraints()) { sb.append(bc.getSubVar()).append(" \u2286 "); sb.append(bc.getSuperVar()).append('\n'); } for (ComplexConstraint bc : getComplexConstraints()) { sb.append(bc.getSubVar()).append(" \u2286 "); sb.append(bc.getSuperVar()).append('\n'); } int size = getBaseConstraints().size() + getSimpleConstraints().size() + getComplexConstraints().size(); sb.append("] size-> ").append(size); // points-to sets sb.append('\n'); sb.append('[').append('\n'); Map<String, String[]> ptSet = getPointsToSets(); for (String key : ptSet.keySet()) { sb.append(key).append(" -> {"); String[] vals = ptSet.get(key); for (String val : vals) { sb.append(val).append(','); } if (vals.length > 0) { sb.setLength(sb.length() - 1); } sb.append('}').append('\n'); } sb.append(']').append('\n'); return sb.toString(); }
/** * Constructs the online graph for the analysis. Additionally an offline graph for HCD is * constructed to speed up the computation of the dynamic transitive closure with it. * * @param bConstr List of all {@link BaseConstraint}s that should be considered.<br> * A {@link BaseConstraint} leads to an entry in a nodes points-to set. * @param sConstr List of all {@link SimpleConstraint}s that should be considered.<br> * A {@link SimpleConstraint} represents an edge in the graph. * @param cConstr List of all {@link ComplexConstraint}s that should be considered.<br> * {@link ComplexConstraint}s are stored in nodes, so they can be accessed faster when * computing the dynamic transitive closure. * @param g The resulting graph. Should be empty. */ private static void buildGraph( Set<BaseConstraint> bConstr, Set<SimpleConstraint> sConstr, Set<ComplexConstraint> cConstr, DirectedGraph g) { // HCD offline - build offline graph List<List<String>> sccs = buildOfflineGraphAndFindSCCs(sConstr, cConstr); // build online graph for (BaseConstraint bc : bConstr) { DirectedGraph.Node n = g.getNode(bc.getSuperVar()); n.addPointerTarget(bc.getSubVar()); } for (SimpleConstraint sc : sConstr) { DirectedGraph.Node src = g.getNode(sc.getSubVar()); DirectedGraph.Node dest = g.getNode(sc.getSuperVar()); g.addEdge(src, dest); } for (ComplexConstraint cc : cConstr) { DirectedGraph.Node n; if (cc.isSubDerefed()) { n = g.getNode(cc.getSubVar()); n.complexConstrMeSub.add(cc.getSuperVar()); } else { n = g.getNode(cc.getSuperVar()); n.complexConstrMeSuper.add(cc.getSubVar()); } } // for HCD mergeOrMarkSCCs(g, sccs); // ... in online graph }
/** * Builds an offline graph for HCD and finds all SCCs in it.<br> * For the offline version {@link BaseConstraint}s are not relevant and {@link SimpleConstraint}s * and {@link ComplexConstraint}s represents an edge in graph. * * @param sConstr List of all {@link SimpleConstraint}s that should be considered. * @param cConstr List of all {@link ComplexConstraint}s that should be considered. * @return a list of all SCCs. One SCC is represented as a list of all variables it contains. */ private static List<List<String>> buildOfflineGraphAndFindSCCs( Collection<SimpleConstraint> sConstr, Collection<ComplexConstraint> cConstr) { HashSet<DirectedGraph.Node> workset = new HashSet<>(); DirectedGraph g = new DirectedGraph(); HashMap<DirectedGraph.Node, String> nodeStrMap = new HashMap<>(); for (SimpleConstraint sc : sConstr) { String srcStr = sc.getSubVar(); String destStr = sc.getSuperVar(); DirectedGraph.Node src = g.getNode(srcStr); DirectedGraph.Node dest = g.getNode(destStr); g.addEdge(src, dest); workset.add(src); workset.add(dest); nodeStrMap.put(src, srcStr); nodeStrMap.put(dest, destStr); } for (ComplexConstraint cc : cConstr) { String srcStr, destStr; if (cc.isSubDerefed()) { srcStr = '*' + cc.getSubVar(); destStr = cc.getSuperVar(); } else { srcStr = cc.getSubVar(); destStr = '*' + cc.getSuperVar(); } DirectedGraph.Node src = g.getNode(srcStr); DirectedGraph.Node dest = g.getNode(destStr); g.addEdge(src, dest); workset.add(src); workset.add(dest); nodeStrMap.put(src, srcStr); nodeStrMap.put(dest, destStr); } // find strongly-connected components (using tarjans linear algorithm) int maxdfs = 1; LinkedList<DirectedGraph.Node> stack = new LinkedList<>(); List<List<String>> sccs = new LinkedList<>(); while (!workset.isEmpty()) { DirectedGraph.Node n = workset.iterator().next(); maxdfs = tarjan(maxdfs, n, workset, stack, nodeStrMap, sccs); } return sccs; }