/* *******************************************************************
 * Copyright (c) 2003,2010 Contributors.
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     Mik Kersten     initial implementation 
 *     Andy Clement, IBM, SpringSource    Extensions for better IDE representation
 * ******************************************************************/

package org.aspectj.asm.internal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.aspectj.asm.AsmManager;
import org.aspectj.asm.HierarchyWalker;
import org.aspectj.asm.IProgramElement;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;

Author:Mik Kersten, Andy Clement
/** * @author Mik Kersten * @author Andy Clement */
public class ProgramElement implements IProgramElement { public transient AsmManager asm; // which structure model is this node part of private static final long serialVersionUID = 171673495267384449L; public static boolean shortITDNames = true; private final static String UNDEFINED = "<undefined>"; private final static int AccPublic = 0x0001; private final static int AccPrivate = 0x0002; private final static int AccProtected = 0x0004; private final static int AccPrivileged = 0x0006; // XXX is this right? private final static int AccStatic = 0x0008; private final static int AccFinal = 0x0010; private final static int AccSynchronized = 0x0020; private final static int AccVolatile = 0x0040; private final static int AccTransient = 0x0080; private final static int AccNative = 0x0100; // private final static int AccInterface = 0x0200; private final static int AccAbstract = 0x0400; // private final static int AccStrictfp = 0x0800; protected String name; private Kind kind; protected IProgramElement parent = null; protected List<IProgramElement> children = Collections.emptyList(); public Map<String, Object> kvpairs = Collections.emptyMap(); protected ISourceLocation sourceLocation = null; public int modifiers; private String handle = null; public AsmManager getModel() { return asm; }
Used during deserialization
/** Used during deserialization */
public ProgramElement() { }
Use to create program element nodes that do not correspond to source locations
/** Use to create program element nodes that do not correspond to source locations */
public ProgramElement(AsmManager asm, String name, Kind kind, List<IProgramElement> children) { this.asm = asm; if (asm == null && !name.equals("<build to view structure>")) { throw new RuntimeException(); } this.name = name; this.kind = kind; if (children != null) { setChildren(children); } } public ProgramElement(AsmManager asm, String name, IProgramElement.Kind kind, ISourceLocation sourceLocation, int modifiers, String comment, List<IProgramElement> children) { this(asm, name, kind, children); this.sourceLocation = sourceLocation; setFormalComment(comment); // if (comment!=null && comment.length()>0) formalComment = comment; this.modifiers = modifiers; } public int getRawModifiers() { return this.modifiers; } public List<IProgramElement.Modifiers> getModifiers() { return genModifiers(this.modifiers); } public Accessibility getAccessibility() { return genAccessibility(this.modifiers); } public void setDeclaringType(String t) { if (t != null && t.length() > 0) { fixMap(); kvpairs.put("declaringType", t); } } public String getDeclaringType() { String dt = (String) kvpairs.get("declaringType"); if (dt == null) { return ""; // assumption that not having one means "" is at HtmlDecorator line 111 } return dt; } public String getPackageName() { if (kind == Kind.PACKAGE) { return getName(); } if (getParent() == null) { return ""; } return getParent().getPackageName(); } public Kind getKind() { return kind; } public boolean isCode() { return kind.equals(Kind.CODE); } public ISourceLocation getSourceLocation() { return sourceLocation; } // not really sure why we have this setter ... how can we be in the situation where we didn't // know the location when we built the node but we learned it later on? public void setSourceLocation(ISourceLocation sourceLocation) { // this.sourceLocation = sourceLocation; } public IMessage getMessage() { return (IMessage) kvpairs.get("message"); // return message; } public void setMessage(IMessage message) { fixMap(); kvpairs.put("message", message); // this.message = message; } public IProgramElement getParent() { return parent; } public void setParent(IProgramElement parent) { this.parent = parent; } public boolean isMemberKind() { return kind.isMember(); } public void setRunnable(boolean value) { fixMap(); if (value) { kvpairs.put("isRunnable", "true"); } else { kvpairs.remove("isRunnable"); // this.runnable = value; } } public boolean isRunnable() { return kvpairs.get("isRunnable") != null; // return runnable; } public boolean isImplementor() { return kvpairs.get("isImplementor") != null; // return implementor; } public void setImplementor(boolean value) { fixMap(); if (value) { kvpairs.put("isImplementor", "true"); } else { kvpairs.remove("isImplementor"); // this.implementor = value; } } public boolean isOverrider() { return kvpairs.get("isOverrider") != null; // return overrider; } public void setOverrider(boolean value) { fixMap(); if (value) { kvpairs.put("isOverrider", "true"); } else { kvpairs.remove("isOverrider"); // this.overrider = value; } } public String getFormalComment() { return (String) kvpairs.get("formalComment"); // return formalComment; } public String toString() { return toLabelString(); } private static List<IProgramElement.Modifiers> genModifiers(int modifiers) { List<IProgramElement.Modifiers> modifiersList = new ArrayList<IProgramElement.Modifiers>(); if ((modifiers & AccStatic) != 0) { modifiersList.add(IProgramElement.Modifiers.STATIC); } if ((modifiers & AccFinal) != 0) { modifiersList.add(IProgramElement.Modifiers.FINAL); } if ((modifiers & AccSynchronized) != 0) { modifiersList.add(IProgramElement.Modifiers.SYNCHRONIZED); } if ((modifiers & AccVolatile) != 0) { modifiersList.add(IProgramElement.Modifiers.VOLATILE); } if ((modifiers & AccTransient) != 0) { modifiersList.add(IProgramElement.Modifiers.TRANSIENT); } if ((modifiers & AccNative) != 0) { modifiersList.add(IProgramElement.Modifiers.NATIVE); } if ((modifiers & AccAbstract) != 0) { modifiersList.add(IProgramElement.Modifiers.ABSTRACT); } return modifiersList; } public static IProgramElement.Accessibility genAccessibility(int modifiers) { if ((modifiers & AccPublic) != 0) { return IProgramElement.Accessibility.PUBLIC; } if ((modifiers & AccPrivate) != 0) { return IProgramElement.Accessibility.PRIVATE; } if ((modifiers & AccProtected) != 0) { return IProgramElement.Accessibility.PROTECTED; } if ((modifiers & AccPrivileged) != 0) { return IProgramElement.Accessibility.PRIVILEGED; } else { return IProgramElement.Accessibility.PACKAGE; } } public String getBytecodeName() { String s = (String) kvpairs.get("bytecodeName"); if (s == null) { return UNDEFINED; } return s; } public void setBytecodeName(String s) { fixMap(); kvpairs.put("bytecodeName", s); } public void setBytecodeSignature(String s) { fixMap(); // Different kinds of format here. The one worth compressing starts with a '(': // (La/b/c/D;Le/f/g/G;)Ljava/lang/String; // maybe want to avoid generics initially. // boolean worthCompressing = s.charAt(0) == '(' && s.indexOf('<') == -1 && s.indexOf('P') == -1; // starts parentheses and // no // // generics // if (worthCompressing) { // kvpairs.put("bytecodeSignatureCompressed", asm.compress(s)); // } else { kvpairs.put("bytecodeSignature", s); // } } public String getBytecodeSignature() { String s = (String) kvpairs.get("bytecodeSignature"); // if (s == null) { // List compressed = (List) kvpairs.get("bytecodeSignatureCompressed"); // if (compressed != null) { // return asm.decompress(compressed, '/'); // } // } // if (s==null) return UNDEFINED; return s; } public String getSourceSignature() { return (String) kvpairs.get("sourceSignature"); } public void setSourceSignature(String string) { fixMap(); // System.err.println(name+" SourceSig=>"+string); kvpairs.put("sourceSignature", string); // sourceSignature = string; } public void setKind(Kind kind) { this.kind = kind; } public void setCorrespondingType(String s) { fixMap(); kvpairs.put("returnType", s); // this.returnType = s; } public void setParentTypes(List<String> ps) { fixMap(); kvpairs.put("parentTypes", ps); } @SuppressWarnings("unchecked") public List<String> getParentTypes() { return (List<String>) (kvpairs == null ? null : kvpairs.get("parentTypes")); }
{@inheritDoc}
/** * {@inheritDoc} */
public void setAnnotationType(String fullyQualifiedAnnotationType) { fixMap(); kvpairs.put("annotationType", fullyQualifiedAnnotationType); } public void setAnnotationRemover(boolean isRemover) { fixMap(); kvpairs.put("annotationRemover", isRemover); } public String getAnnotationType() { if (isAnnotationRemover()) { return null; } return (String) (kvpairs == null ? null : kvpairs.get("annotationType")); } public boolean isAnnotationRemover() { if (kvpairs == null) { return false; } Boolean b = (Boolean) kvpairs.get("annotationRemover"); if (b == null) { return false; } return b.booleanValue(); } public String[] getRemovedAnnotationTypes() { if (!isAnnotationRemover()) { return null; } String annotype = (String) (kvpairs == null ? null : kvpairs.get("annotationType")); if (annotype == null) { return null; } else { return new String[] { annotype }; } } public String getCorrespondingType() { return getCorrespondingType(false); } public String getCorrespondingTypeSignature() { String typename = (String) kvpairs.get("returnType"); if (typename == null) { return null; } return nameToSignature(typename); } public static String nameToSignature(String name) { int len = name.length(); if (len < 8) { if (name.equals("byte")) { return "B"; } if (name.equals("char")) { return "C"; } if (name.equals("double")) { return "D"; } if (name.equals("float")) { return "F"; } if (name.equals("int")) { return "I"; } if (name.equals("long")) { return "J"; } if (name.equals("short")) { return "S"; } if (name.equals("boolean")) { return "Z"; } if (name.equals("void")) { return "V"; } if (name.equals("?")) { return name; } } if (name.endsWith("[]")) { return "[" + nameToSignature(name.substring(0, name.length() - 2)); } if (len != 0) { // check if someone is calling us with something that is a signature already assert name.charAt(0) != '['; if (name.indexOf("<") == -1) { // not parameterized return new StringBuilder("L").append(name.replace('.', '/')).append(';').toString(); } else { StringBuffer nameBuff = new StringBuffer(); int nestLevel = 0; nameBuff.append("L"); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); switch (c) { case '.': nameBuff.append('/'); break; case '<': nameBuff.append("<"); nestLevel++; StringBuffer innerBuff = new StringBuffer(); while (nestLevel > 0) { c = name.charAt(++i); if (c == '<') { nestLevel++; } if (c == '>') { nestLevel--; } if (c == ',' && nestLevel == 1) { nameBuff.append(nameToSignature(innerBuff.toString())); innerBuff = new StringBuffer(); } else { if (nestLevel > 0) { innerBuff.append(c); } } } nameBuff.append(nameToSignature(innerBuff.toString())); nameBuff.append('>'); break; case '>': throw new IllegalStateException("Should by matched by <"); case ',': throw new IllegalStateException("Should only happen inside <...>"); default: nameBuff.append(c); } } nameBuff.append(";"); return nameBuff.toString(); } } else { throw new IllegalArgumentException("Bad type name: " + name); } } public String getCorrespondingType(boolean getFullyQualifiedType) { String returnType = (String) kvpairs.get("returnType"); if (returnType == null) { returnType = ""; } if (getFullyQualifiedType) { return returnType; } return trim(returnType); }
Trim down fully qualified types to their short form (e.g. a.b.c.D becomes D)
/** * Trim down fully qualified types to their short form (e.g. a.b.c.D<e.f.G> becomes D<G>) */
public static String trim(String fqname) { int i = fqname.indexOf("<"); if (i == -1) { int lastdot = fqname.lastIndexOf('.'); if (lastdot == -1) { return fqname; } else { return fqname.substring(lastdot + 1); } } char[] charArray = fqname.toCharArray(); StringBuilder candidate = new StringBuilder(charArray.length); StringBuilder complete = new StringBuilder(charArray.length); for (char c : charArray) { switch (c) { case '.': candidate.setLength(0); break; case '<': case ',': case '>': complete.append(candidate).append(c); candidate.setLength(0); break; default: candidate.append(c); } } complete.append(candidate); return complete.toString(); } public String getName() { return name; } public List<IProgramElement> getChildren() { return children; } public void setChildren(List<IProgramElement> children) { this.children = children; if (children == null) { return; } for (Iterator<IProgramElement> it = children.iterator(); it.hasNext();) { (it.next()).setParent(this); } } public void addChild(IProgramElement child) { if (children == null || children == Collections.EMPTY_LIST) { children = new ArrayList<IProgramElement>(); } children.add(child); child.setParent(this); } public void addChild(int position, IProgramElement child) { if (children == null || children == Collections.EMPTY_LIST) { children = new ArrayList<IProgramElement>(); } children.add(position, child); child.setParent(this); } public boolean removeChild(IProgramElement child) { child.setParent(null); return children.remove(child); } public void setName(String string) { name = string; } public IProgramElement walk(HierarchyWalker walker) { if (children != null) { for (IProgramElement child : children) { walker.process(child); } } return this; } public String toLongString() { final StringBuffer buffer = new StringBuffer(); HierarchyWalker walker = new HierarchyWalker() { private int depth = 0; public void preProcess(IProgramElement node) { for (int i = 0; i < depth; i++) { buffer.append(' '); } buffer.append(node.toString()); buffer.append('\n'); depth += 2; } public void postProcess(IProgramElement node) { depth -= 2; } }; walker.process(this); return buffer.toString(); } public void setModifiers(int i) { this.modifiers = i; }
Convenience mechanism for setting new modifiers which do not require knowledge of the private internal representation
Params:
  • newModifier –
/** * Convenience mechanism for setting new modifiers which do not require knowledge of the private internal representation * * @param newModifier */
public void addModifiers(IProgramElement.Modifiers newModifier) { modifiers |= newModifier.getBit(); } public String toSignatureString() { return toSignatureString(true); } public String toSignatureString(boolean getFullyQualifiedArgTypes) { StringBuffer sb = new StringBuffer(); sb.append(name); List<char[]> ptypes = getParameterTypes(); if (ptypes != null && (!ptypes.isEmpty() || this.kind.equals(IProgramElement.Kind.METHOD)) || this.kind.equals(IProgramElement.Kind.CONSTRUCTOR) || this.kind.equals(IProgramElement.Kind.ADVICE) || this.kind.equals(IProgramElement.Kind.POINTCUT) || this.kind.equals(IProgramElement.Kind.INTER_TYPE_METHOD) || this.kind.equals(IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR)) { sb.append('('); for (Iterator<char[]> it = ptypes.iterator(); it.hasNext();) { char[] arg = it.next(); if (getFullyQualifiedArgTypes) { sb.append(arg); } else { int index = CharOperation.lastIndexOf('.', arg); if (index != -1) { sb.append(CharOperation.subarray(arg, index + 1, arg.length)); } else { sb.append(arg); } } if (it.hasNext()) { sb.append(","); } } sb.append(')'); } return sb.toString(); }
TODO: move the "parent != null"==>injar heuristic to more explicit
/** * TODO: move the "parent != null"==>injar heuristic to more explicit */
public String toLinkLabelString() { return toLinkLabelString(true); } public String toLinkLabelString(boolean getFullyQualifiedArgTypes) { String label; if (kind == Kind.CODE || kind == Kind.INITIALIZER) { label = parent.getParent().getName() + ": "; } else if (kind.isInterTypeMember()) { if (shortITDNames) { // if (name.indexOf('.')!=-1) return toLabelString().substring(name.indexOf('.')+1); label = ""; } else { int dotIndex = name.indexOf('.'); if (dotIndex != -1) { return parent.getName() + ": " + toLabelString().substring(dotIndex + 1); } else { label = parent.getName() + '.'; } } } else if (kind == Kind.CLASS || kind == Kind.ASPECT || kind == Kind.INTERFACE) { label = ""; } else if (kind.equals(Kind.DECLARE_PARENTS)) { label = ""; } else { if (parent != null) { label = parent.getName() + '.'; } else { label = "injar aspect: "; } } label += toLabelString(getFullyQualifiedArgTypes); return label; } public String toLabelString() { return toLabelString(true); } public String toLabelString(boolean getFullyQualifiedArgTypes) { String label = toSignatureString(getFullyQualifiedArgTypes); String details = getDetails(); if (details != null) { label += ": " + details; } return label; } public String getHandleIdentifier() { return getHandleIdentifier(true); } public String getHandleIdentifier(boolean create) { String h = handle; if (null == handle && create) { if (asm == null && name.equals("<build to view structure>")) { h = "<build to view structure>"; } else { try { h = asm.getHandleProvider().createHandleIdentifier(this); } catch (ArrayIndexOutOfBoundsException aioobe) { throw new RuntimeException("AIOOBE whilst building handle for " + this, aioobe); } } } setHandleIdentifier(h); return h; } public void setHandleIdentifier(String handle) { this.handle = handle; } @SuppressWarnings("unchecked") public List<String> getParameterNames() { List<String> parameterNames = (List<String>) kvpairs.get("parameterNames"); return parameterNames; } public void setParameterNames(List<String> list) { if (list == null || list.size() == 0) { return; } fixMap(); kvpairs.put("parameterNames", list); // parameterNames = list; } public List<char[]> getParameterTypes() { List<char[]> l = getParameterSignatures(); if (l == null || l.isEmpty()) { return Collections.emptyList(); } List<char[]> params = new ArrayList<char[]>(); for (Iterator<char[]> iter = l.iterator(); iter.hasNext();) { char[] param = iter.next(); params.add(NameConvertor.convertFromSignature(param)); } return params; } @SuppressWarnings("unchecked") public List<char[]> getParameterSignatures() { List<char[]> parameters = (List<char[]>) kvpairs.get("parameterSigs"); return parameters; } @SuppressWarnings("unchecked") public List<String> getParameterSignaturesSourceRefs() { List<String> parameters = (List<String>) kvpairs.get("parameterSigsSourceRefs"); return parameters; }
Set the parameter signatures for this method/constructor. The bit flags tell us if any were not singletypereferences in the the source. A singletypereference would be 'String' - whilst a qualifiedtypereference would be 'java.lang.String' - this has an effect on the handles.
/** * Set the parameter signatures for this method/constructor. The bit flags tell us if any were not singletypereferences in the * the source. A singletypereference would be 'String' - whilst a qualifiedtypereference would be 'java.lang.String' - this has * an effect on the handles. */
public void setParameterSignatures(List<char[]> list, List<String> sourceRefs) { fixMap(); if (list == null || list.size() == 0) { kvpairs.put("parameterSigs", Collections.EMPTY_LIST); } else { kvpairs.put("parameterSigs", list); } if (sourceRefs != null && sourceRefs.size() != 0) { kvpairs.put("parameterSigsSourceRefs", sourceRefs); } } public String getDetails() { String details = (String) kvpairs.get("details"); return details; } public void setDetails(String string) { fixMap(); kvpairs.put("details", string); } public void setFormalComment(String txt) { if (txt != null && txt.length() > 0) { fixMap(); kvpairs.put("formalComment", txt); } } private void fixMap() { if (kvpairs == Collections.EMPTY_MAP) { kvpairs = new HashMap<String, Object>(); } } public void setExtraInfo(ExtraInformation info) { fixMap(); kvpairs.put("ExtraInformation", info); } public ExtraInformation getExtraInfo() { return (ExtraInformation) kvpairs.get("ExtraInformation"); } public boolean isAnnotationStyleDeclaration() { return kvpairs.get("annotationStyleDeclaration") != null; } public void setAnnotationStyleDeclaration(boolean b) { if (b) { fixMap(); kvpairs.put("annotationStyleDeclaration", "true"); } } @SuppressWarnings("unchecked") public Map<String, List<String>> getDeclareParentsMap() { Map<String, List<String>> s = (Map<String, List<String>>) kvpairs.get("declareparentsmap"); return s; } public void setDeclareParentsMap(Map<String, List<String>> newmap) { fixMap(); kvpairs.put("declareparentsmap", newmap); } public void addFullyQualifiedName(String fqname) { fixMap(); kvpairs.put("itdfqname", fqname); } public String getFullyQualifiedName() { return (String) kvpairs.get("itdfqname"); } }