Logo Search packages:      
Sourcecode: aspectj version File versions

LazyClassGen.java

/* *******************************************************************
 * Copyright (c) 2002 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: 
 *     PARC                 initial implementation 
 *     Andy Clement  6Jul05 generics - signature attribute
 * ******************************************************************/

package org.aspectj.weaver.bcel;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.Attribute;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.Field;
import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.Signature;
import org.aspectj.apache.bcel.classfile.Synthetic;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.generic.BasicType;
import org.aspectj.apache.bcel.generic.ClassGen;
import org.aspectj.apache.bcel.generic.FieldGen;
import org.aspectj.apache.bcel.generic.InstructionConstants;
import org.aspectj.apache.bcel.generic.InstructionFactory;
import org.aspectj.apache.bcel.generic.InstructionHandle;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.ObjectType;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.SignatureUtils;
import org.aspectj.weaver.TypeVariable;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.World;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.UnresolvedType.TypeKind;
import org.aspectj.weaver.bcel.asm.AsmDetector;
import org.aspectj.weaver.bcel.asm.StackMapAdder;

/**
 * Lazy lazy lazy. We don't unpack the underlying class unless necessary. Things like new methods and annotations accumulate in here
 * until they must be written out, don't add them to the underlying MethodGen! Things are slightly different if this represents an
 * Aspect.
 */
00076 public final class LazyClassGen {

      private static final int ACC_SYNTHETIC = 0x1000;

      private static final String[] NO_STRINGS = new String[0];

      int highestLineNumber = 0; // ---- JSR 45 info

      private final SortedMap /* <String, InlinedSourceFileInfo> */inlinedFiles = new TreeMap();

      private boolean regenerateGenericSignatureAttribute = false;

      private BcelObjectType myType; // XXX is not set for types we create
      private ClassGen myGen;
      private final ConstantPool cp;
      private final World world;
      private final String packageName = null;

      private final List /* BcelField */fields = new ArrayList();
      private final List /* LazyMethodGen */methodGens = new ArrayList();
      private final List /* LazyClassGen */classGens = new ArrayList();
      private final List /* AnnotationGen */annotations = new ArrayList();
      private int childCounter = 0;

      private final InstructionFactory fact;

      private boolean isSerializable = false;
      private boolean hasSerialVersionUIDField = false;
      private boolean serialVersionUIDRequiresInitialization = false;
      private long calculatedSerialVersionUID;
      private boolean hasClinit = false;

      private ResolvedType[] extraSuperInterfaces = null;
      private ResolvedType superclass = null;

      // ---

      static class InlinedSourceFileInfo {
            int highestLineNumber;
            int offset; // calculated

            InlinedSourceFileInfo(int highestLineNumber) {
                  this.highestLineNumber = highestLineNumber;
            }
      }

      void addInlinedSourceFileInfo(String fullpath, int highestLineNumber) {
            Object o = inlinedFiles.get(fullpath);
            if (o != null) {
                  InlinedSourceFileInfo info = (InlinedSourceFileInfo) o;
                  if (info.highestLineNumber < highestLineNumber) {
                        info.highestLineNumber = highestLineNumber;
                  }
            } else {
                  inlinedFiles.put(fullpath, new InlinedSourceFileInfo(highestLineNumber));
            }
      }

      void calculateSourceDebugExtensionOffsets() {
            int i = roundUpToHundreds(highestLineNumber);
            for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
                  InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
                  element.offset = i;
                  i = roundUpToHundreds(i + element.highestLineNumber);
            }
      }

      private static int roundUpToHundreds(int i) {
            return ((i / 100) + 1) * 100;
      }

      int getSourceDebugExtensionOffset(String fullpath) {
            return ((InlinedSourceFileInfo) inlinedFiles.get(fullpath)).offset;
      }

      // private Unknown getSourceDebugExtensionAttribute() {
      // int nameIndex = cp.addUtf8("SourceDebugExtension");
      // String data = getSourceDebugExtensionString();
      // //System.err.println(data);
      // byte[] bytes = Utility.stringToUTF(data);
      // int length = bytes.length;
      //
      // return new Unknown(nameIndex, length, bytes, cp);
      // }

      // private LazyClassGen() {}
      // public static void main(String[] args) {
      // LazyClassGen m = new LazyClassGen();
      // m.highestLineNumber = 37;
      // m.inlinedFiles.put("boo/baz/foo.java", new InlinedSourceFileInfo( 83));
      // m.inlinedFiles.put("boo/barz/foo.java", new InlinedSourceFileInfo(292));
      // m.inlinedFiles.put("boo/baz/moo.java", new InlinedSourceFileInfo(128));
      // m.calculateSourceDebugExtensionOffsets();
      // System.err.println(m.getSourceDebugExtensionString());
      // }

      // For the entire pathname, we're using package names. This is probably
      // wrong.
      // private String getSourceDebugExtensionString() {
      // StringBuffer out = new StringBuffer();
      // String myFileName = getFileName();
      // // header section
      // out.append("SMAP\n");
      // out.append(myFileName);
      // out.append("\nAspectJ\n");
      // // stratum section
      // out.append("*S AspectJ\n");
      // // file section
      // out.append("*F\n");
      // out.append("1 ");
      // out.append(myFileName);
      // out.append("\n");
      // int i = 2;
      // for (Iterator iter = inlinedFiles.keySet().iterator(); iter.hasNext();) {
      // String element = (String) iter.next();
      // int ii = element.lastIndexOf('/');
      // if (ii == -1) {
      // out.append(i++); out.append(' ');
      // out.append(element); out.append('\n');
      // } else {
      // out.append("+ "); out.append(i++); out.append(' ');
      // out.append(element.substring(ii+1)); out.append('\n');
      // out.append(element); out.append('\n');
      // }
      // }
      // // emit line section
      // out.append("*L\n");
      // out.append("1#1,");
      // out.append(highestLineNumber);
      // out.append(":1,1\n");
      // i = 2;
      // for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) {
      // InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next();
      // out.append("1#");
      // out.append(i++); out.append(',');
      // out.append(element.highestLineNumber); out.append(":");
      // out.append(element.offset + 1); out.append(",1\n");
      // }
      // // end section
      // out.append("*E\n");
      // // and finish up...
      // return out.toString();
      // }

      // ---- end JSR45-related stuff

      /** Emit disassembled class and newline to out */
