package org.ntlab.deltaViewer; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.ntlab.deltaExtractor.Alias; import org.ntlab.deltaExtractor.Alias.AliasType; import org.ntlab.deltaExtractor.IAliasCollector; import org.ntlab.trace.ArrayAccess; import org.ntlab.trace.ArrayCreate; import org.ntlab.trace.ArrayUpdate; import org.ntlab.trace.FieldAccess; import org.ntlab.trace.FieldUpdate; import org.ntlab.trace.IStatementVisitor; import org.ntlab.trace.MethodExecution; import org.ntlab.trace.AbstractTracePointVisitor; import org.ntlab.trace.MethodInvocation; import org.ntlab.trace.ObjectReference; import org.ntlab.trace.Reference; import org.ntlab.trace.Statement; import org.ntlab.trace.TracePoint; public class ForwardAliasCollector extends AbstractTracePointVisitor implements IAliasCollector { private List<Alias> aliasList = new ArrayList<>(); private FullObjectCallGraph objectCallGraph; private TracePoint firstTracePoint = null; public ForwardAliasCollector() { objectCallGraph = new FullObjectCallGraph(); } @Override public boolean preVisitStatement(Statement statement, TracePoint tp) { if (firstTracePoint == null) { objectCallGraph.addStartPoint(tp.getMethodExecution()); firstTracePoint = tp.duplicate(); // for MagnetRON Alias thisAlias = new Alias(AliasType.THIS, 0, tp.getMethodExecution().getThisObjId(), tp.duplicate()); addAlias(thisAlias); } if (statement instanceof MethodInvocation) { MethodInvocation mi = (MethodInvocation) statement; String methodSignature = mi.getCalledMethodExecution().getSignature(); if (!methodSignature.contains("<clinit>")) { // Not a class initializer. if (!mi.getCalledMethodExecution().isConstructor()) { String receiver = mi.getCalledMethodExecution().getThisObjId(); Alias recerverAlias = new Alias(AliasType.RECEIVER, 0, receiver, tp.duplicate()); addAlias(recerverAlias); } int index = 0; for (ObjectReference arg: mi.getCalledMethodExecution().getArguments()) { Alias argAlias = new Alias(AliasType.ACTUAL_ARGUMENT, index, arg.getId(), tp.duplicate()); addAlias(argAlias); index++; } if (mi.getCalledMethodExecution().isCollectionType() && (methodSignature.contains("add(") || methodSignature.contains("set(") || methodSignature.contains("put(") || methodSignature.contains("push(") || methodSignature.contains("addElement("))) { objectCallGraph.addRelatedPoint(tp.duplicate()); } index = 0; for (ObjectReference arg: mi.getCalledMethodExecution().getArguments()) { Alias argAlias = new Alias(AliasType.FORMAL_PARAMETER, index, arg.getId(), mi.getCalledMethodExecution().getEntryPoint()); addAlias(argAlias); index++; } } } else if (statement instanceof FieldAccess) { FieldAccess fa = (FieldAccess) statement; if (fa.getContainerObjId().equals(fa.getThisObjId())) { Alias thisAlias = new Alias(AliasType.THIS, 0, fa.getThisObjId(), tp.duplicate()); addAlias(thisAlias); } else { Alias containerAlias = new Alias(AliasType.CONTAINER, 0, fa.getContainerObjId(), tp.duplicate()); addAlias(containerAlias); } Alias fieldAlias = new Alias(AliasType.FIELD, 0, fa.getValueObjId(), tp.duplicate()); addAlias(fieldAlias); objectCallGraph.addReference(fa.getReference()); } else if (statement instanceof FieldUpdate) { FieldUpdate fu = (FieldUpdate) statement; if (!fu.getValueClassName().equals("---")) { // Updated by a non-null value. if (fu.getContainerObjId().equals(tp.getMethodExecution().getThisObjId())) { Alias thisAlias = new Alias(AliasType.THIS, 0, tp.getMethodExecution().getThisObjId(), tp.duplicate()); addAlias(thisAlias); } else { Alias containerAlias = new Alias(AliasType.CONTAINER, 0, fu.getContainerObjId(), tp.duplicate()); addAlias(containerAlias); } objectCallGraph.addRelatedPoint(tp.duplicate()); } } else if (statement instanceof ArrayCreate) { ArrayCreate ac = (ArrayCreate) statement; Alias thisAlias = new Alias(AliasType.THIS, 0, tp.getMethodExecution().getThisObjId(), tp.duplicate()); addAlias(thisAlias); Alias arrayCreateAlias = new Alias(AliasType.ARRAY_CREATE, 0, ac.getArrayObjectId(), tp.duplicate()); addAlias(arrayCreateAlias); Reference ref = new Reference(tp.getMethodExecution().getThisObjId(), ac.getArrayObjectId(), tp.getMethodExecution().getThisClassName(), ac.getArrayClassName()); ref.setCreation(true); objectCallGraph.addReference(ref); } else if (statement instanceof ArrayAccess) { ArrayAccess aa = (ArrayAccess) statement; Alias arrayAlias = new Alias(AliasType.ARRAY, 0, aa.getArrayObjectId(), tp.duplicate()); addAlias(arrayAlias); Alias arrayElementAlias = new Alias(AliasType.ARRAY_ELEMENT, aa.getIndex(), aa.getValueObjectId(), tp.duplicate()); addAlias(arrayElementAlias); Reference ref = new Reference(aa.getArrayObjectId(), aa.getValueObjectId(), aa.getArrayClassName(), aa.getValueClassName()); ref.setArray(true); objectCallGraph.addReference(ref); } else if (statement instanceof ArrayUpdate) { ArrayUpdate au = (ArrayUpdate) statement; Alias arrayAlias = new Alias(AliasType.ARRAY, 0, au.getArrayObjectId(), tp.duplicate()); addAlias(arrayAlias); objectCallGraph.addRelatedPoint(tp.duplicate()); } return false; } @Override public boolean postVisitStatement(Statement statement, TracePoint tp) { if (statement instanceof MethodInvocation) { MethodInvocation mi = (MethodInvocation) statement; String returnValue = mi.getCalledMethodExecution().getReturnValue().getId(); String methodSignature = mi.getCalledMethodExecution().getSignature(); if (!methodSignature.contains("<clinit>")) { // Not a class initializer. if (!mi.getCalledMethodExecution().isConstructor()) { if (!mi.getCalledMethodExecution().getReturnValue().getActualType().equals("void")) { Alias returnAlias = new Alias(AliasType.RETURN_VALUE, 0, returnValue, mi.getCalledMethodExecution().getExitPoint()); addAlias(returnAlias); } Alias methodInvAlias = new Alias(AliasType.METHOD_INVOCATION, 0, returnValue, tp.duplicate()); addAlias(methodInvAlias); if (methodSignature.contains("List.get(") || methodSignature.contains("Map.get(")) { String returnClass = mi.getCalledMethodExecution().getReturnValue().getActualType(); Reference ref = new Reference(mi.getCalledMethodExecution().getThisObjId(), returnValue, mi.getCalledMethodExecution().getThisClassName(), returnClass); ref.setCollection(true); objectCallGraph.addReference(ref); } } else { Alias methodInvAlias = new Alias(AliasType.CONSTRACTOR_INVOCATION, 0, returnValue, tp.duplicate()); addAlias(methodInvAlias); String returnClass = mi.getCalledMethodExecution().getReturnValue().getActualType(); Reference ref = new Reference(tp.getMethodExecution().getThisObjId(), returnValue, tp.getMethodExecution().getThisClassName(), returnClass); ref.setCreation(true); objectCallGraph.addReference(ref); } } } else if (statement instanceof FieldAccess) { } else if (statement instanceof FieldUpdate) { } else if (statement instanceof ArrayCreate) { } else if (statement instanceof ArrayAccess) { } else if (statement instanceof ArrayUpdate) { } return false; } @Override public void addAlias(Alias alias) { aliasList.add(alias); } @Override public List<Alias> getAliasList() { return aliasList; } public IObjectCallGraph getObjectCallGraph() { return objectCallGraph; } private class FullObjectCallGraph implements IObjectCallGraph { private List<Reference> references = new ArrayList<>(); private List<MethodExecution> startPoints = new ArrayList<>(); private List<TracePoint> relatedPoints = new ArrayList<>(); public void addReference(Reference r) { if (!references.contains(r)) references.add(r); } public void addStartPoint(MethodExecution me) { startPoints.add(me); } public void addRelatedPoint(TracePoint tp) { relatedPoints.add(tp); } @Override public List<Reference> getReferences() { return references; } @Override public List<MethodExecution> getStartPoints() { return startPoints; } @Override public List<TracePoint> getRelatedPoints() { return relatedPoints; } @Override public Map<MethodExecution, List<MethodExecution>> getCallTree() { return null; } } }