private void buildDoWhileStatement(DoWhileStatementTree doWhileStatementTree) { Block falseBranch = currentBlock; Block loopback = createBlock(); // process condition currentBlock = createBranch(doWhileStatementTree, loopback, falseBranch); buildCondition(doWhileStatementTree.condition(), loopback, falseBranch); // process body addContinueTarget(currentBlock); currentBlock = createBlock(currentBlock); breakTargets.addLast(falseBranch); build(doWhileStatementTree.statement()); breakTargets.removeLast(); continueTargets.removeLast(); loopback.addSuccessor(currentBlock); currentBlock = createBlock(currentBlock); }
public static CFG buildCFG(List<? extends Tree> trees) { return new CFG(trees, null, false); } public static CFG build(MethodTree tree) {
private CFG(BlockTree tree, Symbol.MethodSymbol symbol) { methodSymbol = symbol; exitBlocks.add(createBlock()); currentBlock = createBlock(exitBlock()); for (StatementTree statementTree : Lists.reverse(tree.body())) { build(statementTree); } prune(); computePredecessors(blocks); }
private void buildConditionalOr(BinaryExpressionTree tree) { Block trueBlock = currentBlock; currentBlock = createBlock(trueBlock); // process RHS build(tree.rightOperand()); // process LHS buildConditionalBinaryLHS(tree, trueBlock, currentBlock); }
private void buildReturnStatement(ReturnStatementTree returnStatement) { currentBlock = createUnconditionalJump(returnStatement, exitBlock(), currentBlock); ExpressionTree expression = returnStatement.expression(); if (expression != null) { build(expression); } }
private void build(Tree tree) { switch (tree.kind()) { case BLOCK: build(((BlockTree) tree).body()); break; case RETURN_STATEMENT: buildReturnStatement((ReturnStatementTree) tree); break; case EXPRESSION_STATEMENT: build(((ExpressionStatementTree) tree).expression()); break; case METHOD_INVOCATION: buildMethodInvocation((MethodInvocationTree) tree); break; case IF_STATEMENT: buildIfStatement((IfStatementTree) tree); break; case CONDITIONAL_EXPRESSION: buildConditionalExpression((ConditionalExpressionTree) tree); break; case VARIABLE: buildVariable((VariableTree) tree); break; case MULTIPLY: case EQUAL_TO: case NOT_EQUAL_TO: buildBinaryExpression(tree); break; case ASSIGNMENT:
private void build(ListTree<? extends Tree> trees) { build((List<? extends Tree>) trees); } private void build(List<? extends Tree> trees) {
currentBlock = createBlock(currentBlock); BlockTree finallyBlockTree = tryStatementTree.finallyBlock(); if (finallyBlockTree != null) { currentBlock.isFinallyBlock = true; Block finallyBlock = currentBlock; build(finallyBlockTree); finallyBlock.addExitSuccessor(exitBlock()); exitBlocks.push(currentBlock); addContinueTarget(currentBlock); currentBlock.isFinallyBlock = true; breakTargets.addLast(currentBlock); Block beforeFinally = createBlock(currentBlock); TryStatement tryStatement = new TryStatement(); tryStatement.successorBlock = finallyOrEndBlock; enclosedByCatch.push(false); for (CatchTree catchTree : Lists.reverse(tryStatementTree.catches())) { currentBlock = createBlock(finallyOrEndBlock); enclosedByCatch.push(true); build(catchTree.block()); buildVariable(catchTree.parameter()); currentBlock.isCatchBlock = true; enclosedByCatch.pop(); build(tryStatementTree.block()); build((List<? extends Tree>) tryStatementTree.resourceList()); enclosingTry.pop(); enclosedByCatch.pop();
private void buildTypeCast(Tree tree) { enclosingTry.peek().catches.entrySet().stream() .filter(e -> e.getKey().isSubtypeOf("java.lang.ClassCastException")) .findFirst() .ifPresent(e -> { currentBlock = createBlock(currentBlock); currentBlock.successors.add(e.getValue()); }); currentBlock.elements.add(tree); TypeCastTree typeCastTree = (TypeCastTree) tree; build(typeCastTree.expression()); }
private void buildSynchronizedStatement(SynchronizedStatementTree sst) { // First create the block of the statement, build(sst.block()); // Then create a single block with the SYNCHRONIZED tree as terminator currentBlock = createUnconditionalJump(sst, currentBlock, null); build(sst.expression()); }
@Override public void visitForEachStatement(ForEachStatement tree) { CFG cfg = CFG.buildCFG(Collections.singletonList(tree), true); Symbol var = tree.variable().symbol(); boolean liveVar = true; if(var.owner().isMethodSymbol()) { cfg.setMethodSymbol((Symbol.MethodSymbol) var.owner()); LiveVariables analyze = LiveVariables.analyze(cfg); Set<Symbol> live = analyze.getOut(cfg.reversedBlocks().get(1)); liveVar = live.contains(var); } if(!liveVar) { variables.add(var); } super.visitForEachStatement(tree); if(!liveVar) { variables.remove(var); } }
private void buildNewClass(NewClassTree tree) { handleExceptionalPaths(tree.constructorSymbol()); currentBlock.elements.add(tree); build(tree.arguments()); ExpressionTree enclosingExpression = tree.enclosingExpression(); if (enclosingExpression != null) { build(enclosingExpression); } }
private void analyzeCFG(Map<CFG.Block, Set<Symbol>> in, Map<CFG.Block, Set<Symbol>> kill, Map<CFG.Block, Set<Symbol>> gen) { Deque<CFG.Block> workList = new LinkedList<>(); workList.addAll(cfg.reversedBlocks()); while (!workList.isEmpty()) { CFG.Block block = workList.removeFirst(); Set<Symbol> blockOut = out.computeIfAbsent(block, k -> new HashSet<>()); block.successors().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); block.exceptions().stream().map(in::get).filter(Objects::nonNull).forEach(blockOut::addAll); // in = gen and (out - kill) Set<Symbol> newIn = new HashSet<>(gen.get(block)); newIn.addAll(Sets.difference(blockOut, kill.get(block))); if (newIn.equals(in.get(block))) { continue; } in.put(block, newIn); block.predecessors().forEach(workList::addLast); } }
private static boolean isLiveInMethodEntry(Symbol privateFieldSymbol, MethodTree methodTree) { CFG cfg = CFG.build(methodTree); LiveVariables liveVariables = LiveVariables.analyzeWithFields(cfg); return liveVariables.getIn(cfg.entryBlock()).contains(privateFieldSymbol); }
private void computeExecutableLines(List<? extends Tree> trees) { if(trees.isEmpty()) { return; } // rely on cfg to get every instructions and get most of the token. CFG cfg = CFG.buildCFG(trees); cfg.blocks() .stream() .flatMap(b->b.elements().stream()) .forEach( t -> { if (t.is(NEW_CLASS)) { NewClassTree newClassTree = (NewClassTree) t; new ExecutableLinesTokenVisitor().scanTree(newClassTree.identifier()); executableLines.add(newClassTree.newKeyword().line()); } else if (t.is(TRY_STATEMENT)) { // add last token of try statements executableLines.add(t.lastToken().line()); } else { executableLines.add(t.firstToken().line()); } } ); }
private static CFG.Block getLoopBlock(CFG cfg, Tree loopTree) { return cfg.blocks().stream() .filter(block -> loopTree.equals(block.terminator())) .findFirst() .orElseThrow(() -> new IllegalStateException("CFG necessarily contains the loop block.")); }
private void build(Tree tree) { switch (tree.kind()) { case BLOCK: build(((BlockTree) tree).body()); break; case RETURN_STATEMENT: buildReturnStatement((ReturnStatementTree) tree); break; case EXPRESSION_STATEMENT: build(((ExpressionStatementTree) tree).expression()); break; case METHOD_INVOCATION: buildMethodInvocation((MethodInvocationTree) tree); break; case IF_STATEMENT: buildIfStatement((IfStatementTree) tree); break; case CONDITIONAL_EXPRESSION: buildConditionalExpression((ConditionalExpressionTree) tree); break; case VARIABLE: buildVariable((VariableTree) tree); break; case MULTIPLY: case EQUAL_TO: case NOT_EQUAL_TO: buildBinaryExpression(tree); break; case ASSIGNMENT:
private void buildConditionalAnd(BinaryExpressionTree tree) { Block falseBlock = currentBlock; currentBlock = createBlock(falseBlock); // process RHS build(tree.rightOperand()); // process LHS buildConditionalBinaryLHS(tree, currentBlock, falseBlock); }
@Nullable @Override public CFG cfg() { if (block == null) { return null; } if (cfg == null) { cfg = CFG.build(this); } return cfg; }