Logo Search packages:      
Sourcecode: aspectj version File versions

AsmRelationshipProvider.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * 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 
 * ******************************************************************/

package org.aspectj.weaver.model;

import java.io.File;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.aspectj.asm.AsmManager;
import org.aspectj.asm.IHierarchy;
import org.aspectj.asm.IProgramElement;
import org.aspectj.asm.IRelationship;
import org.aspectj.asm.IRelationshipMap;
import org.aspectj.asm.internal.HandleProviderDelimiter;
import org.aspectj.asm.internal.ProgramElement;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AdviceKind;
import org.aspectj.weaver.Checker;
import org.aspectj.weaver.Lint;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NewParentTypeMunger;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ResolvedTypeMunger;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ResolvedTypeMunger.Kind;
import org.aspectj.weaver.bcel.BcelShadow;
import org.aspectj.weaver.bcel.BcelTypeMunger;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.Pointcut;

public class AsmRelationshipProvider {

      public static final String ADVISES = "advises";
      public static final String ADVISED_BY = "advised by";
      public static final String DECLARES_ON = "declares on";
      public static final String DECLAREDY_BY = "declared by";
      public static final String SOFTENS = "softens";
      public static final String SOFTENED_BY = "softened by";
      public static final String MATCHED_BY = "matched by";
      public static final String MATCHES_DECLARE = "matches declare";
      public static final String INTER_TYPE_DECLARES = "declared on";
      public static final String INTER_TYPE_DECLARED_BY = "aspect declarations";

      public static final String ANNOTATES = "annotates";
      public static final String ANNOTATED_BY = "annotated by";

      /**
       * Add a relationship for a declare error or declare warning
       */
      public static void addDeclareErrorOrWarningRelationship(AsmManager model, Shadow affectedShadow, Checker deow) {
            if (model == null) {
                  return;
            }
            if (affectedShadow.getSourceLocation() == null || deow.getSourceLocation() == null) {
                  return;
            }

            if (World.createInjarHierarchy) {
                  createHierarchyForBinaryAspect(model, deow);
            }

            IProgramElement targetNode = getNode(model, affectedShadow);
            if (targetNode == null) {
                  return;
            }
            String targetHandle = model.getHandleProvider().createHandleIdentifier(targetNode);
            if (targetHandle == null) {
                  return;
            }

            IProgramElement sourceNode = model.getHierarchy().findElementForSourceLine(deow.getSourceLocation());
            String sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
            if (sourceHandle == null) {
                  return;
            }

            IRelationshipMap relmap = model.getRelationshipMap();
            IRelationship foreward = relmap.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY, false, true);
            foreward.addTarget(targetHandle);

