You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AspectJElementHierarchy.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. /* *******************************************************************
  2. * Copyright (c) 2003 Contributors.
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * Mik Kersten initial implementation
  11. * Andy Clement Extensions for better IDE representation
  12. * ******************************************************************/
  13. package org.aspectj.asm.internal;
  14. import java.io.File;
  15. import java.util.ArrayList;
  16. import java.util.Collection;
  17. import java.util.Collections;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import org.aspectj.asm.AsmManager;
  23. import org.aspectj.asm.IHierarchy;
  24. import org.aspectj.asm.IProgramElement;
  25. import org.aspectj.bridge.ISourceLocation;
  26. import org.aspectj.bridge.SourceLocation;
  27. /**
  28. * @author Mik Kersten
  29. * @author Andy Clement
  30. */
  31. public class AspectJElementHierarchy implements IHierarchy {
  32. private static final long serialVersionUID = 6462734311117048620L;
  33. private transient AsmManager asm;
  34. protected IProgramElement root = null;
  35. protected String configFile = null;
  36. // Access to the handleMap and typeMap are now synchronized - at least the find methods and the updateHandleMap function
  37. // see pr305788
  38. private Map<String, IProgramElement> fileMap = null;
  39. private Map<String, IProgramElement> handleMap = new HashMap<>();
  40. private Map<String, IProgramElement> typeMap = null;
  41. public AspectJElementHierarchy(AsmManager asm) {
  42. this.asm = asm;
  43. }
  44. public IProgramElement getElement(String handle) {
  45. return findElementForHandleOrCreate(handle, false);
  46. }
  47. public void setAsmManager(AsmManager asm) { // used when deserializing
  48. this.asm = asm;
  49. }
  50. public IProgramElement getRoot() {
  51. return root;
  52. }
  53. public String toSummaryString() {
  54. StringBuilder s = new StringBuilder();
  55. s.append("FileMap has " + fileMap.size() + " entries\n");
  56. s.append("HandleMap has " + handleMap.size() + " entries\n");
  57. s.append("TypeMap has " + handleMap.size() + " entries\n");
  58. s.append("FileMap:\n");
  59. for (Map.Entry<String, IProgramElement> fileMapEntry : fileMap.entrySet()) {
  60. s.append(fileMapEntry).append("\n");
  61. }
  62. s.append("TypeMap:\n");
  63. for (Map.Entry<String, IProgramElement> typeMapEntry : typeMap.entrySet()) {
  64. s.append(typeMapEntry).append("\n");
  65. }
  66. s.append("HandleMap:\n");
  67. for (Map.Entry<String, IProgramElement> handleMapEntry : handleMap.entrySet()) {
  68. s.append(handleMapEntry).append("\n");
  69. }
  70. return s.toString();
  71. }
  72. public void setRoot(IProgramElement root) {
  73. this.root = root;
  74. handleMap = new HashMap<>();
  75. typeMap = new HashMap<>();
  76. }
  77. public void addToFileMap(String key, IProgramElement value) {
  78. fileMap.put(key, value);
  79. }
  80. public boolean removeFromFileMap(String canonicalFilePath) {
  81. return fileMap.remove(canonicalFilePath) != null;
  82. }
  83. public void setFileMap(Map<String, IProgramElement> fileMap) {
  84. this.fileMap = fileMap;
  85. }
  86. public IProgramElement findInFileMap(String key) {
  87. return fileMap.get(key);
  88. }
  89. public Set<Map.Entry<String, IProgramElement>> getFileMapEntrySet() {
  90. return fileMap.entrySet();
  91. }
  92. public boolean isValid() {
  93. return root != null && fileMap != null;
  94. }
  95. /**
  96. * Returns the first match
  97. *
  98. * @param parent
  99. * @param kind not null
  100. * @return null if not found
  101. */
  102. public IProgramElement findElementForSignature(IProgramElement parent, IProgramElement.Kind kind, String signature) {
  103. for (IProgramElement node : parent.getChildren()) {
  104. if (node.getKind() == kind && signature.equals(node.toSignatureString())) {
  105. return node;
  106. } else {
  107. IProgramElement childSearch = findElementForSignature(node, kind, signature);
  108. if (childSearch != null) {
  109. return childSearch;
  110. }
  111. }
  112. }
  113. return null;
  114. }
  115. public IProgramElement findElementForLabel(IProgramElement parent, IProgramElement.Kind kind, String label) {
  116. for (IProgramElement node : parent.getChildren()) {
  117. if (node.getKind() == kind && label.equals(node.toLabelString())) {
  118. return node;
  119. } else {
  120. IProgramElement childSearch = findElementForLabel(node, kind, label);
  121. if (childSearch != null) {
  122. return childSearch;
  123. }
  124. }
  125. }
  126. return null;
  127. }
  128. /**
  129. * Find the entry in the model that represents a particular type.
  130. *
  131. * @param packageName the package in which the type is declared or null for the default package
  132. * @param typeName the name of the type
  133. * @return the IProgramElement representing the type, or null if not found
  134. */
  135. public IProgramElement findElementForType(String packageName, String typeName) {
  136. synchronized (this) {
  137. // Build a cache key and check the cache
  138. StringBuilder keyb = (packageName == null) ? new StringBuilder() : new StringBuilder(packageName);
  139. keyb.append(".").append(typeName);
  140. String key = keyb.toString();
  141. IProgramElement cachedValue = typeMap.get(key);
  142. if (cachedValue != null) {
  143. return cachedValue;
  144. }
  145. List<IProgramElement> packageNodes = findMatchingPackages(packageName);
  146. for (IProgramElement pkg : packageNodes) {
  147. // this searches each file for a class
  148. for (IProgramElement fileNode : pkg.getChildren()) {
  149. IProgramElement cNode = findClassInNodes(fileNode.getChildren(), typeName, typeName);
  150. if (cNode != null) {
  151. typeMap.put(key, cNode);
  152. return cNode;
  153. }
  154. }
  155. }
  156. }
  157. return null;
  158. // IProgramElement packageNode = null;
  159. // if (packageName == null) {
  160. // packageNode = root;
  161. // } else {
  162. // if (root == null)
  163. // return null;
  164. // List kids = root.getChildren();
  165. // if (kids == null) {
  166. // return null;
  167. // }
  168. // for (Iterator it = kids.iterator(); it.hasNext() && packageNode == null;) {
  169. // IProgramElement node = (IProgramElement) it.next();
  170. // if (packageName.equals(node.getName())) {
  171. // packageNode = node;
  172. // }
  173. // }
  174. // if (packageNode == null) {
  175. // return null;
  176. // }
  177. // }
  178. // // this searches each file for a class
  179. // for (Iterator it = packageNode.getChildren().iterator(); it.hasNext();) {
  180. // IProgramElement fileNode = (IProgramElement) it.next();
  181. // IProgramElement cNode = findClassInNodes(fileNode.getChildren(), typeName, typeName);
  182. // if (cNode != null) {
  183. // typeMap.put(key, cNode);
  184. // return cNode;
  185. // }
  186. // }
  187. // return null;
  188. }
  189. /**
  190. * Look for any package nodes matching the specified package name. There may be multiple in the case where the types within a
  191. * package are split across source folders.
  192. *
  193. * @param packagename the packagename being searched for
  194. * @return a list of package nodes that match that name
  195. */
  196. public List<IProgramElement> findMatchingPackages(String packagename) {
  197. List<IProgramElement> children = root.getChildren();
  198. // The children might be source folders or packages
  199. if (children.size() == 0) {
  200. return Collections.emptyList();
  201. }
  202. if ((children.get(0)).getKind() == IProgramElement.Kind.SOURCE_FOLDER) {
  203. String searchPackageName = (packagename == null ? "" : packagename); // default package means match on ""
  204. // dealing with source folders
  205. List<IProgramElement> matchingPackageNodes = new ArrayList<>();
  206. for (IProgramElement sourceFolder : children) {
  207. List<IProgramElement> possiblePackageNodes = sourceFolder.getChildren();
  208. for (IProgramElement possiblePackageNode : possiblePackageNodes) {
  209. if (possiblePackageNode.getKind() == IProgramElement.Kind.PACKAGE) {
  210. if (possiblePackageNode.getName().equals(searchPackageName)) {
  211. matchingPackageNodes.add(possiblePackageNode);
  212. }
  213. }
  214. }
  215. }
  216. // 'binaries' will be checked automatically by the code above as it is represented as a SOURCE_FOLDER
  217. return matchingPackageNodes;
  218. } else {
  219. // dealing directly with packages below the root, no source folders. Therefore at most one
  220. // thing to return in the list
  221. if (packagename == null) {
  222. // default package
  223. List<IProgramElement> result = new ArrayList<>();
  224. result.add(root);
  225. return result;
  226. }
  227. List<IProgramElement> result = new ArrayList<>();
  228. for (IProgramElement possiblePackage : children) {
  229. if (possiblePackage.getKind() == IProgramElement.Kind.PACKAGE && possiblePackage.getName().equals(packagename)) {
  230. result.add(possiblePackage);
  231. }
  232. if (possiblePackage.getKind() == IProgramElement.Kind.SOURCE_FOLDER) { // might be 'binaries'
  233. if (possiblePackage.getName().equals("binaries")) {
  234. for (IProgramElement possiblePackage2 : possiblePackage.getChildren()) {
  235. if (possiblePackage2.getKind() == IProgramElement.Kind.PACKAGE
  236. && possiblePackage2.getName().equals(packagename)) {
  237. result.add(possiblePackage2);
  238. break; // ok to break here, can't be another entry under binaries
  239. }
  240. }
  241. }
  242. }
  243. }
  244. if (result.isEmpty()) {
  245. return Collections.emptyList();
  246. } else {
  247. return result;
  248. }
  249. }
  250. }
  251. private IProgramElement findClassInNodes(Collection<IProgramElement> nodes, String name, String typeName) {
  252. String baseName;
  253. String innerName;
  254. int dollar = name.indexOf('$');
  255. if (dollar == -1) {
  256. baseName = name;
  257. innerName = null;
  258. } else {
  259. baseName = name.substring(0, dollar);
  260. innerName = name.substring(dollar + 1);
  261. }
  262. for (IProgramElement classNode : nodes) {
  263. if (!classNode.getKind().isType()) {
  264. List<IProgramElement> kids = classNode.getChildren();
  265. if (kids != null && !kids.isEmpty()) {
  266. IProgramElement node = findClassInNodes(kids, name, typeName);
  267. if (node != null) {
  268. return node;
  269. }
  270. }
  271. } else {
  272. if (baseName.equals(classNode.getName())) {
  273. if (innerName == null) {
  274. return classNode;
  275. } else {
  276. return findClassInNodes(classNode.getChildren(), innerName, typeName);
  277. }
  278. } else if (name.equals(classNode.getName())) {
  279. return classNode;
  280. } else if (typeName.equals(classNode.getBytecodeSignature())) {
  281. return classNode;
  282. } else if (classNode.getChildren() != null && !classNode.getChildren().isEmpty()) {
  283. IProgramElement node = findClassInNodes(classNode.getChildren(), name, typeName);
  284. if (node != null) {
  285. return node;
  286. }
  287. }
  288. }
  289. }
  290. return null;
  291. }
  292. /**
  293. * @param sourceFile modified to '/' delimited path for consistency
  294. * @return a new structure node for the file if it was not found in the model
  295. */
  296. public IProgramElement findElementForSourceFile(String sourceFile) {
  297. try {
  298. if (!isValid() || sourceFile == null) {
  299. return IHierarchy.NO_STRUCTURE;
  300. } else {
  301. String correctedPath = asm.getCanonicalFilePath(new File(sourceFile));
  302. // StructureNode node = (StructureNode)getFileMap().get(correctedPath);//findFileNode(filePath, model);
  303. IProgramElement node = findInFileMap(correctedPath);// findFileNode(filePath, model);
  304. if (node != null) {
  305. return node;
  306. } else {
  307. return createFileStructureNode(correctedPath);
  308. }
  309. }
  310. } catch (Exception e) {
  311. return IHierarchy.NO_STRUCTURE;
  312. }
  313. }
  314. /**
  315. * TODO: discriminate columns
  316. */
  317. public IProgramElement findElementForSourceLine(ISourceLocation location) {
  318. try {
  319. return findElementForSourceLine(asm.getCanonicalFilePath(location.getSourceFile()), location.getLine());
  320. } catch (Exception e) {
  321. return null;
  322. }
  323. }
  324. /**
  325. * Never returns null
  326. *
  327. * @param sourceFilePath canonicalized path for consistency
  328. * @param lineNumber if 0 or 1 the corresponding file node will be returned
  329. * @return a new structure node for the file if it was not found in the model
  330. */
  331. public IProgramElement findElementForSourceLine(String sourceFilePath, int lineNumber) {
  332. String canonicalSFP = asm.getCanonicalFilePath(new File(sourceFilePath));
  333. // Used to do this:
  334. // IProgramElement node2 = findNodeForSourceLineHelper(root, canonicalSFP, lineNumber, -1);
  335. // Find the relevant source file node first
  336. IProgramElement node = findNodeForSourceFile(root, canonicalSFP);
  337. if (node == null) {
  338. return createFileStructureNode(sourceFilePath);
  339. }
  340. // Check if there is a more accurate child node of that source file node:
  341. IProgramElement closernode = findCloserMatchForLineNumber(node, lineNumber);
  342. if (closernode == null) {
  343. return node;
  344. } else {
  345. return closernode;
  346. }
  347. }
  348. /**
  349. * Discover the node representing a particular source file.
  350. *
  351. * @param node where in the model to start looking (usually the root on the initial call)
  352. * @param sourcefilePath the source file being searched for
  353. * @return the node representing that source file or null if it cannot be found
  354. */
  355. public IProgramElement findNodeForSourceFile(IProgramElement node, String sourcefilePath) {
  356. // 1. why is <root> a sourcefile node?
  357. // 2. should isSourceFile() return true for a FILE that is a .class file...?
  358. if ((node.getKind().isSourceFile() && !node.getName().equals("<root>")) || node.getKind().isFile()) {
  359. ISourceLocation nodeLoc = node.getSourceLocation();
  360. if (nodeLoc != null && asm.getCanonicalFilePath(nodeLoc.getSourceFile()).equals(sourcefilePath)) {
  361. return node;
  362. }
  363. return null; // no need to search children of a source file node
  364. } else {
  365. // check the children
  366. for (IProgramElement child : node.getChildren()) {
  367. IProgramElement foundit = findNodeForSourceFile(child, sourcefilePath);
  368. if (foundit != null) {
  369. return foundit;
  370. }
  371. }
  372. return null;
  373. }
  374. }
  375. public IProgramElement findElementForOffSet(String sourceFilePath, int lineNumber, int offSet) {
  376. String canonicalSFP = asm.getCanonicalFilePath(new File(sourceFilePath));
  377. IProgramElement node = findNodeForSourceLineHelper(root, canonicalSFP, lineNumber, offSet);
  378. if (node != null) {
  379. return node;
  380. } else {
  381. return createFileStructureNode(sourceFilePath);
  382. }
  383. }
  384. private IProgramElement createFileStructureNode(String sourceFilePath) {
  385. // SourceFilePath might have originated on windows on linux...
  386. int lastSlash = sourceFilePath.lastIndexOf('\\');
  387. if (lastSlash == -1) {
  388. lastSlash = sourceFilePath.lastIndexOf('/');
  389. }
  390. // '!' is used like in URLs "c:/blahblah/X.jar!a/b.class"
  391. int i = sourceFilePath.lastIndexOf('!');
  392. int j = sourceFilePath.indexOf(".class");
  393. if (i > lastSlash && i != -1 && j != -1) {
  394. // we are a binary aspect in the default package
  395. lastSlash = i;
  396. }
  397. String fileName = sourceFilePath.substring(lastSlash + 1);
  398. IProgramElement fileNode = new ProgramElement(asm, fileName, IProgramElement.Kind.FILE_JAVA, new SourceLocation(new File(
  399. sourceFilePath), 1, 1), 0, null, null);
  400. // fileNode.setSourceLocation();
  401. fileNode.addChild(NO_STRUCTURE);
  402. return fileNode;
  403. }
  404. /**
  405. * For a specified node, check if any of the children more accurately represent the specified line.
  406. *
  407. * @param node where to start looking
  408. * @param lineno the line number
  409. * @return any closer match below 'node' or null if nothing is a more accurate match
  410. */
  411. public IProgramElement findCloserMatchForLineNumber(IProgramElement node, int lineno) {
  412. if (node == null || node.getChildren() == null) {
  413. return null;
  414. }
  415. for (IProgramElement child : node.getChildren()) {
  416. ISourceLocation childLoc = child.getSourceLocation();
  417. if (childLoc != null) {
  418. if (childLoc.getLine() <= lineno && childLoc.getEndLine() >= lineno) {
  419. // This child is a better match for that line number
  420. IProgramElement evenCloserMatch = findCloserMatchForLineNumber(child, lineno);
  421. if (evenCloserMatch == null) {
  422. return child;
  423. } else {
  424. return evenCloserMatch;
  425. }
  426. } else if (child.getKind().isType()) { // types are a bit clueless about where they are... do other nodes have
  427. // similar problems??
  428. IProgramElement evenCloserMatch = findCloserMatchForLineNumber(child, lineno);
  429. if (evenCloserMatch != null) {
  430. return evenCloserMatch;
  431. }
  432. }
  433. }
  434. }
  435. return null;
  436. }
  437. private IProgramElement findNodeForSourceLineHelper(IProgramElement node, String sourceFilePath, int lineno, int offset) {
  438. if (matches(node, sourceFilePath, lineno, offset) && !hasMoreSpecificChild(node, sourceFilePath, lineno, offset)) {
  439. return node;
  440. }
  441. if (node != null) {
  442. for (IProgramElement child : node.getChildren()) {
  443. IProgramElement foundNode = findNodeForSourceLineHelper(child, sourceFilePath, lineno, offset);
  444. if (foundNode != null) {
  445. return foundNode;
  446. }
  447. }
  448. }
  449. return null;
  450. }
  451. private boolean matches(IProgramElement node, String sourceFilePath, int lineNumber, int offSet) {
  452. // try {
  453. // if (node != null && node.getSourceLocation() != null)
  454. // System.err.println("====\n1: " +
  455. // sourceFilePath + "\n2: " +
  456. // node.getSourceLocation().getSourceFile().getCanonicalPath().equals(sourceFilePath)
  457. // );
  458. ISourceLocation nodeSourceLocation = (node != null ? node.getSourceLocation() : null);
  459. return node != null
  460. && nodeSourceLocation != null
  461. && nodeSourceLocation.getSourceFile().getAbsolutePath().equals(sourceFilePath)
  462. && ((offSet != -1 && nodeSourceLocation.getOffset() == offSet) || offSet == -1)
  463. && ((nodeSourceLocation.getLine() <= lineNumber && nodeSourceLocation.getEndLine() >= lineNumber) || (lineNumber <= 1 && node
  464. .getKind().isSourceFile()));
  465. // } catch (IOException ioe) {
  466. // return false;
  467. // }
  468. }
  469. private boolean hasMoreSpecificChild(IProgramElement node, String sourceFilePath, int lineNumber, int offSet) {
  470. for (IProgramElement child : node.getChildren()) {
  471. if (matches(child, sourceFilePath, lineNumber, offSet)) {
  472. return true;
  473. }
  474. }
  475. return false;
  476. }
  477. public String getConfigFile() {
  478. return configFile;
  479. }
  480. public void setConfigFile(String configFile) {
  481. this.configFile = configFile;
  482. }
  483. public IProgramElement findElementForHandle(String handle) {
  484. return findElementForHandleOrCreate(handle, true);
  485. }
  486. // TODO: optimize this lookup
  487. // only want to create a file node if can't find the IPE if called through
  488. // findElementForHandle() to mirror behaviour before pr141730
  489. public IProgramElement findElementForHandleOrCreate(String handle, boolean create) {
  490. // try the cache first...
  491. IProgramElement ipe = null;
  492. synchronized (this) {
  493. ipe = handleMap.get(handle);
  494. if (ipe != null) {
  495. return ipe;
  496. }
  497. ipe = findElementForHandle(root, handle);
  498. if (ipe == null && create) {
  499. ipe = createFileStructureNode(getFilename(handle));
  500. }
  501. if (ipe != null) {
  502. cache(handle, ipe);
  503. }
  504. }
  505. return ipe;
  506. }
  507. private IProgramElement findElementForHandle(IProgramElement parent, String handle) {
  508. for (IProgramElement node : parent.getChildren()) {
  509. String nodeHid = node.getHandleIdentifier();
  510. if (handle.equals(nodeHid)) {
  511. return node;
  512. } else {
  513. if (handle.startsWith(nodeHid)) {
  514. // it must be down here if it is anywhere
  515. IProgramElement childSearch = findElementForHandle(node, handle);
  516. if (childSearch != null) {
  517. return childSearch;
  518. }
  519. }
  520. }
  521. }
  522. return null;
  523. }
  524. //
  525. // private IProgramElement findElementForBytecodeInfo(
  526. // IProgramElement node,
  527. // String parentName,
  528. // String name,
  529. // String signature) {
  530. // for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) {
  531. // IProgramElement curr = (IProgramElement)it.next();
  532. // if (parentName.equals(curr.getParent().getBytecodeName())
  533. // && name.equals(curr.getBytecodeName())
  534. // && signature.equals(curr.getBytecodeSignature())) {
  535. // return node;
  536. // } else {
  537. // IProgramElement childSearch = findElementForBytecodeInfo(curr, parentName, name, signature);
  538. // if (childSearch != null) return childSearch;
  539. // }
  540. // }
  541. // return null;
  542. // }
  543. protected void cache(String handle, IProgramElement pe) {
  544. if (!AsmManager.isCompletingTypeBindings()) {
  545. handleMap.put(handle, pe);
  546. }
  547. }
  548. public void flushTypeMap() {
  549. typeMap.clear();
  550. }
  551. public void flushHandleMap() {
  552. handleMap.clear();
  553. }
  554. public void flushFileMap() {
  555. fileMap.clear();
  556. }
  557. public void forget(IProgramElement compilationUnitNode, IProgramElement typeNode) {
  558. String k = null;
  559. synchronized (this) {
  560. // handle map
  561. // type map
  562. for (Map.Entry<String, IProgramElement> typeMapEntry : typeMap.entrySet()) {
  563. if (typeMapEntry.getValue() == typeNode) {
  564. k = typeMapEntry.getKey();
  565. break;
  566. }
  567. }
  568. if (k != null) {
  569. typeMap.remove(k);
  570. }
  571. }
  572. if (compilationUnitNode != null) {
  573. k = null;
  574. for (Map.Entry<String, IProgramElement> entry : fileMap.entrySet()) {
  575. if (entry.getValue() == compilationUnitNode) {
  576. k = entry.getKey();
  577. break;
  578. }
  579. }
  580. if (k != null) {
  581. fileMap.remove(k);
  582. }
  583. }
  584. }
  585. // TODO rename this method ... it does more than just the handle map
  586. public void updateHandleMap(Set<String> deletedFiles) {
  587. // Only delete the entries we need to from the handle map - for performance reasons
  588. List<String> forRemoval = new ArrayList<>();
  589. Set<String> k = null;
  590. synchronized (this) {
  591. k = handleMap.keySet();
  592. for (String handle : k) {
  593. IProgramElement ipe = handleMap.get(handle);
  594. if (ipe == null) {
  595. System.err.println("handleMap expectation not met, where is the IPE for " + handle);
  596. }
  597. if (ipe == null || deletedFiles.contains(getCanonicalFilePath(ipe))) {
  598. forRemoval.add(handle);
  599. }
  600. }
  601. for (String handle : forRemoval) {
  602. handleMap.remove(handle);
  603. }
  604. forRemoval.clear();
  605. k = typeMap.keySet();
  606. for (String typeName : k) {
  607. IProgramElement ipe = typeMap.get(typeName);
  608. if (deletedFiles.contains(getCanonicalFilePath(ipe))) {
  609. forRemoval.add(typeName);
  610. }
  611. }
  612. for (String typeName : forRemoval) {
  613. typeMap.remove(typeName);
  614. }
  615. forRemoval.clear();
  616. }
  617. for (Map.Entry<String, IProgramElement> entry : fileMap.entrySet()) {
  618. String filePath = entry.getKey();
  619. if (deletedFiles.contains(getCanonicalFilePath(entry.getValue()))) {
  620. forRemoval.add(filePath);
  621. }
  622. }
  623. for (String filePath : forRemoval) {
  624. fileMap.remove(filePath);
  625. }
  626. }
  627. private String getFilename(String hid) {
  628. return asm.getHandleProvider().getFileForHandle(hid);
  629. }
  630. private String getCanonicalFilePath(IProgramElement ipe) {
  631. if (ipe.getSourceLocation() != null) {
  632. return asm.getCanonicalFilePath(ipe.getSourceLocation().getSourceFile());
  633. }
  634. return "";
  635. }
  636. }