00223       public static void disassemble(String path, String name, PrintStream out) throws IOException {
            if (null == out) {
                  return;
            }
            // out.println("classPath: " + classPath);

            BcelWorld world = new BcelWorld(path);

            UnresolvedType ut = UnresolvedType.forName(name);
            ut.setNeedsModifiableDelegate(true);
            LazyClassGen clazz = new LazyClassGen(BcelWorld.getBcelObjectType(world.resolve(ut)));
            clazz.print(out);
            out.println();
      }

      public String getNewGeneratedNameTag() {
            return new Integer(childCounter++).toString();
      }

      // ----

      public LazyClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces,
                  World world) {
            myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces);
            cp = myGen.getConstantPool();
            fact = new InstructionFactory(myGen, cp);
            regenerateGenericSignatureAttribute = true;
            this.world = world;
      }

      // Non child type, so it comes from a real type in the world.
      public LazyClassGen(BcelObjectType myType) {
            myGen = new ClassGen(myType.getJavaClass());
            cp = myGen.getConstantPool();
            fact = new InstructionFactory(myGen, cp);
            this.myType = myType;
            world = myType.getResolvedTypeX().getWorld();

            /* Does this class support serialization */
            if (implementsSerializable(getType())) {
                  isSerializable = true;

                  // ResolvedMember[] fields = getType().getDeclaredFields();
                  // for (int i = 0; i < fields.length; i++) {
                  // ResolvedMember field = fields[i];
                  // if (field.getName().equals("serialVersionUID")
                  // && field.isStatic() && field.getType().equals(ResolvedType.LONG))
                  // {
                  // hasSerialVersionUIDField = true;
                  // }
                  // }
                  hasSerialVersionUIDField = hasSerialVersionUIDField(getType());

                  ResolvedMember[] methods = getType().getDeclaredMethods();
                  for (int i = 0; i < methods.length; i++) {
                        ResolvedMember method = methods[i];
                        if (method.getName().equals("<clinit>")) {
                              if (method.getKind() != Member.STATIC_INITIALIZATION) {
                                    throw new RuntimeException("qui?");
                              }
                              hasClinit = true;
                        }
                  }

                  // Do we need to calculate an SUID and add it?
                  if (!hasSerialVersionUIDField && world.isAddSerialVerUID()) {
                        calculatedSerialVersionUID = myGen.getSUID();
                        FieldGen fg = new FieldGen(Constants.ACC_PRIVATE | Constants.ACC_FINAL | Constants.ACC_STATIC, BasicType.LONG,
                                    "serialVersionUID", getConstantPool());
                        addField(fg);
                        hasSerialVersionUIDField = true;
                        serialVersionUIDRequiresInitialization = true;
                        // warn about what we've done?
                        if (world.getLint().calculatingSerialVersionUID.isEnabled())
                              world.getLint().calculatingSerialVersionUID.signal(new String[] { getClassName(),
                                          Long.toString(calculatedSerialVersionUID) + "L" }, null, null);
                  }
            }

            ResolvedMember[] methods = myType.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++) {
                  addMethodGen(new LazyMethodGen((BcelMethod) methods[i], this));
            }

            // Method[] methods = myGen.getMethods();
            // for (int i = 0; i < methods.length; i++) {
            // addMethodGen(new LazyMethodGen(methods[i], this));
            // }

            ResolvedMember[] fields = myType.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                  this.fields.add(fields[i]);
            }
      }

      public static boolean hasSerialVersionUIDField(ResolvedType type) {

            ResolvedMember[] fields = type.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                  ResolvedMember field = fields[i];
                  if (field.getName().equals("serialVersionUID") && field.isStatic() && field.getType().equals(ResolvedType.LONG)) {
                        return true;
                  }
            }

            return false;
      }

      // public void addAttribute(Attribute i) {
      // myGen.addAttribute(i);
      // }

      // ----

      public String getInternalClassName() {
            return getConstantPool().getConstantString_CONSTANTClass(myGen.getClassNameIndex());
            // getConstantPool().getConstantString(
            // myGen.getClassNameIndex(),
            // Constants.CONSTANT_Class);

      }

      public String getInternalFileName() {
            String str = getInternalClassName();
            int index = str.lastIndexOf('/');
            if (index == -1) {
                  return getFileName();
            } else {
                  return str.substring(0, index + 1) + getFileName();
            }
      }

      /**
       * Returns the packagename - if its the default package we return an empty string
       */
