<commit_before>package polyglot.visit;

import polyglot.ast.*;
import polyglot.types.*;
import polyglot.util.*;
import java.util.*;

public class FlowGraph {
  /**
   * Maps from AST nodes to path maps and hence to <code>Peer</code>s
   * that represent occurrences of the
   * AST node in the flow graph.  In particular, <code>peerMap</code>
   * maps <code>IdentityKey(Node)</code>s to path maps.  A path map is a
   * map from paths (<code>ListKey(List of Terms)</code>) to
   * <code>Peer</code>s.  In particular, if <code>n</code> is an AST
   * node in a finally block, then there will be a <code>Peer</code> of
   * <code>n</code> for each possible path to the finally block, and the
   * path map records which <code>Peer</code> corresponds to which path.
   * If <code>n</code> does not occur in a finally block, then the path
   * map should have only a single entry, from an empty list to the
   * unique <code>Peer</code> for <code>n</code>.
   *
   * <p>
   * <b>WARNING</b>: the AST must be a tree, not a DAG.  Otherwise the
   * same peer may be used for a node that appears at multiple points in
   * the AST.  These points may have different data flows.
   * </p>
   */  
  protected Map peerMap;
  
  /**
   * The root of the AST that this is a flow graph for.
   */
  protected Term root;
  
  /**
   * Is the flow in this flow graph forward or backward?
   */
  protected boolean forward;

  FlowGraph(Term root, boolean forward) {
    this.root = root;
    this.forward = forward;
    this.peerMap = new HashMap();
  }

  public Term startNode() { return forward ? root.entry() : root; }
  public Term finishNode() { return forward ? root : root.entry(); }
  public Term entryNode() { return root.entry(); }
  public Term exitNode() { return root; }
  public Term root() { return root; }
  public boolean forward() { return forward; }

  public Collection pathMaps() {
    return peerMap.values();
  }

  public Map pathMap(Node n) {
    return (Map) peerMap.get(new IdentityKey(n));
  }

  /**
   * Return a collection of all <code>Peer</code>s in this flow graph.
   */
  public Collection peers() {
    Collection c = new ArrayList();
    for (Iterator i = peerMap.values().iterator(); i.hasNext(); ) {
      Map m = (Map) i.next();
      for (Iterator j = m.values().iterator(); j.hasNext(); ) {
        c.add(j.next());
      }
    }
    return c;
  }

  /**
   * Retrieve the <code>Peer</code> for the <code>Term n</code>, where 
   * <code>n</code> does not appear in a finally block. If no such Peer 
   * exists, then one will be created.
   * 
   * @param df unused; for legacy purposes only?
   */
  public Peer peer(Term n, DataFlow df) {
    return peer(n, Collections.EMPTY_LIST, df);
  }

  /**
   * Return a collection of all of the <code>Peer</code>s for the given 
   * <code>Term n</code>. 
   */
  public Collection peers(Term n) {
    IdentityKey k = new IdentityKey(n);
    Map pathMap = (Map) peerMap.get(k);
    return pathMap.values();
  }

  /**<commit_msg>Made peers(Term n) return an empty list rather than throw an exception if n is not an AST node in the flow graph.<commit_after>package polyglot.visit;

import polyglot.ast.*;
import polyglot.types.*;
import polyglot.util.*;
import java.util.*;

public class FlowGraph {
  /**
   * Maps from AST nodes to path maps and hence to <code>Peer</code>s
   * that represent occurrences of the
   * AST node in the flow graph.  In particular, <code>peerMap</code>
   * maps <code>IdentityKey(Node)</code>s to path maps.  A path map is a
   * map from paths (<code>ListKey(List of Terms)</code>) to
   * <code>Peer</code>s.  In particular, if <code>n</code> is an AST
   * node in a finally block, then there will be a <code>Peer</code> of
   * <code>n</code> for each possible path to the finally block, and the
   * path map records which <code>Peer</code> corresponds to which path.
   * If <code>n</code> does not occur in a finally block, then the path
   * map should have only a single entry, from an empty list to the
   * unique <code>Peer</code> for <code>n</code>.
   *
   * <p>
   * <b>WARNING</b>: the AST must be a tree, not a DAG.  Otherwise the
   * same peer may be used for a node that appears at multiple points in
   * the AST.  These points may have different data flows.
   * </p>
   */  
  protected Map peerMap;
  
  /**
   * The root of the AST that this is a flow graph for.
   */
  protected Term root;
  
  /**
   * Is the flow in this flow graph forward or backward?
   */
  protected boolean forward;

  FlowGraph(Term root, boolean forward) {
    this.root = root;
    this.forward = forward;
    this.peerMap = new HashMap();
  }

  public Term startNode() { return forward ? root.entry() : root; }
  public Term finishNode() { return forward ? root : root.entry(); }
  public Term entryNode() { return root.entry(); }
  public Term exitNode() { return root; }
  public Term root() { return root; }
  public boolean forward() { return forward; }

  public Collection pathMaps() {
    return peerMap.values();
  }

  public Map pathMap(Node n) {
    return (Map) peerMap.get(new IdentityKey(n));
  }

  /**
   * Return a collection of all <code>Peer</code>s in this flow graph.
   */
  public Collection peers() {
    Collection c = new ArrayList();
    for (Iterator i = peerMap.values().iterator(); i.hasNext(); ) {
      Map m = (Map) i.next();
      for (Iterator j = m.values().iterator(); j.hasNext(); ) {
        c.add(j.next());
      }
    }
    return c;
  }

  /**
   * Retrieve the <code>Peer</code> for the <code>Term n</code>, where 
   * <code>n</code> does not appear in a finally block. If no such Peer 
   * exists, then one will be created.
   * 
   * @param df unused; for legacy purposes only?
   */
  public Peer peer(Term n, DataFlow df) {
    return peer(n, Collections.EMPTY_LIST, df);
  }

  /**
   * Return a collection of all of the <code>Peer</code>s for the given 
   * <code>Term n</code>. 
   */
  public Collection peers(Term n) {
    IdentityKey k = new IdentityKey(n);
    Map pathMap = (Map) peerMap.get(k);
    if (pathMap == null) {
        return Collections.EMPTY_LIST;
    }
    return pathMap.values();
  }

  /**
{'fraction_non_alphanumeric': 0.12572815533980583, 'fraction_numerical': 0.0, 'mean_word_length': 2.8558951965065504, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3932098', 'n_tokens_mistral': 1970, 'n_tokens_neox': 1922, 'n_words': 735}