code: package gr.uom.java.ast.decomposition.cfg;
  
  import java.util.ArrayList;
  import java.util.LinkedHashMap;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.TreeSet;
  
  public class BasicBlockCFG {
  	private List<BasicBlock> basicBlocks;
  	private Map<BasicBlock, Set<BasicBlock>> forwardReachableBlocks;
  	
  	public BasicBlockCFG(CFG cfg) {
  		this.basicBlocks = new ArrayList<BasicBlock>();
  		this.forwardReachableBlocks = new LinkedHashMap<BasicBlock, Set<BasicBlock>>();
  		TreeSet<GraphNode> allNodes = new TreeSet<GraphNode>(cfg.nodes);
  		Map<CFGBlockNode, List<CFGNode>> directlyNestedNodesInBlocks = cfg.getDirectlyNestedNodesInBlocks();
  		for(CFGBlockNode blockNode : directlyNestedNodesInBlocks.keySet()) {
  			if(blockNode instanceof CFGTryNode) {
  				CFGTryNode tryNode = (CFGTryNode)blockNode;
  				if(!tryNode.hasResources())
  					allNodes.add(tryNode);
  			}
  		}
  		for(GraphNode node : allNodes) {
  			CFGNode cfgNode = (CFGNode)node;
  			if(cfgNode instanceof CFGTryNode && !((CFGTryNode)cfgNode).hasResources()) {
  				CFGTryNode tryNode = (CFGTryNode)cfgNode;
  				if(!basicBlocks.isEmpty()) {
  					BasicBlock basicBlock = basicBlocks.get(basicBlocks.size()-1);
  					basicBlock.addTryNode(tryNode);
  				}
  			}
  			else if(cfgNode.isLeader()) {
  				BasicBlock basicBlock = new BasicBlock(cfgNode);
  				if(!basicBlocks.isEmpty()) {
  					BasicBlock previousBlock = basicBlocks.get(basicBlocks.size()-1);
  					previousBlock.setNextBasicBlock(basicBlock);
  					basicBlock.setPreviousBasicBlock(previousBlock);
  				}
  				basicBlocks.add(basicBlock);
  			}
  			else {
  				BasicBlock basicBlock = basicBlocks.get(basicBlocks.size()-1);
  				basicBlock.add(cfgNode);
  			}
  		}
  		//special handling for the try statement that is first node
  		for(CFGBlockNode blockNode : directlyNestedNodesInBlocks.keySet()) {
  			if(blockNode instanceof CFGTryNode) {
  				CFGTryNode tryNode = (CFGTryNode)blockNode;
  				if(tryNode.id == 1 && !basicBlocks.isEmpty() && !tryNode.hasResources()) {
  					BasicBlock basicBlock = basicBlocks.get(0);
  					basicBlock.addTryNode(tryNode);
  				}
  			}
  		}
  		BasicBlock.resetBlockNum();
  	}
  
  	public List<BasicBlock> getBasicBlocks() {
  		return basicBlocks;
  	}
  
  	public Set<BasicBlock> forwardReachableBlocks(BasicBlock basicBlock) {
  		if(forwardReachableBlocks.containsKey(basicBlock))
  			return forwardReachableBlocks.get(basicBlock);
  		Set<BasicBlock> reachableBlocks = new LinkedHashSet<BasicBlock>();
  		reachableBlocks.add(basicBlock);
  		CFGNode lastNode = basicBlock.getLastNode();
  		for(GraphEdge edge : lastNode.outgoingEdges) {
  			Flow flow = (Flow)edge;
  			if(!flow.isLoopbackFlow()) {
  				CFGNode dstNode = (CFGNode)flow.dst;
  				BasicBlock dstBasicBlock = dstNode.getBasicBlock();
  				reachableBlocks.add(dstBasicBlock);
  				reachableBlocks.addAll(forwardReachableBlocks(dstBasicBlock));
  			}
  		}
  		forwardReachableBlocks.put(basicBlock, reachableBlocks);
  		return reachableBlocks;
  	}
  }
  