| 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); |
| } |
| } |