00358       public String getPackageName() {
            if (packageName != null)
                  return packageName;
            String str = getInternalClassName();
            int index = str.indexOf("<");
            if (index != -1)
                  str = str.substring(0, index); // strip off the generics guff
            index = str.lastIndexOf("/");
            if (index == -1)
                  return "";
            return str.substring(0, index).replace('/', '.');
      }

      public void addMethodGen(LazyMethodGen gen) {
            // assert gen.getClassName() == super.getClassName();
            methodGens.add(gen);
            if (highestLineNumber < gen.highestLineNumber)
                  highestLineNumber = gen.highestLineNumber;
      }

      public boolean removeMethodGen(LazyMethodGen gen) {
            return methodGens.remove(gen);
      }

      public void addMethodGen(LazyMethodGen gen, ISourceLocation sourceLocation) {
            addMethodGen(gen);
            if (!gen.getMethod().isPrivate()) {
                  warnOnAddedMethod(gen.getMethod(), sourceLocation);
            }
      }

      public void errorOnAddedField(FieldGen field, ISourceLocation sourceLocation) {
            if (isSerializable && !hasSerialVersionUIDField) {
                  getWorld().getLint().serialVersionUIDBroken.signal(
                              new String[] { myType.getResolvedTypeX().getName(), field.getName() }, sourceLocation, null);
            }
      }

      public void warnOnAddedInterface(String name, ISourceLocation sourceLocation) {
            warnOnModifiedSerialVersionUID(sourceLocation, "added interface " + name);
      }

      public void warnOnAddedMethod(Method method, ISourceLocation sourceLocation) {
            warnOnModifiedSerialVersionUID(sourceLocation, "added non-private method " + method.getName());
      }

      public void warnOnAddedStaticInitializer(Shadow shadow, ISourceLocation sourceLocation) {
            if (!hasClinit) {
                  warnOnModifiedSerialVersionUID(sourceLocation, "added static initializer");
            }
      }

      public void warnOnModifiedSerialVersionUID(ISourceLocation sourceLocation, String reason) {
            if (isSerializable && !hasSerialVersionUIDField)
                  getWorld().getLint().needsSerialVersionUIDField.signal(new String[] { myType.getResolvedTypeX().getName().toString(),
                              reason }, sourceLocation, null);
      }

      public World getWorld() {
            return world;
      }

      public List getMethodGens() {
            return methodGens; // ???Collections.unmodifiableList(methodGens);
      }

      public List/* BcelField */getFieldGens() {
            return fields;
            // return myGen.getFields();
      }

      // public Field getField(String name) {
      // Field[] allFields = myGen.getFields();
      // if (allFields==null) return null;
      // for (int i = 0; i < allFields.length; i++) {
      // Field field = allFields[i];
      // if (field.getName().equals(name)) return field;
      // }
      // return null;
      // }

      private void writeBack(BcelWorld world) {
            if (getConstantPool().getSize() > Short.MAX_VALUE) {
                  reportClassTooBigProblem();
                  return;
            }

            if (annotations.size() > 0) {
                  for (Iterator iter = annotations.iterator(); iter.hasNext();) {
                        AnnotationGen element = (AnnotationGen) iter.next();
                        myGen.addAnnotation(element);
                  }
                  // Attribute[] annAttributes =
                  // org.aspectj.apache.bcel.classfile.Utility.getAnnotationAttributes(
                  // getConstantPool(),annotations);
                  // for (int i = 0; i < annAttributes.length; i++) {
                  // Attribute attribute = annAttributes[i];
                  // System.err.println("Adding attribute for "+attribute);
                  // myGen.addAttribute(attribute);
                  // }
            }

            // Add a weaver version attribute to the file being produced (if
            // necessary...)
            if (!myGen.hasAttribute("org.aspectj.weaver.WeaverVersion")) {
                  myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverVersionInfo(), getConstantPool()));
            }

            if (myType != null && myType.getWeaverState() != null) {
                  myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverState(myType.getWeaverState()), getConstantPool()));
            }

            // FIXME ATAJ needed only for slow Aspects.aspectOf() - keep or remove
            // make a lot of test fail since the test compare weaved class file
            // based on some test data as text files...
            // if (!myGen.isInterface()) {
            // addAjClassField();
            // }

            addAjcInitializers();

            // 17Feb05 - ASC - Skip this for now - it crashes IBM 1.4.2 jvms
            // (pr80430). Will be revisited when contents
            // of attribute are confirmed to be correct.
            boolean sourceDebugExtensionSupportSwitchedOn = false;

            if (sourceDebugExtensionSupportSwitchedOn) {
                  calculateSourceDebugExtensionOffsets();
            }

            int len = methodGens.size();
            myGen.setMethods(Method.NoMethods);
            for (int i = 0; i < len; i++) {
                  LazyMethodGen gen = (LazyMethodGen) methodGens.get(i);
                  // we skip empty clinits
                  if (isEmptyClinit(gen))
                        continue;
                  myGen.addMethod(gen.getMethod());
            }

            len = fields.size();
            myGen.setFields(Field.NoFields);
            for (int i = 0; i < len; i++) {
                  BcelField gen = (BcelField) fields.get(i);
                  myGen.addField(gen.getField(cp));
            }

            if (sourceDebugExtensionSupportSwitchedOn) {
                  if (inlinedFiles.size() != 0) {
                        if (hasSourceDebugExtensionAttribute(myGen)) {
                              world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.OVERWRITE_JSR45, getFileName()), null,
                                          null);
                        }
                        // myGen.addAttribute(getSourceDebugExtensionAttribute());
                  }
            }

            fixupGenericSignatureAttribute();
      }

      /**
       * When working with Java generics, a signature attribute is attached to the type which indicates how it was declared. This
       * routine ensures the signature attribute for the class we are about to write out is correct. Basically its responsibilities
       * are:
       * <ol>
       * <li>
       * Checking whether the attribute needs changing (ie. did weaving change the type hierarchy) - if it did, remove the old
       * attribute
       * <li>
       * Check if we need an attribute at all, are we generic? are our supertypes parameterized/generic?
       * <li>
       * Build the new attribute which includes all typevariable, supertype and superinterface information
       * </ol>
       */
