/* This file is part of Green.
*
* Copyright (C) 2005 The Research Foundation of State University of New York
* All Rights Under Copyright Reserved, The Research Foundation of S.U.N.Y.
*
* Green is free software, licensed under the terms of the Eclipse
* Public License, version 1.0. The license is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package edu.buffalo.cse.green.relationships;
import static org.eclipse.jdt.core.IJavaElement.TYPE;
import static org.eclipse.jdt.core.IJavaElement.TYPE_PARAMETER;
import static org.eclipse.jdt.core.dom.ASTNode.BLOCK;
import static org.eclipse.jdt.core.dom.ASTNode.EXPRESSION_STATEMENT;
import static org.eclipse.jdt.core.dom.ASTNode.METHOD_INVOCATION;
import java.util.AbstractList;
import java.util.Collection;
import java.util.List;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.internal.core.TypeParameter;
import edu.buffalo.cse.green.GreenException;
import edu.buffalo.cse.green.editor.model.RelationshipKind;
/**
* Provides support for the recognition of relationships and the caching of
* added and removed relationships
*
* @author bcmartin
*/
public abstract class RelationshipRecognizer extends RelationshipVisitor {
/**
* @see edu.buffalo.cse.relationship.RelationshipCache
*/
private RelationshipCache _cache;
/**
* Runs the relationship recognizer on the given compilation unit; When the
* method completes, the relationship information in the cache will contain
* everything necessary to update the diagram.
*
* @param cu - The <code>CompilationUnit</code> to run the recognizer on.
* @param cache - The data structure containing information about the
* relationships contained in the editor.
*/
public final void run(CompilationUnit cu, RelationshipCache cache) {
_cache = cache;
// run the recognizer
try {
cu.accept(this);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
/**
* Handles the recognition of a relationship.
*
* @param sourceType - The <code>IType</code> containing the source code
* that triggered the relationship.
* @param targetType - The <code>IType</code> referenced by the source code
* in the source type.
* @param partClass - The <code>Class</code> representing the controller
* part of this relationship.
* @param features - The unique <code>ASTNode</code>s that identify this
* relationship .
*
* @author Gene Wang
*/
protected final void fireFoundRelationship(
IType sourceType,
ITypeBinding target,
Class partClass,
AbstractList<ASTNode> features) {
IType targetType = null;
if(target.getJavaElement() instanceof TypeParameter) {
//Type is parameterized type (such as <E>), true target type
//is the declaring element
//LOOKINTO TypeParameter is a JDT internal class, there may
//be a way of avoiding using this.
targetType = (IType) target.getDeclaringClass().getJavaElement();
}
else {
targetType = (IType) target.getJavaElement();
}
// ensure the relationship contains the necessary information
if ((sourceType == null) || (target == null)) {
GreenException.illegalOperation(
"Cannot add a relationship that has a missing source/"
+ "target type");
}
if (target.isParameterizedType()) {
for (ITypeBinding interfaceBinding : target.getInterfaces()) {
IType interfType = (IType) interfaceBinding.getJavaElement();
if (interfType.getFullyQualifiedName().equals(
Collection.class.getName())) {
IJavaElement element = (target.getTypeArguments()[0].getJavaElement());
if (element.getElementType() == TYPE) {
targetType = (IType) element;
} else if (element.getElementType() == TYPE_PARAMETER) {
targetType = (IType) target.getJavaElement();
}
}
}
}
_cache.add(sourceType, targetType, partClass,
new Relationship(features));
}
/**
* Processes calls to the add() method if they are called on a parameterized
* variable.
*
* @param features - The features of the relationship.
* @param variable - The name of the variable.
* @param node - The block node to search.
*/
protected void processAddInvocations(List<ASTNode> features,
Name variable, ASTNode node) {
if (!(variable instanceof SimpleName)) {
return;
}
Block block = null;
while (node != null) {
if (node.getNodeType() == BLOCK) {
block = (Block) node;
break;
}
node = node.getParent();
}
for (Statement stmt
: (AbstractList<Statement>) (List) block.statements()) {
if (stmt.getNodeType() == EXPRESSION_STATEMENT) {
ExpressionStatement eStmt = (ExpressionStatement) stmt;
Expression e = eStmt.getExpression();
if (e.getNodeType() == METHOD_INVOCATION) {
MethodInvocation m = (MethodInvocation) e;
if (m.getExpression() instanceof SimpleName) {
SimpleName name = (SimpleName) m.getExpression();
SimpleName var = (SimpleName) variable;
if (name.getIdentifier().equals(var.getIdentifier())) {
if (m.getName().getIdentifier().equals("add")) {
features.add(stmt);
}
}
}
}
}
}
}
/**
* @return The kind of relationship.
*/
public abstract RelationshipKind getFlags();
}