package ast;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
public class XmlVisitor extends ASTVisitor implements NodeMapping{
private static final String MAPPING_ATTRIBUTE = "id"; // Used to map xml node to AST node
private static final String EXPRESSION_ELEMENT = "Expr"; // Wraps expressions
private Stack<Element> xmlElementStack = new Stack<Element>();
private Document doc;
private int indent = 0;
private int lastId = 0;
private Map<String, ASTNode> xmlToAst = new HashMap<String, ASTNode>();
private Set<IBinding> namesFromHeap = new HashSet<IBinding>();
private Set<IBinding> currentIfConditionbindings = new HashSet<IBinding>();
private boolean insideIfCondition;
private Element lastElement;
public XmlVisitor() throws ParserConfigurationException {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
doc = docBuilder.newDocument();
Element sourceFileElement = doc.createElement("SourceFile");
doc.appendChild(sourceFileElement);
xmlElementStack.push(sourceFileElement);
}
public Document getDocument() {
return doc;
}
private Element push(String name) {
Element e = doc.createElement(name);
xmlElementStack.peek().appendChild(e);
xmlElementStack.push(e);
return e;
}
private Element pop() {
return xmlElementStack.pop();
}
@Override
public void preVisit(org.eclipse.jdt.core.dom.ASTNode node) {
Element e = push(node.getClass().getSimpleName());
String idx = String.valueOf(lastId++);
e.setAttribute(MAPPING_ATTRIBUTE, idx);
xmlToAst.put(idx, node);
}
@Override
public boolean visit(IfStatement node) {
assert insideIfCondition == false;
insideIfCondition = true;
node.getExpression().accept(this);
Set<IBinding> conditionBindings = currentIfConditionbindings;
currentIfConditionbindings = new HashSet<IBinding>();
insideIfCondition = false;
node.getThenStatement().accept(this);
if (node.getElseStatement() != null) {
node.getElseStatement().accept(this);
}
namesFromHeap.addAll(conditionBindings);
return false;
}
@Override
public void postVisit(org.eclipse.jdt.core.dom.ASTNode node) {
if (node instanceof ParenthesizedExpression) {
// do nothing
} else if (node instanceof Expression) {
Expression expr = (Expression) node;
if (expr.resolveConstantExpressionValue() != null) {
Node oldNode = pop();
try {
xmlElementStack.peek().removeChild(oldNode);
} catch (RuntimeException e) {
System.out.println("HELLO");
throw e;
}
Element newNode = push("Constant");
updateType(expr, expr.resolveTypeBinding());
newNode.setAttribute("value", expr
.resolveConstantExpressionValue().toString());
newNode.setAttribute("node", node.getClass().getSimpleName());
newNode.setAttribute(MAPPING_ATTRIBUTE, ((Element)oldNode).getAttribute(MAPPING_ATTRIBUTE));
}
}
lastElement = pop();
indent -= 1;
}
@Override
public boolean visit(QualifiedName node) {
updateType(node, Utils.getTypeBinding(node));
updateScope(node);
Element elem = replaceTop("Name");
if (Utils.isFinal(node))
elem.setAttribute("final", "true");
if (Utils.isFinalSuffix(node))
elem.setAttribute("finalSuffix", "true");
elem.setAttribute("name", Utils.getNamePrefix(node));
elem.setAttribute("fullname", node.getFullyQualifiedName());
return false;
}
private Element replaceTop(String newName) {
Element oldXml = (Element) xmlElementStack.pop();
xmlElementStack.peek().removeChild(oldXml);
Element newXml = push(newName);
NamedNodeMap attrMap = oldXml.getAttributes();
for (int i = 0; i < attrMap.getLength(); i++) {
Node n = attrMap.item(i);
newXml.setAttribute(n.getNodeName(), n.getNodeValue());
}
return newXml;
}
@Override
public boolean visit(FieldAccess node) {
updateType(node.getName(), Utils.getTypeBinding(node.getName()));
Element elem = replaceTop("Name");
if (Utils.isFinal(node.getName()))
elem.setAttribute("final", "true");
if (Utils.isFinalSuffix(node.getName()))
elem.setAttribute("finalSuffix", "true");
elem.setAttribute("scope", "field");
elem.setAttribute("name", Utils.getNamePrefix(node.getName()));
elem.setAttribute("fullname", node.toString());
if ((new HeapVisitor()).check(node, namesFromHeap)) {
elem.setAttribute("fromHeap", "true");
}
return false;
}
private void updateType(Expression node, ITypeBinding type) {
// ITypeBinding type = Utils.getTypeBinding(node);
// ITypeBinding type = node.resolveTypeBinding();
Element xml = (Element) xmlElementStack.peek();
if (type != null) {
String ext = "";
ITypeBinding ex = type.getSuperclass();
while (ex != null) {
ext += ex.getName() + ", ";
ex = ex.getSuperclass();
}
type.getSuperclass();
xml.setAttribute("type", type.getName());
if (type.isArray()) {
xml.setAttribute("isArray", "true");
}
if (ext.length() > 0) {
xml.setAttribute("superclasses", ext);
}
ITypeBinding[] interfaces = type.getInterfaces();
String impl = "";
for (ITypeBinding inter : interfaces) {
impl += inter.getName() + ", ";
}
if (impl.length() > 0) {
xml.setAttribute("interfaces", impl);
}
String[] simplenumericTypes = { "int", "long", "short", "byte",
"char", "float", "double" };
if (type.isPrimitive()
& Utils.contains(simplenumericTypes, type.getName())) {
xml.setAttribute("numeric", "true");
}
}
}
private void updateScope(Name node) {
Element xml = (Element) xmlElementStack.peek();
IBinding binding = Utils.getBinding(node);
if (binding != null && binding.getKind() == IBinding.VARIABLE) {
IVariableBinding varBinding = (IVariableBinding) binding;
if (varBinding.isField()) {
xml.setAttribute("scope", "field");
if ((varBinding.getModifiers() & org.eclipse.jdt.core.dom.Modifier.PRIVATE) > 0) {
xml.setAttribute("private", varBinding.getDeclaringClass()
.getName());
}
} else {
xml.setAttribute("scope", "local");
}
if (namesFromHeap.contains(binding))
xml.setAttribute("fromHeap", "true");
}
}
//
// private boolean isFinal(Name node) {
// while (true) {
// IBinding binding = node.resolveBinding();
// int modifiers = 0;
// if (binding != null) {
// modifiers = binding.getModifiers();
// }
// if ((modifiers & org.eclipse.jdt.core.dom.Modifier.FINAL) == 0)
// return false;
// if (node.isQualifiedName()) {
// node = ((QualifiedName) node).getQualifier();
// } else {
// break;
// }
// }
// return true;
// }
@Override
public boolean visit(SimpleName node) {
Element xml = (Element) xmlElementStack.peek();
updateType(node, Utils.getTypeBinding(node));
updateScope(node);
xml = replaceTop("Name");
xml.setAttribute("name", node.getIdentifier());
if (Utils.isFinalFieldAccess(node))
xml.setAttribute("final", "true");
return false;
}
private void updateBindings(ASTNode node) {
if (!insideIfCondition)
return;
if (node instanceof Name) {
IBinding binding = ((Name) node).resolveBinding();
if (namesFromHeap.contains(binding)) {
namesFromHeap.remove(binding);
currentIfConditionbindings.add(binding);
}
}
}
@Override
public boolean visit(org.eclipse.jdt.core.dom.InfixExpression node) {
Element xml = (Element) xmlElementStack.peek();
if (node.getOperator() != null) {
xml.setAttribute("operator", node.getOperator().toString());
}
if (Operator.NOT_EQUALS.equals(node.getOperator())
|| Operator.EQUALS.equals(node.getOperator())) {
if (node.getLeftOperand().getNodeType() == ASTNode.NULL_LITERAL) {
updateBindings(node.getRightOperand());
} else if (node.getRightOperand().getNodeType() == ASTNode.NULL_LITERAL) {
updateBindings(node.getLeftOperand());
}
}
push(EXPRESSION_ELEMENT);
node.getLeftOperand().accept(this);
pop().setAttribute(MAPPING_ATTRIBUTE, lastElement.getAttribute(MAPPING_ATTRIBUTE));
push(EXPRESSION_ELEMENT);
node.getRightOperand().accept(this);
pop().setAttribute(MAPPING_ATTRIBUTE, lastElement.getAttribute(MAPPING_ATTRIBUTE));
if (node.extendedOperands() != null) {
for (ASTNode n : (List<ASTNode>) node.extendedOperands()) {
push(EXPRESSION_ELEMENT);
n.accept(this);
pop().setAttribute(MAPPING_ATTRIBUTE, lastElement.getAttribute(MAPPING_ATTRIBUTE));;
}
}
return false;
}
@Override
public boolean visit(Assignment node) {
replaceTop("ChangeVal");
Element xml = (Element) xmlElementStack.peek();
String kind = node.getOperator().toString();
String a = "other";
if (kind == "+=") {
a = "inc";
}
if (kind == "-=") {
a = "dec";
}
if (kind == "=") {
a = "assign";
}
if (kind == "*=") {
a = "mul";
}
if (kind == "/=") {
a = "div";
}
xml.setAttribute("kind", a);
xml.setAttribute("realNode", "Assignment");
push("LeftOfAssignment");
node.getLeftHandSide().accept(this);
pop();
push("RightOfAssignment");
node.getRightHandSide().accept(this);
pop();
if ((new HeapVisitor()).check(node.getRightHandSide(), namesFromHeap)) {
if (node.getLeftHandSide() instanceof Name) {
namesFromHeap.add(((Name) node.getLeftHandSide())
.resolveBinding());
} else if (node.getLeftHandSide() instanceof FieldAccess) {
namesFromHeap.add(((FieldAccess) node.getLeftHandSide())
.resolveFieldBinding());
}
}
return false;
}
@Override
public boolean visit(PrefixExpression node) {
replaceTop("ChangeVal");
Element xml = (Element) xmlElementStack.peek();
String kind = node.getOperator().toString();
String a = "dec";
if (kind == "++") {
a = "inc";
}
xml.setAttribute("kind", a);
xml.setAttribute("realNode", "PrefixExpression");
push("LeftOfAssignment");
node.getOperand().accept(this);
pop();
push("RightOfAssignment");
pop();
return false;
}
@Override
public boolean visit(org.eclipse.jdt.core.dom.EnhancedForStatement node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("isLoop", "true");
return super.visit(node);
};
@Override
public boolean visit(org.eclipse.jdt.core.dom.ForStatement node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("isLoop", "true");
//create artificial element for initialisers
push("Initializers");
if (node.initializers() != null) {
for (Object n : node.initializers()) {
((ASTNode) n).accept(this);
}
}
pop();
//create artificial element for the loop condition
push("Condition");
if (node.getExpression() != null)
node.getExpression().accept(this);
pop();
push("Updaters");
if (node.updaters() != null) {
for (Object n : node.updaters()) {
((ASTNode) n).accept(this);
}
}
pop();
if (node.getBody() != null) {
if (node.getBody().getNodeType() != ASTNode.BLOCK) {
push("Block");
node.getBody().accept(this);
pop();
} else {
node.getBody().accept(this);
}
}
return false;
};
@Override
public boolean visit(BooleanLiteral node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("value", String.valueOf(node.booleanValue()));
return super.visit(node);
}
@Override
public boolean visit(WhileStatement node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("isLoop", "true");
push("Condition");
if (node.getExpression() != null) {
node.getExpression().accept(this);
}
pop();
if (node.getBody() != null) {
node.getBody().accept(this);
}
return false;
}
@Override
public boolean visit(DoStatement node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("isLoop", "true");
return super.visit(node);
}
@Override
public boolean visit(PostfixExpression node) {
replaceTop("ChangeVal");
Element xml = (Element) xmlElementStack.peek();
String kind = node.getOperator().toString();
String a = "dec";
if (kind == "++") {
a = "inc";
}
xml.setAttribute("kind", a);
xml.setAttribute("realNode", "PostfixExpression");
push("LeftOfAssignment");
node.getOperand().accept(this);
pop();
push("RightOfAssignment");
pop();
return false;
}
@Override
public ASTNode getNode(String index) {
return xmlToAst.containsKey(index) ? xmlToAst.get(index) : null;
}
@Override
public boolean visit(ArrayAccess node) {
Element xml = (Element) xmlElementStack.peek();
xml.setAttribute("fromHeap", "true");
return true;
}
@Override
public boolean visit(VariableDeclarationStatement node) {
// node.
// if ((new HeapVisitor()).check(node.getRightHandSide())){
// namesFromHeap.add(((Name)node.getLeftHandSide()).resolveBinding());
// }
//
// Element xml = (Element) xmlNodeStack.peek();
// xml.setAttribute("fromHeap", "true");
VariableDeclarationFragment frag = (VariableDeclarationFragment) node
.fragments().get(node.fragments().size() - 1);
if (frag.getInitializer() != null) {
if ((new HeapVisitor()).check(frag.getInitializer(), namesFromHeap)) {
namesFromHeap.add((frag.getName()).resolveBinding());
}
}
return true;
}
@Override
public boolean visit(MethodDeclaration node) {
Element elem = (Element) xmlElementStack.peek();
if (node.isConstructor()) {
elem.setAttribute("constructor", "true");
}
for (int i = 0; i < node.parameters().size(); i++) {
SingleVariableDeclaration dec = (SingleVariableDeclaration) node
.parameters().get(i);
if (!dec.getType().isPrimitiveType()) {
IBinding binding = dec.getName().resolveBinding();
namesFromHeap.add(binding);
}
// System.out.println(dec);
}
return true;
}
public boolean visit(ParenthesizedExpression node) {
Element curNode = pop();
xmlElementStack.peek().removeChild(curNode);
node.getExpression().accept(this);
xmlElementStack.push(curNode);
return false;
}
@Override
public boolean visit(MethodInvocation node) {
Element elem = (Element) xmlElementStack.peek();
// expression
if (node.getExpression() != null){
node.getExpression().accept(this);
// IMethodBinding mb = Utils.findMethod(node.getExpression().resolveTypeBinding(), node.getName().toString());
//// ITypeBinding bind = node.getExpression().resolveTypeBinding();
// System.out.println(mb);
};
elem.setAttribute("methodName", node.getName().toString());
List<ASTNode> arguments = node.arguments();
if (!arguments.isEmpty()) {
push("MethodArguments");
for (ASTNode arg : arguments) {
push("MethodArgument");
arg.accept(this);
pop();
}
pop();
}
return false;
}
}