00532       private void fixupGenericSignatureAttribute() {

            if (getWorld() != null && !getWorld().isInJava5Mode()) {
                  return;
            }

            // TODO asc generics Temporarily assume that types we generate dont need
            // a signature attribute (closure/etc).. will need
            // revisiting no doubt...
            // if (myType == null) {
            // return;
            // }

            // 1. Has anything changed that would require us to modify this
            // attribute?
            if (!regenerateGenericSignatureAttribute) {
                  return;
            }

            // 2. Find the old attribute
            Signature sigAttr = null;
            if (myType != null) { // if null, this is a type built from scratch, it
                  // won't already have a sig attribute
                  sigAttr = (Signature) myGen.getAttribute("Signature");
            }

            // 3. Do we need an attribute?
            boolean needAttribute = false;
            // If we had one before, we definetly still need one as types can't be
            // 'removed' from the hierarchy
            if (sigAttr != null) {
                  needAttribute = true;
            }

            // check the interfaces
            if (!needAttribute) {
                  if (myType != null) {
                        ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces();
                        for (int i = 0; i < interfaceRTXs.length; i++) {
                              ResolvedType typeX = interfaceRTXs[i];
                              if (typeX.isGenericType() || typeX.isParameterizedType())
                                    needAttribute = true;
                        }
                        if (extraSuperInterfaces != null) {
                              for (int i = 0; i < extraSuperInterfaces.length; i++) {
                                    ResolvedType interfaceType = extraSuperInterfaces[i];
                                    if (interfaceType.isGenericType() || interfaceType.isParameterizedType())
                                          needAttribute = true;
                              }
                        }
                  }

                  if (myType == null) {
                        ResolvedType superclassRTX = superclass;
                        if (superclassRTX != null) {
                              if (superclassRTX.isGenericType() || superclassRTX.isParameterizedType())
                                    needAttribute = true;
                        }
                  } else {
                        // check the supertype
                        ResolvedType superclassRTX = getSuperClass();
                        if (superclassRTX.isGenericType() || superclassRTX.isParameterizedType())
                              needAttribute = true;
                  }
            }

            if (needAttribute) {
                  StringBuffer signature = new StringBuffer();
                  // first, the type variables...
                  if (myType != null) {
                        TypeVariable[] tVars = myType.getTypeVariables();
                        if (tVars.length > 0) {
                              signature.append("<");
                              for (int i = 0; i < tVars.length; i++) {
                                    TypeVariable variable = tVars[i];
                                    signature.append(variable.getSignature());
                              }
                              signature.append(">");
                        }
                  }
                  // now the supertype
                  String supersig = getSuperClass().getSignatureForAttribute();
                  signature.append(supersig);
                  if (myType != null) {
                        ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces();
                        for (int i = 0; i < interfaceRTXs.length; i++) {
                              String s = interfaceRTXs[i].getSignatureForAttribute();
                              signature.append(s);
                        }
                        if (extraSuperInterfaces != null) {
                              for (int i = 0; i < extraSuperInterfaces.length; i++) {
                                    String s = extraSuperInterfaces[i].getSignatureForAttribute();
                                    signature.append(s);
                              }
                        }
                  }
                  if (sigAttr != null) {
                        myGen.removeAttribute(sigAttr);
                  }
                  myGen.addAttribute(createSignatureAttribute(signature.toString()));
            }
      }

      /**
       * Helper method to create a signature attribute based on a string signature: e.g. "Ljava/lang/Object;LI<Ljava/lang/Double;>;"
       */
