From 17a082b29ea69cbbfbb5fa8225b63ffdda12975b Mon Sep 17 00:00:00 2001 From: aclement Date: Wed, 17 Sep 2008 21:18:05 +0000 Subject: [PATCH] copes with source folders in the model when searching for types --- .../asm/internal/AspectJElementHierarchy.java | 506 ++++++++++-------- 1 file changed, 292 insertions(+), 214 deletions(-) diff --git a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java index 43a43c7d6..5dbeacf5a 100644 --- a/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java +++ b/asm/src/org/aspectj/asm/internal/AspectJElementHierarchy.java @@ -11,149 +11,234 @@ * Andy Clement Extensions for better IDE representation * ******************************************************************/ - package org.aspectj.asm.internal; -import java.io.*; -import java.util.*; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; -import org.aspectj.asm.*; -import org.aspectj.bridge.*; +import org.aspectj.asm.AsmManager; +import org.aspectj.asm.IHierarchy; +import org.aspectj.asm.IProgramElement; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.bridge.SourceLocation; /** * @author Mik Kersten */ public class AspectJElementHierarchy implements IHierarchy { - + private static final long serialVersionUID = 6462734311117048620L; - - protected IProgramElement root = null; - protected String configFile = null; - - private Map fileMap = null; - private Map handleMap = null; - private Map typeMap = null; - + + protected IProgramElement root = null; + protected String configFile = null; + + private Map fileMap = null; + private Map handleMap = null; + private Map typeMap = null; + public IProgramElement getElement(String handle) { return findElementForHandleOrCreate(handle, false); } - public IProgramElement getRoot() { - return root; - } + public IProgramElement getRoot() { + return root; + } - public void setRoot(IProgramElement root) { - this.root = root; - handleMap = new HashMap(); - typeMap = new HashMap(); - } + public void setRoot(IProgramElement root) { + this.root = root; + handleMap = new HashMap(); + typeMap = new HashMap(); + } - public void addToFileMap( Object key, Object value ){ - fileMap.put( key, value ); + public void addToFileMap(Object key, Object value) { + fileMap.put(key, value); } - + public boolean removeFromFileMap(Object key) { if (fileMap.containsKey(key)) { - return (fileMap.remove(key)!=null); + return (fileMap.remove(key) != null); } - return true; + return true; } public void setFileMap(HashMap fileMap) { - this.fileMap = fileMap; - } + this.fileMap = fileMap; + } - public Object findInFileMap( Object key ) { + public Object findInFileMap(Object key) { return fileMap.get(key); } - public Set getFileMapEntrySet() { return fileMap.entrySet(); } - + public boolean isValid() { - return root != null && fileMap != null; - } - - /** + return root != null && fileMap != null; + } + + /** * Returns the first match * * @param parent - * @param kind not null + * @param kind not null * @return null if not found */ public IProgramElement findElementForSignature(IProgramElement parent, IProgramElement.Kind kind, String signature) { - for (Iterator it = parent.getChildren().iterator(); it.hasNext(); ) { - IProgramElement node = (IProgramElement)it.next(); + for (Iterator it = parent.getChildren().iterator(); it.hasNext();) { + IProgramElement node = (IProgramElement) it.next(); if (node.getKind() == kind && signature.equals(node.toSignatureString())) { return node; } else { IProgramElement childSearch = findElementForSignature(node, kind, signature); - if (childSearch != null) return childSearch; + if (childSearch != null) + return childSearch; } } return null; } - - public IProgramElement findElementForLabel( - IProgramElement parent, - IProgramElement.Kind kind, - String label) { - - for (Iterator it = parent.getChildren().iterator(); it.hasNext(); ) { - IProgramElement node = (IProgramElement)it.next(); + + public IProgramElement findElementForLabel(IProgramElement parent, IProgramElement.Kind kind, String label) { + + for (Iterator it = parent.getChildren().iterator(); it.hasNext();) { + IProgramElement node = (IProgramElement) it.next(); if (node.getKind() == kind && label.equals(node.toLabelString())) { return node; } else { IProgramElement childSearch = findElementForLabel(node, kind, label); - if (childSearch != null) return childSearch; + if (childSearch != null) + return childSearch; } } - return null; + return null; } - + /** - * @param packageName if null default package is searched - * @param className can't be null - */ + * Find the entry in the model that represents a particular type. + * + * @param packageName the package in which the type is declared or null for the default package + * @param typeName the name of the type + * @return the IProgramElement representing the type, or null if not found + */ public IProgramElement findElementForType(String packageName, String typeName) { - StringBuffer keyb = (packageName == null) ? new StringBuffer() : - new StringBuffer(packageName); - keyb.append("."); - keyb.append(typeName); + + // Build a cache key and check the cache + StringBuffer keyb = (packageName == null) ? new StringBuffer() : new StringBuffer(packageName); + keyb.append(".").append(typeName); String key = keyb.toString(); - IProgramElement ret = (IProgramElement) typeMap.get(key); - if (ret == null) { - IProgramElement packageNode = null; - if (packageName == null) { - packageNode = root; - } else { - if (root == null) return null; - List kids = root.getChildren(); - if (kids == null) return null; - for (Iterator it = kids.iterator(); it.hasNext(); ) { - IProgramElement node = (IProgramElement)it.next(); - if (packageName.equals(node.getName())) { - packageNode = node; - } - } - if (packageNode == null) return null; - } - + IProgramElement cachedValue = (IProgramElement) typeMap.get(key); + if (cachedValue != null) { + return cachedValue; + } + + List packageNodes = findMatchingPackages(packageName); + + for (Iterator iterator = packageNodes.iterator(); iterator.hasNext();) { + IProgramElement pkg = (IProgramElement) iterator.next(); // this searches each file for a class - for (Iterator it = packageNode.getChildren().iterator(); it.hasNext(); ) { - IProgramElement fileNode = (IProgramElement)it.next(); + for (Iterator it = pkg.getChildren().iterator(); it.hasNext();) { + IProgramElement fileNode = (IProgramElement) it.next(); IProgramElement cNode = findClassInNodes(fileNode.getChildren(), typeName, typeName); if (cNode != null) { - ret = cNode; - typeMap.put(key,ret); - } - } + typeMap.put(key, cNode); + return cNode; + } + } } - return ret; + return null; + + // IProgramElement packageNode = null; + // if (packageName == null) { + // packageNode = root; + // } else { + // if (root == null) + // return null; + // List kids = root.getChildren(); + // if (kids == null) { + // return null; + // } + // for (Iterator it = kids.iterator(); it.hasNext() && packageNode == null;) { + // IProgramElement node = (IProgramElement) it.next(); + // if (packageName.equals(node.getName())) { + // packageNode = node; + // } + // } + // if (packageNode == null) { + // return null; + // } + // } + + // // this searches each file for a class + // for (Iterator it = packageNode.getChildren().iterator(); it.hasNext();) { + // IProgramElement fileNode = (IProgramElement) it.next(); + // IProgramElement cNode = findClassInNodes(fileNode.getChildren(), typeName, typeName); + // if (cNode != null) { + // typeMap.put(key, cNode); + // return cNode; + // } + // } + // return null; } - + + /** + * Look for any package nodes matching the specified package name. There may be multiple in the case where the types within a + * package are split across source folders. + * + * @param packagename the packagename being searched for + * @return a list of package nodes that match that name + */ + public List/* IProgramElement */findMatchingPackages(String packagename) { + List children = root.getChildren(); + // The children might be source folders or packages + if (children.size() == 0) { + return Collections.EMPTY_LIST; + } + if (((IProgramElement) children.get(0)).getKind() == IProgramElement.Kind.SOURCE_FOLDER) { + // dealing with source folders + List matchingPackageNodes = new ArrayList(); + for (Iterator iterator = children.iterator(); iterator.hasNext();) { + IProgramElement sourceFolder = (IProgramElement) iterator.next(); + List possiblePackageNodes = sourceFolder.getChildren(); + for (Iterator iterator2 = possiblePackageNodes.iterator(); iterator2.hasNext();) { + IProgramElement possiblePackageNode = (IProgramElement) iterator2.next(); + if (possiblePackageNode.getKind() == IProgramElement.Kind.PACKAGE) { + if (possiblePackageNode.getName().equals(packagename)) { + matchingPackageNodes.add(possiblePackageNode); + } + } + } + } + return matchingPackageNodes; + } else { + // dealing directly with packages below the root, no source folders. Therefore at most one + // thing to return in the list + if (packagename == null) { + // default package + List result = new ArrayList(); + result.add(root); + return result; + } + for (Iterator iterator = children.iterator(); iterator.hasNext();) { + IProgramElement possiblePackage = (IProgramElement) iterator.next(); + if (possiblePackage.getKind() == IProgramElement.Kind.PACKAGE) { + if (possiblePackage.getName().equals(packagename)) { + List result = new ArrayList(); + result.add(possiblePackage); + return result; + } + } + } + } + return Collections.EMPTY_LIST; + } + private IProgramElement findClassInNodes(Collection nodes, String name, String typeName) { String baseName; String innerName; @@ -163,20 +248,22 @@ public class AspectJElementHierarchy implements IHierarchy { innerName = null; } else { baseName = name.substring(0, dollar); - innerName = name.substring(dollar+1); + innerName = name.substring(dollar + 1); } - - for (Iterator j = nodes.iterator(); j.hasNext(); ) { - IProgramElement classNode = (IProgramElement)j.next(); + + for (Iterator j = nodes.iterator(); j.hasNext();) { + IProgramElement classNode = (IProgramElement) j.next(); if (baseName.equals(classNode.getName())) { - if (innerName == null) return classNode; - else return findClassInNodes(classNode.getChildren(), innerName, typeName); + if (innerName == null) + return classNode; + else + return findClassInNodes(classNode.getChildren(), innerName, typeName); } else if (name.equals(classNode.getName())) { return classNode; - } else if (typeName.equals(classNode.getBytecodeSignature())) { + } else if (typeName.equals(classNode.getBytecodeSignature())) { return classNode; - } else if (classNode.getChildren() != null && !classNode.getChildren().isEmpty()){ - IProgramElement node = findClassInNodes(classNode.getChildren(),name, typeName); + } else if (classNode.getChildren() != null && !classNode.getChildren().isEmpty()) { + IProgramElement node = findClassInNodes(classNode.getChildren(), name, typeName); if (node != null) { return node; } @@ -185,69 +272,63 @@ public class AspectJElementHierarchy implements IHierarchy { return null; } - /** - * @param sourceFilePath modified to '/' delimited path for consistency - * @return a new structure node for the file if it was not found in the model + * @param sourceFilePath modified to '/' delimited path for consistency + * @return a new structure node for the file if it was not found in the model */ public IProgramElement findElementForSourceFile(String sourceFile) { - try { - if (!isValid() || sourceFile == null) { - return IHierarchy.NO_STRUCTURE; - } else { - String correctedPath = - AsmManager.getDefault().getCanonicalFilePath(new File(sourceFile)); - //StructureNode node = (StructureNode)getFileMap().get(correctedPath);//findFileNode(filePath, model); - IProgramElement node = (IProgramElement)findInFileMap(correctedPath);//findFileNode(filePath, model); - if (node != null) { - return node; - } else { - return createFileStructureNode(correctedPath); - } - } + try { + if (!isValid() || sourceFile == null) { + return IHierarchy.NO_STRUCTURE; + } else { + String correctedPath = AsmManager.getDefault().getCanonicalFilePath(new File(sourceFile)); + // StructureNode node = (StructureNode)getFileMap().get(correctedPath);//findFileNode(filePath, model); + IProgramElement node = (IProgramElement) findInFileMap(correctedPath);// findFileNode(filePath, model); + if (node != null) { + return node; + } else { + return createFileStructureNode(correctedPath); + } + } } catch (Exception e) { return IHierarchy.NO_STRUCTURE; } - } + } /** * TODO: discriminate columns */ public IProgramElement findElementForSourceLine(ISourceLocation location) { try { - return findElementForSourceLine( - AsmManager.getDefault().getCanonicalFilePath( - location.getSourceFile()), - location.getLine()); + return findElementForSourceLine(AsmManager.getDefault().getCanonicalFilePath(location.getSourceFile()), location + .getLine()); } catch (Exception e) { return null; } } /** - * Never returns null + * Never returns null * - * @param sourceFilePath canonicalized path for consistency - * @param lineNumber if 0 or 1 the corresponding file node will be returned - * @return a new structure node for the file if it was not found in the model + * @param sourceFilePath canonicalized path for consistency + * @param lineNumber if 0 or 1 the corresponding file node will be returned + * @return a new structure node for the file if it was not found in the model */ public IProgramElement findElementForSourceLine(String sourceFilePath, int lineNumber) { - String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath( - new File(sourceFilePath)); + String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath(new File(sourceFilePath)); IProgramElement node = findNodeForSourceLineHelper(root, canonicalSFP, lineNumber, -1); if (node != null) { - return node; - } else { + return node; + } else { return createFileStructureNode(sourceFilePath); } } public IProgramElement findElementForOffSet(String sourceFilePath, int lineNumber, int offSet) { - String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath( - new File(sourceFilePath)); + String canonicalSFP = AsmManager.getDefault().getCanonicalFilePath(new File(sourceFilePath)); IProgramElement node = findNodeForSourceLineHelper(root, canonicalSFP, lineNumber, offSet); if (node != null) { - return node; + return node; } else { return createFileStructureNode(sourceFilePath); } @@ -259,68 +340,61 @@ public class AspectJElementHierarchy implements IHierarchy { if (lastSlash == -1) { lastSlash = sourceFilePath.lastIndexOf('/'); } - // '!' is used like in URLs "c:/blahblah/X.jar!a/b.class" + // '!' 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(fileName, IProgramElement.Kind.FILE_JAVA, new SourceLocation(new File(sourceFilePath), 1, 1),0,null,null); - //fileNode.setSourceLocation(); + String fileName = sourceFilePath.substring(lastSlash + 1); + IProgramElement fileNode = new ProgramElement(fileName, IProgramElement.Kind.FILE_JAVA, new SourceLocation(new File( + sourceFilePath), 1, 1), 0, null, null); + // fileNode.setSourceLocation(); fileNode.addChild(NO_STRUCTURE); return fileNode; } - private IProgramElement findNodeForSourceLineHelper(IProgramElement node, String sourceFilePath, int lineNumber, int offSet) { - if (matches(node, sourceFilePath, lineNumber, offSet) - && !hasMoreSpecificChild(node, sourceFilePath, lineNumber, offSet)) { - return node; - } - + if (matches(node, sourceFilePath, lineNumber, offSet) && !hasMoreSpecificChild(node, sourceFilePath, lineNumber, offSet)) { + return node; + } + if (node != null && node.getChildren() != null) { - for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) { - IProgramElement foundNode = findNodeForSourceLineHelper( - (IProgramElement)it.next(), - sourceFilePath, - lineNumber, - offSet); - if (foundNode != null) return foundNode; + for (Iterator it = node.getChildren().iterator(); it.hasNext();) { + IProgramElement foundNode = findNodeForSourceLineHelper((IProgramElement) it.next(), sourceFilePath, lineNumber, + offSet); + if (foundNode != null) + return foundNode; } } - - return null; + + return null; } - + private boolean matches(IProgramElement node, String sourceFilePath, int lineNumber, int offSet) { -// try { -// if (node != null && node.getSourceLocation() != null) -// System.err.println("====\n1: " + -// sourceFilePath + "\n2: " + -// node.getSourceLocation().getSourceFile().getCanonicalPath().equals(sourceFilePath) -// ); - return node != null + // try { + // if (node != null && node.getSourceLocation() != null) + // System.err.println("====\n1: " + + // sourceFilePath + "\n2: " + + // node.getSourceLocation().getSourceFile().getCanonicalPath().equals(sourceFilePath) + // ); + return node != null && node.getSourceLocation() != null && node.getSourceLocation().getSourceFile().getAbsolutePath().equals(sourceFilePath) - && ((offSet != -1 && node.getSourceLocation().getOffset() == offSet) - || offSet == -1 ) - && ((node.getSourceLocation().getLine() <= lineNumber - && node.getSourceLocation().getEndLine() >= lineNumber) - || - (lineNumber <= 1 - && node.getKind().isSourceFile()) - ); -// } catch (IOException ioe) { -// return false; -// } - } - + && ((offSet != -1 && node.getSourceLocation().getOffset() == offSet) || offSet == -1) + && ((node.getSourceLocation().getLine() <= lineNumber && node.getSourceLocation().getEndLine() >= lineNumber) || (lineNumber <= 1 && node + .getKind().isSourceFile())); + // } catch (IOException ioe) { + // return false; + // } + } + private boolean hasMoreSpecificChild(IProgramElement node, String sourceFilePath, int lineNumber, int offSet) { - for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) { - IProgramElement child = (IProgramElement)it.next(); - if (matches(child, sourceFilePath, lineNumber, offSet)) return true; + for (Iterator it = node.getChildren().iterator(); it.hasNext();) { + IProgramElement child = (IProgramElement) it.next(); + if (matches(child, sourceFilePath, lineNumber, offSet)) + return true; } return false; } @@ -332,11 +406,11 @@ public class AspectJElementHierarchy implements IHierarchy { public void setConfigFile(String configFile) { this.configFile = configFile; } - + public IProgramElement findElementForHandle(String handle) { - return findElementForHandleOrCreate(handle,true); + return findElementForHandleOrCreate(handle, true); } - + // TODO: optimize this lookup // only want to create a file node if can't find the IPE if called through // findElementForHandle() to mirror behaviour before pr141730 @@ -346,81 +420,84 @@ public class AspectJElementHierarchy implements IHierarchy { if (ipe != null) { return ipe; } - - ipe = findElementForHandle(root,handle); + + ipe = findElementForHandle(root, handle); if (ipe == null && create) { ipe = createFileStructureNode(getFilename(handle)); } if (ipe != null) { - cache(handle,ipe); + cache(handle, ipe); } return ipe; } - + private IProgramElement findElementForHandle(IProgramElement parent, String handle) { - for (Iterator it = parent.getChildren().iterator(); it.hasNext(); ) { - IProgramElement node = (IProgramElement)it.next(); + for (Iterator it = parent.getChildren().iterator(); it.hasNext();) { + IProgramElement node = (IProgramElement) it.next(); String nodeHid = node.getHandleIdentifier(); if (handle.equals(nodeHid)) { return node; } else { if (handle.startsWith(nodeHid)) { // it must be down here if it is anywhere - IProgramElement childSearch = findElementForHandle(node,handle); - if (childSearch != null) return childSearch; + IProgramElement childSearch = findElementForHandle(node, handle); + if (childSearch != null) + return childSearch; } } } return null; } - -// -// private IProgramElement findElementForBytecodeInfo( -// IProgramElement node, -// String parentName, -// String name, -// String signature) { -// for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) { -// IProgramElement curr = (IProgramElement)it.next(); -// if (parentName.equals(curr.getParent().getBytecodeName()) -// && name.equals(curr.getBytecodeName()) -// && signature.equals(curr.getBytecodeSignature())) { -// return node; -// } else { -// IProgramElement childSearch = findElementForBytecodeInfo(curr, parentName, name, signature); -// if (childSearch != null) return childSearch; -// } -// } -// return null; -// } - + + // + // private IProgramElement findElementForBytecodeInfo( + // IProgramElement node, + // String parentName, + // String name, + // String signature) { + // for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) { + // IProgramElement curr = (IProgramElement)it.next(); + // if (parentName.equals(curr.getParent().getBytecodeName()) + // && name.equals(curr.getBytecodeName()) + // && signature.equals(curr.getBytecodeSignature())) { + // return node; + // } else { + // IProgramElement childSearch = findElementForBytecodeInfo(curr, parentName, name, signature); + // if (childSearch != null) return childSearch; + // } + // } + // return null; + // } + protected void cache(String handle, IProgramElement pe) { if (!AsmManager.isCompletingTypeBindings()) { - handleMap.put(handle,pe); + handleMap.put(handle, pe); } } public void flushTypeMap() { typeMap.clear(); - + } public void flushHandleMap() { handleMap.clear(); } + public void flushFileMap() { fileMap.clear(); } - // TODO rename this method ... it does more than just the handle map + // TODO rename this method ... it does more than just the handle map public void updateHandleMap(Set deletedFiles) { // Only delete the entries we need to from the handle map - for performance reasons List forRemoval = new ArrayList(); Set k = handleMap.keySet(); for (Iterator iter = k.iterator(); iter.hasNext();) { String handle = (String) iter.next(); - IProgramElement ipe = (IProgramElement)handleMap.get(handle); - if (deletedFiles.contains(getCanonicalFilePath(ipe)))forRemoval.add(handle); + IProgramElement ipe = (IProgramElement) handleMap.get(handle); + if (deletedFiles.contains(getCanonicalFilePath(ipe))) + forRemoval.add(handle); } for (Iterator iter = forRemoval.iterator(); iter.hasNext();) { String handle = (String) iter.next(); @@ -430,8 +507,9 @@ public class AspectJElementHierarchy implements IHierarchy { k = typeMap.keySet(); for (Iterator iter = k.iterator(); iter.hasNext();) { String typeName = (String) iter.next(); - IProgramElement ipe = (IProgramElement)typeMap.get(typeName); - if (deletedFiles.contains(getCanonicalFilePath(ipe))) forRemoval.add(typeName); + IProgramElement ipe = (IProgramElement) typeMap.get(typeName); + if (deletedFiles.contains(getCanonicalFilePath(ipe))) + forRemoval.add(typeName); } for (Iterator iter = forRemoval.iterator(); iter.hasNext();) { String typeName = (String) iter.next(); @@ -441,25 +519,25 @@ public class AspectJElementHierarchy implements IHierarchy { k = fileMap.keySet(); for (Iterator iter = k.iterator(); iter.hasNext();) { String filePath = (String) iter.next(); - IProgramElement ipe = (IProgramElement)fileMap.get(filePath); - if (deletedFiles.contains(getCanonicalFilePath(ipe))) forRemoval.add(filePath); + IProgramElement ipe = (IProgramElement) fileMap.get(filePath); + if (deletedFiles.contains(getCanonicalFilePath(ipe))) + forRemoval.add(filePath); } for (Iterator iter = forRemoval.iterator(); iter.hasNext();) { String filePath = (String) iter.next(); fileMap.remove(filePath); } } - + private String getFilename(String hid) { return AsmManager.getDefault().getHandleProvider().getFileForHandle(hid); } - + private String getCanonicalFilePath(IProgramElement ipe) { if (ipe.getSourceLocation() != null) { - return AsmManager.getDefault().getCanonicalFilePath(ipe.getSourceLocation().getSourceFile()); + return AsmManager.getDefault().getCanonicalFilePath(ipe.getSourceLocation().getSourceFile()); } return ""; } } - -- 2.39.5