/**
*
*/
package se.sics.kompics.ide.builder;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import se.sics.kompics.ide.Activator;
import se.sics.kompics.ide.Model;
import se.sics.kompics.ide.model.ast.ASTChannel;
import se.sics.kompics.ide.model.ast.ASTComponent;
import se.sics.kompics.ide.model.ast.ASTComponentDefinition;
import se.sics.kompics.ide.model.ast.ASTEvent;
import se.sics.kompics.ide.model.ast.ASTHandler;
import se.sics.kompics.ide.model.ast.ASTModelObject;
import se.sics.kompics.ide.model.ast.ASTPort;
import se.sics.kompics.ide.model.ast.ASTPortType;
import se.sics.kompics.ide.model.ast.ASTSubscription;
import se.sics.kompics.model.kompicsComponents.Channel;
import se.sics.kompics.model.kompicsComponents.ComponentDefinition;
import se.sics.kompics.model.kompicsComponents.Event;
import se.sics.kompics.model.kompicsComponents.Handler;
import se.sics.kompics.model.kompicsComponents.KompicsComponentsFactory;
import se.sics.kompics.model.kompicsComponents.Port;
import se.sics.kompics.model.kompicsComponents.PortType;
import se.sics.kompics.model.kompicsComponents.Subscription;
/**
* The <code>ModelVisitor</code> .
*
* @author Lars Kroll <lkr@lars-kroll.com>
* @version $Id: $
*
*/
public class ModelVisitor extends ASTVisitor {
private ASTNode root;
private KompicsModelBuilder builder;
private KompicsComponentsFactory factory = KompicsComponentsFactory.eINSTANCE;
private Stack<ASTModelObject> visitStack = new Stack<ASTModelObject>();
private Map<String, ASTHandler> handlerVars = new HashMap<String, ASTHandler>();
private Map<String, ASTPort> portVars = new HashMap<String, ASTPort>();
private Map<String, ASTComponent> componentVars = new HashMap<String, ASTComponent>();
private List<MethodInvocation> deferredMethods = new LinkedList<MethodInvocation>();
private boolean retryFlag = false;
public ModelVisitor(ASTNode root, KompicsModelBuilder builder) {
this.setRoot(root);
this.setBuilder(builder);
}
/**
* @return the builder
*/
public KompicsModelBuilder getBuilder() {
return builder;
}
/**
* @param builder
* the builder to set
*/
public void setBuilder(KompicsModelBuilder builder) {
this.builder = builder;
}
/**
* @return the root
*/
public ASTNode getRoot() {
return root;
}
/**
* @param root
* the root to set
*/
public void setRoot(ASTNode root) {
this.root = root;
}
//
// OVERRIDES
//
@Override
public boolean visit(TypeDeclaration type) {
ITypeBinding binding = type.resolveBinding();
return createModel(type, binding);
}
@Override
public void endVisit(TypeDeclaration type) {
if (!visitStack.isEmpty()) {
ITypeBinding binding = type.resolveBinding();
IBinding stackBinding = visitStack.peek().getBinding();
if (binding.isEqualTo(stackBinding)) {
if (isInSupertypes(binding, "se.sics.kompics.ComponentDefinition")) {
retryDeferred();
deferredMethods.clear();
portVars.clear(); // Assume that only top-leve;
handlerVars.clear(); // components define handlers
componentVars.clear(); // , ports and component instances
}
visitStack.pop();
}
}
}
@Override
public boolean visit(MethodInvocation method) {
IMethodBinding binding = method.resolveMethodBinding();
createModel(method, binding);
return false;
}
@Override
public boolean visit(AnonymousClassDeclaration type) {
ITypeBinding binding = type.resolveBinding();
// Activator.log("Anonymous Class with supertypes: "
// + listSuperTypes(binding));
return createModel(type, binding);
}
//
// PRIVATE
//
private void createModel(MethodInvocation method, IMethodBinding binding) {
// Activator.log("Method: " + binding.getName() + " from "
// + binding.getDeclaringClass().getQualifiedName());
String name = binding.getName();
String decClass = binding.getDeclaringClass().getQualifiedName();
if ((name.equals("provides")) || (name.equals("negative"))
&& decClass.equals("se.sics.kompics.ComponentDefinition")) {
createPort(method, ASTModelObject.PROVIDED_PORT);
} else if ((name.equals("requires")) || (name.equals("positive"))
&& decClass.equals("se.sics.kompics.ComponentDefinition")) {
createPort(method, ASTModelObject.REQUIRED_PORT);
} else if ((name.equals("indication")) || (name.equals("positive"))
&& decClass.equals("se.sics.kompics.PortType")) {
createEvent(method, ASTModelObject.PROVIDED_PORT);
} else if ((name.equals("request")) || (name.equals("negative"))
&& decClass.equals("se.sics.kompics.PortType")) {
createEvent(method, ASTModelObject.REQUIRED_PORT);
} else if ((name.equals("subscribe") && decClass
.equals("se.sics.kompics.ComponentDefinition"))) {
addSubscription(method);
} else if ((name.equals("connect"))
&& decClass.equals("se.sics.kompics.ComponentDefinition")) {
createChannel(method);
} else if ((name.equals("create"))
&& decClass.equals("se.sics.kompics.ComponentDefinition")) {
createComponentInstance(method);
}
}
private boolean createModel(TypeDeclaration type, ITypeBinding binding) {
if (isInSupertypes(binding, "se.sics.kompics.ComponentDefinition")) {
createComponent(type);
return true;
} else if (isInSupertypes(binding, "se.sics.kompics.PortType")) {
createPortType(type);
return true;
} else if (isInSupertypes(binding, "se.sics.kompics.Event")) {
createEvent(type);
return false;
} else if (isInSupertypes(binding, "se.sics.kompics.Handler")) {
createHandler(type, binding);
return false;
}
return true;
}
private boolean createModel(AnonymousClassDeclaration type, ITypeBinding binding) {
// if (isInSupertypes(binding, "se.sics.kompics.ComponentDefinition")) {
// createComponent(type);
// return true;
// } else if (isInSupertypes(binding, "se.sics.kompics.PortType")) {
// createPortType(type);
// return true;
// } else if (isInSupertypes(binding, "se.sics.kompics.Event")) {
// createEvent(type);
// return false;
// } else
if (isInSupertypes(binding, "se.sics.kompics.Handler")) {
createHandler(type, binding);
return false;
}
return true;
}
private void createChannel(MethodInvocation method) {
if (visitStack.isEmpty())
return; // need Component as top level element
// Activator.log("Trying to scan channel from method invocation: " +
// method);
ASTModelObject stackObject = visitStack.peek();
List<Expression> args = method.arguments();
if (args.size() < 2) {
Activator
.log("Method 'connect' called with less than two arguments. (Doesn't make much sense, does it?)");
return; // need at least two arguments to connect
}
Expression ex1 = args.get(0);
// Activator.log("Expression 1: " + ex1.toString() + " of type " +
// ASTNode.nodeClassForType(ex1.getNodeType()));
// Activator.log("Method Invocation Expression: " +
// mi1.getExpression().toString() + " of type " +
// ASTNode.nodeClassForType(mi1.getExpression().getNodeType()));
Expression ex2 = args.get(1);
ITypeBinding bind1 = ex1.resolveTypeBinding();
ITypeBinding bind2 = ex2.resolveTypeBinding();
// Activator.log("Bind 1: " + listSuperTypes(bind1));
// Activator.log("Bind 2: " + listSuperTypes(bind2));
ITypeBinding posBind = null, negBind = null;
Expression posEx = null, negEx = null;
if (isInSupertypes(bind1, "se.sics.kompics.Positive")) {
posBind = bind1;
posEx = ex1;
if (isInSupertypes(bind2, "se.sics.kompics.Positive"))
return; // Can't connect two positive ports
} else if (isInSupertypes(bind1, "se.sics.kompics.Negative")) {
negBind = bind1;
negEx = ex1;
if (isInSupertypes(bind2, "se.sics.kompics.Negative"))
return; // Can't connect two negative ports
}
if (isInSupertypes(bind2, "se.sics.kompics.Positive")) {
posBind = bind2;
posEx = ex2;
if (isInSupertypes(bind1, "se.sics.kompics.Positive"))
return; // Can't connect two positive ports
} else if (isInSupertypes(bind2, "se.sics.kompics.Negative")) {
negBind = bind2;
negEx = ex2;
if (isInSupertypes(bind1, "se.sics.kompics.Negative"))
return; // Can't connect two negative ports
}
if ((posBind == null) || (negBind == null)) {
Activator.log("Either " + bind1.getQualifiedName() + " or " + bind2.getQualifiedName()
+ " appears to be a non matching type for 'connect'.");
return; // One of the arguments has wrong type
}
ITypeBinding[] posTypes = posBind.getTypeArguments();
ITypeBinding[] negTypes = negBind.getTypeArguments();
if ((posTypes.length < 1) || (negTypes.length < 1)) {
Activator.log("Either " + posTypes + " or " + negTypes
+ " doesn't have enough type parameters (< 1).");
return; // One is missing type arguments
}
ITypeBinding posTypeBind = posTypes[0];
ITypeBinding negTypeBind = negTypes[0];
// if (!posTypeBind.isEqualTo(negTypeBind))
// return; // Can't connect two ports of different types
// Try to get ports out of the variables
ASTPort posPort = findPort(posEx, posTypeBind, ASTModelObject.PROVIDED_PORT);
ASTPort negPort = findPort(negEx, negTypeBind, ASTModelObject.REQUIRED_PORT);
if (posPort == null) {
if (!retryFlag) {
defer(method);
return;
}
Activator.log("Couldn't find port for expression: " + posEx);
return;
}
if (negPort == null) {
if (!retryFlag) {
defer(method);
return;
}
Activator.log("Couldn't find port for expression: " + negEx);
return;
}
Channel ch = factory.createChannel();
String chID = "Channel:(" + posPort.getId() + "," + negPort.getId() + ")";
ASTChannel astch = new ASTChannel(chID, ch, method);
astch = Model.add(astch);
ch.setPortType(posPort.getModel().getPortType());
ch.setProvided(posPort.getModel());
ch.setRequired(negPort.getModel());
astch.setBinding(method.resolveMethodBinding());
astch.setLocationBinding(findBinding(method.getParent()));
astch.addChild(posPort);
astch.addChild(negPort);
stackObject.addChild(astch);
astch.setParent(stackObject);
}
private void addSubscription(MethodInvocation method) {
if (!visitStack.isEmpty()) {
ASTModelObject stackObject = visitStack.peek();
List<Expression> args = method.arguments();
if (args.size() > 1) {
Expression handlerEx = args.get(0);
Expression portEx = args.get(1);
ITypeBinding handlerBind = handlerEx.resolveTypeBinding();
ITypeBinding portBind = portEx.resolveTypeBinding();
// Get Handler
ITypeBinding[] handlerTypes = handlerBind.getTypeArguments();
if (handlerTypes.length < 1)
return;
ITypeBinding handlerParamBind = handlerTypes[0];
String handlerVar = findVariableName(handlerEx, handlerBind);
if (handlerVar == null)
return; // Can't find the right handler without a variable
// name
ASTHandler asth = handlerVars.get(handlerVar);
if (asth == null) {
String error = "Could not find Handler for Event "
+ handlerParamBind.getQualifiedName();
error += "\n trying to defer...";
if (!defer(method)) {
error += "failed";
// TODO Add warning marker for missing handler
} else {
error += "done";
}
Activator.log(error);
return;
}
// Get Port
if (portEx.getNodeType() == ASTNode.METHOD_INVOCATION) {
MethodInvocation mi = (MethodInvocation) portEx;
if (mi.getName().getIdentifier().equals("control")) {
Expression miEx = mi.getExpression();
if (miEx.getNodeType() == ASTNode.SIMPLE_NAME) {
String miVar = ((SimpleName) miEx).getIdentifier();
ASTComponent comp = componentVars.get(miVar);
if (comp == null) {
Activator.log("Couldn't find component for variable " + miVar);
defer(method);
return;
}
ASTPort astp = comp.getControlPort();
Subscription s = factory.createSubscription();
String sID = "Subscription:(" + astp.getId() + "," + asth.getId() + ")";
ASTSubscription asts = new ASTSubscription(sID, s, method);
asts.setBinding(method.resolveMethodBinding());
asts.setLocationBinding(findBinding(method));
asts.setHandler(asth);
asts.setPort(astp);
asts.addToModel(asth.getModel(), ASTModelObject.NONE);
asts.addToModel(astp.getModel(), ASTModelObject.NONE);
astp.addChild(asts);
astp.addToModel(asts.getModel(), ASTModelObject.NONE);
asth.addToModel(asts.getModel(), ASTModelObject.NONE);
return;
} else {
return; // The component will be out of scope and hard to locate.
}
} else {
return; // The port will be out of scope and hard to locate.
}
}
ITypeBinding[] portTypes = portBind.getTypeArguments();
if (handlerTypes.length < 1)
return;
ITypeBinding portParamBind = portTypes[0];
String portVar = findVariableName(portEx, portBind);
if (portVar == null)
return; // Can't find the right port without a variable name
ASTPort astp = portVars.get(portVar);
if (astp == null) {
String error = "Could not find Port of Type "
+ portParamBind.getQualifiedName();
error += "\n trying to defer...";
if (!defer(method)) {
error += "failed";
// TODO Add warning marker for missing port
} else {
error += "done";
}
Activator.log(error);
return;
}
// add handler subscription to port
// Activator.log("Handler "
// + asth.getModel().getEventType().getType()
// + " subscribed to port "
// + astp.getModel().getPortType().getType()
// + " in Component "
// + astp.getParent().getBinding().getName());
Subscription s = factory.createSubscription();
String sID = "Subscription:(" + astp.getId() + "," + asth.getId() + ")";
ASTSubscription asts = new ASTSubscription(sID, s, method);
asts.setBinding(method.resolveMethodBinding());
asts.setLocationBinding(findBinding(method));
asts.setHandler(asth);
asts.setPort(astp);
asts.addToModel(asth.getModel(), ASTModelObject.NONE);
asts.addToModel(astp.getModel(), ASTModelObject.NONE);
astp.addChild(asts);
astp.addToModel(asts.getModel(), ASTModelObject.NONE);
asth.addToModel(asts.getModel(), ASTModelObject.NONE);
}
}
}
private void createEvent(TypeDeclaration type) {
ITypeBinding binding = type.resolveBinding();
ASTEvent aste = Model.getEvent(binding.getQualifiedName());
if (aste == null) {
Event e = factory.createEvent();
e.setType(binding.getQualifiedName());
aste = new ASTEvent("Event:" + binding.getQualifiedName(), e, type);
aste = Model.add(aste);
aste.setBinding(binding);
} else {
aste.setNode(type);
}
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
astmo.addChild(aste);
aste.setParent(astmo);
astmo.addToModel(aste.getModel(), ASTModelObject.NONE);
}
}
private void createHandler(ASTNode type, ITypeBinding binding) {
// Activator.log("Creating Handler");
ITypeBinding[] paramBind = binding.getSuperclass().getTypeArguments();
if (paramBind.length > 0) { // Should have exactly 1, but anyway
ITypeBinding eventBinding = paramBind[0];
ASTEvent aste = Model.getEvent(eventBinding.getQualifiedName());
if (aste == null) { // The compilation unit, where the Event
// is declared hasn't been scanned yet
Event e = factory.createEvent();
e.setType(eventBinding.getQualifiedName());
aste = new ASTEvent("Event:" + eventBinding.getQualifiedName(), e, null);
// can't add the ASTNode because we don't know the compilation
// unit
aste = Model.add(aste);
aste.setBinding(eventBinding);
} else {
if (aste.getBinding() == null) {
aste.setBinding(eventBinding);
}
}
Handler h = factory.createHandler();
h.setEventType(aste.getModel());
ASTHandler asth = null;
String hID = "";
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
hID = astmo.getId() + "/Handler:" + aste.getId();
asth = new ASTHandler(hID, h, type);
asth = Model.add(asth);
astmo.addChild(asth);
astmo.addToModel(h, ASTModelObject.NONE);
String varName = findVariableName(type, binding);
if (varName != null) {
handlerVars.put(varName, asth);
} else {
Activator.log("Couldn't find variable for handler of type "
+ eventBinding.getQualifiedName());
}
} else {
hID = binding.getQualifiedName() + "/Handler:" + aste.getId();
asth = new ASTHandler(hID, h, type);
asth = Model.add(asth);
}
asth.setBinding(binding);
}
}
private void createPort(MethodInvocation method, int envMod) {
if (visitStack.isEmpty())
return; // Can't add ports anywhere but in ComponentDefinitions
ASTModelObject astmo = visitStack.peek();
if (!(astmo instanceof ASTComponentDefinition))
return; // Can't add ports anywhere but in ComponentDefinitions
ASTComponentDefinition astcd = (ASTComponentDefinition) astmo;
List<Expression> args = method.arguments();
// String argStr = "";
// for (Expression e : args) {
// argStr += e.resolveTypeBinding().getQualifiedName() + " // ";
// }
// Activator.log("Method " + binding.getName() + " has type args: " +
// argStr);
if (!args.isEmpty()) {
Expression e = args.get(0);
ITypeBinding eBind = e.resolveTypeBinding();
ITypeBinding[] paramBind = eBind.getTypeArguments();
// Activator.log("Method " + binding.getName() +
// " has generic type arg: " + paramBind[0].getQualifiedName());
if (paramBind.length > 0) {
ITypeBinding portTypeBinding = paramBind[0];
ASTPortType apt = Model.getPort(portTypeBinding.getQualifiedName());
if (apt == null) { // The compilation unit, where the PortType
// is declared hasn't been scanned yet
PortType pt = factory.createPortType();
pt.setType(portTypeBinding.getQualifiedName());
apt = new ASTPortType("PortType:" + portTypeBinding.getQualifiedName(), pt,
null);
// can't add ASTNode because we don't know the compilation
// unit
apt = Model.add(apt);
apt.setBinding(portTypeBinding);
}
Port p = factory.createPort();
p.setPortType(apt.getModel());
String pID = astcd.getId() + "/Port:" + apt.getId() + ":"
+ method.getStartPosition();
ASTPort astp = new ASTPort(pID, p, method);
astp.setBinding(method.resolveMethodBinding()); // Might not be
// very helpful
ASTNode parent = method.getParent();
IBinding parentBind = findBinding(parent);
astp.setLocationBinding(parentBind); // may be null
astp = Model.add(astp);
switch (envMod) {
case ASTModelObject.PROVIDED_PORT:
p.setProvided(true);
astcd.addProvided(astp);
break;
case ASTModelObject.REQUIRED_PORT:
p.setProvided(false);
astcd.addRequired(astp);
}
astmo.addChild(astp);
astp.setParent(astmo);
String varName = findVariableName(method, method.resolveTypeBinding());
if (varName != null) {
portVars.put(varName, astp);
} else {
Activator.log("Couldn't find variable for port of type "
+ astp.getModel().getPortType().getType());
}
}
}
}
private void createEvent(MethodInvocation method, int envMod) {
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
List<Expression> args = method.arguments();
// String argStr = "";
// for (Expression e : args) {
// argStr += e.resolveTypeBinding().getQualifiedName() + " // ";
// }
// Activator.log("Method " + binding.getName() + " has type args: "
// +
// argStr);
if (!args.isEmpty()) {
Expression ex = args.get(0);
ITypeBinding eBind = ex.resolveTypeBinding();
ITypeBinding[] paramBind = eBind.getTypeArguments();
// Activator.log("Method " + binding.getName() +
// " has generic type arg: " + paramBind[0].getQualifiedName());
if (paramBind.length > 0) {
ITypeBinding eventBinding = paramBind[0];
ASTEvent aste = Model.getEvent(eventBinding.getQualifiedName());
if (aste == null) { // The compilation unit, where the Event
// is declared hasn't been scanned yet
Event e = factory.createEvent();
e.setType(eventBinding.getQualifiedName());
aste = new ASTEvent("Event:" + eventBinding.getQualifiedName(), e, null);
// can't add ASTNode because we don't know the
// compilation unit
aste = Model.add(aste);
aste.setBinding(eventBinding);
}
astmo.addChild(aste);
astmo.addToModel(aste.getModel(), envMod);
}
}
}
}
private void createPortType(TypeDeclaration type) {
ITypeBinding binding = type.resolveBinding();
PortType p = factory.createPortType();
p.setType(binding.getQualifiedName());
ASTPortType astp = new ASTPortType("PortType:" + binding.getQualifiedName(), p, type);
astp = Model.add(astp);
astp.setBinding(binding);
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
astmo.addChild(astp);
astp.setParent(astmo);
astmo.addToModel(p, ASTModelObject.NONE);
}
visitStack.push(astp);
}
private void createComponent(TypeDeclaration type) {
ITypeBinding binding = type.resolveBinding();
ComponentDefinition c = factory.createComponentDefinition();
c.setType(binding.getQualifiedName());
ASTComponentDefinition astc = new ASTComponentDefinition("ComponentDefinition:"
+ binding.getQualifiedName(), c, type);
astc = Model.add(astc);
astc.setBinding(binding);
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
astmo.addChild(astc);
astc.setParent(astmo);
astmo.addToModel(c, ASTModelObject.NONE);
}
visitStack.push(astc);
}
private void createComponentInstance(MethodInvocation method) {
List<Expression> args = method.arguments();
if (args.isEmpty())
return;
Expression classEx = args.get(0);
ITypeBinding classBind = classEx.resolveTypeBinding();
ITypeBinding[] paramBind = classBind.getTypeArguments();
if (paramBind.length < 1)
return;
ITypeBinding compBind = paramBind[0];
ASTComponentDefinition astcd = Model.getComponent(compBind.getQualifiedName());
if (astcd == null) {
String error = "Could not find a ComponentDefinition of type ";
error += compBind.getQualifiedName() + "\n";
error += " If it is in your path, then it most likely hasn't been scanned, yet.\n";
// error +=
// " This represents somewhat of a problem, though, since Component creation calls can't be deferred";
// error +=
// " until another compilation unit has been scanned. \n Thus I have no idea how to fix that problem ;(";
error += "Trying to defer...";
Activator.log(error);
builder.defer(root);
return;
}
String varName = findVariableName(method, method.resolveTypeBinding());
ASTComponent c = astcd.createInstance(varName, method);
c.setBinding(astcd.getBinding());
ASTNode parent = method.getParent();
IBinding parentBind = findBinding(parent);
c.setLocationBinding(parentBind);
if (!visitStack.isEmpty()) {
ASTModelObject astmo = visitStack.peek();
astmo.addChild(c);
if (astmo instanceof ASTComponentDefinition) {
ASTComponentDefinition astcdLoc = (ASTComponentDefinition) astmo;
astcdLoc.addSubInstance(c);
}
if (varName != null) {
componentVars.put(varName, c);
} else {
Activator.log("Couldn't find variable for component instance of type "
+ c.getModel().getType().getType());
}
}
}
//
// HELPERS
//
private boolean defer(MethodInvocation method) {
if (retryFlag)
return false;
deferredMethods.add(method);
return true;
}
private void retryDeferred() {
// Activator.log("Retrying deferred methods for " +
// visitStack.peek().getBinding().getName());
retryFlag = true;
for (MethodInvocation method : deferredMethods) {
IMethodBinding binding = method.resolveMethodBinding();
createModel(method, binding);
}
retryFlag = false;
}
private boolean isInSupertypes(ITypeBinding binding, String qualifiedName) {
if (binding == null)
return false;
String typeName = binding.getQualifiedName();
if (typeName.equalsIgnoreCase(qualifiedName) || typeName.startsWith(qualifiedName + "<")) {
return true;
} else if (typeName.equalsIgnoreCase("java.lang.Object")) {
return false;
} else {
return isInSupertypes(binding.getSuperclass(), qualifiedName);
}
}
private String listSuperTypes(ITypeBinding binding) {
if (binding == null)
return "";
if (binding.getQualifiedName().equalsIgnoreCase("java.lang.Object")) {
return "java.lang.Object";
} else {
return binding.getQualifiedName() + " extends "
+ listSuperTypes(binding.getSuperclass());
}
}
private IBinding findBinding(ASTNode node) {
if (node == null) {
return null;
}
switch (node.getNodeType()) {
case ASTNode.ANONYMOUS_CLASS_DECLARATION:
return ((AnonymousClassDeclaration) node).resolveBinding();
case ASTNode.METHOD_DECLARATION:
return ((MethodDeclaration) node).resolveBinding();
case ASTNode.TYPE_DECLARATION:
return ((TypeDeclaration) node).resolveBinding();
default:
ASTNode parent = node.getParent();
if (parent.equals(node)) {
return null;
} else {
return findBinding(parent);
}
}
}
private String findVariableName(ASTNode node, ITypeBinding type) {
// Activator.log("Scanning node of type " + node.getClass() +
// " for variable information.");
if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
return ((SimpleName) node).getIdentifier();
} else if (node.getNodeType() == ASTNode.QUALIFIED_NAME) {
return ((QualifiedName) node).getName().getIdentifier();
} else if (node.getNodeType() == ASTNode.ASSIGNMENT) {
return findVariableName((Assignment) node, type);
} else if (node.getNodeType() == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
VariableDeclarationFragment vdf = (VariableDeclarationFragment) node;
return findVariableName(vdf, type);
} else if (node.getNodeType() == ASTNode.TYPE_DECLARATION) {
ITypeBinding declBind = ((TypeDeclaration) node).resolveBinding();
if (declBind.isEqualTo(type)) {
return findVariableName(node.getParent(), type);
} else {
Activator.log("Reached top-level definition (" + declBind.getQualifiedName()
+ ") while searching for variable name.");
return null;
}
} else {
return findVariableName(node.getParent(), type);
}
}
private String findVariableName(VariableDeclarationFragment node, ITypeBinding type) {
ASTNode parent = node.getParent();
ITypeBinding varType = null;
if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
VariableDeclarationStatement vds = (VariableDeclarationStatement) parent;
varType = vds.getType().resolveBinding();
} else if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
VariableDeclarationExpression vde = (VariableDeclarationExpression) parent;
varType = vde.resolveTypeBinding();
}
SimpleName varName = node.getName();
if (varType == null)
return null;
if (isInSupertypes(type, varType.getQualifiedName())) {
return varName.getIdentifier();
} else {
Activator.log("Type " + varType.getQualifiedName() + " did not match "
+ type.getQualifiedName());
return null;
}
}
private String findVariableName(Assignment node, ITypeBinding type) {
Expression left = node.getLeftHandSide();
Expression right = node.getRightHandSide();
ITypeBinding rightBinding = right.resolveTypeBinding();
if (isInSupertypes(type, rightBinding.getQualifiedName())) {
if ((left.getNodeType() == ASTNode.SIMPLE_NAME)
|| (left.getNodeType() == ASTNode.SIMPLE_NAME)) {
return findVariableName(left, type);
} else {
Activator.log("Left Expression was " + left.toString());
return null;
}
} else {
Activator.log("Type " + rightBinding.getQualifiedName() + " did not match "
+ type.getQualifiedName());
return null;
}
}
private ASTPort findPort(Expression ex, ITypeBinding portType, int envMod) {
if (ex.getNodeType() == ASTNode.SIMPLE_NAME) {
String varName = ((SimpleName) ex).getIdentifier();
return portVars.get(varName);
} else if (ex.getNodeType() == ASTNode.METHOD_INVOCATION) {
MethodInvocation mi = (MethodInvocation) ex;
Expression miEx = mi.getExpression();
if (miEx.getNodeType() == ASTNode.SIMPLE_NAME) {
String varName = ((SimpleName) miEx).getIdentifier();
ASTComponent comp = componentVars.get(varName);
if (comp == null) {
Activator.log("Couldn't find Component for variable " + varName);
return null;
}
switch (envMod) {
case ASTModelObject.PROVIDED_PORT:
return comp.getProvided(portType.getQualifiedName());
case ASTModelObject.REQUIRED_PORT:
return comp.getRequired(portType.getQualifiedName());
default:
return null;
}
} else {
Activator.log("MethodInvocation Expression " + miEx + " is of type "
+ miEx.getClass());
}
}
Activator.log("Couldn't find a port for expression: " + ex + " of type " + ex.getClass());
return null;
}
// private String getTypeName(Type type) {
// String scName = "Unknown";
// if (type != null) {
// if (type.isSimpleType()) {
// SimpleType scSType = (SimpleType) type;
// scName = scSType.getName().getFullyQualifiedName();
// } else if (type.isQualifiedType()) {
// QualifiedType scQType = (QualifiedType) type;
// scName = scQType.getName().getFullyQualifiedName();
// }
// }
// return scName;
// }
}