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.

AsmManager.java 44KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  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 v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Mik Kersten initial implementation
  11. * Andy Clement incremental support and switch on/off state
  12. * ******************************************************************/
  13. package org.aspectj.asm;
  14. import java.io.BufferedWriter;
  15. import java.io.EOFException;
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.io.FileOutputStream;
  20. import java.io.FileWriter;
  21. import java.io.IOException;
  22. import java.io.ObjectInputStream;
  23. import java.io.ObjectOutputStream;
  24. import java.io.Writer;
  25. import java.util.ArrayList;
  26. import java.util.Collection;
  27. import java.util.Enumeration;
  28. import java.util.HashMap;
  29. import java.util.HashSet;
  30. import java.util.Hashtable;
  31. import java.util.Iterator;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Properties;
  35. import java.util.Set;
  36. import org.aspectj.asm.internal.AspectJElementHierarchy;
  37. import org.aspectj.asm.internal.HandleProviderDelimiter;
  38. import org.aspectj.asm.internal.JDTLikeHandleProvider;
  39. import org.aspectj.asm.internal.RelationshipMap;
  40. import org.aspectj.bridge.ISourceLocation;
  41. import org.aspectj.util.IStructureModel;
  42. /**
  43. * The Abstract Structure Model (ASM) represents the containment hierarchy and crosscutting structure map for AspectJ programs. It
  44. * is used by IDE views such as the document outline, and by other tools such as ajdoc to show both AspectJ declarations and
  45. * crosscutting links, such as which advice affects which join point shadows.
  46. *
  47. * @author Mik Kersten
  48. * @author Andy Clement
  49. */
  50. public class AsmManager implements IStructureModel {
  51. // For testing ONLY
  52. public static boolean recordingLastActiveStructureModel = true;
  53. public static AsmManager lastActiveStructureModel;
  54. public static boolean forceSingletonBehaviour = false;
  55. // SECRETAPI asc pull the secret options together into a system API you lazy fool
  56. public static boolean attemptIncrementalModelRepairs = false;
  57. // Dumping the model is expensive
  58. public static boolean dumpModelPostBuild = false;
  59. // For offline debugging, you can now ask for the AsmManager to
  60. // dump the model - see the method setReporting()
  61. private static boolean dumpModel = false;
  62. private static boolean dumpRelationships = false;
  63. private static boolean dumpDeltaProcessing = false;
  64. private static IModelFilter modelFilter = null;
  65. private static String dumpFilename = "";
  66. private static boolean reporting = false;
  67. private static boolean completingTypeBindings = false;
  68. private final List<IHierarchyListener> structureListeners = new ArrayList<IHierarchyListener>();
  69. // The model is 'manipulated' by the AjBuildManager.setupModel() code which
  70. // trashes all the
  71. // fields when setting up a new model for a batch build.
  72. // Due to the requirements of incremental compilation we need to tie some of
  73. // the info
  74. // below to the AjState for a compilation and recover it if switching
  75. // between projects.
  76. protected IHierarchy hierarchy;
  77. /*
  78. * Map from String > String - it maps absolute paths for inpath dirs/jars to workspace relative paths suitable for handle
  79. * inclusion
  80. */
  81. protected Map<File, String> inpathMap;
  82. private IRelationshipMap mapper;
  83. private IElementHandleProvider handleProvider;
  84. private final CanonicalFilePathMap canonicalFilePathMap = new CanonicalFilePathMap();
  85. // Record the Set<File> for which the model has been modified during the
  86. // last incremental build
  87. private final Set<File> lastBuildChanges = new HashSet<File>();
  88. // Record the Set<File> of aspects that wove the files listed in lastBuildChanges
  89. final Set<File> aspectsWeavingInLastBuild = new HashSet<File>();
  90. // static {
  91. // setReporting("c:/model.nfo",true,true,true,true);
  92. // }
  93. private AsmManager() {
  94. }
  95. public static AsmManager createNewStructureModel(Map<File, String> inpathMap) {
  96. if (forceSingletonBehaviour && lastActiveStructureModel != null) {
  97. return lastActiveStructureModel;
  98. }
  99. AsmManager asm = new AsmManager();
  100. asm.inpathMap = inpathMap;
  101. asm.hierarchy = new AspectJElementHierarchy(asm);
  102. asm.mapper = new RelationshipMap();
  103. asm.handleProvider = new JDTLikeHandleProvider(asm);
  104. // call initialize on the handleProvider when we create a new ASM
  105. // to give handleProviders the chance to reset any state
  106. asm.handleProvider.initialize();
  107. asm.resetDeltaProcessing();
  108. setLastActiveStructureModel(asm);
  109. return asm;
  110. }
  111. public IHierarchy getHierarchy() {
  112. return hierarchy;
  113. }
  114. public IRelationshipMap getRelationshipMap() {
  115. return mapper;
  116. }
  117. public void fireModelUpdated() {
  118. notifyListeners();
  119. if (dumpModelPostBuild && hierarchy.getConfigFile() != null) {
  120. writeStructureModel(hierarchy.getConfigFile());
  121. }
  122. }
  123. /**
  124. * Constructs map each time it's called.
  125. */
  126. public HashMap<Integer, List<IProgramElement>> getInlineAnnotations(String sourceFile, boolean showSubMember,
  127. boolean showMemberAndType) {
  128. if (!hierarchy.isValid()) {
  129. return null;
  130. }
  131. HashMap<Integer, List<IProgramElement>> annotations = new HashMap<Integer, List<IProgramElement>>();
  132. IProgramElement node = hierarchy.findElementForSourceFile(sourceFile);
  133. if (node == IHierarchy.NO_STRUCTURE) {
  134. return null;
  135. } else {
  136. IProgramElement fileNode = node;
  137. ArrayList<IProgramElement> peNodes = new ArrayList<IProgramElement>();
  138. getAllStructureChildren(fileNode, peNodes, showSubMember, showMemberAndType);
  139. for (Iterator<IProgramElement> it = peNodes.iterator(); it.hasNext();) {
  140. IProgramElement peNode = it.next();
  141. List<IProgramElement> entries = new ArrayList<IProgramElement>();
  142. entries.add(peNode);
  143. ISourceLocation sourceLoc = peNode.getSourceLocation();
  144. if (null != sourceLoc) {
  145. Integer hash = new Integer(sourceLoc.getLine());
  146. List<IProgramElement> existingEntry = annotations.get(hash);
  147. if (existingEntry != null) {
  148. entries.addAll(existingEntry);
  149. }
  150. annotations.put(hash, entries);
  151. }
  152. }
  153. return annotations;
  154. }
  155. }
  156. private void getAllStructureChildren(IProgramElement node, List<IProgramElement> result, boolean showSubMember,
  157. boolean showMemberAndType) {
  158. List<IProgramElement> children = node.getChildren();
  159. if (node.getChildren() == null) {
  160. return;
  161. }
  162. for (IProgramElement next : children) {
  163. List<IRelationship> rels = mapper.get(next);
  164. if (next != null
  165. && ((next.getKind() == IProgramElement.Kind.CODE && showSubMember) || (next.getKind() != IProgramElement.Kind.CODE && showMemberAndType))
  166. && rels != null && rels.size() > 0) {
  167. result.add(next);
  168. }
  169. getAllStructureChildren(next, result, showSubMember, showMemberAndType);
  170. }
  171. }
  172. public void addListener(IHierarchyListener listener) {
  173. structureListeners.add(listener);
  174. }
  175. public void removeStructureListener(IHierarchyListener listener) {
  176. structureListeners.remove(listener);
  177. }
  178. // this shouldn't be needed - but none of the people that add listeners
  179. // in the test suite ever remove them. AMC added this to be called in
  180. // setup() so that the test cases would cease leaking listeners and go
  181. // back to executing at a reasonable speed.
  182. public void removeAllListeners() {
  183. structureListeners.clear();
  184. }
  185. private void notifyListeners() {
  186. for (IHierarchyListener listener : structureListeners) {
  187. listener.elementsUpdated(hierarchy);
  188. }
  189. }
  190. public IElementHandleProvider getHandleProvider() {
  191. return handleProvider;
  192. }
  193. public void setHandleProvider(IElementHandleProvider handleProvider) {
  194. this.handleProvider = handleProvider;
  195. }
  196. public void writeStructureModel(String configFilePath) {
  197. try {
  198. String filePath = genExternFilePath(configFilePath);
  199. FileOutputStream fos = new FileOutputStream(filePath);
  200. ObjectOutputStream s = new ObjectOutputStream(fos);
  201. s.writeObject(hierarchy); // Store the program element tree
  202. s.writeObject(mapper); // Store the relationships
  203. s.flush();
  204. fos.flush();
  205. fos.close();
  206. s.close();
  207. } catch (IOException e) {
  208. // System.err.println("AsmManager: Unable to write structure model: "
  209. // +configFilePath+" because of:");
  210. // e.printStackTrace();
  211. }
  212. }
  213. /**
  214. * @param configFilePath path to an ".lst" file
  215. */
  216. public void readStructureModel(String configFilePath) {
  217. boolean hierarchyReadOK = false;
  218. try {
  219. if (configFilePath == null) {
  220. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  221. } else {
  222. String filePath = genExternFilePath(configFilePath);
  223. FileInputStream in = new FileInputStream(filePath);
  224. ObjectInputStream s = new ObjectInputStream(in);
  225. hierarchy = (AspectJElementHierarchy) s.readObject();
  226. ((AspectJElementHierarchy) hierarchy).setAsmManager(this);
  227. hierarchyReadOK = true;
  228. mapper = (RelationshipMap) s.readObject();
  229. s.close();
  230. }
  231. } catch (FileNotFoundException fnfe) {
  232. // That is OK
  233. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  234. } catch (EOFException eofe) {
  235. // Might be an old format sym file that is missing its relationships
  236. if (!hierarchyReadOK) {
  237. System.err.println("AsmManager: Unable to read structure model: " + configFilePath + " because of:");
  238. eofe.printStackTrace();
  239. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  240. }
  241. } catch (Exception e) {
  242. // System.err.println("AsmManager: Unable to read structure model: "+
  243. // configFilePath+" because of:");
  244. // e.printStackTrace();
  245. hierarchy.setRoot(IHierarchy.NO_STRUCTURE);
  246. } finally {
  247. notifyListeners();
  248. }
  249. }
  250. private String genExternFilePath(String configFilePath) {
  251. // sometimes don't have ".lst"
  252. if (configFilePath.lastIndexOf(".lst") != -1) {
  253. configFilePath = configFilePath.substring(0, configFilePath.lastIndexOf(".lst"));
  254. }
  255. return configFilePath + ".ajsym";
  256. }
  257. public String getCanonicalFilePath(File f) {
  258. return canonicalFilePathMap.get(f);
  259. }
  260. public CanonicalFilePathMap getCanonicalFilePathMap() {
  261. return canonicalFilePathMap;
  262. }
  263. private static class CanonicalFilePathMap {
  264. private static final int MAX_SIZE = 4000;
  265. private final Map<String, String> pathMap = new HashMap<String, String>(20);
  266. // // guards to ensure correctness and liveness
  267. // private boolean cacheInUse = false;
  268. // private boolean stopRequested = false;
  269. //
  270. // private synchronized boolean isCacheInUse() {
  271. // return cacheInUse;
  272. // }
  273. //
  274. // private synchronized void setCacheInUse(boolean val) {
  275. // cacheInUse = val;
  276. // if (val) {
  277. // notifyAll();
  278. // }
  279. // }
  280. //
  281. // private synchronized boolean isStopRequested() {
  282. // return stopRequested;
  283. // }
  284. //
  285. // private synchronized void requestStop() {
  286. // stopRequested = true;
  287. // }
  288. //
  289. // /**
  290. // * Begin prepopulating the map by adding an entry from
  291. // * file.getPath -> file.getCanonicalPath for each file in
  292. // * the list. Do this on a background thread.
  293. // * @param files
  294. // */
  295. // public void prepopulate(final List files) {
  296. // stopRequested = false;
  297. // setCacheInUse(false);
  298. // if (pathMap.size() > MAX_SIZE) {
  299. // pathMap.clear();
  300. // }
  301. // new Thread() {
  302. // public void run() {
  303. // System.out.println("Starting cache population: " +
  304. // System.currentTimeMillis());
  305. // Iterator it = files.iterator();
  306. // while (!isStopRequested() && it.hasNext()) {
  307. // File f = (File)it.next();
  308. // if (pathMap.get(f.getPath()) == null) {
  309. // // may reuse cache across compiles from ides...
  310. // try {
  311. // pathMap.put(f.getPath(),f.getCanonicalPath());
  312. // } catch (IOException ex) {
  313. // pathMap.put(f.getPath(),f.getPath());
  314. // }
  315. // }
  316. // }
  317. // System.out.println("Cached " + files.size());
  318. // setCacheInUse(true);
  319. // System.out.println("Cache populated: " + System.currentTimeMillis());
  320. // }
  321. // }.start();
  322. // }
  323. //
  324. // /**
  325. // * Stop pre-populating the cache - our customers are ready to use it.
  326. // * If there are any cache misses from this point on, we'll populate
  327. // the
  328. // * cache as we go.
  329. // * The handover is done this way to ensure that only one thread is
  330. // ever
  331. // * accessing the cache, and that we minimize synchronization.
  332. // */
  333. // public synchronized void handover() {
  334. // if (!isCacheInUse()) {
  335. // requestStop();
  336. // try {
  337. // while (!isCacheInUse()) wait();
  338. // } catch (InterruptedException intEx) { } // just continue
  339. // }
  340. // }
  341. public String get(File f) {
  342. // if (!cacheInUse) { // unsynchronized test - should never be
  343. // parallel
  344. // // threads at this point
  345. // throw new IllegalStateException(
  346. // "Must take ownership of cache before using by calling " +
  347. // "handover()");
  348. // }
  349. String ret = pathMap.get(f.getPath());
  350. if (ret == null) {
  351. try {
  352. ret = f.getCanonicalPath();
  353. } catch (IOException ioEx) {
  354. ret = f.getPath();
  355. }
  356. pathMap.put(f.getPath(), ret);
  357. if (pathMap.size() > MAX_SIZE) {
  358. pathMap.clear();
  359. }
  360. }
  361. return ret;
  362. }
  363. }
  364. // SECRETAPI
  365. public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile) {
  366. reporting = true;
  367. dumpModel = dModel;
  368. dumpRelationships = dRels;
  369. dumpDeltaProcessing = dDeltaProcessing;
  370. if (deletefile) {
  371. new File(filename).delete();
  372. }
  373. dumpFilename = filename;
  374. }
  375. public static void setReporting(String filename, boolean dModel, boolean dRels, boolean dDeltaProcessing, boolean deletefile,
  376. IModelFilter aFilter) {
  377. setReporting(filename, dModel, dRels, dDeltaProcessing, deletefile);
  378. modelFilter = aFilter;
  379. }
  380. public static boolean isReporting() {
  381. return reporting;
  382. }
  383. public static void setDontReport() {
  384. reporting = false;
  385. dumpDeltaProcessing = false;
  386. dumpModel = false;
  387. dumpRelationships = false;
  388. }
  389. // NB. If the format of this report changes then the model tests
  390. // (@see org.aspectj.systemtest.model.ModelTestCase) will fail in
  391. // their comparison. The tests are assuming that both the model
  392. // and relationship map are reported and as a consequence single
  393. // testcases test that both the model and relationship map are correct.
  394. public void reportModelInfo(String reasonForReport) {
  395. if (!dumpModel && !dumpRelationships) {
  396. return;
  397. }
  398. try {
  399. FileWriter fw = new FileWriter(dumpFilename, true);
  400. BufferedWriter bw = new BufferedWriter(fw);
  401. if (dumpModel) {
  402. bw.write("=== MODEL STATUS REPORT ========= " + reasonForReport + "\n");
  403. dumptree(bw, hierarchy.getRoot(), 0);
  404. bw.write("=== END OF MODEL REPORT =========\n");
  405. }
  406. if (dumpRelationships) {
  407. bw.write("=== RELATIONSHIPS REPORT ========= " + reasonForReport + "\n");
  408. dumprels(bw);
  409. bw.write("=== END OF RELATIONSHIPS REPORT ==\n");
  410. }
  411. Properties p = summarizeModel().getProperties();
  412. Enumeration<Object> pkeyenum = p.keys();
  413. bw.write("=== Properties of the model and relationships map =====\n");
  414. while (pkeyenum.hasMoreElements()) {
  415. String pkey = (String) pkeyenum.nextElement();
  416. bw.write(pkey + "=" + p.getProperty(pkey) + "\n");
  417. }
  418. bw.flush();
  419. fw.close();
  420. } catch (IOException e) {
  421. System.err.println("InternalError: Unable to report model information:");
  422. e.printStackTrace();
  423. }
  424. }
  425. public static void dumptree(Writer w, IProgramElement node, int indent) throws IOException {
  426. for (int i = 0; i < indent; i++) {
  427. w.write(" ");
  428. }
  429. String loc = "";
  430. if (node != null) {
  431. if (node.getSourceLocation() != null) {
  432. loc = node.getSourceLocation().toString();
  433. if (modelFilter != null) {
  434. loc = modelFilter.processFilelocation(loc);
  435. }
  436. }
  437. }
  438. w.write(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc + "\n");
  439. if (node != null) {
  440. for (IProgramElement child : node.getChildren()) {
  441. dumptree(w, child, indent + 2);
  442. }
  443. }
  444. }
  445. public static void dumptree(IProgramElement node, int indent) throws IOException {
  446. for (int i = 0; i < indent; i++) {
  447. System.out.print(" ");
  448. }
  449. String loc = "";
  450. if (node != null) {
  451. if (node.getSourceLocation() != null) {
  452. loc = node.getSourceLocation().toString();
  453. }
  454. }
  455. System.out.println(node + " [" + (node == null ? "null" : node.getKind().toString()) + "] " + loc);
  456. if (node != null) {
  457. for (IProgramElement child : node.getChildren()) {
  458. dumptree(child, indent + 2);
  459. }
  460. }
  461. }
  462. public void dumprels(Writer w) throws IOException {
  463. int ctr = 1;
  464. Set<String> entries = mapper.getEntries();
  465. for (String hid : entries) {
  466. List<IRelationship> rels = mapper.get(hid);
  467. for (IRelationship ir : rels) {
  468. List<String> targets = ir.getTargets();
  469. for (String thid : targets) {
  470. StringBuffer sb = new StringBuffer();
  471. if (modelFilter == null || modelFilter.wantsHandleIds()) {
  472. sb.append("Hid:" + (ctr++) + ":");
  473. }
  474. sb.append("(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") " + thid + "\n");
  475. w.write(sb.toString());
  476. }
  477. }
  478. }
  479. }
  480. private void dumprelsStderr(String key) {
  481. System.err.println("Relationships dump follows: " + key);
  482. int ctr = 1;
  483. Set<String> entries = mapper.getEntries();
  484. for (String hid : entries) {
  485. for (IRelationship ir : mapper.get(hid)) {
  486. List<String> targets = ir.getTargets();
  487. for (String thid : targets) {
  488. System.err.println("Hid:" + (ctr++) + ":(targets=" + targets.size() + ") " + hid + " (" + ir.getName() + ") "
  489. + thid);
  490. }
  491. }
  492. }
  493. System.err.println("End of relationships dump for: " + key);
  494. }
  495. // ===================== DELTA PROCESSING CODE ============== start
  496. // ==========//
  497. /**
  498. * Removes the hierarchy structure for the specified files from the structure model. Returns true if it deleted anything
  499. */
  500. public boolean removeStructureModelForFiles(Writer fw, Collection<File> files) throws IOException {
  501. boolean modelModified = false;
  502. Set<String> deletedNodes = new HashSet<String>();
  503. for (File fileForCompilation : files) {
  504. String correctedPath = getCanonicalFilePath(fileForCompilation);
  505. IProgramElement progElem = (IProgramElement) hierarchy.findInFileMap(correctedPath);
  506. if (progElem != null) {
  507. // Found it, let's remove it
  508. if (dumpDeltaProcessing) {
  509. fw.write("Deleting " + progElem + " node for file " + fileForCompilation + "\n");
  510. }
  511. removeNode(progElem);
  512. lastBuildChanges.add(fileForCompilation);
  513. deletedNodes.add(getCanonicalFilePath(progElem.getSourceLocation().getSourceFile()));
  514. if (!hierarchy.removeFromFileMap(correctedPath)) {
  515. throw new RuntimeException("Whilst repairing model, couldn't remove entry for file: " + correctedPath
  516. + " from the filemap");
  517. }
  518. modelModified = true;
  519. }
  520. }
  521. if (modelModified) {
  522. hierarchy.updateHandleMap(deletedNodes);
  523. }
  524. return modelModified;
  525. }
  526. public void processDelta(Collection<File> files_tobecompiled, Set<File> files_added, Set<File> files_deleted) {
  527. try {
  528. Writer fw = null;
  529. // Are we recording this ?
  530. if (dumpDeltaProcessing) {
  531. FileWriter filew = new FileWriter(dumpFilename, true);
  532. fw = new BufferedWriter(filew);
  533. fw.write("=== Processing delta changes for the model ===\n");
  534. fw.write("Files for compilation:#" + files_tobecompiled.size() + ":" + files_tobecompiled + "\n");
  535. fw.write("Files added :#" + files_added.size() + ":" + files_added + "\n");
  536. fw.write("Files deleted :#" + files_deleted.size() + ":" + files_deleted + "\n");
  537. }
  538. long stime = System.currentTimeMillis();
  539. // Let's remove all the files that are deleted on this compile
  540. removeStructureModelForFiles(fw, files_deleted);
  541. long etime1 = System.currentTimeMillis(); // etime1-stime = time to
  542. // fix up the model
  543. repairRelationships(fw);
  544. long etime2 = System.currentTimeMillis(); // etime2-stime = time to
  545. // repair the
  546. // relationship map
  547. removeStructureModelForFiles(fw, files_tobecompiled);
  548. if (dumpDeltaProcessing) {
  549. fw.write("===== Delta Processing timing ==========\n");
  550. fw.write("Hierarchy=" + (etime1 - stime) + "ms Relationshipmap=" + (etime2 - etime1) + "ms\n");
  551. fw.write("===== Traversal ========================\n");
  552. // fw.write("Source handles processed="+srchandlecounter+"\n");
  553. // fw.write("Target handles processed="+tgthandlecounter+"\n");
  554. fw.write("========================================\n");
  555. fw.flush();
  556. fw.close();
  557. }
  558. reportModelInfo("After delta processing");
  559. } catch (IOException e) {
  560. e.printStackTrace();
  561. }
  562. }
  563. private String getTypeNameFromHandle(String handle, Map<String, String> cache) {
  564. try {
  565. String typename = cache.get(handle);
  566. if (typename != null) {
  567. return typename;
  568. }
  569. // inpath handle - but for which type?
  570. // let's do it the slow way, we can optimize this with a cache perhaps
  571. int hasPackage = handle.indexOf(HandleProviderDelimiter.PACKAGEFRAGMENT.getDelimiter());
  572. int typeLocation = handle.indexOf(HandleProviderDelimiter.TYPE.getDelimiter());
  573. if (typeLocation == -1) {
  574. typeLocation = handle.indexOf(HandleProviderDelimiter.ASPECT_TYPE.getDelimiter());
  575. }
  576. if (typeLocation == -1) {
  577. // unexpected - time to give up
  578. return "";
  579. }
  580. StringBuffer qualifiedTypeNameFromHandle = new StringBuffer();
  581. if (hasPackage != -1) {
  582. int classfileLoc = handle.indexOf(HandleProviderDelimiter.CLASSFILE.getDelimiter(), hasPackage);
  583. qualifiedTypeNameFromHandle.append(handle.substring(hasPackage + 1, classfileLoc));
  584. qualifiedTypeNameFromHandle.append('.');
  585. }
  586. qualifiedTypeNameFromHandle.append(handle.substring(typeLocation + 1));
  587. typename = qualifiedTypeNameFromHandle.toString();
  588. cache.put(handle, typename);
  589. return typename;
  590. } catch (StringIndexOutOfBoundsException sioobe) {
  591. // debug for 330170
  592. System.err.println("Handle processing problem, the handle is: " + handle);
  593. sioobe.printStackTrace(System.err);
  594. return "";
  595. }
  596. }
  597. /**
  598. * two kinds of relationships
  599. *
  600. * A affects B B affectedBy A
  601. *
  602. * Both of these relationships are added when 'B' is modified. Concrete examples are 'advises/advisedby' or
  603. * 'annotates/annotatedby'.
  604. *
  605. * What we need to do is when 'B' is going to be woven, remove all relationships that may reoccur when it is woven. So - remove
  606. * 'affects' relationships where the target is 'B', remove all 'affectedBy' relationships where the source is 'B'.
  607. *
  608. */
  609. public void removeRelationshipsTargettingThisType(String typename) {
  610. boolean debug = false;
  611. if (debug) {
  612. System.err.println(">>removeRelationshipsTargettingThisType " + typename);
  613. }
  614. String pkg = null;
  615. String type = typename;
  616. int lastSep = typename.lastIndexOf('.');
  617. if (lastSep != -1) {
  618. pkg = typename.substring(0, lastSep);
  619. type = typename.substring(lastSep + 1);
  620. }
  621. boolean didsomething = false;
  622. IProgramElement typeNode = hierarchy.findElementForType(pkg, type);
  623. // Reasons for that being null:
  624. // 1. the file has fundamental errors and so doesn't exist in the model
  625. // (-proceedOnError probably forced us to weave)
  626. if (typeNode == null) {
  627. return;
  628. }
  629. Set<String> sourcesToRemove = new HashSet<String>();
  630. Map<String, String> handleToTypenameCache = new HashMap<String, String>();
  631. // Iterate over the source handles in the relationships map, the aim
  632. // here is to remove any 'affected by'
  633. // relationships where the source of the relationship is the specified
  634. // type (since it will be readded
  635. // when the type is woven)
  636. Set<String> sourcehandlesSet = mapper.getEntries();
  637. List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
  638. for (String hid : sourcehandlesSet) {
  639. if (isPhantomHandle(hid)) {
  640. // inpath handle - but for which type?
  641. // TODO promote cache for reuse during one whole model update
  642. if (!getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
  643. continue;
  644. }
  645. }
  646. IProgramElement sourceElement = hierarchy.getElement(hid);
  647. if (sourceElement == null || sameType(hid, sourceElement, typeNode)) {
  648. // worth continuing as there may be a relationship to remove
  649. relationshipsToRemove.clear();
  650. List<IRelationship> relationships = mapper.get(hid);
  651. for (IRelationship relationship : relationships) {
  652. if (relationship.getKind() == IRelationship.Kind.USES_POINTCUT) {
  653. continue; // these relationships are added at compile
  654. }
  655. // time, argh
  656. if (relationship.isAffects()) {
  657. continue; // we want 'affected by' relationships - (e.g.
  658. }
  659. // advised by)
  660. relationshipsToRemove.add(relationship); // all the relationships can
  661. // be removed, regardless of
  662. // the target(s)
  663. }
  664. // Now, were any relationships emptied during that processing
  665. // and so need removing for this source handle
  666. if (relationshipsToRemove.size() > 0) {
  667. didsomething = true;
  668. if (relationshipsToRemove.size() == relationships.size()) {
  669. sourcesToRemove.add(hid);
  670. } else {
  671. for (int i = 0; i < relationshipsToRemove.size(); i++) {
  672. relationships.remove(relationshipsToRemove.get(i));
  673. }
  674. }
  675. }
  676. }
  677. }
  678. // Remove sources that have no valid relationships any more
  679. for (String hid : sourcesToRemove) {
  680. // System.err.println(
  681. // " source handle: all relationships have gone for "+hid);
  682. mapper.removeAll(hid);
  683. IProgramElement ipe = hierarchy.getElement(hid);
  684. if (ipe != null) {
  685. // If the relationship was hanging off a 'code' node, delete it.
  686. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  687. if (debug) {
  688. System.err.println(" source handle: it was code node, removing that as well... code=" + ipe + " parent="
  689. + ipe.getParent());
  690. }
  691. removeSingleNode(ipe);
  692. }
  693. }
  694. }
  695. if (debug) {
  696. dumprelsStderr("after processing 'affectedby'");
  697. }
  698. if (didsomething) { // did we do anything?
  699. sourcesToRemove.clear();
  700. // removing 'affects' relationships
  701. if (debug) {
  702. dumprelsStderr("before processing 'affects'");
  703. }
  704. // Iterate over the source handles in the relationships map
  705. sourcehandlesSet = mapper.getEntries();
  706. for (String hid : sourcehandlesSet) {
  707. relationshipsToRemove.clear();
  708. List<IRelationship> relationships = mapper.get(hid);
  709. for (IRelationship rel : relationships) {
  710. if (rel.getKind() == IRelationship.Kind.USES_POINTCUT) {
  711. continue; // these relationships are added at compile
  712. }
  713. // time, argh
  714. if (!rel.isAffects()) {
  715. continue;
  716. }
  717. List<String> targets = rel.getTargets();
  718. List<String> targetsToRemove = new ArrayList<String>();
  719. // find targets that target the type we are interested in,
  720. // they need removing
  721. for (String targethid : targets) {
  722. if (isPhantomHandle(hid) && !getTypeNameFromHandle(hid, handleToTypenameCache).equals(typename)) {
  723. continue;
  724. }
  725. // Does this point to the same type?
  726. IProgramElement existingTarget = hierarchy.getElement(targethid);
  727. if (existingTarget == null || sameType(targethid, existingTarget, typeNode)) {
  728. targetsToRemove.add(targethid);
  729. }
  730. }
  731. if (targetsToRemove.size() != 0) {
  732. if (targetsToRemove.size() == targets.size()) {
  733. relationshipsToRemove.add(rel);
  734. } else {
  735. // Remove all the targets that are no longer valid
  736. for (String togo : targetsToRemove) {
  737. targets.remove(togo);
  738. }
  739. }
  740. }
  741. }
  742. // Now, were any relationships emptied during that processing
  743. // and so need removing for this source handle
  744. if (relationshipsToRemove.size() > 0) {
  745. // Are we removing *all* of the relationships for this
  746. // source handle?
  747. if (relationshipsToRemove.size() == relationships.size()) {
  748. sourcesToRemove.add(hid);
  749. } else {
  750. for (int i = 0; i < relationshipsToRemove.size(); i++) {
  751. relationships.remove(relationshipsToRemove.get(i));
  752. }
  753. }
  754. }
  755. }
  756. // Remove sources that have no valid relationships any more
  757. for (String hid : sourcesToRemove) {
  758. // System.err.println(
  759. // " source handle: all relationships have gone for "+hid);
  760. mapper.removeAll(hid);
  761. IProgramElement ipe = hierarchy.getElement(hid);
  762. if (ipe != null) {
  763. // If the relationship was hanging off a 'code' node, delete
  764. // it.
  765. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  766. if (debug) {
  767. System.err.println(" source handle: it was code node, removing that as well... code=" + ipe
  768. + " parent=" + ipe.getParent());
  769. }
  770. removeSingleNode(ipe);
  771. }
  772. }
  773. }
  774. if (debug) {
  775. dumprelsStderr("after processing 'affects'");
  776. }
  777. }
  778. if (debug) {
  779. System.err.println("<<removeRelationshipsTargettingThisFile");
  780. }
  781. }
  782. /**
  783. * Return true if the target element is in the type specified.
  784. */
  785. private boolean sameType(String hid, IProgramElement target, IProgramElement type) {
  786. IProgramElement containingType = target;
  787. if (target == null) {
  788. throw new RuntimeException("target can't be null!");
  789. }
  790. if (type == null) {
  791. throw new RuntimeException("type can't be null!");
  792. }
  793. if (target.getKind().isSourceFile() || target.getKind().isFile()) { // isFile() covers pr263487
  794. // @AJ aspect with broken relationship endpoint - we couldn't find
  795. // the real
  796. // endpoint (the declare parents or ITD or similar) so defaulted to
  797. // the
  798. // first line of the source file...
  799. // FRAGILE
  800. // Let's assume the worst, and that it is the same type if the
  801. // source files
  802. // are the same. This will break for multiple top level types in a
  803. // file...
  804. if (target.getSourceLocation() == null) {
  805. return false; // these four possibilities should really be FIXED
  806. }
  807. // so we don't have this situation
  808. if (type.getSourceLocation() == null) {
  809. return false;
  810. }
  811. if (target.getSourceLocation().getSourceFile() == null) {
  812. return false;
  813. }
  814. if (type.getSourceLocation().getSourceFile() == null) {
  815. return false;
  816. }
  817. return (target.getSourceLocation().getSourceFile().equals(type.getSourceLocation().getSourceFile()));
  818. }
  819. try {
  820. while (!containingType.getKind().isType()) {
  821. containingType = containingType.getParent();
  822. }
  823. } catch (Throwable t) {
  824. // Example:
  825. // java.lang.RuntimeException: Exception whilst walking up from target X.class kind=(file)
  826. // hid=(=importProb/binaries<x(X.class)
  827. throw new RuntimeException("Exception whilst walking up from target " + target.toLabelString() + " kind=("
  828. + target.getKind() + ") hid=(" + target.getHandleIdentifier() + ")", t);
  829. }
  830. return (type.equals(containingType));
  831. }
  832. /**
  833. * @param handle a JDT like handle, following the form described in AsmRelationshipProvider.findOrFakeUpNode
  834. * @return true if the handle contains ';' - the char indicating that it is a phantom handle
  835. */
  836. private boolean isPhantomHandle(String handle) {
  837. int phantomMarker = handle.indexOf(HandleProviderDelimiter.PHANTOM.getDelimiter());
  838. return phantomMarker != -1
  839. && handle.charAt(phantomMarker - 1) == HandleProviderDelimiter.PACKAGEFRAGMENTROOT.getDelimiter();
  840. }
  841. /**
  842. * Go through all the relationships in the model, if any endpoints no longer exist (the node it points to has been deleted from
  843. * the model) then delete the relationship.
  844. */
  845. private void repairRelationships(Writer fw) {
  846. try {
  847. // IHierarchy model = AsmManager.getDefault().getHierarchy();
  848. // TODO Speed this code up by making this assumption:
  849. // the only piece of the handle that is interesting is the file
  850. // name. We are working at file granularity, if the
  851. // file does not exist (i.e. its not in the filemap) then any handle
  852. // inside that file cannot exist.
  853. if (dumpDeltaProcessing) {
  854. fw.write("Repairing relationships map:\n");
  855. }
  856. // Now sort out the relationships map
  857. // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
  858. Set<String> sourcesToRemove = new HashSet<String>();
  859. Set<String> nonExistingHandles = new HashSet<String>(); // Cache of handles that we
  860. // *know* are invalid
  861. // int srchandlecounter = 0;
  862. // int tgthandlecounter = 0;
  863. // Iterate over the source handles in the relationships map
  864. Set<String> keyset = mapper.getEntries(); // These are source handles
  865. for (String hid : keyset) {
  866. // srchandlecounter++;
  867. // Do we already know this handle points to nowhere?
  868. if (nonExistingHandles.contains(hid)) {
  869. sourcesToRemove.add(hid);
  870. } else if (!isPhantomHandle(hid)) {
  871. // We better check if it actually exists
  872. IProgramElement existingElement = hierarchy.getElement(hid);
  873. if (dumpDeltaProcessing) {
  874. fw.write("Looking for handle [" + hid + "] in model, found: " + existingElement + "\n");
  875. }
  876. // Did we find it?
  877. if (existingElement == null) {
  878. // No, so delete this relationship
  879. sourcesToRemove.add(hid);
  880. nonExistingHandles.add(hid); // Speed up a bit you swine
  881. } else {
  882. // Ok, so the source is valid, what about the targets?
  883. List<IRelationship> relationships = mapper.get(hid);
  884. List<IRelationship> relationshipsToRemove = new ArrayList<IRelationship>();
  885. // Iterate through the relationships against this source
  886. // handle
  887. for (Iterator<IRelationship> reliter = relationships.iterator(); reliter.hasNext();) {
  888. IRelationship rel = reliter.next();
  889. List<String> targets = rel.getTargets();
  890. List<String> targetsToRemove = new ArrayList<String>();
  891. // Iterate through the targets for this relationship
  892. for (Iterator<String> targetIter = targets.iterator(); targetIter.hasNext();) {
  893. String targethid = targetIter.next();
  894. // tgthandlecounter++;
  895. // Do we already know it doesn't exist?
  896. if (nonExistingHandles.contains(targethid)) {
  897. if (dumpDeltaProcessing) {
  898. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel[" + rel.getName()
  899. + "] does not exist\n");
  900. }
  901. targetsToRemove.add(targethid);
  902. } else if (!isPhantomHandle(targethid)) {
  903. // We better check
  904. IProgramElement existingTarget = hierarchy.getElement(targethid);
  905. if (existingTarget == null) {
  906. if (dumpDeltaProcessing) {
  907. fw.write("Target handle [" + targethid + "] for srchid[" + hid + "]rel["
  908. + rel.getName() + "] does not exist\n");
  909. }
  910. targetsToRemove.add(targethid);
  911. nonExistingHandles.add(targethid);
  912. }
  913. }
  914. }
  915. // Do we have some targets that need removing?
  916. if (targetsToRemove.size() != 0) {
  917. // Are we removing *all* of the targets for this
  918. // relationship (i.e. removing the relationship)
  919. if (targetsToRemove.size() == targets.size()) {
  920. if (dumpDeltaProcessing) {
  921. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  922. + "]: removing it\n");
  923. }
  924. relationshipsToRemove.add(rel);
  925. } else {
  926. // Remove all the targets that are no longer
  927. // valid
  928. for (String togo : targetsToRemove) {
  929. targets.remove(togo);
  930. }
  931. // Should have already been caught above,
  932. // but lets double check ...
  933. if (targets.size() == 0) {
  934. if (dumpDeltaProcessing) {
  935. fw.write("No targets remain for srchid[" + hid + "] rel[" + rel.getName()
  936. + "]: removing it\n");
  937. }
  938. relationshipsToRemove.add(rel); // TODO
  939. // Should
  940. // only
  941. // remove
  942. // this
  943. // relationship
  944. // for
  945. // the
  946. // srchid
  947. // ?
  948. }
  949. }
  950. }
  951. }
  952. // Now, were any relationships emptied during that
  953. // processing and so need removing for this source
  954. // handle
  955. if (relationshipsToRemove.size() > 0) {
  956. // Are we removing *all* of the relationships for
  957. // this source handle?
  958. if (relationshipsToRemove.size() == relationships.size()) {
  959. // We know they are all going to go, so just
  960. // delete the source handle.
  961. sourcesToRemove.add(hid);
  962. } else {
  963. // MEMORY LEAK - we don't remove the
  964. // relationships !!
  965. for (int i = 0; i < relationshipsToRemove.size(); i++) {
  966. IRelationship irel = relationshipsToRemove.get(i);
  967. verifyAssumption(mapper.remove(hid, irel), "Failed to remove relationship " + irel.getName()
  968. + " for shid " + hid);
  969. }
  970. List<IRelationship> rels = mapper.get(hid);
  971. if (rels == null || rels.size() == 0) {
  972. sourcesToRemove.add(hid);
  973. }
  974. }
  975. }
  976. }
  977. }
  978. }
  979. // Remove sources that have no valid relationships any more
  980. for (Iterator<String> srciter = sourcesToRemove.iterator(); srciter.hasNext();) {
  981. String hid = srciter.next();
  982. mapper.removeAll(hid);
  983. IProgramElement ipe = hierarchy.getElement(hid);
  984. if (ipe != null) {
  985. // If the relationship was hanging off a 'code' node, delete
  986. // it.
  987. if (ipe.getKind().equals(IProgramElement.Kind.CODE)) {
  988. // System.err.println("Deleting code node");
  989. removeSingleNode(ipe);
  990. }
  991. }
  992. }
  993. } catch (IOException ioe) {
  994. System.err.println("Failed to repair relationships:");
  995. ioe.printStackTrace();
  996. }
  997. }
  998. /**
  999. * Removes a specified program element from the structure model. We go to the parent of the program element, ask for all its
  1000. * children and remove the node we want to delete from the list of children.
  1001. */
  1002. private void removeSingleNode(IProgramElement progElem) {
  1003. if (progElem == null) {
  1004. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1005. }
  1006. boolean deleteOK = false;
  1007. IProgramElement parent = progElem.getParent();
  1008. List<IProgramElement> kids = parent.getChildren();
  1009. for (int i = 0, max = kids.size(); i < max; i++) {
  1010. if (kids.get(i).equals(progElem)) {
  1011. kids.remove(i);
  1012. deleteOK = true;
  1013. break;
  1014. }
  1015. }
  1016. if (!deleteOK) {
  1017. System.err.println("unexpectedly failed to delete node from model. hid=" + progElem.getHandleIdentifier());
  1018. }
  1019. }
  1020. /**
  1021. * Removes a specified program element from the structure model. Two processing stages:
  1022. * <p>
  1023. * First: We go to the parent of the program element, ask for all its children and remove the node we want to delete from the
  1024. * list of children.
  1025. * <p>
  1026. * Second:We check if that parent has any other children. If it has no other children and it is either a CODE node or a PACKAGE
  1027. * node, we delete it too.
  1028. */
  1029. private void removeNode(IProgramElement progElem) {
  1030. // StringBuffer flightrecorder = new StringBuffer();
  1031. try {
  1032. // flightrecorder.append("In removeNode, about to chuck away: "+
  1033. // progElem+"\n");
  1034. if (progElem == null) {
  1035. throw new IllegalStateException("AsmManager.removeNode(): programElement unexpectedly null");
  1036. }
  1037. // boolean deleteOK = false;
  1038. IProgramElement parent = progElem.getParent();
  1039. // flightrecorder.append("Parent of it is "+parent+"\n");
  1040. List<IProgramElement> kids = parent.getChildren();
  1041. // flightrecorder.append("Which has "+kids.size()+" kids\n");
  1042. for (int i = 0; i < kids.size(); i++) {
  1043. // flightrecorder.append("Comparing with "+kids.get(i)+"\n");
  1044. if (kids.get(i).equals(progElem)) {
  1045. kids.remove(i);
  1046. // flightrecorder.append("Removing it\n");
  1047. // deleteOK=true;
  1048. break;
  1049. }
  1050. }
  1051. // verifyAssumption(deleteOK,flightrecorder.toString());
  1052. // Are there any kids left for this node?
  1053. if (parent.getChildren().size() == 0
  1054. && parent.getParent() != null
  1055. && (parent.getKind().equals(IProgramElement.Kind.CODE) || parent.getKind().equals(IProgramElement.Kind.PACKAGE))) {
  1056. // This node is on its own, we should trim it too *as long as
  1057. // its not a structural node* which we currently check by
  1058. // making sure its a code node
  1059. // We should trim if it
  1060. // System.err.println("Deleting parent:"+parent);
  1061. removeNode(parent);
  1062. }
  1063. } catch (NullPointerException npe) {
  1064. // Occurred when commenting out other 2 ras classes in wsif??
  1065. // reproducable?
  1066. // System.err.println(flightrecorder.toString());
  1067. npe.printStackTrace();
  1068. }
  1069. }
  1070. public static void verifyAssumption(boolean b, String info) {
  1071. if (!b) {
  1072. System.err.println("=========== ASSERTION IS NOT TRUE =========v");
  1073. System.err.println(info);
  1074. Thread.dumpStack();
  1075. System.err.println("=========== ASSERTION IS NOT TRUE =========^");
  1076. throw new RuntimeException("Assertion is false");
  1077. }
  1078. }
  1079. public static void verifyAssumption(boolean b) {
  1080. if (!b) {
  1081. Thread.dumpStack();
  1082. throw new RuntimeException("Assertion is false");
  1083. }
  1084. }
  1085. // ===================== DELTA PROCESSING CODE ============== end
  1086. // ==========//
  1087. /**
  1088. * A ModelInfo object captures basic information about the structure model. It is used for testing and producing debug info.
  1089. */
  1090. public static class ModelInfo {
  1091. private final Hashtable<String, Integer> nodeTypeCount = new Hashtable<String, Integer>();
  1092. private final Properties extraProperties = new Properties();
  1093. private ModelInfo(IHierarchy hierarchy, IRelationshipMap relationshipMap) {
  1094. IProgramElement ipe = hierarchy.getRoot();
  1095. walkModel(ipe);
  1096. recordStat("FileMapSize", new Integer(hierarchy.getFileMapEntrySet().size()).toString());
  1097. recordStat("RelationshipMapSize", new Integer(relationshipMap.getEntries().size()).toString());
  1098. }
  1099. private void walkModel(IProgramElement ipe) {
  1100. countNode(ipe);
  1101. for (IProgramElement child : ipe.getChildren()) {
  1102. walkModel(child);
  1103. }
  1104. }
  1105. private void countNode(IProgramElement ipe) {
  1106. String node = ipe.getKind().toString();
  1107. Integer ctr = nodeTypeCount.get(node);
  1108. if (ctr == null) {
  1109. nodeTypeCount.put(node, new Integer(1));
  1110. } else {
  1111. ctr = new Integer(ctr.intValue() + 1);
  1112. nodeTypeCount.put(node, ctr);
  1113. }
  1114. }
  1115. public String toString() {
  1116. StringBuffer sb = new StringBuffer();
  1117. sb.append("Model node summary:\n");
  1118. Enumeration<String> nodeKeys = nodeTypeCount.keys();
  1119. while (nodeKeys.hasMoreElements()) {
  1120. String key = nodeKeys.nextElement();
  1121. Integer ct = nodeTypeCount.get(key);
  1122. sb.append(key + "=" + ct + "\n");
  1123. }
  1124. sb.append("Model stats:\n");
  1125. Enumeration<Object> ks = extraProperties.keys();
  1126. while (ks.hasMoreElements()) {
  1127. String k = (String) ks.nextElement();
  1128. String v = extraProperties.getProperty(k);
  1129. sb.append(k + "=" + v + "\n");
  1130. }
  1131. return sb.toString();
  1132. }
  1133. public Properties getProperties() {
  1134. Properties p = new Properties();
  1135. for (Map.Entry<String, Integer> entry : nodeTypeCount.entrySet()) {
  1136. p.setProperty(entry.getKey(), entry.getValue().toString());
  1137. }
  1138. p.putAll(extraProperties);
  1139. return p;
  1140. }
  1141. public void recordStat(String string, String string2) {
  1142. extraProperties.setProperty(string, string2);
  1143. }
  1144. }
  1145. public ModelInfo summarizeModel() {
  1146. return new ModelInfo(getHierarchy(), getRelationshipMap());
  1147. }
  1148. /**
  1149. * Set to indicate whether we are currently building a structure model, should be set up front.
  1150. */
  1151. // public static void setCreatingModel(boolean b) {
  1152. // creatingModel = b;
  1153. // }
  1154. //
  1155. // /**
  1156. // * returns true if we are currently generating a structure model, enables guarding of expensive operations on an empty/null
  1157. // * model.
  1158. // */
  1159. // public static boolean isCreatingModel() {
  1160. // return creatingModel;
  1161. // }
  1162. public static void setCompletingTypeBindings(boolean b) {
  1163. completingTypeBindings = b;
  1164. }
  1165. public static boolean isCompletingTypeBindings() {
  1166. return completingTypeBindings;
  1167. }
  1168. // public void setRelationshipMap(IRelationshipMap irm) {
  1169. // mapper = irm;
  1170. // }
  1171. //
  1172. // public void setHierarchy(IHierarchy ih) {
  1173. // hierarchy = ih;
  1174. // }
  1175. public void resetDeltaProcessing() {
  1176. lastBuildChanges.clear();
  1177. aspectsWeavingInLastBuild.clear();
  1178. }
  1179. /**
  1180. * @return the Set of files for which the structure model was modified (they may have been removed or otherwise rebuilt). Set is
  1181. * empty for a full build.
  1182. */
  1183. public Set<File> getModelChangesOnLastBuild() {
  1184. return lastBuildChanges;
  1185. }
  1186. /**
  1187. * @return the Set of aspects that wove files on the last build (either incremental or full build)
  1188. */
  1189. public Set<File> getAspectsWeavingFilesOnLastBuild() {
  1190. return aspectsWeavingInLastBuild;
  1191. }
  1192. public void addAspectInEffectThisBuild(File f) {
  1193. aspectsWeavingInLastBuild.add(f);
  1194. }
  1195. public static void setLastActiveStructureModel(AsmManager structureModel) {
  1196. if (recordingLastActiveStructureModel) {
  1197. lastActiveStructureModel = structureModel;
  1198. }
  1199. }
  1200. public String getHandleElementForInpath(String binaryPath) {
  1201. return inpathMap.get(new File(binaryPath));
  1202. }
  1203. }