<commit_before>package org.ucombinator.jaam.tools.loopidentifier

import org.jgrapht.Graphs
import org.ucombinator.jaam.serializer.Serializer
import org.ucombinator.jaam.tools.app.App
import org.ucombinator.jaam.util.{Soot, Stmt}
import soot.{PackManager, Scene, SootClass, SootMethod}
import org.ucombinator.jaam.tools.app.{Origin, App}
import soot.jimple.{Stmt => SootStmt, _}
import soot.jimple.toolkits.annotation.logic.Loop
import soot.Value
import soot.options.Options
import soot.toolkits.graph.LoopNestTree

import scala.collection.JavaConverters._
import scala.collection.mutable

/*
  Goal: identify different types of loops being used. Specifically:
    - constant literal loops
    - determined loops (constants via variables)
    - variable loops
  This must be done over both regular for loops as well as for-each loops.

  TODO:
    [x] - search all methods (not just given specific "main" method)
    [ ] - identify further loop patterns in Jimple
 */

object Main {
  def main(input: List[String], printBodies: Boolean, printStatements: Boolean) {
    val (c, m) = prepFromInput(input)

    // Count up all loops found.
    val loops = mutable.Map[Class[_], mutable.Set[LoopIdentity]]()

    val class_names = Soot.loadedClasses.keys
    val classes = class_names.map(Soot.getSootClass)
    for (c <- classes) {
      if (Soot.loadedClasses(c.getName).origin == Origin.APP) {
        // Search through only concrete methods.
        for (method <- c.getMethods.asScala.filter(_.isConcrete)) {
          val lnt = new LoopNestTree(Soot.getBody(method))
          if (lnt.size > 0) {
            // Print the method body if (a) it was requested and (b) this method contains at least one loop.
            if (printBodies) {
              println("Statements in method: " + method)
              method.getActiveBody.getUnits.asScala.foreach(u => println("  " + u))
            }
            // Identify all the loops in the method.
            lnt.asScala.foreach(loop => {
              val ident = identifyLoop(loop, method)
              val s = loops.getOrElse(ident.getClass, mutable.Set[LoopIdentity]())
              s.add(ident)
              loops(ident.getClass) = s
            })
          }
        }
      }
    }

    for ((cls, idents) <- loops) {
      println(cls.getSimpleName + ": " + idents.size)
      idents.foreach(ident => {
        println("  " + ident.stmt.sourceFile + ":" + ident.stmt.line + " in " + ident.method.getName)
        println("    index: " + ident.stmt.index + ", " + ident.stmt)
        println("    prehead: " + ident.prehead)
        if (printStatements) {
          println("    statements:")
          ident.loop.getLoopStatements.asScala.foreach(s => println("      " + s))
        }
      })
      println()
    }
  }

  def printRed(x: Any): Unit = {
    println(Console.RED + x + Console.RESET)
  }

  def printYellow(x: Any): Unit = {
    println(Console.YELLOW + x + Console.RESET)
  }

  def printBlue(x: Any): Unit = {
    println(Console.BLUE + x + Console.RESET)
  }

  def getAssignees(statements: java.util.List[SootStmt]): Set[Value] = {
    // Get list of all values assigned to in a set of statements.
    statements.asScala.toSet.filter(s => s.isInstanceOf[AssignStmt]).map(s => s.asInstanceOf[AssignStmt].getLeftOp)
  }

