From 51d049b924d4a522b02c8603375d9860a3a15b5e Mon Sep 17 00:00:00 2001 From: sahilagichani Date: Thu, 12 Dec 2024 21:27:59 +0100 Subject: [PATCH] refactor buildtraps method, removed javapoet testcase --- .../sootup/core/graph/BlockGraphIterator.java | 337 +++++++++--------- .../core/graph/ForwardingStmtGraph.java | 1 - .../core/graph/ImmutableBlockStmtGraph.java | 1 - .../core/graph/MutableBlockStmtGraph.java | 1 - .../java/sootup/core/graph/StmtGraph.java | 8 +- .../BlockGraphIteratorAndTrapAggregator.java | 155 ++++---- .../core/util/printer/JimplePrinter.java | 22 +- .../core/util/printer/LabeledStmtPrinter.java | 48 +-- sootup.tests/pom.xml | 7 - .../sootup/tests/JimpleSerializationTest.java | 204 +++-------- 10 files changed, 326 insertions(+), 458 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/graph/BlockGraphIterator.java b/sootup.core/src/main/java/sootup/core/graph/BlockGraphIterator.java index ffcb1a6d82..3a094fdd34 100644 --- a/sootup.core/src/main/java/sootup/core/graph/BlockGraphIterator.java +++ b/sootup.core/src/main/java/sootup/core/graph/BlockGraphIterator.java @@ -1,194 +1,187 @@ package sootup.core.graph; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import sootup.core.jimple.common.stmt.JGotoStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.types.ClassType; import sootup.core.util.DotExporter; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; - -/** - * Iterates over the blocks - */ +/** Iterates over the blocks */ public class BlockGraphIterator implements Iterator> { - private final StmtGraph stmtGraph; - @Nonnull - private final ArrayDeque> trapHandlerBlocks = new ArrayDeque<>(); - - @Nonnull - private final ArrayDeque> nestedBlocks = new ArrayDeque<>(); - @Nonnull - private final ArrayDeque> otherBlocks = new ArrayDeque<>(); - @Nonnull - private final Set> iteratedBlocks; - - public BlockGraphIterator(StmtGraph stmtGraph) { - this.stmtGraph = stmtGraph; - final Collection> blocks = stmtGraph.getBlocks(); - iteratedBlocks = new LinkedHashSet<>(blocks.size(), 1); - Stmt startingStmt = stmtGraph.getStartingStmt(); - if (startingStmt != null) { - final BasicBlock startingBlock = stmtGraph.getStartingStmtBlock(); - updateFollowingBlocks(startingBlock); - nestedBlocks.addFirst(startingBlock); - } + private final StmtGraph stmtGraph; + @Nonnull private final ArrayDeque> trapHandlerBlocks = new ArrayDeque<>(); + + @Nonnull private final ArrayDeque> nestedBlocks = new ArrayDeque<>(); + @Nonnull private final ArrayDeque> otherBlocks = new ArrayDeque<>(); + @Nonnull private final Set> iteratedBlocks; + + public BlockGraphIterator(StmtGraph stmtGraph) { + this.stmtGraph = stmtGraph; + final Collection> blocks = stmtGraph.getBlocks(); + iteratedBlocks = new LinkedHashSet<>(blocks.size(), 1); + Stmt startingStmt = stmtGraph.getStartingStmt(); + if (startingStmt != null) { + final BasicBlock startingBlock = stmtGraph.getStartingStmtBlock(); + updateFollowingBlocks(startingBlock); + nestedBlocks.addFirst(startingBlock); } - - @Nullable - private BasicBlock retrieveNextBlock() { - BasicBlock nextBlock; - do { - if (!nestedBlocks.isEmpty()) { - nextBlock = nestedBlocks.pollFirst(); - } else if (!trapHandlerBlocks.isEmpty()) { - nextBlock = trapHandlerBlocks.pollFirst(); - } else if (!otherBlocks.isEmpty()) { - nextBlock = otherBlocks.pollFirst(); - } else { - Collection> blocks = stmtGraph.getBlocks(); - if (iteratedBlocks.size() < blocks.size()) { - // graph is not connected! iterate/append all not connected blocks at the end in no - // particular order. - for (BasicBlock block : blocks) { - if (!iteratedBlocks.contains(block)) { - nestedBlocks.addLast(block); - } - } - if (!nestedBlocks.isEmpty()) { - return nestedBlocks.pollFirst(); - } - } - - return null; + } + + @Nullable + private BasicBlock retrieveNextBlock() { + BasicBlock nextBlock; + do { + if (!nestedBlocks.isEmpty()) { + nextBlock = nestedBlocks.pollFirst(); + } else if (!trapHandlerBlocks.isEmpty()) { + nextBlock = trapHandlerBlocks.pollFirst(); + } else if (!otherBlocks.isEmpty()) { + nextBlock = otherBlocks.pollFirst(); + } else { + Collection> blocks = stmtGraph.getBlocks(); + if (iteratedBlocks.size() < blocks.size()) { + // graph is not connected! iterate/append all not connected blocks at the end in no + // particular order. + for (BasicBlock block : blocks) { + if (!iteratedBlocks.contains(block)) { + nestedBlocks.addLast(block); } + } + if (!nestedBlocks.isEmpty()) { + return nestedBlocks.pollFirst(); + } + } - // skip retrieved nextBlock if its already returned - } while (iteratedBlocks.contains(nextBlock)); - return nextBlock; - } + return null; + } - @Override - @Nonnull - public BasicBlock next() { - BasicBlock currentBlock = retrieveNextBlock(); - if (currentBlock == null) { - throw new NoSuchElementException("Iterator has no more Blocks."); - } - updateFollowingBlocks(currentBlock); - iteratedBlocks.add(currentBlock); - return currentBlock; + // skip retrieved nextBlock if its already returned + } while (iteratedBlocks.contains(nextBlock)); + return nextBlock; + } + + @Override + @Nonnull + public BasicBlock next() { + BasicBlock currentBlock = retrieveNextBlock(); + if (currentBlock == null) { + throw new NoSuchElementException("Iterator has no more Blocks."); + } + updateFollowingBlocks(currentBlock); + iteratedBlocks.add(currentBlock); + return currentBlock; + } + + private void updateFollowingBlocks(BasicBlock currentBlock) { + // collect traps + final Stmt tailStmt = currentBlock.getTail(); + for (Map.Entry> entry : + currentBlock.getExceptionalSuccessors().entrySet()) { + BasicBlock trapHandlerBlock = entry.getValue(); + trapHandlerBlocks.addLast(trapHandlerBlock); + nestedBlocks.addFirst(trapHandlerBlock); } - private void updateFollowingBlocks(BasicBlock currentBlock) { - // collect traps - final Stmt tailStmt = currentBlock.getTail(); - for (Map.Entry> entry : - currentBlock.getExceptionalSuccessors().entrySet()) { - BasicBlock trapHandlerBlock = entry.getValue(); - trapHandlerBlocks.addLast(trapHandlerBlock); - nestedBlocks.addFirst(trapHandlerBlock); + final List> successors = currentBlock.getSuccessors(); + + for (int i = successors.size() - 1; i >= 0; i--) { + if (i == 0 && tailStmt.fallsThrough()) { + // non-branching successors i.e. not a BranchingStmt or is the first successor (i.e. its + // false successor) of + // JIfStmt + nestedBlocks.addFirst(successors.get(0)); + } else { + + // create the longest FallsThroughStmt sequence possible + final BasicBlock successorBlock = successors.get(i); + BasicBlock leaderOfFallsthroughBlocks = successorBlock; + while (true) { + final List> itPreds = + leaderOfFallsthroughBlocks.getPredecessors(); + + BasicBlock finalLeaderOfFallsthroughBlocks = leaderOfFallsthroughBlocks; + final Optional> fallsthroughPredOpt = + itPreds.stream() + .filter( + b -> + b.getTail().fallsThrough() + && b.getSuccessors().get(0) == finalLeaderOfFallsthroughBlocks) + .findAny(); + if (!fallsthroughPredOpt.isPresent()) { + break; + } + BasicBlock predecessorBlock = fallsthroughPredOpt.get(); + if (predecessorBlock.getTail().fallsThrough() + && predecessorBlock.getSuccessors().get(0) == leaderOfFallsthroughBlocks) { + leaderOfFallsthroughBlocks = predecessorBlock; + } else { + break; + } } - final List> successors = currentBlock.getSuccessors(); - - for (int i = successors.size() - 1; i >= 0; i--) { - if (i == 0 && tailStmt.fallsThrough()) { - // non-branching successors i.e. not a BranchingStmt or is the first successor (i.e. its - // false successor) of - // JIfStmt - nestedBlocks.addFirst(successors.get(0)); - } else { - - // create the longest FallsThroughStmt sequence possible - final BasicBlock successorBlock = successors.get(i); - BasicBlock leaderOfFallsthroughBlocks = successorBlock; - while (true) { - final List> itPreds = - leaderOfFallsthroughBlocks.getPredecessors(); - - BasicBlock finalLeaderOfFallsthroughBlocks = leaderOfFallsthroughBlocks; - final Optional> fallsthroughPredOpt = - itPreds.stream() - .filter( - b -> - b.getTail().fallsThrough() - && b.getSuccessors().get(0) == finalLeaderOfFallsthroughBlocks) - .findAny(); - if (!fallsthroughPredOpt.isPresent()) { - break; - } - BasicBlock predecessorBlock = fallsthroughPredOpt.get(); - if (predecessorBlock.getTail().fallsThrough() - && predecessorBlock.getSuccessors().get(0) == leaderOfFallsthroughBlocks) { - leaderOfFallsthroughBlocks = predecessorBlock; - } else { - break; - } - } - - // find a return Stmt inside the current Block - Stmt succTailStmt = successorBlock.getTail(); - boolean hasNoSuccessorStmts = succTailStmt.getExpectedSuccessorCount() == 0; - boolean isExceptionFree = successorBlock.getExceptionalSuccessors().isEmpty(); - - boolean isLastStmtCandidate = hasNoSuccessorStmts && isExceptionFree; - // remember branching successors - if (tailStmt instanceof JGotoStmt) { - if (isLastStmtCandidate) { - nestedBlocks.removeFirstOccurrence(currentBlock); - otherBlocks.addLast(leaderOfFallsthroughBlocks); - } else { - otherBlocks.addFirst(leaderOfFallsthroughBlocks); - } - } else if (!nestedBlocks.contains(leaderOfFallsthroughBlocks)) { - // JSwitchStmt, JIfStmt - if (isLastStmtCandidate) { - nestedBlocks.addLast(leaderOfFallsthroughBlocks); - } else { - nestedBlocks.addFirst(leaderOfFallsthroughBlocks); - } - } - } + // find a return Stmt inside the current Block + Stmt succTailStmt = successorBlock.getTail(); + boolean hasNoSuccessorStmts = succTailStmt.getExpectedSuccessorCount() == 0; + boolean isExceptionFree = successorBlock.getExceptionalSuccessors().isEmpty(); + + boolean isLastStmtCandidate = hasNoSuccessorStmts && isExceptionFree; + // remember branching successors + if (tailStmt instanceof JGotoStmt) { + if (isLastStmtCandidate) { + nestedBlocks.removeFirstOccurrence(currentBlock); + otherBlocks.addLast(leaderOfFallsthroughBlocks); + } else { + otherBlocks.addFirst(leaderOfFallsthroughBlocks); + } + } else if (!nestedBlocks.contains(leaderOfFallsthroughBlocks)) { + // JSwitchStmt, JIfStmt + if (isLastStmtCandidate) { + nestedBlocks.addLast(leaderOfFallsthroughBlocks); + } else { + nestedBlocks.addFirst(leaderOfFallsthroughBlocks); + } } + } + } + } + + @Override + public boolean hasNext() { + final boolean hasIteratorMoreElements; + BasicBlock b = retrieveNextBlock(); + if (b != null) { + // reinsert at FIRST position -> not great for performance - but easier handling in + // next() + nestedBlocks.addFirst(b); + hasIteratorMoreElements = true; + } else { + hasIteratorMoreElements = false; } - @Override - public boolean hasNext() { - final boolean hasIteratorMoreElements; - BasicBlock b = retrieveNextBlock(); - if (b != null) { - // reinsert at FIRST position -> not great for performance - but easier handling in - // next() - nestedBlocks.addFirst(b); - hasIteratorMoreElements = true; - } else { - hasIteratorMoreElements = false; - } - - // "assertion" that all elements are iterated - if (!hasIteratorMoreElements) { - final int returnedSize = iteratedBlocks.size(); - final Collection> blocks = stmtGraph.getBlocks(); - final int actualSize = blocks.size(); - if (returnedSize != actualSize) { - String info = - blocks.stream() - .filter(n -> !iteratedBlocks.contains(n)) - .map(BasicBlock::getStmts) - .collect(Collectors.toList()) - .toString(); - throw new IllegalStateException( - "There are " - + (actualSize - returnedSize) - + " Blocks that are not iterated! i.e. the StmtGraph is not connected from its startingStmt!" - + info - + DotExporter.createUrlToWebeditor(stmtGraph)); - } - } - return hasIteratorMoreElements; + // "assertion" that all elements are iterated + if (!hasIteratorMoreElements) { + final int returnedSize = iteratedBlocks.size(); + final Collection> blocks = stmtGraph.getBlocks(); + final int actualSize = blocks.size(); + if (returnedSize != actualSize) { + String info = + blocks.stream() + .filter(n -> !iteratedBlocks.contains(n)) + .map(BasicBlock::getStmts) + .collect(Collectors.toList()) + .toString(); + throw new IllegalStateException( + "There are " + + (actualSize - returnedSize) + + " Blocks that are not iterated! i.e. the StmtGraph is not connected from its startingStmt!" + + info + + DotExporter.createUrlToWebeditor(stmtGraph)); + } } + return hasIteratorMoreElements; + } } diff --git a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java index a01278307f..32e161e475 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ForwardingStmtGraph.java @@ -23,7 +23,6 @@ */ import java.util.*; import javax.annotation.Nonnull; -import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.types.ClassType; diff --git a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java index 43fcd10152..03ed3d469a 100644 --- a/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/ImmutableBlockStmtGraph.java @@ -26,7 +26,6 @@ import java.util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.types.ClassType; diff --git a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java index 2798f6640f..9cd15096ee 100644 --- a/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/MutableBlockStmtGraph.java @@ -22,7 +22,6 @@ * #L% */ -import com.google.common.collect.ComparisonChain; import com.google.common.collect.Lists; import java.util.*; import javax.annotation.Nonnull; diff --git a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java index bb3b919e27..b3f4be517b 100644 --- a/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java +++ b/sootup.core/src/main/java/sootup/core/graph/StmtGraph.java @@ -29,7 +29,6 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.ref.IdentityRef; import sootup.core.jimple.common.ref.JCaughtExceptionRef; import sootup.core.jimple.common.stmt.*; @@ -202,9 +201,9 @@ public Collection getEntrypoints() { public void validateStmtConnectionsInGraph() { try { List handlerStmts = new ArrayList<>(); - for (Stmt stmt: getNodes()){ + for (Stmt stmt : getNodes()) { if (stmt instanceof JIdentityStmt) { - //JThrowStmt? + // JThrowStmt? IdentityRef rightOp = ((JIdentityStmt) stmt).getRightOp(); if (rightOp instanceof JCaughtExceptionRef) { handlerStmts.add(stmt); @@ -219,8 +218,7 @@ public void validateStmtConnectionsInGraph() { if (predecessors(stmt).isEmpty()) { if (!(stmt == getStartingStmt() - || handlerStmts.stream() - .anyMatch(handler -> handler == stmt))) { + || handlerStmts.stream().anyMatch(handler -> handler == stmt))) { throw new IllegalStateException( "Stmt '" + stmt diff --git a/sootup.core/src/main/java/sootup/core/util/printer/BlockGraphIteratorAndTrapAggregator.java b/sootup.core/src/main/java/sootup/core/util/printer/BlockGraphIteratorAndTrapAggregator.java index 3401074610..4914156a23 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/BlockGraphIteratorAndTrapAggregator.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/BlockGraphIteratorAndTrapAggregator.java @@ -1,5 +1,11 @@ package sootup.core.util.printer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import sootup.core.graph.BasicBlock; import sootup.core.graph.BlockGraphIterator; import sootup.core.graph.MutableBasicBlockImpl; @@ -10,96 +16,93 @@ import sootup.core.jimple.common.stmt.Stmt; import sootup.core.types.ClassType; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** - * Iterates over the Blocks and collects/aggregates Trap information - * It is used to collect and aggregate traps for serializing Jimple in the JimplePrinter + * Iterates over the Blocks and collects/aggregates Trap information It is used to collect and + * aggregate traps for serializing Jimple in the JimplePrinter */ class BlockGraphIteratorAndTrapAggregator extends BlockGraphIterator { - @Nonnull - private final List collectedTraps = new ArrayList<>(); + @Nonnull private final List collectedTraps = new ArrayList<>(); - Map activeTraps = new HashMap<>(); - BasicBlock lastIteratedBlock; // dummy value to remove n-1 unnecessary null-checks - JNopStmt lastStmt = null; + Map activeTraps = new HashMap<>(); + BasicBlock lastIteratedBlock; // dummy value to remove n-1 unnecessary null-checks + JNopStmt lastStmt = null; - /* - * @param dummyBlock is just an empty instantiation of type V - as neither BasicBlock nor V instantiable we need a concrete object from the using subclass itclass. - * */ - public BlockGraphIteratorAndTrapAggregator(StmtGraph stmtGraph) { - super(stmtGraph); - lastIteratedBlock = new MutableBasicBlockImpl(); - } + /* + * @param dummyBlock is just an empty instantiation of type V - as neither BasicBlock nor V instantiable we need a concrete object from the using subclass itclass. + * */ + public BlockGraphIteratorAndTrapAggregator(StmtGraph stmtGraph) { + super(stmtGraph); + lastIteratedBlock = new MutableBasicBlockImpl(); + } - @Nullable - public JNopStmt getLastStmt() { - return lastStmt; - } + @Nullable + public JNopStmt getLastStmt() { + return lastStmt; + } - @Nonnull - @Override - public BasicBlock next() { - final BasicBlock block = super.next(); + @Nonnull + @Override + public BasicBlock next() { + final BasicBlock block = super.next(); - final Map> currentBlocksExceptions = - block.getExceptionalSuccessors(); - final Map> lastBlocksExceptions = - lastIteratedBlock.getExceptionalSuccessors(); + final Map> currentBlocksExceptions = + block.getExceptionalSuccessors(); + final Map> lastBlocksExceptions = + lastIteratedBlock.getExceptionalSuccessors(); - // former trap info is not in the current blocks info -> add it to the trap collection - lastBlocksExceptions.forEach( - (type, trapHandlerBlock) -> { - if (trapHandlerBlock != block.getExceptionalSuccessors().get(type)) { - final Stmt trapBeginStmt = activeTraps.remove(type); - if (trapBeginStmt == null) { - throw new IllegalStateException("Trap start for '" + type + "' is not in the Map!"); - } - // trapend is exclusive! - collectedTraps.add( - new Trap(type, trapBeginStmt, block.getHead(), trapHandlerBlock.getHead())); - } - }); + // former trap info is not in the current blocks info -> add it to the trap collection + lastBlocksExceptions.forEach( + (type, trapHandlerBlock) -> { + if (trapHandlerBlock != block.getExceptionalSuccessors().get(type)) { + final Stmt trapBeginStmt = activeTraps.remove(type); + if (trapBeginStmt == null) { + throw new IllegalStateException("Trap start for '" + type + "' is not in the Map!"); + } + // trapend is exclusive! + collectedTraps.add( + new Trap(type, trapBeginStmt, block.getHead(), trapHandlerBlock.getHead())); + } + }); - // is there a new trap in the current block -> add it to currentTraps - block - .getExceptionalSuccessors() - .forEach( - (type, trapHandlerBlock) -> { - if (trapHandlerBlock != lastBlocksExceptions.get(type)) { - activeTraps.put(type, block.getHead()); - } - }); + // is there a new trap in the current block -> add it to currentTraps + block + .getExceptionalSuccessors() + .forEach( + (type, trapHandlerBlock) -> { + if (trapHandlerBlock != lastBlocksExceptions.get(type)) { + activeTraps.put(type, block.getHead()); + } + }); - lastIteratedBlock = block; - return block; - } + lastIteratedBlock = block; + return block; + } - /** - * for jimple serialization - this info contains only valid/useful information if all stmts are - * iterated i.e. hasNext() == false! - * - * @return List of Traps - */ - public List getTraps() { + /** + * for jimple serialization - this info contains only valid/useful information if all stmts are + * iterated i.e. hasNext() == false! + * + * @return List of Traps + */ + public List getTraps() { - if (hasNext()) { - throw new IllegalStateException("Iterator needs to be iterated completely!"); - } + if (hasNext()) { + throw new IllegalStateException("Iterator needs to be iterated completely!"); + } - // check for dangling traps that are not collected as the endStmt was not visited. - if (!activeTraps.isEmpty()) { - lastStmt = new JNopStmt(StmtPositionInfo.getNoStmtPositionInfo()); -// throw new IllegalArgumentException( -// "Invalid StmtGraph. A Trap is not created as a traps endStmt was not visited during the iteration of all Stmts."); - activeTraps.forEach((type, beginning) -> collectedTraps.add(new Trap(type, beginning, lastStmt, lastIteratedBlock.getExceptionalSuccessors().get(type).getHead()))); - } - return collectedTraps; + // check for dangling traps that are not collected as the endStmt was not visited. + if (!activeTraps.isEmpty()) { + lastStmt = new JNopStmt(StmtPositionInfo.getNoStmtPositionInfo()); + activeTraps.forEach( + (type, beginning) -> + collectedTraps.add( + new Trap( + type, + beginning, + lastStmt, + lastIteratedBlock.getExceptionalSuccessors().get(type).getHead()))); } + return collectedTraps; + } } diff --git a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java index d05ff99b19..69525e58d4 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/JimplePrinter.java @@ -22,7 +22,10 @@ * #L% */ -import com.google.common.collect.ComparisonChain; +import java.io.PrintWriter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import sootup.core.graph.*; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Local; @@ -35,12 +38,6 @@ import sootup.core.types.ClassType; import sootup.core.types.Type; -import javax.annotation.Nonnull; -import java.io.PrintWriter; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - /** * Prints out a class and all its methods. * @@ -339,7 +336,8 @@ private void printStatementsInBody(Body body, LabeledStmtPrinter printer) { } private void printStmts(StmtGraph stmtGraph, LabeledStmtPrinter printer) { - Iterable linearizedStmtGraph = printer.initializeSootMethod(stmtGraph); + final List traps = printer.buildTraps(stmtGraph); + Iterable linearizedStmtGraph = printer.initializeSootMethod(stmtGraph, traps); Stmt previousStmt; @@ -357,10 +355,10 @@ private void printStmts(StmtGraph stmtGraph, LabeledStmtPrinter printer) { // a trap) final boolean currentStmtHasLabel = labels.get(currentStmt) != null; - if (previousStmt.branches() + if (currentStmtHasLabel + || previousStmt.branches() || stmtGraph.predecessors(currentStmt).size() != 1 - || previousStmt.getExpectedSuccessorCount() == 0 - || currentStmtHasLabel) { + || previousStmt.getExpectedSuccessorCount() == 0) { printer.newline(); } @@ -383,7 +381,7 @@ private void printStmts(StmtGraph stmtGraph, LabeledStmtPrinter printer) { // Print out exceptions { - Iterator trapIt = printer.buildTraps(stmtGraph).iterator(); + Iterator trapIt = traps.iterator(); if (trapIt.hasNext()) { printer.newline(); diff --git a/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java b/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java index abaf19a05b..6fa53f0506 100644 --- a/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java +++ b/sootup.core/src/main/java/sootup/core/util/printer/LabeledStmtPrinter.java @@ -22,12 +22,10 @@ * #L% */ +import com.google.common.collect.ComparisonChain; import java.util.*; import javax.annotation.Nonnull; - -import com.google.common.collect.ComparisonChain; -import sootup.core.graph.BasicBlock; -import sootup.core.graph.StmtGraph; +import sootup.core.graph.*; import sootup.core.jimple.Jimple; import sootup.core.jimple.basic.Trap; import sootup.core.jimple.common.ref.IdentityRef; @@ -109,16 +107,15 @@ public void stmtRef(Stmt stmt, boolean branchTarget) { * * @return the linearized StmtGraph */ - public Iterable initializeSootMethod(@Nonnull StmtGraph stmtGraph) { + public Iterable initializeSootMethod(@Nonnull StmtGraph stmtGraph, List traps) { this.graph = stmtGraph; - final List linearizedStmtGraph = getStmts(stmtGraph); + final List linearizedStmtGraph = getStmts(stmtGraph, traps); return linearizedStmtGraph; } @Nonnull - public List getStmts(@Nonnull StmtGraph stmtGraph) { - final Collection targetStmtsOfBranches = getLabeledStmts(stmtGraph); - final List traps = buildTraps(stmtGraph); + public List getStmts(@Nonnull StmtGraph stmtGraph, List traps) { + final Collection targetStmtsOfBranches = getLabeledStmts(stmtGraph, traps); final int maxEstimatedSize = targetStmtsOfBranches.size() + traps.size() * 3; labels = new HashMap<>(maxEstimatedSize, 1); @@ -140,7 +137,7 @@ public List getStmts(@Nonnull StmtGraph stmtGraph) { // or is the begin of a trap-range) or does it mark the end of a trap range // does it need a label for (Stmt stmt : targetStmtsOfBranches) { - if ((stmt instanceof JNopStmt) || stmtGraph.isStmtBranchTarget(stmt) || trapStmts.contains(stmt)) { + if (trapStmts.contains(stmt) || stmtGraph.isStmtBranchTarget(stmt)) { labelStmts.add(stmt); } else { refStmts.add(stmt); @@ -167,6 +164,15 @@ public List getStmts(@Nonnull StmtGraph stmtGraph) { references.put(s, Integer.toString(refCount++)); } } + + // add Nop Stmt to Jimple just for serialization + for (Stmt s : targetStmtsOfBranches) { + if (s instanceof JNopStmt) { + linearizedStmtGraph.add(s); + labels.put(s, String.format(formatString, ++labelCount)); + } + } + return linearizedStmtGraph; } @@ -233,12 +239,12 @@ public List buildTraps(StmtGraph stmtGraph) { /** Comparator which sorts the trap output in getTraps() */ public Comparator getTrapComparator(@Nonnull Map stmtsBlockIdx) { return (a, b) -> - ComparisonChain.start() - .compare(stmtsBlockIdx.get(a.getBeginStmt()), stmtsBlockIdx.get(b.getBeginStmt())) - .compare(stmtsBlockIdx.get(a.getEndStmt()), stmtsBlockIdx.get(b.getEndStmt())) - // [ms] would be nice to have the traps ordered by exception hierarchy as well - .compare(a.getExceptionType().toString(), b.getExceptionType().toString()) - .result(); + ComparisonChain.start() + .compare(stmtsBlockIdx.get(a.getBeginStmt()), stmtsBlockIdx.get(b.getBeginStmt())) + .compare(stmtsBlockIdx.get(a.getEndStmt()), stmtsBlockIdx.get(b.getEndStmt())) + // [ms] would be nice to have the traps ordered by exception hierarchy as well + .compare(a.getExceptionType().toString(), b.getExceptionType().toString()) + .result(); } /** @@ -252,23 +258,25 @@ public Comparator getTrapComparator(@Nonnull Map stmtsBlock * @return A collection of all the Stmts that are targets of a BranchingStmt */ @Nonnull - public Collection getLabeledStmts(StmtGraph stmtGraph) { + public Collection getLabeledStmts(StmtGraph stmtGraph, List traps) { Set stmtList = new HashSet<>(); Collection stmtGraphNodes = stmtGraph.getNodes(); for (Stmt stmt : stmtGraphNodes) { if (stmt instanceof BranchingStmt) { if (stmt instanceof JIfStmt) { - stmtList.add((Stmt) stmtGraph.getBranchTargetsOf((JIfStmt) stmt).get(JIfStmt.FALSE_BRANCH_IDX)); + stmtList.add( + (Stmt) stmtGraph.getBranchTargetsOf((JIfStmt) stmt).get(JIfStmt.FALSE_BRANCH_IDX)); } else if (stmt instanceof JGotoStmt) { // [ms] bounds are validated in Body if its a valid StmtGraph - stmtList.add((Stmt) stmtGraph.getBranchTargetsOf((JGotoStmt) stmt).get(JGotoStmt.BRANCH_IDX)); + stmtList.add( + (Stmt) stmtGraph.getBranchTargetsOf((JGotoStmt) stmt).get(JGotoStmt.BRANCH_IDX)); } else if (stmt instanceof JSwitchStmt) { stmtList.addAll(stmtGraph.getBranchTargetsOf((BranchingStmt) stmt)); } } } - for (Trap trap : buildTraps(stmtGraph)) { + for (Trap trap : traps) { stmtList.add(trap.getBeginStmt()); stmtList.add(trap.getEndStmt()); stmtList.add(trap.getHandlerStmt()); diff --git a/sootup.tests/pom.xml b/sootup.tests/pom.xml index 1562de85a6..ff60954428 100644 --- a/sootup.tests/pom.xml +++ b/sootup.tests/pom.xml @@ -44,13 +44,6 @@ slf4j-simple test - - com.squareup - javapoet - 1.13.0 - test - - diff --git a/sootup.tests/src/test/java/sootup/tests/JimpleSerializationTest.java b/sootup.tests/src/test/java/sootup/tests/JimpleSerializationTest.java index b8d9e2812d..0fdc463796 100644 --- a/sootup.tests/src/test/java/sootup/tests/JimpleSerializationTest.java +++ b/sootup.tests/src/test/java/sootup/tests/JimpleSerializationTest.java @@ -1,177 +1,55 @@ package sootup.tests; -import com.squareup.javapoet.*; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.*; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.model.SourceType; -import sootup.core.signatures.MethodSignature; -import sootup.core.types.PrimitiveType; -import sootup.core.types.VoidType; import sootup.java.bytecode.frontend.inputlocation.JavaClassPathAnalysisInputLocation; import sootup.java.core.JavaSootMethod; import sootup.java.core.views.JavaView; -import sootup.jimple.frontend.JimpleAnalysisInputLocation; -import sootup.jimple.frontend.JimpleStringAnalysisInputLocation; -import sootup.jimple.frontend.JimpleView; - -import javax.lang.model.element.Modifier; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.assertTrue; @Tag("Java8") public class JimpleSerializationTest { - @Test - public void testTrapSerialization() { - AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation("src/test/resources/bugs/1119_trap-serialization", SourceType.Application, Collections.emptyList()); - JavaView view = new JavaView(inputLocation); - - Optional methodOpt = view.getMethod(view.getIdentifierFactory().parseMethodSignature( - "" - )); - assertTrue(methodOpt.isPresent()); - JavaSootMethod method = methodOpt.get(); - method.getBody().toString(); - } - - @Test - public void testBasicTrapSerialization() { - AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation("src/test/resources/bugs/1119_trap-serialization", SourceType.Application, Collections.emptyList()); - JavaView javaView = new JavaView(inputLocation); - Optional nestedTrap = javaView.getMethod(javaView.getIdentifierFactory().parseMethodSignature( - "" - )); - - assertTrue(nestedTrap.isPresent()); - JavaSootMethod nestedTrapMethod = nestedTrap.get(); - System.out.println(nestedTrapMethod.getBody()); - nestedTrapMethod.getBody().getStmtGraph().toString(); - } - - @Test - public void testJimpleTrapSerialization() { - String jimpleString = "class DummyClass extends java.lang.Object {\n" + - "\tint testTrapSerialization() {\n" + - "\t\tsootUp.RQ1.jb_a.JB_A this;\n" + - "\t\tunknown $stack4, $stack5, a, b, e;\n" + - "\n" + - "\n" + - "\t\tthis := @this: sootUp.RQ1.jb_a.JB_A;\n" + - "\t\ta = 0;\n" + - "\t\tb = 10;\n" + - "\n" + - "\t label1:\n" + - "\t\tb = b / a;\n" + - "\t\t$stack4 = b;\n" + - "\t\treturn a;\n" + - "\n" + - "\t label2:\n" + - "\t\treturn $stack4;\n" + - "\n" + - "\t label3:\n" + - "\t\t$stack5 := @caughtexception;\n" + - "\t\te = $stack5;\n" + - "\n" + - "\t\treturn b;\n" + - "\n" + - "\t catch java.lang.ArithmeticException from label1 to label2 with label3;\n" + - "\t catch java.lang.NullPointerException from label1 to label2 with label3;\n" + - "\t}\n" + - "}"; - - JimpleStringAnalysisInputLocation analysisInputLocation = new JimpleStringAnalysisInputLocation(jimpleString, SourceType.Application, Collections.emptyList()); - JimpleView view = new JimpleView(analysisInputLocation); - assertTrue(view.getClass(analysisInputLocation.getClassType()).isPresent()); - MethodSignature methodSig = - view.getIdentifierFactory() - .getMethodSignature( - analysisInputLocation.getClassType(), - "testTrapSerialization", - PrimitiveType.IntType.getInstance(), - Collections.emptyList()); - assertTrue(view.getMethod(methodSig).isPresent()); - } - - - @Test - public void addNopInEndOfTryCatchFinally() throws IOException { - // Define the method body - CodeBlock methodBody = CodeBlock.builder() - .addStatement("$T> result = new $T<>()", Map.class, Map.Entry.class, HashMap.class) - .beginControlFlow("try") - .addStatement("result.put($S, new $T.SimpleEntry<>($S, $S))", "try", AbstractMap.class, "Key1", "Value1") - .addStatement("return result") - .nextControlFlow("catch ($T e)", Exception.class) - .addStatement("result.put($S, new $T.SimpleEntry<>($S, $S))", "catch", AbstractMap.class, "Key2", "Value2") - .addStatement("return result") - .nextControlFlow("finally") - .addStatement("result.put($S, new $T.SimpleEntry<>($S, $S))", "finally", AbstractMap.class, "Key3", "Value3") - .endControlFlow() - .addStatement("return result") - .addStatement("return result") - .build(); - - // Create the method - MethodSpec tryCatchFinallyMethod = MethodSpec.methodBuilder("tryCatchFinallyMethod") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(ParameterizedTypeName.get(Map.class, String.class)) - .addCode(methodBody) - .build(); - - // Create the class - TypeSpec tryCatchFinallyClass = TypeSpec.classBuilder("TryCatchFinallyExample") - .addModifiers(Modifier.PUBLIC) - .addMethod(tryCatchFinallyMethod) - .build(); - - // Write to a Java file - JavaFile javaFile = JavaFile.builder("com.example", tryCatchFinallyClass) - .build(); - - // Write the generated Java file to the file system - javaFile.writeTo(Paths.get("./src/test/resources/bugs/1119_trap-serialization/com/linecorp/centraldogma/server/internal/storage/repository/git/")); - } - - @Test - public void addNopInEndOfNestedTrap() throws IOException { - // Define the method body with nested try-catch blocks - CodeBlock methodBody = CodeBlock.builder() - .beginControlFlow("try") - .addStatement("System.out.println($S)", "Outer try block") - .beginControlFlow("try") - .addStatement("System.out.println($S)", "Inner try block") - .addStatement("throw new RuntimeException($S)", "Inner exception") - .nextControlFlow("catch (Exception e)") - .addStatement("System.out.println($S + e.getMessage())", "Caught inner exception: ") - .endControlFlow() - .nextControlFlow("catch (Exception e)") - .addStatement("System.out.println($S + e.getMessage())", "Caught outer exception: ") - .endControlFlow() - .build(); - - // Create the method - MethodSpec nestedTryCatchMethod = MethodSpec.methodBuilder("nestedTryCatch") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .returns(void.class) - .addCode(methodBody) - .build(); - - // Create the class - TypeSpec nestedTryCatchClass = TypeSpec.classBuilder("NestedTryCatchExample") - .addModifiers(Modifier.PUBLIC) - .addMethod(nestedTryCatchMethod) - .build(); - - // Write to a Java file - JavaFile javaFile = JavaFile.builder("com.example", nestedTryCatchClass) - .build(); - - // Write the generated Java file to the file system - javaFile.writeTo(Paths.get("./src/test/resources/bugs/1119_trap-serialization/com/linecorp/centraldogma/server/internal/storage/repository/git/")); - } - + @Test + public void testTrapSerialization() { + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation( + "src/test/resources/bugs/1119_trap-serialization", + SourceType.Application, + Collections.emptyList()); + JavaView view = new JavaView(inputLocation); + + Optional methodOpt = + view.getMethod( + view.getIdentifierFactory() + .parseMethodSignature( + "")); + assertTrue(methodOpt.isPresent()); + JavaSootMethod method = methodOpt.get(); + method.getBody().toString(); + } + + @Test + public void testBasicTrapSerialization() { + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation( + "src/test/resources/bugs/1119_trap-serialization", + SourceType.Application, + Collections.emptyList()); + JavaView javaView = new JavaView(inputLocation); + Optional nestedTrap = + javaView.getMethod( + javaView + .getIdentifierFactory() + .parseMethodSignature( + "")); + + assertTrue(nestedTrap.isPresent()); + JavaSootMethod nestedTrapMethod = nestedTrap.get(); + nestedTrapMethod.getBody().getStmtGraph().toString(); + } }