            IRelationship back = relmap.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE, false, true);
            if (back != null && back.getTargets() != null) {
                  back.addTarget(sourceHandle);
            }
            if (sourceNode.getSourceLocation() != null) {
                  model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile());
            }
      }

      private static boolean isMixinRelated(ResolvedTypeMunger typeTransformer) {
            Kind kind = typeTransformer.getKind();
            return kind == ResolvedTypeMunger.MethodDelegate2 || kind == ResolvedTypeMunger.FieldHost
                        || (kind == ResolvedTypeMunger.Parent && ((NewParentTypeMunger) typeTransformer).isMixin());
      }

      /**
       * Add a relationship for a type transformation (declare parents, intertype method declaration, declare annotation on type).
       */
      public static void addRelationship(AsmManager model, ResolvedType onType, ResolvedTypeMunger typeTransformer,
                  ResolvedType originatingAspect) {
            if (model == null) {
                  return;
            }
            if (World.createInjarHierarchy && isBinaryAspect(originatingAspect)) {
                  createHierarchy(model, typeTransformer, originatingAspect);
            }

            if (originatingAspect.getSourceLocation() != null) {
                  String sourceHandle = "";
                  IProgramElement sourceNode = null;
                  if (typeTransformer.getSourceLocation() != null && typeTransformer.getSourceLocation().getOffset() != -1
                              && !isMixinRelated(typeTransformer)) {
                        sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(),
                                    originatingAspect.getClassName());
                        IProgramElement closer = model.getHierarchy().findCloserMatchForLineNumber(sourceNode,
                                    typeTransformer.getSourceLocation().getLine());
                        if (closer != null) {
                              sourceNode = closer;
                        }
                        sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
                  } else {
                        sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(),
                                    originatingAspect.getClassName());
                        // sourceNode =
                        // asm.getHierarchy().findElementForSourceLine(originatingAspect
                        // .getSourceLocation());
                        sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
                  }
                  // sourceNode =
                  // asm.getHierarchy().findElementForType(originatingAspect
                  // .getPackageName(),
                  // originatingAspect.getClassName());
                  // // sourceNode =
                  // asm.getHierarchy().findElementForSourceLine(munger
                  // .getSourceLocation());
                  // sourceHandle =
                  // asm.getHandleProvider().createHandleIdentifier(sourceNode);
                  if (sourceHandle == null) {
                        return;
                  }
                  String targetHandle = findOrFakeUpNode(model, onType);
                  if (targetHandle == null) {
                        return;
                  }
                  IRelationshipMap mapper = model.getRelationshipMap();
                  IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES, false,
                              true);
                  foreward.addTarget(targetHandle);

                  IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY, false,
                              true);
                  back.addTarget(sourceHandle);
                  if (sourceNode != null && sourceNode.getSourceLocation() != null) {
                        // May have been a bug in the compiled aspect - so it didn't get put in the model
                        model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile());
                  }
            }
      }

      private static String findOrFakeUpNode(AsmManager model, ResolvedType onType) {
            IHierarchy hierarchy = model.getHierarchy();
            ISourceLocation sourceLocation = onType.getSourceLocation();
            String canonicalFilePath = model.getCanonicalFilePath(sourceLocation.getSourceFile());
            int lineNumber = sourceLocation.getLine();
            // Find the relevant source file node first
            IProgramElement node = hierarchy.findNodeForSourceFile(hierarchy.getRoot(), canonicalFilePath);
            if (node == null) {
                  // Does not exist in the model - probably an inpath
                  String bpath = onType.getBinaryPath();
                  if (bpath == null) {
                        return model.getHandleProvider().createHandleIdentifier(createFileStructureNode(model, canonicalFilePath));
                  } else {
                        IProgramElement programElement = model.getHierarchy().getRoot();
                        // =Foo/,<g(G.class[G
                        StringBuffer phantomHandle = new StringBuffer();

                        // =Foo
                        phantomHandle.append(programElement.getHandleIdentifier());

                        // /, - the comma is a 'well defined char' that means inpath
                        phantomHandle.append(HandleProviderDelimiter.PACKAGEFRAGMENTROOT.getDelimiter()).append(
                                    HandleProviderDelimiter.PHANTOM.getDelimiter());

                        int pos = bpath.indexOf('!');
                        if (pos != -1) {
                              // jar or dir
                              String jarPath = bpath.substring(0, pos);
                              String element = model.getHandleElementForInpath(jarPath);
                              if (element != null) {
                                    phantomHandle.append(element);
                              }
                        }

                        // <g
                        String packageName = onType.getPackageName();
                        phantomHandle.append(HandleProviderDelimiter.PACKAGEFRAGMENT.getDelimiter()).append(packageName);

                        // (G.class
                        // could fix the binary path to only be blah.class bit
                        int dotClassPosition = bpath.lastIndexOf(".class");// what to do if -1
                        if (dotClassPosition == -1) {
                              phantomHandle.append(HandleProviderDelimiter.CLASSFILE.getDelimiter()).append("UNKNOWN.class");
                        } else {
                              int startPosition = dotClassPosition;
                              char ch;
                              while (startPosition > 0 && ((ch = bpath.charAt(startPosition)) != '/' && ch != '\\' && ch != '!')) {
                                    startPosition--;
                              }
                              String classFile = bpath.substring(startPosition + 1, dotClassPosition + 6);
                              phantomHandle.append(HandleProviderDelimiter.CLASSFILE.getDelimiter()).append(classFile);
                        }

                        // [G
                        phantomHandle.append(HandleProviderDelimiter.TYPE.getDelimiter()).append(onType.getClassName());

                        return phantomHandle.toString();
                  }
            } else {
                  // Check if there is a more accurate child node of that source file node:
                  IProgramElement closernode = hierarchy.findCloserMatchForLineNumber(node, lineNumber);
                  if (closernode == null) {
                        return model.getHandleProvider().createHandleIdentifier(node);
                  } else {
                        return model.getHandleProvider().createHandleIdentifier(closernode);
                  }
            }

      }

      public static IProgramElement createFileStructureNode(AsmManager asm, String sourceFilePath) {
            // SourceFilePath might have originated on windows on linux...
            int lastSlash = sourceFilePath.lastIndexOf('\\');
            if (lastSlash == -1) {
                  lastSlash = sourceFilePath.lastIndexOf('/');
            }
            // '!' is used like in URLs "c:/blahblah/X.jar!a/b.class"
            int i = sourceFilePath.lastIndexOf('!');
            int j = sourceFilePath.indexOf(".class");
            if (i > lastSlash && i != -1 && j != -1) {
                  // we are a binary aspect in the default package
                  lastSlash = i;
            }
            String fileName = sourceFilePath.substring(lastSlash + 1);
            IProgramElement fileNode = new ProgramElement(asm, fileName, IProgramElement.Kind.FILE_JAVA, new SourceLocation(new File(
                        sourceFilePath), 1, 1), 0, null, null);
            // fileNode.setSourceLocation();
            fileNode.addChild(IHierarchy.NO_STRUCTURE);
            return fileNode;
      }

      private static boolean isBinaryAspect(ResolvedType aspect) {
            return aspect.getBinaryPath() != null;
      }

      /**
       * Returns the binarySourceLocation for the given sourcelocation. This isn't cached because it's used when faulting in the
       * binary nodes and is called with ISourceLocations for all advice, pointcuts and deows contained within the
       * resolvedDeclaringAspect.
       */
      private static ISourceLocation getBinarySourceLocation(ResolvedType aspect, ISourceLocation sl) {
            if (sl == null) {
                  return null;
            }
            String sourceFileName = null;
            if (aspect instanceof ReferenceType) {
                  String s = ((ReferenceType) aspect).getDelegate().getSourcefilename();
                  int i = s.lastIndexOf('/');
                  if (i != -1) {
                        sourceFileName = s.substring(i + 1);
                  } else {
                        sourceFileName = s;
                  }
            }
            ISourceLocation sLoc = new SourceLocation(getBinaryFile(aspect), sl.getLine(), sl.getEndLine(),
                        ((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourceFileName);
            return sLoc;
      }

      private static ISourceLocation createSourceLocation(String sourcefilename, ResolvedType aspect, ISourceLocation sl) {
            ISourceLocation sLoc = new SourceLocation(getBinaryFile(aspect), sl.getLine(), sl.getEndLine(),
                        ((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourcefilename);
            return sLoc;
      }

      private static String getSourceFileName(ResolvedType aspect) {
            String sourceFileName = null;
            if (aspect instanceof ReferenceType) {
                  String s = ((ReferenceType) aspect).getDelegate().getSourcefilename();
                  int i = s.lastIndexOf('/');
                  if (i != -1) {
                        sourceFileName = s.substring(i + 1);
                  } else {
                        sourceFileName = s;
                  }
            }
            return sourceFileName;
      }

      /**
       * Returns the File with pathname to the class file, for example either C:\temp
       * \ajcSandbox\workspace\ajcTest16957.tmp\simple.jar!pkg\BinaryAspect.class if the class file is in a jar file, or
       * C:\temp\ajcSandbox\workspace\ajcTest16957.tmp!pkg\BinaryAspect.class if the class file is in a directory
       */
      private static File getBinaryFile(ResolvedType aspect) {
            String s = aspect.getBinaryPath();
            File f = aspect.getSourceLocation().getSourceFile();
            // Replace the source file suffix with .class
            int i = f.getPath().lastIndexOf('.');
            String path = null;
            if (i != -1) {
                  path = f.getPath().substring(0, i) + ".class";
            } else {
                  path = f.getPath() + ".class";
            }
            return new File(s + "!" + path);
      }

      /**
       * Create a basic hierarchy to represent an aspect only available in binary (from the aspectpath).
       */
      private static void createHierarchy(AsmManager model, ResolvedTypeMunger typeTransformer, ResolvedType aspect) {
            // assert aspect != null;

            // Check if already defined in the model
            // IProgramElement filenode =
            // model.getHierarchy().findElementForType(aspect.getPackageName(),
            // aspect.getClassName());
            // SourceLine(typeTransformer.getSourceLocation());
            IProgramElement filenode = model.getHierarchy().findElementForSourceLine(typeTransformer.getSourceLocation());
            if (filenode == null) {
                  if (typeTransformer.getKind() == ResolvedTypeMunger.MethodDelegate2
                              || typeTransformer.getKind() == ResolvedTypeMunger.FieldHost) {
                        // not yet faulting these in
                        return;
                  }
            }
            // the call to findElementForSourceLine(ISourceLocation) returns a file
            // node
            // if it can't find a node in the hierarchy for the given
            // sourcelocation.
            // Therefore, if this is returned, we know we can't find one and have to
            // // continue to fault in the model.
            // if (filenode != null) { //
            if (!filenode.getKind().equals(IProgramElement.Kind.FILE_JAVA)) {
                  return;
            }

            // create the class file node
            ISourceLocation binLocation = getBinarySourceLocation(aspect, aspect.getSourceLocation());
            String f = getBinaryFile(aspect).getName();
            IProgramElement classFileNode = new ProgramElement(model, f, IProgramElement.Kind.FILE, binLocation, 0, null, null);

            // create package ipe if one exists....
            IProgramElement root = model.getHierarchy().getRoot();
            IProgramElement binaries = model.getHierarchy().findElementForLabel(root, IProgramElement.Kind.SOURCE_FOLDER, "binaries");
            if (binaries == null) {
                  binaries = new ProgramElement(model, "binaries", IProgramElement.Kind.SOURCE_FOLDER, new ArrayList());
                  root.addChild(binaries);
            }
            // if (aspect.getPackageName() != null) {
            String packagename = aspect.getPackageName() == null ? "" : aspect.getPackageName();
            // check that there doesn't already exist a node with this name
            IProgramElement pkgNode = model.getHierarchy().findElementForLabel(binaries, IProgramElement.Kind.PACKAGE, packagename);
            // note packages themselves have no source location
            if (pkgNode == null) {
                  pkgNode = new ProgramElement(model, packagename, IProgramElement.Kind.PACKAGE, new ArrayList());
                  binaries.addChild(pkgNode);
                  pkgNode.addChild(classFileNode);
            } else {
                  // need to add it first otherwise the handle for classFileNode
                  // may not be generated correctly if it uses information from
                  // it's parent node
                  pkgNode.addChild(classFileNode);
                  for (Iterator iter = pkgNode.getChildren().iterator(); iter.hasNext();) {
                        IProgramElement element = (IProgramElement) iter.next();
                        if (!element.equals(classFileNode) && element.getHandleIdentifier().equals(classFileNode.getHandleIdentifier())) {
                              // already added the classfile so have already
                              // added the structure for this aspect
                              pkgNode.removeChild(classFileNode);
                              return;
                        }
                  }
            }
            // } else {
            // // need to add it first otherwise the handle for classFileNode
            // // may not be generated correctly if it uses information from
            // // it's parent node
            // root.addChild(classFileNode);
            // for (Iterator iter = root.getChildren().iterator(); iter.hasNext();)
            // {
            // IProgramElement element = (IProgramElement) iter.next();
            // if (!element.equals(classFileNode) &&
            // element.getHandleIdentifier().equals
            // (classFileNode.getHandleIdentifier())) {
            // // already added the sourcefile so have already
            // // added the structure for this aspect
            // root.removeChild(classFileNode);
            // return;
            // }
            // }
            // }

            // add and create empty import declaration ipe
            // no import container for binary type - 265693
            // classFileNode.addChild(new ProgramElement(model, "import declarations", IProgramElement.Kind.IMPORT_REFERENCE, null, 0,
            // null, null));

            // add and create aspect ipe
            IProgramElement aspectNode = new ProgramElement(model, aspect.getSimpleName(), IProgramElement.Kind.ASPECT,
                        getBinarySourceLocation(aspect, aspect.getSourceLocation()), aspect.getModifiers(), null, null);
            classFileNode.addChild(aspectNode);

            addChildNodes(model, aspect, aspectNode, aspect.getDeclaredPointcuts());

            addChildNodes(model, aspect, aspectNode, aspect.getDeclaredAdvice());
            addChildNodes(model, aspect, aspectNode, aspect.getDeclares());
            addChildNodes(model, aspect, aspectNode, aspect.getTypeMungers());
      }

      /**
       * Adds a declare annotation relationship, sometimes entities don't have source locs (methods/fields) so use other variants of
       * this method if that is the case as they will look the entities up in the structure model.
       */
      public static void addDeclareAnnotationRelationship(AsmManager model, ISourceLocation declareAnnotationLocation,
                  ISourceLocation annotatedLocation) {
            if (model == null) {
                  return;
            }

            IProgramElement sourceNode = model.getHierarchy().findElementForSourceLine(declareAnnotationLocation);
            String sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
            if (sourceHandle == null) {
                  return;
            }

            IProgramElement targetNode = model.getHierarchy().findElementForSourceLine(annotatedLocation);
            String targetHandle = model.getHandleProvider().createHandleIdentifier(targetNode);
            if (targetHandle == null) {
                  return;
            }

            IRelationshipMap mapper = model.getRelationshipMap();
            IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true);
            foreward.addTarget(targetHandle);

            IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true);
            back.addTarget(sourceHandle);
            if (sourceNode.getSourceLocation() != null) {
                  model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile());
            }
      }

      /**
       * Creates the hierarchy for binary aspects
       */
      public static void createHierarchyForBinaryAspect(AsmManager asm, ShadowMunger munger) {
            if (!munger.isBinary()) {
                  return;
            }

            IProgramElement sourceFileNode = asm.getHierarchy().findElementForSourceLine(munger.getSourceLocation());
            // the call to findElementForSourceLine(ISourceLocation) returns a file
            // node
            // if it can't find a node in the hierarchy for the given
            // sourcelocation.
            // Therefore, if this is returned, we know we can't find one and have to
            // continue to fault in the model.
            if (!sourceFileNode.getKind().equals(IProgramElement.Kind.FILE_JAVA)) {
                  return;
            }

            ResolvedType aspect = munger.getDeclaringType();

            // create the class file node
            IProgramElement classFileNode = new ProgramElement(asm, sourceFileNode.getName(), IProgramElement.Kind.FILE, munger
                        .getBinarySourceLocation(aspect.getSourceLocation()), 0, null, null);

            // create package ipe if one exists....
            IProgramElement root = asm.getHierarchy().getRoot();
            IProgramElement binaries = asm.getHierarchy().findElementForLabel(root, IProgramElement.Kind.SOURCE_FOLDER, "binaries");
            if (binaries == null) {
                  binaries = new ProgramElement(asm, "binaries", IProgramElement.Kind.SOURCE_FOLDER, new ArrayList());
                  root.addChild(binaries);
            }
            // if (aspect.getPackageName() != null) {
            String packagename = aspect.getPackageName() == null ? "" : aspect.getPackageName();
            // check that there doesn't already exist a node with this name
            IProgramElement pkgNode = asm.getHierarchy().findElementForLabel(binaries, IProgramElement.Kind.PACKAGE, packagename);
            // note packages themselves have no source location
            if (pkgNode == null) {
                  pkgNode = new ProgramElement(asm, packagename, IProgramElement.Kind.PACKAGE, new ArrayList());
                  binaries.addChild(pkgNode);
                  pkgNode.addChild(classFileNode);
            } else {
                  // need to add it first otherwise the handle for classFileNode
                  // may not be generated correctly if it uses information from
                  // it's parent node
                  pkgNode.addChild(classFileNode);
                  for (Iterator iter = pkgNode.getChildren().iterator(); iter.hasNext();) {
                        IProgramElement element = (IProgramElement) iter.next();
                        if (!element.equals(classFileNode) && element.getHandleIdentifier().equals(classFileNode.getHandleIdentifier())) {
                              // already added the classfile so have already
                              // added the structure for this aspect
                              pkgNode.removeChild(classFileNode);
                              return;
                        }
                  }
            }
            // } else {
            // // need to add it first otherwise the handle for classFileNode
            // // may not be generated correctly if it uses information from
            // // it's parent node
            // root.addChild(classFileNode);
            // for (Iterator iter = root.getChildren().iterator(); iter.hasNext();)
            // {
            // IProgramElement element = (IProgramElement) iter.next();
            // if (!element.equals(classFileNode) &&
            // element.getHandleIdentifier().equals
            // (classFileNode.getHandleIdentifier())) {
            // // already added the sourcefile so have already
            // // added the structure for this aspect
            // root.removeChild(classFileNode);
            // return;
            // }
            // }
            // }

            // add and create empty import declaration ipe
            // classFileNode.addChild(new ProgramElement(asm, "import declarations", IProgramElement.Kind.IMPORT_REFERENCE, null, 0,
            // null,
            // null));

            // add and create aspect ipe
            IProgramElement aspectNode = new ProgramElement(asm, aspect.getSimpleName(), IProgramElement.Kind.ASPECT, munger
                        .getBinarySourceLocation(aspect.getSourceLocation()), aspect.getModifiers(), null, null);
            classFileNode.addChild(aspectNode);

            String sourcefilename = getSourceFileName(aspect);
            addPointcuts(asm, sourcefilename, aspect, aspectNode, aspect.getDeclaredPointcuts());
            addChildNodes(asm, aspect, aspectNode, aspect.getDeclaredAdvice());
            addChildNodes(asm, aspect, aspectNode, aspect.getDeclares());
            addChildNodes(asm, aspect, aspectNode, aspect.getTypeMungers());

      }

      private static void addPointcuts(AsmManager model, String sourcefilename, ResolvedType aspect,
                  IProgramElement containingAspect, ResolvedMember[] pointcuts) {
            for (int i = 0; i < pointcuts.length; i++) {
                  ResolvedMember pointcut = pointcuts[i];
                  if (pointcut instanceof ResolvedPointcutDefinition) {
                        ResolvedPointcutDefinition rpcd = (ResolvedPointcutDefinition) pointcut;
                        Pointcut p = rpcd.getPointcut();
                        ISourceLocation sLoc = (p == null ? null : p.getSourceLocation());
                        if (sLoc == null) {
                              sLoc = rpcd.getSourceLocation();
                        }
                        ISourceLocation pointcutLocation = createSourceLocation(sourcefilename, aspect, sLoc);
                        ProgramElement pointcutElement = new ProgramElement(model, pointcut.getName(), IProgramElement.Kind.POINTCUT,
                                    pointcutLocation, pointcut.getModifiers(), NO_COMMENT, Collections.EMPTY_LIST);
                        containingAspect.addChild(pointcutElement);
                  }
            }
      }

      private static final String NO_COMMENT = null;

      private static void addChildNodes(AsmManager asm, ResolvedType aspect, IProgramElement parent, ResolvedMember[] children) {
            for (int i = 0; i < children.length; i++) {
                  ResolvedMember pcd = children[i];
                  if (pcd instanceof ResolvedPointcutDefinition) {
                        ResolvedPointcutDefinition rpcd = (ResolvedPointcutDefinition) pcd;
                        Pointcut p = rpcd.getPointcut();
                        ISourceLocation sLoc = (p == null ? null : p.getSourceLocation());
                        if (sLoc == null) {
                              sLoc = rpcd.getSourceLocation();
                        }
                        parent.addChild(new ProgramElement(asm, pcd.getName(), IProgramElement.Kind.POINTCUT, getBinarySourceLocation(
                                    aspect, sLoc), pcd.getModifiers(), null, Collections.EMPTY_LIST));
                  }
            }
      }

      private static void addChildNodes(AsmManager asm, ResolvedType aspect, IProgramElement parent, Collection children) {
            int deCtr = 1;
            int dwCtr = 1;
            for (Iterator iter = children.iterator(); iter.hasNext();) {
                  Object element = iter.next();
                  if (element instanceof DeclareErrorOrWarning) {
                        DeclareErrorOrWarning decl = (DeclareErrorOrWarning) element;
                        int counter = 0;
                        if (decl.isError()) {
                              counter = deCtr++;
                        } else {
                              counter = dwCtr++;
                        }
                        parent.addChild(createDeclareErrorOrWarningChild(asm, aspect, decl, counter));
                  } else if (element instanceof Advice) {
                        Advice advice = (Advice) element;
                        parent.addChild(createAdviceChild(asm, advice));
                  } else if (element instanceof DeclareParents) {
                        parent.addChild(createDeclareParentsChild(asm, (DeclareParents) element));
                  } else if (element instanceof BcelTypeMunger) {
                        IProgramElement newChild = createIntertypeDeclaredChild(asm, aspect, (BcelTypeMunger) element);
                        // newChild==null means it is something that could not be handled by createIntertypeDeclaredChild()
                        if (newChild != null) {
                              parent.addChild(newChild);
                        }
                  }
            }
      }

      // private static IProgramElement
      // createDeclareErrorOrWarningChild(AsmManager asm, ShadowMunger munger,
      // DeclareErrorOrWarning decl, int count) {
      // IProgramElement deowNode = new ProgramElement(asm, decl.getName(),
      // decl.isError() ? IProgramElement.Kind.DECLARE_ERROR
      // : IProgramElement.Kind.DECLARE_WARNING,
      // munger.getBinarySourceLocation(decl.getSourceLocation()), decl
      // .getDeclaringType().getModifiers(), null, null);
      // deowNode.setDetails("\"" +
      // AsmRelationshipUtils.genDeclareMessage(decl.getMessage()) + "\"");
      // if (count != -1) {
      // deowNode.setBytecodeName(decl.getName() + "_" + count);
      // }
      // return deowNode;
      // }

      private static IProgramElement createDeclareErrorOrWarningChild(AsmManager model, ResolvedType aspect,
                  DeclareErrorOrWarning decl, int count) {
            IProgramElement deowNode = new ProgramElement(model, decl.getName(), decl.isError() ? IProgramElement.Kind.DECLARE_ERROR
                        : IProgramElement.Kind.DECLARE_WARNING, getBinarySourceLocation(aspect, decl.getSourceLocation()), decl
                        .getDeclaringType().getModifiers(), null, null);
            deowNode.setDetails("\"" + AsmRelationshipUtils.genDeclareMessage(decl.getMessage()) + "\"");
            if (count != -1) {
                  deowNode.setBytecodeName(decl.getName() + "_" + count);
            }
            return deowNode;
      }

      private static IProgramElement createAdviceChild(AsmManager model, Advice advice) {
            IProgramElement adviceNode = new ProgramElement(model, advice.getKind().getName(), IProgramElement.Kind.ADVICE, advice
                        .getBinarySourceLocation(advice.getSourceLocation()), advice.getSignature().getModifiers(), null,
                        Collections.EMPTY_LIST);
            adviceNode.setDetails(AsmRelationshipUtils.genPointcutDetails(advice.getPointcut()));
            adviceNode.setBytecodeName(advice.getSignature().getName());
            return adviceNode;
      }

      /**
       * Half baked implementation - will need completing if we go down this route rather than replacing it all for binary aspects.
       * Doesn't attempt to get parameter names correct - they may have been lost during (de)serialization of the munger, but the
       * member could still be located so they might be retrievable.
       */
      private static IProgramElement createIntertypeDeclaredChild(AsmManager model, ResolvedType aspect, BcelTypeMunger itd) {
            ResolvedTypeMunger rtMunger = itd.getMunger();

            ResolvedMember sig = rtMunger.getSignature();
            Kind kind = rtMunger.getKind();
            if (kind == ResolvedTypeMunger.Field) { // ITD FIELD
                  // String name = rtMunger.getSignature().toString();
                  String name = sig.getDeclaringType().getClassName() + "." + sig.getName();
                  if (name.indexOf("$") != -1) {
                        name = name.substring(name.indexOf("$") + 1);
                  }
                  IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_FIELD, getBinarySourceLocation(
                              aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.EMPTY_LIST);
                  pe.setCorrespondingType(sig.getReturnType().getName());
                  return pe;
            } else if (kind == ResolvedTypeMunger.Method) { // ITD
                  // METHOD
                  String name = sig.getDeclaringType().getClassName() + "." + sig.getName();
                  if (name.indexOf("$") != -1) {
                        name = name.substring(name.indexOf("$") + 1);
                  }
                  IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_METHOD, getBinarySourceLocation(
                              aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.EMPTY_LIST);
                  setParams(pe, sig);
                  return pe;
            } else if (kind == ResolvedTypeMunger.Constructor) {
                  String name = sig.getDeclaringType().getClassName() + "." + sig.getDeclaringType().getClassName();
                  if (name.indexOf("$") != -1) {
                        name = name.substring(name.indexOf("$") + 1);
                  }
                  IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR,
                              getBinarySourceLocation(aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null,
                              Collections.EMPTY_LIST);
                  setParams(pe, sig);
                  return pe;
                  // } else if (kind == ResolvedTypeMunger.MethodDelegate2) {
                  // String name = sig.getDeclaringType().getClassName() + "." + sig.getName();
                  // if (name.indexOf("$") != -1) {
                  // name = name.substring(name.indexOf("$") + 1);
                  // }
                  // IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_METHOD, getBinarySourceLocation(
                  // aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.EMPTY_LIST);
                  // setParams(pe, sig);
                  // return pe;
            }
            // other cases ignored for now
            return null;
      }

      private static void setParams(IProgramElement pe, ResolvedMember sig) {
            // do it for itds too
            UnresolvedType[] ts = sig.getParameterTypes();
            pe.setParameterNames(Collections.EMPTY_LIST);
            String[] pnames = sig.getParameterNames();
            if (ts == null) {
                  pe.setParameterSignatures(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
            } else {
                  List paramSigs = new ArrayList();
                  List paramNames = new ArrayList();
                  for (int i = 0; i < ts.length; i++) {
                        paramSigs.add(ts[i].getSignature().toCharArray());
                        // paramNames.add(pnames[i]);
                  }
                  pe.setParameterSignatures(paramSigs, Collections.EMPTY_LIST);
                  // pe.setParameterNames(paramNames);
            }
            pe.setCorrespondingType(sig.getReturnType().getName());
      }

      private static IProgramElement createDeclareParentsChild(AsmManager model, DeclareParents decp) {
            IProgramElement decpElement = new ProgramElement(model, "declare parents", IProgramElement.Kind.DECLARE_PARENTS,
                        getBinarySourceLocation(decp.getDeclaringType(), decp.getSourceLocation()), Modifier.PUBLIC, null,
                        Collections.EMPTY_LIST);
            return decpElement;
      }

      public static String getHandle(AsmManager asm, Advice advice) {
            if (null == advice.handle) {
                  ISourceLocation sl = advice.getSourceLocation();
                  if (sl != null) {
                        IProgramElement ipe = asm.getHierarchy().findElementForSourceLine(sl);
                        advice.handle = asm.getHandleProvider().createHandleIdentifier(ipe);
                  }
            }
            return advice.handle;
      }

      public static void addAdvisedRelationship(AsmManager model, Shadow matchedShadow, ShadowMunger munger) {
            if (model == null) {
                  return;
            }

            if (munger instanceof Advice) {
                  Advice advice = (Advice) munger;

                  if (advice.getKind().isPerEntry() || advice.getKind().isCflow()) {
                        // TODO: might want to show these in the future
                        return;
                  }

                  if (World.createInjarHierarchy) {
                        createHierarchyForBinaryAspect(model, advice);
                  }

                  IRelationshipMap mapper = model.getRelationshipMap();
                  IProgramElement targetNode = getNode(model, matchedShadow);
                  if (targetNode == null) {
                        return;
                  }
                  boolean runtimeTest = advice.hasDynamicTests();

                  IProgramElement.ExtraInformation extra = new IProgramElement.ExtraInformation();

                  String adviceHandle = getHandle(model, advice);
                  if (adviceHandle == null) {
                        return;
                  }

                  extra.setExtraAdviceInformation(advice.getKind().getName());
                  IProgramElement adviceElement = model.getHierarchy().findElementForHandle(adviceHandle);
                  if (adviceElement != null) {
                        adviceElement.setExtraInfo(extra);
                  }
                  String targetHandle = targetNode.getHandleIdentifier();
                  if (advice.getKind().equals(AdviceKind.Softener)) {
                        IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.DECLARE_SOFT, SOFTENS, runtimeTest, true);
                        if (foreward != null) {
                              foreward.addTarget(targetHandle);
                        }

                        IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, SOFTENED_BY, runtimeTest, true);
                        if (back != null) {
                              back.addTarget(adviceHandle);
                        }
                  } else {
                        IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.ADVICE, ADVISES, runtimeTest, true);
                        if (foreward != null) {
                              foreward.addTarget(targetHandle);
                        }

                        IRelationship back = mapper.get(targetHandle, IRelationship.Kind.ADVICE, ADVISED_BY, runtimeTest, true);
                        if (back != null) {
                              back.addTarget(adviceHandle);
                        }
                  }
                  if (adviceElement.getSourceLocation() != null) {
                        model.addAspectInEffectThisBuild(adviceElement.getSourceLocation().getSourceFile());
                  }
            }
      }

      protected static IProgramElement getNode(AsmManager model, Shadow shadow) {
            Member enclosingMember = shadow.getEnclosingCodeSignature();
            // This variant will not be tricked by ITDs that would report they are
            // in the target type already.
            // This enables us to discover the ITD declaration (in the aspect) and
            // advise it appropriately.

            // Have to be smart here, for a code node within an ITD we want to
            // lookup the declaration of the
            // ITD in the aspect in order to add the code node at the right place -
            // and not lookup the
            // ITD as it applies in some target type. Due to the use of
            // effectiveSignature we will find
            // that shadow.getEnclosingCodeSignature() will return a member
            // representing the ITD as it will
            // appear in the target type. So here, we do an extra bit of analysis to
            // make sure we
            // do the right thing in the ITD case.
            IProgramElement enclosingNode = null;
            if (shadow instanceof BcelShadow) {
                  Member actualEnclosingMember = ((BcelShadow) shadow).getRealEnclosingCodeSignature();

                  if (actualEnclosingMember == null) {
                        enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember);
                  } else {
                        UnresolvedType type = enclosingMember.getDeclaringType();
                        UnresolvedType actualType = actualEnclosingMember.getDeclaringType();

                        // if these are not the same, it is an ITD and we need to use
                        // the latter to lookup
                        if (type.equals(actualType)) {
                              enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember);
                        } else {
                              enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), actualEnclosingMember);
                        }
                  }
            } else {
                  enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember);
            }

            if (enclosingNode == null) {
                  Lint.Kind err = shadow.getIWorld().getLint().shadowNotInStructure;
                  if (err.isEnabled()) {
                        err.signal(shadow.toString(), shadow.getSourceLocation());
                  }
                  return null;
            }

            Member shadowSig = shadow.getSignature();
            // pr235204
            if (shadow.getKind() == Shadow.MethodCall || shadow.getKind() == Shadow.ConstructorCall
                        || !shadowSig.equals(enclosingMember)) {
                  IProgramElement bodyNode = findOrCreateCodeNode(model, enclosingNode, shadowSig, shadow);
                  return bodyNode;
            } else {
                  return enclosingNode;
            }
      }

      private static boolean sourceLinesMatch(ISourceLocation location1, ISourceLocation location2) {
            return (location1.getLine() == location2.getLine());
      }

      /**
       * Finds or creates a code IProgramElement for the given shadow.
       * 
       * The byteCodeName of the created node is set to 'shadowSig.getName() + "!" + counter', eg "println!3". The counter is the
       * occurence count of children within the enclosingNode which have the same name. So, for example, if a method contains two
       * System.out.println statements, the first one will have byteCodeName 'println!1' and the second will have byteCodeName
       * 'println!2'. This is to ensure the two nodes have unique handles when the handles do not depend on sourcelocations.
       * 
       * Currently the shadows are examined in the sequence they appear in the source file. This means that the counters are
       * consistent over incremental builds. All aspects are compiled up front and any new aspect created will force a full build.
       * Moreover, if the body of the enclosingShadow is changed, then the model for this is rebuilt from scratch.
       */
      private static IProgramElement findOrCreateCodeNode(AsmManager asm, IProgramElement enclosingNode, Member shadowSig,
                  Shadow shadow) {
            for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext();) {
                  IProgramElement node = (IProgramElement) it.next();
                  int excl = node.getBytecodeName().lastIndexOf('!');
                  if (((excl != -1 && shadowSig.getName().equals(node.getBytecodeName().substring(0, excl))) || shadowSig.getName()
                              .equals(node.getBytecodeName()))
                              && shadowSig.getSignature().equals(node.getBytecodeSignature())
                              && sourceLinesMatch(node.getSourceLocation(), shadow.getSourceLocation())) {
                        return node;
                  }
            }

            ISourceLocation sl = shadow.getSourceLocation();

            // XXX why not use shadow file? new SourceLocation(sl.getSourceFile(),
            // sl.getLine()),
            SourceLocation peLoc = new SourceLocation(enclosingNode.getSourceLocation().getSourceFile(), sl.getLine());
            peLoc.setOffset(sl.getOffset());
            IProgramElement peNode = new ProgramElement(asm, shadow.toString(), IProgramElement.Kind.CODE, peLoc, 0, null, null);

            // check to see if the enclosing shadow already has children with the
            // same name. If so we want to add a counter to the byteCodeName
            // otherwise
            // we wont get unique handles
            int numberOfChildrenWithThisName = 0;
            for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext();) {
                  IProgramElement child = (IProgramElement) it.next();
                  if (child.getName().equals(shadow.toString())) {
                        numberOfChildrenWithThisName++;
                  }
            }
            peNode.setBytecodeName(shadowSig.getName() + "!" + String.valueOf(numberOfChildrenWithThisName + 1));
            peNode.setBytecodeSignature(shadowSig.getSignature());
            enclosingNode.addChild(peNode);
            return peNode;
      }

      private static IProgramElement lookupMember(IHierarchy model, UnresolvedType declaringType, Member member) {
            IProgramElement typeElement = model.findElementForType(declaringType.getPackageName(), declaringType.getClassName());
            if (typeElement == null) {
                  return null;
            }
            for (Iterator it = typeElement.getChildren().iterator(); it.hasNext();) {
                  IProgramElement element = (IProgramElement) it.next();
                  if (member.getName().equals(element.getBytecodeName()) && member.getSignature().equals(element.getBytecodeSignature())) {
                        return element;
                  }
            }
            // if we can't find the member, we'll just put it in the class
            return typeElement;
      }

      /**
       * Add a relationship for a matching declare annotation method or declare annotation constructor. Locating the method is a messy
       * (for messy read 'fragile') bit of code that could break at any moment but it's working for my simple testcase.
       */
      public static void addDeclareAnnotationMethodRelationship(ISourceLocation sourceLocation, String affectedTypeName,
                  ResolvedMember affectedMethod, AsmManager model) {
            if (model == null) {
                  return;
            }

            String pkg = null;
            String type = affectedTypeName;
            int packageSeparator = affectedTypeName.lastIndexOf(".");
            if (packageSeparator != -1) {
                  pkg = affectedTypeName.substring(0, packageSeparator);
                  type = affectedTypeName.substring(packageSeparator + 1);
            }

            IHierarchy hierarchy = model.getHierarchy();

            IProgramElement typeElem = hierarchy.findElementForType(pkg, type);
            if (typeElem == null)
                  return;

            StringBuffer parmString = new StringBuffer("(");
            UnresolvedType[] args = affectedMethod.getParameterTypes();
            // Type[] args = method.getArgumentTypes();
            for (int i = 0; i < args.length; i++) {
                  String s = args[i].getName();// Utility.signatureToString(args[i].
                  // getName()getSignature(), false);
                  parmString.append(s);
                  if ((i + 1) < args.length)
                        parmString.append(",");
            }
            parmString.append(")");
            IProgramElement methodElem = null;

            if (affectedMethod.getName().startsWith("<init>")) {
                  // its a ctor
                  methodElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.CONSTRUCTOR, type + parmString);
                  if (methodElem == null && args.length == 0)
                        methodElem = typeElem; // assume default ctor
            } else {
                  // its a method
                  methodElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.METHOD, affectedMethod.getName()
                              + parmString);
            }

            if (methodElem == null)
                  return;

            try {
                  String targetHandle = methodElem.getHandleIdentifier();
                  if (targetHandle == null)
                        return;

                  IProgramElement sourceNode = hierarchy.findElementForSourceLine(sourceLocation);
                  String sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
                  if (sourceHandle == null)
                        return;

                  IRelationshipMap mapper = model.getRelationshipMap();
                  IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true);
                  foreward.addTarget(targetHandle);

                  IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true);
                  back.addTarget(sourceHandle);
            } catch (Throwable t) { // I'm worried about that code above, this will
                  // make sure we don't explode if it plays up
                  t.printStackTrace(); // I know I know .. but I don't want to lose
                  // it!
            }
      }

      /**
       * Add a relationship for a matching declare ATfield. Locating the field is trickier than it might seem since we have no line
       * number info for it, we have to dig through the structure model under the fields' type in order to locate it.
       */
      public static void addDeclareAnnotationFieldRelationship(AsmManager model, ISourceLocation declareLocation,
                  String affectedTypeName, ResolvedMember affectedFieldName) {
            if (model == null) {
                  return;
            }

            String pkg = null;
            String type = affectedTypeName;
            int packageSeparator = affectedTypeName.lastIndexOf(".");
            if (packageSeparator != -1) {
                  pkg = affectedTypeName.substring(0, packageSeparator);
                  type = affectedTypeName.substring(packageSeparator + 1);
            }
            IHierarchy hierarchy = model.getHierarchy();
            IProgramElement typeElem = hierarchy.findElementForType(pkg, type);
            if (typeElem == null) {
                  return;
            }

            IProgramElement fieldElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.FIELD, affectedFieldName
                        .getName());
            if (fieldElem == null) {
                  return;
            }

            String targetHandle = fieldElem.getHandleIdentifier();
            if (targetHandle == null) {
                  return;
            }

            IProgramElement sourceNode = hierarchy.findElementForSourceLine(declareLocation);
            String sourceHandle = model.getHandleProvider().createHandleIdentifier(sourceNode);
            if (sourceHandle == null) {
                  return;
            }

            IRelationshipMap relmap = model.getRelationshipMap();
            IRelationship foreward = relmap.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true);
            foreward.addTarget(targetHandle);
            IRelationship back = relmap.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true);
            back.addTarget(sourceHandle);
      }

}

Generated by  Doxygen 1.6.0   Back to index