00638       private Signature createSignatureAttribute(String signature) {
            int nameIndex = cp.addUtf8("Signature");
            int sigIndex = cp.addUtf8(signature);
            return new Signature(nameIndex, 2, sigIndex, cp);
      }

      /**
       * 
       */
      private void reportClassTooBigProblem() {
            // PR 59208
            // we've generated a class that is just toooooooooo big (you've been
            // generating programs
            // again haven't you? come on, admit it, no-one writes classes this big
            // by hand).
            // create an empty myGen so that we can give back a return value that
            // doesn't upset the
            // rest of the process.
            myGen = new ClassGen(myGen.getClassName(), myGen.getSuperclassName(), myGen.getFileName(), myGen.getModifiers(), myGen
                        .getInterfaceNames());
            // raise an error against this compilation unit.
            getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CLASS_TOO_BIG, this.getClassName()),
                        new SourceLocation(new File(myGen.getFileName()), 0), null);
      }

      private static boolean hasSourceDebugExtensionAttribute(ClassGen gen) {
            return gen.hasAttribute("SourceDebugExtension");
      }

      public JavaClass getJavaClass(BcelWorld world) {
            writeBack(world);
            return myGen.getJavaClass();
      }

      public byte[] getJavaClassBytesIncludingReweavable(BcelWorld world) {
            writeBack(world);
            byte[] wovenClassFileData = myGen.getJavaClass().getBytes();
            // if is java 6 class file
            if (myGen.getMajor() >= Constants.MAJOR_1_6 && world.shouldGenerateStackMaps() && AsmDetector.isAsmAround) {
                  wovenClassFileData = StackMapAdder.addStackMaps(world, wovenClassFileData);
            }

            WeaverStateInfo wsi = myType.getWeaverState();// getOrCreateWeaverStateInfo
            // ();
            if (wsi != null && wsi.isReweavable()) { // && !reweavableDataInserted
                  // reweavableDataInserted = true;
                  return wsi.replaceKeyWithDiff(wovenClassFileData);
            } else {
                  return wovenClassFileData;
            }
      }

      public void addGeneratedInner(LazyClassGen newClass) {
            classGens.add(newClass);
      }

      public void addInterface(ResolvedType newInterface, ISourceLocation sourceLocation) {
            regenerateGenericSignatureAttribute = true;

            if (extraSuperInterfaces == null) {
                  extraSuperInterfaces = new ResolvedType[1];
                  extraSuperInterfaces[0] = newInterface;
            } else {
                  ResolvedType[] x = new ResolvedType[extraSuperInterfaces.length + 1];
                  System.arraycopy(extraSuperInterfaces, 0, x, 1, extraSuperInterfaces.length);
                  x[0] = newInterface;
                  extraSuperInterfaces = x;
            }
            myGen.addInterface(newInterface.getRawName());
            if (!newInterface.equals(UnresolvedType.SERIALIZABLE))
                  warnOnAddedInterface(newInterface.getName(), sourceLocation);
      }

      public void setSuperClass(ResolvedType newSuperclass) {
            regenerateGenericSignatureAttribute = true;
            superclass = newSuperclass;
            // myType.addParent(typeX); // used for the attribute
            if (newSuperclass.getGenericType() != null) {
                  newSuperclass = newSuperclass.getGenericType();
            }
            myGen.setSuperclassName(newSuperclass.getName()); // used in the real
            // class data
      }

      // public String getSuperClassname() {
      // return myGen.getSuperclassName();
      // }

      public ResolvedType getSuperClass() {
            if (superclass != null) {
                  return superclass;
            }
            return myType.getSuperclass();
      }

      public String[] getInterfaceNames() {
            return myGen.getInterfaceNames();
      }

      // non-recursive, may be a bug, ha ha.
      private List getClassGens() {
            List ret = new ArrayList();
            ret.add(this);
            ret.addAll(classGens);
            return ret;
      }

      public List getChildClasses(BcelWorld world) {
            if (classGens.isEmpty())
                  return Collections.EMPTY_LIST;
            List ret = new ArrayList();
            for (Iterator i = classGens.iterator(); i.hasNext();) {
                  LazyClassGen clazz = (LazyClassGen) i.next();
                  byte[] bytes = clazz.getJavaClass(world).getBytes();
                  String name = clazz.getName();
                  int index = name.lastIndexOf('$');
                  // XXX this could be bad, check use of dollar signs.
                  name = name.substring(index + 1);
                  ret.add(new UnwovenClassFile.ChildClass(name, bytes));
            }
            return ret;
      }

      public String toString() {
            return toShortString();
      }

      public String toShortString() {
            String s = org.aspectj.apache.bcel.classfile.Utility.accessToString(myGen.getModifiers(), true);
            if (s != "")
                  s += " ";
            s += org.aspectj.apache.bcel.classfile.Utility.classOrInterface(myGen.getModifiers());
            s += " ";
            s += myGen.getClassName();
            return s;
      }

      public String toLongString() {
            ByteArrayOutputStream s = new ByteArrayOutputStream();
            print(new PrintStream(s));
            return new String(s.toByteArray());
      }

      public void print() {
            print(System.out);
      }

      public void print(PrintStream out) {
            List classGens = getClassGens();
            for (Iterator iter = classGens.iterator(); iter.hasNext();) {
                  LazyClassGen element = (LazyClassGen) iter.next();
                  element.printOne(out);
                  if (iter.hasNext())
                        out.println();
            }
      }

      private void printOne(PrintStream out) {
            out.print(toShortString());
            out.print(" extends ");
            out.print(org.aspectj.apache.bcel.classfile.Utility.compactClassName(myGen.getSuperclassName(), false));

            int size = myGen.getInterfaces().length;

            if (size > 0) {
                  out.print(" implements ");
                  for (int i = 0; i < size; i++) {
                        out.print(myGen.getInterfaceNames()[i]);
                        if (i < size - 1)
                              out.print(", ");
                  }
            }
            out.print(":");
            out.println();
            // XXX make sure to pass types correctly around, so this doesn't happen.
            if (myType != null) {
                  myType.printWackyStuff(out);
            }
            Field[] fields = myGen.getFields();
            for (int i = 0, len = fields.length; i < len; i++) {
                  out.print("  ");
                  out.println(fields[i]);
            }
            List methodGens = getMethodGens();
            for (Iterator iter = methodGens.iterator(); iter.hasNext();) {
                  LazyMethodGen gen = (LazyMethodGen) iter.next();
                  // we skip empty clinits
                  if (isEmptyClinit(gen))
                        continue;
                  gen.print(out, (myType != null ? myType.getWeaverVersionAttribute() : WeaverVersionInfo.UNKNOWN));
                  if (iter.hasNext())
                        out.println();
            }
            // out.println("  ATTRIBS: " + Arrays.asList(myGen.getAttributes()));

            out.println("end " + toShortString());
      }

      private boolean isEmptyClinit(LazyMethodGen gen) {

            if (!gen.getName().equals("<clinit>"))
                  return false;
            // System.err.println("checking clinig: " + gen);
            InstructionHandle start = gen.getBody().getStart();
            while (start != null) {
                  if (Range.isRangeHandle(start) || (start.getInstruction().opcode == Constants.RETURN)) {
                        start = start.getNext();
                  } else {
                        return false;
                  }
            }

            return true;
      }

      public ConstantPool getConstantPool() {
            return cp;
      }

      public String getName() {
            return myGen.getClassName();
      }

      public boolean isWoven() {
            return myType.getWeaverState() != null;
      }

      public boolean isReweavable() {
            if (myType.getWeaverState() == null)
                  return true;
            return myType.getWeaverState().isReweavable();
      }

      public Set getAspectsAffectingType() {
            if (myType.getWeaverState() == null)
                  return null;
            return myType.getWeaverState().getAspectsAffectingType();
      }

      public WeaverStateInfo getOrCreateWeaverStateInfo(boolean inReweavableMode) {
            WeaverStateInfo ret = myType.getWeaverState();
            if (ret != null)
                  return ret;
            ret = new WeaverStateInfo(inReweavableMode);
            myType.setWeaverState(ret);
            return ret;
      }

      public InstructionFactory getFactory() {
            return fact;
      }

      public LazyMethodGen getStaticInitializer() {
            for (Iterator i = methodGens.iterator(); i.hasNext();) {
                  LazyMethodGen gen = (LazyMethodGen) i.next();
                  // OPTIMIZE persist kind of member into the gen object? for clinit
                  if (gen.getName().equals("<clinit>"))
                        return gen;
            }
            LazyMethodGen clinit = new LazyMethodGen(Modifier.STATIC, Type.VOID, "<clinit>", new Type[0], NO_STRINGS, this);
            clinit.getBody().insert(InstructionConstants.RETURN);
            methodGens.add(clinit);
            return clinit;
      }

      public LazyMethodGen getAjcPreClinit() {
            for (Iterator i = methodGens.iterator(); i.hasNext();) {
                  LazyMethodGen gen = (LazyMethodGen) i.next();
                  if (gen.getName().equals(NameMangler.AJC_PRE_CLINIT_NAME))
                        return gen;
            }
            LazyMethodGen ajcClinit = new LazyMethodGen(Modifier.STATIC, Type.VOID, NameMangler.AJC_PRE_CLINIT_NAME, new Type[0],
                        NO_STRINGS, this);
            ajcClinit.getBody().insert(InstructionConstants.RETURN);
            methodGens.add(ajcClinit);

            getStaticInitializer().getBody().insert(Utility.createInvoke(getFactory(), ajcClinit));
            return ajcClinit;
      }

      // reflective thisJoinPoint support
      Map/* BcelShadow, Field */tjpFields = new HashMap();
      public static final ObjectType proceedingTjpType = new ObjectType("org.aspectj.lang.ProceedingJoinPoint");
      public static final ObjectType tjpType = new ObjectType("org.aspectj.lang.JoinPoint");
      public static final ObjectType staticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$StaticPart");
      public static final ObjectType enclosingStaticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$EnclosingStaticPart");
      private static final ObjectType sigType = new ObjectType("org.aspectj.lang.Signature");
      // private static final ObjectType slType =
      // new ObjectType("org.aspectj.lang.reflect.SourceLocation");
      private static final ObjectType factoryType = new ObjectType("org.aspectj.runtime.reflect.Factory");
      private static final ObjectType classType = new ObjectType("java.lang.Class");

      public Field getTjpField(BcelShadow shadow, final boolean isEnclosingJp) {
            Field ret = (Field) tjpFields.get(shadow);
            if (ret != null)
                  return ret;

            int modifiers = Modifier.STATIC | Modifier.FINAL;

            // XXX - Do we ever inline before or after advice? If we do, then we
            // better include them in the check below. (or just change it to
            // shadow.getEnclosingMethod().getCanInline())

            // If the enclosing method is around advice, we could inline the join
            // point
            // that has led to this shadow. If we do that then the TJP we are
            // creating
            // here must be PUBLIC so it is visible to the type in which the
            // advice is inlined. (PR71377)
            LazyMethodGen encMethod = shadow.getEnclosingMethod();
            boolean shadowIsInAroundAdvice = false;
            if (encMethod != null && encMethod.getName().startsWith(NameMangler.PREFIX + "around")) {
                  shadowIsInAroundAdvice = true;
            }

            if (getType().isInterface() || shadowIsInAroundAdvice) {
                  modifiers |= Modifier.PUBLIC;
            } else {
                  modifiers |= Modifier.PRIVATE;
            }
            ObjectType jpType = null;
            if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We
                  // didn't have different
                  // staticjp types in 1.2
                  jpType = staticTjpType;
            } else {
                  jpType = isEnclosingJp ? enclosingStaticTjpType : staticTjpType;
            }
            FieldGen fGen = new FieldGen(modifiers, jpType, "ajc$tjp_" + tjpFields.size(), getConstantPool());
            addField(fGen);
            ret = fGen.getField();
            tjpFields.put(shadow, ret);
            return ret;
      }

      // FIXME ATAJ needed only for slow Aspects.aspectOf - keep or remove
      // private void addAjClassField() {
      // // Andy: Why build it again??
      // Field ajClassField = new FieldGen(
      // Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
      // classType,
      // "aj$class",
      // getConstantPool()).getField();
      // addField(ajClassField);
      //
      // InstructionList il = new InstructionList();
      // il.append(new PUSH(getConstantPool(), getClassName()));
      // il.append(fact.createInvoke("java.lang.Class", "forName", classType,
      // new Type[] {Type.STRING}, Constants.INVOKESTATIC));
      // il.append(fact.createFieldAccess(getClassName(), ajClassField.getName(),
      // classType, Constants.PUTSTATIC));
      //
      // getStaticInitializer().getBody().insert(il);
      // }

      private void addAjcInitializers() {
            if (tjpFields.size() == 0 && !serialVersionUIDRequiresInitialization)
                  return;
            InstructionList il = null;

            if (tjpFields.size() > 0) {
                  il = initializeAllTjps();
            }

            if (serialVersionUIDRequiresInitialization) {
                  if (il == null) {
                        il = new InstructionList();
                  }
                  il.append(InstructionFactory.PUSH(getConstantPool(), calculatedSerialVersionUID));
                  il.append(getFactory().createFieldAccess(getClassName(), "serialVersionUID", BasicType.LONG, Constants.PUTSTATIC));
            }

            getStaticInitializer().getBody().insert(il);
      }

      private InstructionList initializeAllTjps() {
            InstructionList list = new InstructionList();
            InstructionFactory fact = getFactory();

            // make a new factory
            list.append(fact.createNew(factoryType));
            list.append(InstructionFactory.createDup(1));

            list.append(InstructionFactory.PUSH(getConstantPool(), getFileName()));

            // load the current Class object
            // XXX check that this works correctly for inners/anonymous
            list.append(InstructionFactory.PUSH(getConstantPool(), getClassName()));
            // XXX do we need to worry about the fact the theorectically this could
            // throw
            // a ClassNotFoundException
            list.append(fact.createInvoke("java.lang.Class", "forName", classType, new Type[] { Type.STRING }, Constants.INVOKESTATIC));

            list.append(fact.createInvoke(factoryType.getClassName(), "<init>", Type.VOID, new Type[] { Type.STRING, classType },
                        Constants.INVOKESPECIAL));

            list.append(InstructionFactory.createStore(factoryType, 0));

            List entries = new ArrayList(tjpFields.entrySet());
            Collections.sort(entries, new Comparator() {
                  public int compare(Object a, Object b) {
                        Map.Entry ae = (Map.Entry) a;
                        Map.Entry be = (Map.Entry) b;
                        return ((Field) ae.getValue()).getName().compareTo(((Field) be.getValue()).getName());
                  }
            });

            for (Iterator i = entries.iterator(); i.hasNext();) {
                  Map.Entry entry = (Map.Entry) i.next();
                  initializeTjp(fact, list, (Field) entry.getValue(), (BcelShadow) entry.getKey());
            }

            return list;
      }

      private void initializeTjp(InstructionFactory fact, InstructionList list, Field field, BcelShadow shadow) {
            Member sig = shadow.getSignature();
            // ResolvedMember mem =
            // shadow.getSignature().resolve(shadow.getWorld());

            // load the factory
            list.append(InstructionFactory.createLoad(factoryType, 0));

            // load the kind
            list.append(InstructionFactory.PUSH(getConstantPool(), shadow.getKind().getName()));

            // create the signature
            list.append(InstructionFactory.createLoad(factoryType, 0));

            String signatureMakerName = SignatureUtils.getSignatureMakerName(sig);
            ObjectType signatureType = new ObjectType(SignatureUtils.getSignatureType(sig));

            if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We
                  // didn't have optimized
                  // factory methods in 1.2
                  list.append(InstructionFactory.PUSH(getConstantPool(), SignatureUtils.getSignatureString(sig, shadow.getWorld())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.METHOD)) {
                  BcelWorld w = shadow.getWorld();

                  // For methods, push the parts of the signature on.
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getModifiers(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), sig.getName()));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterTypes())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterNames(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getExceptions(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getReturnType())));
                  // And generate a call to the variant of makeMethodSig() that takes
                  // 7 strings
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY7,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.MONITORENTER)) {
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.MONITOREXIT)) {
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.HANDLER)) {
                  BcelWorld w = shadow.getWorld();
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterTypes())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterNames(w))));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY3,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.CONSTRUCTOR)) {
                  BcelWorld w = shadow.getWorld();
                  if (w.isJoinpointArrayConstructionEnabled() && sig.getDeclaringType().isArray()) {
                        // its the magical new jp
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(Modifier.PUBLIC)));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterTypes())));
                        list.append(InstructionFactory.PUSH(getConstantPool(), ""));// makeString
                        // (
                        // ""
                        // )
                        // )
                        // )
                        // ;
                        // /
                        // /
                        // sig
                        // .
                        // getParameterNames
                        // (
                        // w
                        // )
                        // )
                        // )
                        // )
                        // ;
                        list.append(InstructionFactory.PUSH(getConstantPool(), ""));// makeString
                        // (
                        // ""
                        // )
                        // )
                        // )
                        // ;
                        // /
                        // /
                        // sig
                        // .
                        // getExceptions
                        // (
                        // w
                        // )
                        // )
                        // )
                        // )
                        // ;
                        list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY5,
                                    Constants.INVOKEVIRTUAL));
                  } else {
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getModifiers(w))));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterTypes())));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterNames(w))));
                        list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getExceptions(w))));
                        list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY5,
                                    Constants.INVOKEVIRTUAL));
                  }
            } else if (sig.getKind().equals(Member.FIELD)) {
                  BcelWorld w = shadow.getWorld();
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getModifiers(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), sig.getName()));
                  // see pr227401
                  UnresolvedType dType = sig.getDeclaringType();
                  if (dType.getTypekind() == TypeKind.PARAMETERIZED || dType.getTypekind() == TypeKind.GENERIC) {
                        dType = sig.getDeclaringType().resolve(world).getGenericType();
                  }
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(dType)));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getReturnType())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY4,
                              Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.ADVICE)) {
                  BcelWorld w = shadow.getWorld();
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getModifiers(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), sig.getName()));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterTypes())));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getParameterNames(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getExceptions(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString((sig.getReturnType()))));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, new Type[] { Type.STRING,
                              Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING }, Constants.INVOKEVIRTUAL));
            } else if (sig.getKind().equals(Member.STATIC_INITIALIZATION)) {
                  BcelWorld w = shadow.getWorld();
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getModifiers(w))));
                  list.append(InstructionFactory.PUSH(getConstantPool(), makeString(sig.getDeclaringType())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY2,
                              Constants.INVOKEVIRTUAL));
            } else {
                  list.append(InstructionFactory.PUSH(getConstantPool(), SignatureUtils.getSignatureString(sig, shadow.getWorld())));
                  list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1,
                              Constants.INVOKEVIRTUAL));
            }

            // XXX should load source location from shadow
            list.append(Utility.createConstant(fact, shadow.getSourceLine()));

            final String factoryMethod;

            if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We
                  // didn't have makeESJP() in
                  // 1.2
                  list.append(fact.createInvoke(factoryType.getClassName(), "makeSJP", staticTjpType, new Type[] { Type.STRING, sigType,
                              Type.INT }, Constants.INVOKEVIRTUAL));

                  // put it in the field
                  list.append(fact.createFieldAccess(getClassName(), field.getName(), staticTjpType, Constants.PUTSTATIC));

            } else {
                  if (staticTjpType.equals(field.getType())) {
                        factoryMethod = "makeSJP";
                  } else if (enclosingStaticTjpType.equals(field.getType())) {
                        factoryMethod = "makeESJP";
                  } else {
                        throw new Error("should not happen");
                  }
                  list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), new Type[] { Type.STRING,
                              sigType, Type.INT }, Constants.INVOKEVIRTUAL));
                  // put it in the field
                  list.append(fact.createFieldAccess(getClassName(), field.getName(), field.getType(), Constants.PUTSTATIC));
            }
      }

      protected String makeString(int i) {
            return Integer.toString(i, 16); // ??? expensive
      }

      protected String makeString(UnresolvedType t) {
            // this is the inverse of the odd behavior for Class.forName w/ arrays
            if (t.isArray()) {
                  // this behavior matches the string used by the eclipse compiler for
                  // Foo.class literals
                  return t.getSignature().replace('/', '.');
            } else {
                  if (t.isParameterizedType()) {
                        return t.getRawType().getName();
                  } else {
                        return t.getName();
                  }
            }
      }

      protected String makeString(UnresolvedType[] types) {
            if (types == null)
                  return "";
            StringBuffer buf = new StringBuffer();
            for (int i = 0, len = types.length; i < len; i++) {
                  buf.append(makeString(types[i]));
                  buf.append(':');
            }
            return buf.toString();
      }

      protected String makeString(String[] names) {
            if (names == null)
                  return "";
            StringBuffer buf = new StringBuffer();
            for (int i = 0, len = names.length; i < len; i++) {
                  buf.append(names[i]);
                  buf.append(':');
            }
            return buf.toString();
      }

      public ResolvedType getType() {
            if (myType == null)
                  return null;
            return myType.getResolvedTypeX();
      }

      public BcelObjectType getBcelObjectType() {
            return myType;
      }

      public String getFileName() {
            return myGen.getFileName();
      }

      // for *new* fields
      private void addField(FieldGen field) {
            makeSyntheticAndTransientIfNeeded(field);
            BcelField bcelField = null;
            if (getBcelObjectType() != null) {
                  bcelField = new BcelField(getBcelObjectType(), field.getField());
            } else {
                  bcelField = new BcelField(getName(), field.getField(), world);
            }
            fields.add(bcelField);
            // myGen.addField(field.getField());
      }

      private void makeSyntheticAndTransientIfNeeded(FieldGen field) {
            if (field.getName().startsWith(NameMangler.PREFIX) && !field.getName().startsWith("ajc$interField$")
                        && !field.getName().startsWith("ajc$instance$")) {
                  // it's an aj added field
                  // first do transient
                  if (!field.isStatic()) {
                        field.setModifiers(field.getModifiers() | Constants.ACC_TRANSIENT);
                  }
                  // then do synthetic
                  if (getWorld().isInJava5Mode()) {
                        // add the synthetic modifier flag
                        field.setModifiers(field.getModifiers() | ACC_SYNTHETIC);
                  }
                  if (!hasSyntheticAttribute(field.getAttributes())) {
                        // belt and braces, do the attribute even on Java 5 in addition
                        // to the modifier flag
                        // Attribute[] oldAttrs = field.getAttributes();
                        // Attribute[] newAttrs = new Attribute[oldAttrs.length + 1];
                        // System.arraycopy(oldAttrs, 0, newAttrs, 0, oldAttrs.length);
                        ConstantPool cpg = myGen.getConstantPool();
                        int index = cpg.addUtf8("Synthetic");
                        Attribute synthetic = new Synthetic(index, 0, new byte[0], cpg);
                        field.addAttribute(synthetic);
                        // newAttrs[newAttrs.length - 1] = synthetic;
                        // field.setAttributes(newAttrs);
                  }
            }
      }

      private boolean hasSyntheticAttribute(List attributes) {
            for (int i = 0; i < attributes.size(); i++) {
                  if (((Attribute) attributes.get(i)).getName().equals("Synthetic")) {
                        return true;
                  }
            }
            return false;
      }

      public void addField(FieldGen field, ISourceLocation sourceLocation) {
            addField(field);
            if (!(field.isPrivate() && (field.isStatic() || field.isTransient()))) {
                  errorOnAddedField(field, sourceLocation);
            }
      }

      public String getClassName() {
            return myGen.getClassName();
      }

      public boolean isInterface() {
            return myGen.isInterface();
      }

      public boolean isAbstract() {
            return myGen.isAbstract();
      }

      public LazyMethodGen getLazyMethodGen(Member m) {
            return getLazyMethodGen(m.getName(), m.getSignature(), false);
      }

      public LazyMethodGen getLazyMethodGen(String name, String signature) {
            return getLazyMethodGen(name, signature, false);
      }

      public LazyMethodGen getLazyMethodGen(String name, String signature, boolean allowMissing) {
            for (Iterator i = methodGens.iterator(); i.hasNext();) {
                  LazyMethodGen gen = (LazyMethodGen) i.next();
                  if (gen.getName().equals(name) && gen.getSignature().equals(signature))
                        return gen;
            }

            if (!allowMissing) {
                  throw new BCException("Class " + this.getName() + " does not have a method " + name + " with signature " + signature);
            }

            return null;
      }

      public void forcePublic() {
            myGen.setModifiers(Utility.makePublic(myGen.getModifiers()));
      }

      public boolean hasAnnotation(UnresolvedType t) {

            // annotations on the real thing
            AnnotationGen agens[] = myGen.getAnnotations();
            if (agens == null)
                  return false;
            for (int i = 0; i < agens.length; i++) {
                  AnnotationGen gen = agens[i];
                  if (t.equals(UnresolvedType.forSignature(gen.getTypeSignature())))
                        return true;
            }

            // annotations added during this weave

            return false;
      }

      public void addAnnotation(AnnotationGen a) {
            if (!hasAnnotation(UnresolvedType.forSignature(a.getTypeSignature()))) {
                  annotations.add(new AnnotationGen(a, getConstantPool(), true));
            }
      }

      // this test is like asking:
      // if
      // (UnresolvedType.SERIALIZABLE.resolve(getType().getWorld()).isAssignableFrom
      // (getType())) {
      // only we don't do that because this forces us to find all the supertypes
      // of the type,
      // and if one of them is missing we fail, and it's not worth failing just to
      // put out
      // a warning message!
      private boolean implementsSerializable(ResolvedType aType) {
            if (aType.getSignature().equals(UnresolvedType.SERIALIZABLE.getSignature()))
                  return true;

            ResolvedType[] interfaces = aType.getDeclaredInterfaces();
            for (int i = 0; i < interfaces.length; i++) {
                  if (interfaces[i].isMissing())
                        continue;
                  if (implementsSerializable(interfaces[i]))
                        return true;
            }
            ResolvedType superType = aType.getSuperclass();
            if (superType != null && !superType.isMissing()) {
                  return implementsSerializable(superType);
            }
            return false;
      }

      public boolean isAtLeastJava5() {
            return (myGen.getMajor() >= Constants.MAJOR_1_5);
      }

      /**
       * Return the next available field name with the specified 'prefix', e.g. for prefix 'class$' where class$0, class$1 exist then
       * return class$2
       */
01436       public String allocateField(String prefix) {
            int highestAllocated = -1;
            List/* BcelField */fs = getFieldGens();
            for (int i = 0; i < fs.size(); i++) {
                  BcelField field = (BcelField) fs.get(i);
                  if (field.getName().startsWith(prefix)) {
                        try {
                              int num = Integer.parseInt(field.getName().substring(prefix.length()));
                              if (num > highestAllocated)
                                    highestAllocated = num;
                        } catch (NumberFormatException nfe) {
                              // something wrong with the number on the end of that
                              // field...
                        }
                  }
            }
            return prefix + Integer.toString(highestAllocated + 1);
      }

}

Generated by  Doxygen 1.6.0   Back to index