  abstract class LoopIdentity(val loop: Loop, val method: SootMethod) {
    val head: SootStmt = loop.getHead
    val stmt: Stmt = Stmt(head, method)
    val prehead: Stmt = stmt.prevSyntactic
    val exits: Int = loop.getLoopExits.size()
    val assignees: Set[Value] = getAssignees(loop.getLoopStatements)
  }
  case class UnidentifiedLoop(override val loop: Loop, override val method: SootMethod) extends LoopIdentity(loop, method)
  case class SimpleInfiniteLoop(override val loop: Loop, override val method: SootMethod) extends LoopIdentity(loop, method)<commit_msg>Remove unused print functions<commit_after>package org.ucombinator.jaam.tools.loopidentifier

import org.jgrapht.Graphs
import org.ucombinator.jaam.serializer.Serializer
import org.ucombinator.jaam.tools.app.App
import org.ucombinator.jaam.util.{Soot, Stmt}
import soot.{PackManager, Scene, SootClass, SootMethod}
import org.ucombinator.jaam.tools.app.{Origin, App}
import soot.jimple.{Stmt => SootStmt, _}
import soot.jimple.toolkits.annotation.logic.Loop
import soot.Value
import soot.options.Options
import soot.toolkits.graph.LoopNestTree

import scala.collection.JavaConverters._
import scala.collection.mutable

/*
  Goal: identify different types of loops being used. Specifically:
    - constant literal loops
    - determined loops (constants via variables)
    - variable loops
  This must be done over both regular for loops as well as for-each loops.

  TODO:
    [x] - search all methods (not just given specific "main" method)
    [ ] - identify further loop patterns in Jimple
 */

object Main {
  def main(input: List[String], printBodies: Boolean, printStatements: Boolean) {
    val (c, m) = prepFromInput(input)

    // Count up all loops found.
    val loops = mutable.Map[Class[_], mutable.Set[LoopIdentity]]()

    val class_names = Soot.loadedClasses.keys
    val classes = class_names.map(Soot.getSootClass)
    for (c <- classes) {
      if (Soot.loadedClasses(c.getName).origin == Origin.APP) {
        // Search through only concrete methods.
        for (method <- c.getMethods.asScala.filter(_.isConcrete)) {
          val lnt = new LoopNestTree(Soot.getBody(method))
          if (lnt.size > 0) {
            // Print the method body if (a) it was requested and (b) this method contains at least one loop.
            if (printBodies) {
              println("Statements in method: " + method)
              method.getActiveBody.getUnits.asScala.foreach(u => println("  " + u))
            }
            // Identify all the loops in the method.
            lnt.asScala.foreach(loop => {
              val ident = identifyLoop(loop, method)
              val s = loops.getOrElse(ident.getClass, mutable.Set[LoopIdentity]())
              s.add(ident)
              loops(ident.getClass) = s
            })
          }
        }
      }
    }

    for ((cls, idents) <- loops) {
      println(cls.getSimpleName + ": " + idents.size)
      idents.foreach(ident => {
        println("  " + ident.stmt.sourceFile + ":" + ident.stmt.line + " in " + ident.method.getName)
        println("    index: " + ident.stmt.index + ", " + ident.stmt)
        println("    prehead: " + ident.prehead)
        if (printStatements) {
          println("    statements:")
          ident.loop.getLoopStatements.asScala.foreach(s => println("      " + s))
        }
      })
      println()
    }
  }

  def getAssignees(statements: java.util.List[SootStmt]): Set[Value] = {
    // Get list of all values assigned to in a set of statements.
    statements.asScala.toSet.filter(s => s.isInstanceOf[AssignStmt]).map(s => s.asInstanceOf[AssignStmt].getLeftOp)
  }

  abstract class LoopIdentity(val loop: Loop, val method: SootMethod) {
    val head: SootStmt = loop.getHead
    val stmt: Stmt = Stmt(head, method)
    val prehead: Stmt = stmt.prevSyntactic
    val exits: Int = loop.getLoopExits.size()
    val assignees: Set[Value] = getAssignees(loop.getLoopStatements)
  }
  case class UnidentifiedLoop(override val loop: Loop, override val method: SootMethod) extends LoopIdentity(loop, method)
  case class SimpleInfiniteLoop(override val loop: Loop, override val method: SootMethod) extends LoopIdentity(loop, method)
{'fraction_non_alphanumeric': 0.11398480202639648, 'fraction_numerical': 0.0002666311158512198, 'mean_word_length': 2.8412698412698414, 'pattern_counts': {'":': 4, '<': 9, '<?xml version=': 0, '>': 19, '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': '827522', 'n_tokens_mistral': 2394, 'n_tokens_neox': 2309, 'n_words': 583}