<commit_before>package org.ucombinator.jaam.tools

// TODO: nodes for loops (allows us to group methods that are in the same loop)
// TODO: vertical separation
// TODO: how confident are we in the coverage of rsa_commander?
// TODO: headlabel
// TODO: Compound graphs so loops live inside methods?
// TODO: test coverage

import java.io.FileOutputStream
import java.io.FileInputStream
import java.io.PrintStream
import java.util.jar.JarEntry
import java.util.jar.JarInputStream

import scala.collection.JavaConversions._
import scala.collection.immutable
import scala.collection.mutable

import org.jgrapht._
import org.jgrapht.io.DOTExporter
import org.jgrapht.graph._

import soot.{Main => SootMain, Unit => SootUnit, Value => SootValue, _}
import soot.jimple.{Stmt => SootStmt, IfStmt}
import soot.jimple.toolkits.annotation.logic.{Loop => SootLoop}
import soot.jimple.toolkits.callgraph.{CallGraph, CHATransformer, Edge}
import soot.options.Options
import soot.tagkit.GenericAttribute
import soot.toolkits.graph.LoopNestTree

import org.ucombinator.jaam.serializer
import org.ucombinator.jaam.serializer.TaintAddress
import org.ucombinator.jaam.util.CachedHashCode
import org.ucombinator.jaam.util.Stmt

object LoopAnalyzer {
  private var loops = Map.empty[SootMethod, Set[SootLoop]]
  def getLoops(m: SootMethod): Set[SootLoop] = {
    loops.get(m) match {
      case Some(l) => l
      case None =>
        var body: Body = null
        try {
          body = m.retrieveActiveBody
        } catch {
          case _: RuntimeException =>
            // println("Unable to retrieve body for " + m.getName)
        }
        val result = if (body != null) {
          new LoopNestTree(body).toSet
        } else {
          Set.empty[SootLoop]
        }
        loops = loops + (m -> result)
        result
    }
  }

  case class LoopTree(loop: SootLoop, method: SootMethod, children: Set[LoopTree]) {
    def contains(stmt: SootStmt): Boolean = {
      loop.getLoopStatements.contains(stmt)
    }
    def isParent(other: LoopTree): Boolean = {
      other.loop.getLoopStatements.toSet.subsetOf(loop.getLoopStatements.toSet)
    }
    def insert(child: LoopTree): LoopTree = {
      val grandchildren: Set[LoopTree] = children filter child.isParent
      val parents: Set[LoopTree] = children filter { _.isParent(child) }

      if (parents.nonEmpty) {
        assert(parents.size <= 1,<commit_msg>Filter ExceptionLoops out of loop sets in Loop2<commit_after>package org.ucombinator.jaam.tools

// TODO: nodes for loops (allows us to group methods that are in the same loop)
// TODO: vertical separation
// TODO: how confident are we in the coverage of rsa_commander?
// TODO: headlabel
// TODO: Compound graphs so loops live inside methods?
// TODO: test coverage

import java.io.FileOutputStream
import java.io.FileInputStream
import java.io.PrintStream
import java.util.jar.JarEntry
import java.util.jar.JarInputStream

import scala.collection.JavaConversions._
import scala.collection.immutable
import scala.collection.mutable

import org.jgrapht._
import org.jgrapht.io.DOTExporter
import org.jgrapht.graph._

import soot.{Main => SootMain, Unit => SootUnit, Value => SootValue, _}
import soot.jimple.{IfStmt, Stmt => SootStmt}
import soot.jimple.toolkits.annotation.logic.{Loop => SootLoop}
import soot.jimple.toolkits.callgraph.{CHATransformer, CallGraph, Edge}
import soot.options.Options
import soot.tagkit.GenericAttribute
import soot.toolkits.graph.LoopNestTree

import org.ucombinator.jaam.serializer
import org.ucombinator.jaam.serializer.TaintAddress
import org.ucombinator.jaam.tools.loopidentifier.Main.{ExceptionLoop, identifyLoop}
import org.ucombinator.jaam.util.CachedHashCode
import org.ucombinator.jaam.util.Stmt

object LoopAnalyzer {
  private var loops = Map.empty[SootMethod, Set[SootLoop]]
  def getLoops(m: SootMethod): Set[SootLoop] = {
    loops.get(m) match {
      case Some(l) => l
      case None =>
        var body: Body = null
        try {
          body = m.retrieveActiveBody
        } catch {
          case _: RuntimeException =>
            // println("Unable to retrieve body for " + m.getName)
        }
        val result = if (body != null) {
          // Filter out ExceptionLoops from the set, since they aren't real loops.
          new LoopNestTree(body).toSet.filterNot(loop => identifyLoop(loop, m).isInstanceOf[ExceptionLoop])
        } else {
          Set.empty[SootLoop]
        }
        loops = loops + (m -> result)
        result
    }
  }

  case class LoopTree(loop: SootLoop, method: SootMethod, children: Set[LoopTree]) {
    def contains(stmt: SootStmt): Boolean = {
      loop.getLoopStatements.contains(stmt)
    }
    def isParent(other: LoopTree): Boolean = {
      other.loop.getLoopStatements.toSet.subsetOf(loop.getLoopStatements.toSet)
    }
    def insert(child: LoopTree): LoopTree = {
      val grandchildren: Set[LoopTree] = children filter child.isParent
      val parents: Set[LoopTree] = children filter { _.isParent(child) }

      if (parents.nonEmpty) {
        assert(parents.size <= 1,
{'fraction_non_alphanumeric': 0.10185185185185185, 'fraction_numerical': 0.000591016548463357, 'mean_word_length': 3.395670995670996, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 22, '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': '5896200', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1580, 'n_words': 388}