code: package gr.uom.java.ast.decomposition.cfg;
  
  import java.util.ArrayList;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Set;
  
  import org.eclipse.jdt.core.dom.VariableDeclaration;
  
  public class ReachingAliasSet {
  
  	private List<LinkedHashSet<VariableDeclaration>> aliasSets;
  	
  	public ReachingAliasSet() {
  		this.aliasSets = new ArrayList<LinkedHashSet<VariableDeclaration>>();
  	}
  	
  	private ReachingAliasSet(List<LinkedHashSet<VariableDeclaration>> aliasSets) {
  		this.aliasSets = aliasSets;
  	}
  	
  	public void insertAlias(VariableDeclaration leftHandSideReference, VariableDeclaration rightHandSideReference) {
  		boolean rightHandSideReferenceFound = false;
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			if(aliasSet.contains(rightHandSideReference)) {
  				rightHandSideReferenceFound = true;
  				aliasSet.add(leftHandSideReference);
  			}
  		}
  		if(!rightHandSideReferenceFound) {
  			LinkedHashSet<VariableDeclaration> aliasSet = new LinkedHashSet<VariableDeclaration>();
  			aliasSet.add(leftHandSideReference);
  			aliasSet.add(rightHandSideReference);
  			aliasSets.add(aliasSet);
  		}
  		List<LinkedHashSet<VariableDeclaration>> aliasSetsToBeRemoved = new ArrayList<LinkedHashSet<VariableDeclaration>>();
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			if(aliasSet.contains(leftHandSideReference)) {
  				if(!aliasSet.contains(rightHandSideReference))
  					aliasSet.remove(leftHandSideReference);
  				if(aliasSet.size() == 1)
  					aliasSetsToBeRemoved.add(aliasSet);
  			}
  		}
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSetsToBeRemoved) {
  			aliasSets.remove(aliasSet);
  		}
  	}
  	
  	public void removeAlias(VariableDeclaration leftHandSideReference) {
  		List<LinkedHashSet<VariableDeclaration>> aliasSetsToBeRemoved = new ArrayList<LinkedHashSet<VariableDeclaration>>();
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			if(aliasSet.contains(leftHandSideReference)) {
  				aliasSet.remove(leftHandSideReference);
  				if(aliasSet.size() == 1)
  					aliasSetsToBeRemoved.add(aliasSet);
  			}
  		}
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSetsToBeRemoved) {
  			aliasSets.remove(aliasSet);
  		}
  	}
  	
  	public boolean containsAlias(VariableDeclaration variableDeclaration) {
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			if(aliasSet.contains(variableDeclaration))
  				return true;
  		}
  		return false;
  	}
  	
  	public boolean containsAlias(AbstractVariable variable) {
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			for(VariableDeclaration alias : aliasSet) {
  				if(alias.resolveBinding().getKey().equals(variable.getVariableBindingKey()))
  					return true;
  			}
  		}
  		return false;
  	}
  	
  	public Set<VariableDeclaration> getAliases(VariableDeclaration variableDeclaration) {
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			if(aliasSet.contains(variableDeclaration)) {
  				Set<VariableDeclaration> aliases = new LinkedHashSet<VariableDeclaration>();
  				for(VariableDeclaration alias : aliasSet) {
  					if(!alias.equals(variableDeclaration))
  						aliases.add(alias);
  				}
  				return aliases;
  			}
  		}
  		return null;
  	}
  	
  	public Set<VariableDeclaration> getAliases(AbstractVariable variable) {
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			boolean containsVariable = false;
  			for(VariableDeclaration alias : aliasSet) {
  				if(alias.resolveBinding().getKey().equals(variable.getVariableBindingKey())) {
  					containsVariable = true;
  					break;
  				}
  			}
  			if(containsVariable) {
  				Set<VariableDeclaration> aliases = new LinkedHashSet<VariableDeclaration>();
  				for(VariableDeclaration alias : aliasSet) {
  					if(!alias.resolveBinding().getKey().equals(variable.getVariableBindingKey()))
  						aliases.add(alias);
  				}
  				return aliases;
  			}
  		}
  		return null;
  	}
  	
  	public ReachingAliasSet copy() {
  		List<LinkedHashSet<VariableDeclaration>> aliasSetsCopy = new ArrayList<LinkedHashSet<VariableDeclaration>>();
  		for(LinkedHashSet<VariableDeclaration> aliasSet : aliasSets) {
  			LinkedHashSet<VariableDeclaration> aliasSetCopy = new LinkedHashSet<VariableDeclaration>(aliasSet);
  			aliasSetsCopy.add(aliasSetCopy);
  		}
  		return new ReachingAliasSet(aliasSetsCopy);
  	}
  	
  	public String toString() {
  		return aliasSets.toString();
  	}
  }
  