package annotations.el;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import annotations.util.coll.VivifyingMap;
/**
* Manages all annotations within expressions, that is, annotations on typecasts,
* instanceofs, and object creations.
* We can use this class for methods, field initializers, and static initializers.
*/
public class AExpression extends AElement {
/** The method's annotated typecasts; map key is the offset of the checkcast bytecode */
public final VivifyingMap<RelativeLocation, ATypeElement> typecasts =
ATypeElement.<RelativeLocation>newVivifyingLHMap_ATE();
/** The method's annotated "instanceof" tests; map key is the offset of the instanceof bytecode */
public final VivifyingMap<RelativeLocation, ATypeElement> instanceofs =
ATypeElement.<RelativeLocation>newVivifyingLHMap_ATE();
/** The method's annotated "new" invocations; map key is the offset of the new bytecode */
public final VivifyingMap<RelativeLocation, ATypeElement> news =
ATypeElement.<RelativeLocation>newVivifyingLHMap_ATE();
/** A method invocation's annotated type arguments; map key is the offset of the invokestatic bytecode */
public final VivifyingMap<RelativeLocation, ATypeElement> calls =
ATypeElement.<RelativeLocation>newVivifyingLHMap_ATE();
/** A member reference's annotated type parameters; map key is the offset of the invokestatic bytecode */
public final VivifyingMap<RelativeLocation, ATypeElement> refs =
ATypeElement.<RelativeLocation>newVivifyingLHMap_ATE();
/** The method's annotated lambda expressions; map key is the offset of the invokedynamic bytecode */
public final VivifyingMap<RelativeLocation, AMethod> funs =
new VivifyingMap<RelativeLocation, AMethod>(
new LinkedHashMap<RelativeLocation, AMethod>()) {
@Override
public AMethod createValueFor(RelativeLocation k) {
return new AMethod("" + k); // FIXME: find generated method name
}
@Override
public boolean subPrune(AMethod v) {
return v.prune();
}
};
protected Object id;
AExpression(Object id) {
super(id);
this.id = id;
}
AExpression(AExpression expr) {
super(expr);
copyMapContents(expr.typecasts, typecasts);
copyMapContents(expr.instanceofs, instanceofs);
copyMapContents(expr.news, news);
copyMapContents(expr.calls, calls);
copyMapContents(expr.refs, refs);
copyMapContents(expr.funs, funs);
id = expr.id;
}
@Override
public AExpression clone() {
return new AExpression(this);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(AElement o) {
return o instanceof AExpression &&
((AExpression) o).equalsExpression(this);
}
protected boolean equalsExpression(AExpression o) {
return super.equals(o)
&& typecasts.equals(o.typecasts)
&& instanceofs.equals(o.instanceofs)
&& news.equals(o.news)
&& refs.equals(o.refs)
&& calls.equals(o.calls)
&& funs.equals(o.funs);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return super.hashCode() + typecasts.hashCode()
+ instanceofs.hashCode() + news.hashCode()
+ refs.hashCode() + calls.hashCode() + funs.hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean prune() {
return super.prune() & typecasts.prune() & instanceofs.prune()
& news.prune() & refs.prune() & calls.prune() & funs.prune();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
SortedMap<RelativeLocation, ATypeElement> map =
new TreeMap<RelativeLocation, ATypeElement>();
RelativeLocation prev = null;
// sb.append("AExpression ");
// sb.append(id);
for (Map.Entry<RelativeLocation, ATypeElement> em : typecasts.entrySet()) {
sb.append("typecast: ");
RelativeLocation loc = em.getKey();
sb.append(loc);
sb.append(": ");
AElement ae = em.getValue();
sb.append(ae.toString());
sb.append(' ');
}
for (Map.Entry<RelativeLocation, ATypeElement> em : instanceofs.entrySet()) {
sb.append("instanceof: ");
RelativeLocation loc = em.getKey();
sb.append(loc);
sb.append(": ");
AElement ae = em.getValue();
sb.append(ae.toString());
sb.append(' ');
}
for (Map.Entry<RelativeLocation, ATypeElement> em : news.entrySet()) {
sb.append("new ");
RelativeLocation loc = em.getKey();
sb.append(loc);
sb.append(": ");
AElement ae = em.getValue();
sb.append(ae.toString());
sb.append(' ');
}
map.putAll(refs);
for (Entry<RelativeLocation, ATypeElement> em : map.entrySet()) {
RelativeLocation loc = em.getKey();
AElement ae = em.getValue();
boolean isOffset = loc.index < 0;
if (prev == null
|| (isOffset ? loc.offset == prev.offset
: loc.index == prev.index)) {
sb.append("reference ");
sb.append(isOffset ? "*" + loc.offset : "#" + loc.index);
sb.append(": ");
sb.append(ae.toString());
}
if (loc.type_index >= 0) {
sb.append("typearg " + loc);
sb.append(": ");
sb.append(ae.toString());
sb.append(' ');
}
prev = loc;
}
prev = null;
map.clear();
map.putAll(calls);
for (Entry<RelativeLocation, ATypeElement> em : map.entrySet()) {
RelativeLocation loc = em.getKey();
AElement ae = em.getValue();
boolean isOffset = loc.index < 0;
if (prev == null
|| (isOffset ? loc.offset == prev.offset
: loc.index == prev.index)) {
sb.append("call ");
sb.append(isOffset ? "*" + loc.offset : "#" + loc.index);
sb.append(": ");
}
if (loc.type_index >= 0) {
sb.append("typearg " + loc);
sb.append(": ");
sb.append(ae.toString());
sb.append(' ');
}
prev = loc;
}
prev = null;
map.clear();
for (Map.Entry<RelativeLocation, AMethod> em : funs.entrySet()) {
sb.append("lambda ");
RelativeLocation loc = em.getKey();
sb.append(loc);
sb.append(": ");
AElement ae = em.getValue();
sb.append(ae.toString());
sb.append(' ');
}
return sb.toString();
}
@Override
public <R, T> R accept(ElementVisitor<R, T> v, T t) {
return v.visitExpression(this, t);
}
}