import org.aspectj.apache.bcel.classfile.ClassParser;
import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.asm.AsmManager;
-import org.aspectj.asm.IHierarchy;
import org.aspectj.asm.IProgramElement;
import org.aspectj.asm.internal.AspectJElementHierarchy;
import org.aspectj.bridge.IMessage;
/**
*
- * @param inFile directory containing classes or zip/jar class archive
+ * @param inFile
+ * directory containing classes or zip/jar class archive
*/
public void addLibraryJarFile(File inFile) throws IOException {
List<ResolvedType> addedAspects = null;
/**
* Look for .class files that represent aspects in the supplied directory - return the list of accumulated aspects.
*
- * @param directory the directory in which to look for Aspect .class files
+ * @param directory
+ * the directory in which to look for Aspect .class files
* @return the list of discovered aspects
* @throws FileNotFoundException
* @throws IOException
* Determine if the supplied bytes represent an aspect, if they do then create a ResolvedType instance for the aspect and return
* it, otherwise return null
*
- * @param classbytes the classbytes that might represent an aspect
- * @param name the name of the class
- * @param directory directory which contained the class file
+ * @param classbytes
+ * the classbytes that might represent an aspect
+ * @param name
+ * the name of the class
+ * @param directory
+ * directory which contained the class file
* @return a ResolvedType if the classbytes represent an aspect, otherwise null
*/
private ResolvedType isAspect(byte[] classbytes, String name, File dir) throws IOException {
return c;
}
+ private Set<IProgramElement> candidatesForRemoval = null;
+
// variation of "weave" that sources class files from an external source.
public Collection<String> weave(IClassFileProvider input) throws IOException {
if (trace.isTraceEnabled()) {
Collection<String> wovenClassNames = new ArrayList<String>();
IWeaveRequestor requestor = input.getRequestor();
- for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) {
- UnwovenClassFile classFile = i.next();
- if (world.getModel() != null /* AsmManager.isCreatingModel() */&& !isBatchWeave) {
- // remove all relationships where this file being woven is the target of the relationship
- world.getModelAsAsmManager().removeRelationshipsTargettingThisType(classFile.getClassName());
+ if (world.getModel() != null && world.isMinimalModel()) {
+ candidatesForRemoval = new HashSet<IProgramElement>();
+ }
+ if (world.getModel() != null && !isBatchWeave) {
+ AsmManager manager = world.getModelAsAsmManager();
+ for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) {
+ UnwovenClassFile classFile = i.next();
+ // remove all relationships where this file being woven is
+ // the target of the relationship
+ manager.removeRelationshipsTargettingThisType(classFile.getClassName());
}
}
if (trace.isTraceEnabled()) {
trace.exit("weave", wovenClassNames);
}
+ if (world.getModel() != null && world.isMinimalModel()) {
+ candidatesForRemoval.clear();
+ }
return wovenClassNames;
}
// can we remove it from the model now? we know it contains no relationship endpoints...
AsmManager model = world.getModelAsAsmManager();
if (world.isMinimalModel() && model != null && !classType.isAspect()) {
- IHierarchy hierarchy = model.getHierarchy();
+ AspectJElementHierarchy hierarchy = (AspectJElementHierarchy) model.getHierarchy();
String pkgname = classType.getResolvedTypeX().getPackageName();
String tname = classType.getResolvedTypeX().getSimpleBaseName();
IProgramElement typeElement = hierarchy.findElementForType(pkgname, tname);
+ if (typeElement != null && hasInnerType(typeElement)) {
+ // Cannot remove it right now (has inner type), schedule it
+ // for possible deletion later if all inner types are
+ // removed
+ candidatesForRemoval.add(typeElement);
+ }
if (typeElement != null && !hasInnerType(typeElement)) {
-
- // Set<String> deleted = new HashSet<String>();
- // deleted.add(model.getCanonicalFilePath(typeElement.getSourceLocation().getSourceFile()));
- // hierarchy.updateHandleMap(deleted);
IProgramElement parent = typeElement.getParent();
// parent may have children: PACKAGE DECL, IMPORT-REFERENCE, TYPE_DECL
if (parent != null) {
- // if it was the only type we should probably remove the others too.
+ // if it was the only type we should probably remove
+ // the others too.
parent.removeChild(typeElement);
if (parent.getKind().isSourceFile()) {
- IProgramElement compilationUnit = parent;
- boolean anyOtherTypeDeclarations = false;
- for (IProgramElement child : compilationUnit.getChildren()) {
- IProgramElement.Kind k = child.getKind();
- if (k.isType()) {
- anyOtherTypeDeclarations = true;
- break;
- }
- }
- // If the compilation unit node contained no other types, there is no need to keep it
- if (!anyOtherTypeDeclarations) {
- IProgramElement cuParent = compilationUnit.getParent();
- if (cuParent != null) {
- compilationUnit.setParent(null);
- cuParent.removeChild(compilationUnit);
- }
- // need to update some caches and structures too?
- ((AspectJElementHierarchy) model.getHierarchy()).forget(parent, typeElement);
- } else {
- ((AspectJElementHierarchy) model.getHierarchy()).forget(null, typeElement);
- }
+ removeSourceFileIfNoMoreTypeDeclarationsInside(hierarchy, typeElement, parent);
} else {
- ((AspectJElementHierarchy) model.getHierarchy()).forget(null, typeElement);
+ hierarchy.forget(null, typeElement);
+ // At this point, the child has been removed. We
+ // should now check if the parent is in our
+ // 'candidatesForRemoval' set. If it is then that
+ // means we were going to remove it but it had a
+ // child. Now we can check if it still has a child -
+ // if it doesn't it can also be removed!
+
+ walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(hierarchy, tname, parent);
}
+
}
}
}
}
}
+ private void walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(AspectJElementHierarchy hierarchy, String tname,
+ IProgramElement typeThatHasChildRemoved) {
+ // typeThatHasChildRemoved might be a source file, type or a method/ctor
+ // - for a method/ctor find the type/sourcefile
+ while (typeThatHasChildRemoved != null
+ && !(typeThatHasChildRemoved.getKind().isType() || typeThatHasChildRemoved.getKind().isSourceFile())) {
+ // this will take us 'up' through methods that contain anonymous
+ // inner classes
+ typeThatHasChildRemoved = typeThatHasChildRemoved.getParent();
+ }
+ // now typeThatHasChildRemoved points to the type or sourcefile that has
+ // had something removed
+ if (candidatesForRemoval.contains(typeThatHasChildRemoved) && !hasInnerType(typeThatHasChildRemoved)) {
+ // now we can get rid of it
+ IProgramElement parent = typeThatHasChildRemoved.getParent();
+ if (parent != null) {
+ parent.removeChild(typeThatHasChildRemoved);
+ candidatesForRemoval.remove(typeThatHasChildRemoved);
+ if (parent.getKind().isSourceFile()) {
+ removeSourceFileIfNoMoreTypeDeclarationsInside(hierarchy, typeThatHasChildRemoved, parent);
+ // System.out.println("Removed on second pass: " +
+ // typeThatHasChildRemoved.getName());
+ } else {
+ // System.out.println("On later pass, parent of type " +
+ // typeThatHasChildRemoved.getName()
+ // + " was found not to be a sourcefile, recursing up...");
+ walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(hierarchy, tname, parent);
+ }
+ }
+ }
+ }
+
+ private void removeSourceFileIfNoMoreTypeDeclarationsInside(AspectJElementHierarchy hierarchy, IProgramElement typeElement,
+ IProgramElement sourceFileNode) {
+ IProgramElement compilationUnit = sourceFileNode;
+ boolean anyOtherTypeDeclarations = false;
+ for (IProgramElement child : compilationUnit.getChildren()) {
+ IProgramElement.Kind k = child.getKind();
+ if (k.isType()) {
+ anyOtherTypeDeclarations = true;
+ break;
+ }
+ }
+ // If the compilation unit node contained no
+ // other types, there is no need to keep it
+ if (!anyOtherTypeDeclarations) {
+ IProgramElement cuParent = compilationUnit.getParent();
+ if (cuParent != null) {
+ compilationUnit.setParent(null);
+ cuParent.removeChild(compilationUnit);
+ }
+ // need to update some caches and structures too?
+ hierarchy.forget(sourceFileNode, typeElement);
+ } else {
+ hierarchy.forget(null, typeElement);
+ }
+ }
+
// ---- writing
// TODO could be smarter - really only matters if inner type has been woven, but there is a chance we haven't woven it *yet*
* Perform a fast match of the specified list of shadowmungers against the specified type. A subset of those that might match is
* returned.
*
- * @param list list of all shadow mungers that might match
- * @param type the target type
+ * @param list
+ * list of all shadow mungers that might match
+ * @param type
+ * the target type
* @return a list of shadow mungers that might match with those that cannot (according to fast match rules) removed
*/
private List<ShadowMunger> fastMatch(List<ShadowMunger> list, ResolvedType type) {