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.

RootDocImpl.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /* -*- Mode: JDE; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  3. * This file is part of the debugger and core tools for the AspectJ(tm)
  4. * programming language; see http://aspectj.org
  5. *
  6. * The contents of this file are subject to the Mozilla Public License
  7. * Version 1.1 (the "License"); you may not use this file except in
  8. * compliance with the License. You may obtain a copy of the License at
  9. * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is AspectJ.
  17. *
  18. * The Initial Developer of the Original Code is Xerox Corporation. Portions
  19. * created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
  20. * All Rights Reserved.
  21. */
  22. package org.aspectj.tools.ajdoc;
  23. import org.aspectj.compiler.base.ast.TypeDec;
  24. import org.aspectj.compiler.base.ast.World;
  25. import com.sun.javadoc.ClassDoc;
  26. import com.sun.javadoc.PackageDoc;
  27. import java.util.ArrayList;
  28. import java.util.Collection;
  29. import java.util.Collections;
  30. import java.util.HashSet;
  31. import java.util.Iterator;
  32. import java.util.List;
  33. import java.util.Set;
  34. /**
  35. * This is responsible for constituting the world
  36. * of specified[classes|packages] and all classes.
  37. * It ensures that any classes compiled are included (if appropriate)
  38. * but does not ensure that linked classes are.
  39. */
  40. public class RootDocImpl
  41. extends DocImpl
  42. implements org.aspectj.ajdoc.RootDoc,
  43. Quietable {
  44. /** The collection of packages specified to be documented. */
  45. private final Set specifiedPackages;
  46. /** The collection of types specified to be documented. */
  47. private final Set specifiedClasses;
  48. /** The collection of packages visible in this world. */
  49. private final Set packages = new HashSet();
  50. /** The collection of classes visible in this world. */
  51. private final Set classes = new HashSet();
  52. /** The documentation options. */
  53. private final String[][] options;
  54. /** The World delegate. */
  55. private final World world;
  56. /** Determines whether items are included */
  57. private final AccessChecker filter;
  58. public RootDocImpl(World world, String[][] options,
  59. Collection pkgnames, Collection classnames,
  60. AccessChecker filter) {
  61. this.world = world;
  62. this.options = options;
  63. this.filter = (null != filter ? filter : AccessChecker.PUBLIC);
  64. Set set = createSpecifiedPackages(pkgnames);
  65. specifiedPackages = set; // modifiable to prune empty packages
  66. set = createSpecifiedClasses(classnames);
  67. specifiedClasses = Collections.unmodifiableSet(set);
  68. // adds all world classes and packages for classes and packages
  69. // addWorldTypes(); // todo re-enable as needed
  70. // make sure specified are added - should duplicate world
  71. // but should come after since packages are removed if empty
  72. addSpecifiedPackages();
  73. addSpecifiedClasses();
  74. setupDominatesRelations();
  75. ensureWorldInclusion();
  76. }
  77. /* ------------------------------------------------------------
  78. * Implementation of RootDoc
  79. * ------------------------------------------------------------
  80. */
  81. /**
  82. * Returns the classes visible in this world.
  83. *
  84. * @return an array of ClassDoc representing the visible
  85. * classes in this world.
  86. */
  87. public ClassDoc[] classes() {
  88. return (ClassDoc[])classes.toArray
  89. (new org.aspectj.ajdoc.ClassDoc[classes.size()]);
  90. }
  91. /**
  92. * Returns a type visible in this world
  93. * for the name <code>className</code>. If there is
  94. * no visible package, this method will return
  95. * <code>null</code>.
  96. *
  97. * @return an instance of ClassDoc in this world
  98. * that corresponds to <code>className</code>.
  99. * <code>null</code> is returned if there exists
  100. * no such visible type named <code>className</code>.
  101. */
  102. public ClassDoc classNamed(String className) {
  103. ClassDoc[] docs = classes();
  104. for (int i = 0; i < docs.length; i++) {
  105. ClassDoc doc = docs[i];
  106. if (doc.name().equals(className)) {
  107. return doc;
  108. }
  109. }
  110. return null;
  111. }
  112. /**
  113. * Returns a package visible in this world
  114. * for the name <code>packageName</code>. If there is
  115. * no visible package, this method will return
  116. * <code>null</code>.
  117. *
  118. * @return an instance of PackageDoc in this world
  119. * that corresponds to <code>packageName</code>.
  120. * <code>null</code> is returned if there exists
  121. * no such visible package named <code>packageName</code>.
  122. */
  123. public PackageDoc packageNamed(String packageName) {
  124. for (Iterator i = packages.iterator(); i.hasNext();) {
  125. PackageDoc doc = (PackageDoc)i.next();
  126. if (doc.name().equals(packageName)) {
  127. return doc;
  128. }
  129. }
  130. return null;
  131. }
  132. /**
  133. * Returns the underlying world.
  134. *
  135. * @return an instance of World representing all
  136. * the CompilationUnits.
  137. */
  138. public World world() {
  139. return world;
  140. }
  141. /**
  142. * Returns the documentation options.
  143. *
  144. * @return the documentation options.
  145. */
  146. public String[][] options() {
  147. return options;
  148. }
  149. /**
  150. * Returns the types specified to be documented.
  151. *
  152. * @return an array of ClassDoc representing the
  153. * specified types.
  154. */
  155. public ClassDoc[] specifiedClasses() {
  156. return (ClassDoc[])specifiedClasses.toArray
  157. (new org.aspectj.ajdoc.ClassDoc[specifiedClasses.size()]);
  158. }
  159. /**
  160. * Returns the packages specified to be documented.
  161. *
  162. * @return an array of PackageDoc representing the
  163. * specified packages.
  164. */
  165. public PackageDoc[] specifiedPackages() {
  166. return (PackageDoc[])specifiedPackages.toArray
  167. (new org.aspectj.ajdoc.PackageDoc[specifiedPackages.size()]);
  168. }
  169. /* ------------------------------------------------------------
  170. * Implementation of Quietable
  171. * ------------------------------------------------------------
  172. */
  173. /** <code>true</code> when notices should be printed. */
  174. private boolean notice = true;
  175. /** Supresses output notices. */
  176. public void quiet() { notice = false; }
  177. /** Allows output notices. */
  178. public void speak() { notice = true; }
  179. /* ------------------------------------------------------------
  180. * Implementation of DocErrReporter
  181. * ------------------------------------------------------------
  182. */
  183. /**
  184. * Prints the error message <code>msg</code> using
  185. * the current error handler.
  186. *
  187. * @param msg the error message.
  188. */
  189. public void printError(String msg) {
  190. err().printError(msg);
  191. }
  192. /**
  193. * Prints the notice message <code>msg</code> using
  194. * the current error handler.
  195. *
  196. * @param msg the notice message.
  197. */
  198. public void printNotice(String msg) {
  199. if (notice) err().printNotice(msg);
  200. }
  201. /**
  202. * Prints the warning message <code>msg</code> using
  203. * the current error handler.
  204. *
  205. * @param msg the warning message.
  206. */
  207. public void printWarning(String msg) {
  208. err().printWarning(msg);
  209. }
  210. /* ------------------------------------------------------------
  211. * Implementation of Doc
  212. * ------------------------------------------------------------
  213. */
  214. /**
  215. * Returns <code>null</code>.
  216. *
  217. * @return <code>null</code>.
  218. */
  219. public String name() {
  220. return "who knows???";
  221. }
  222. /* ------------------------------------------------------------
  223. * Helper methods
  224. * ------------------------------------------------------------
  225. */
  226. /**
  227. * Creates only PackageDocs that were included on the command
  228. * line, even if they are empty. Should be used only for
  229. * specifiedPackages.
  230. */
  231. private HashSet createSpecifiedPackages(Collection pkgnames) {
  232. HashSet result = new HashSet();
  233. for (Iterator i = pkgnames.iterator(); i.hasNext();) {
  234. String pkgname = (String)i.next();
  235. PackageDocImpl pkgdoc = PackageDocImpl.getPackageDoc(pkgname);
  236. pkgdoc.setIncluded(true);
  237. result.add(pkgdoc);
  238. }
  239. return result;
  240. }
  241. private void addWorldTypes() {
  242. for (Iterator i = world.getTypes().iterator(); i.hasNext();) {
  243. TypeDec td = (TypeDec)i.next();
  244. ClassDocImpl cd = ClassDocImpl.getInstance(td);
  245. addClass(cd);
  246. cd.setIncluded(filter.canAccess(td));
  247. }
  248. }
  249. /**
  250. * Creates only ClassDocs that were included on the command
  251. * line, and then only if they pass the filter.
  252. * Should be used only for specifiedClasses.
  253. * todo: createClasses uses to use all classes if no names
  254. */
  255. private HashSet createSpecifiedClasses(Collection classnames) {
  256. HashSet result = new HashSet();
  257. if (classnames != null) {
  258. for (Iterator i = classnames.iterator(); i.hasNext();) {
  259. String classname = (String)i.next();
  260. for (Iterator j = world.getTypes().iterator(); j.hasNext();) {
  261. TypeDec td = (TypeDec)j.next();
  262. if (filter.canAccess(td)) {
  263. ClassDoc cd = ClassDocImpl.getInstance(td);
  264. if (cd.qualifiedName().equals(classname)) {
  265. result.add(cd);
  266. // add inner classes since not specified explicitly
  267. ClassDoc[] inners = cd.innerClasses(); // no cycles, right?
  268. if (null != inners) {
  269. for (int l = 0; l < inners.length; l++) {
  270. result.add(inners[l]);
  271. }
  272. }
  273. break;
  274. }
  275. }
  276. }
  277. // todo: warn if class specified but not in world?
  278. }
  279. }
  280. return result;
  281. }
  282. private void addSpecifiedClasses() {
  283. for (Iterator i = new ArrayList(specifiedClasses).iterator(); i.hasNext();) {
  284. ClassDoc cd = (ClassDoc)i.next();
  285. addClass(cd);
  286. }
  287. }
  288. private void addSpecifiedPackages() {
  289. for (Iterator i = new ArrayList(specifiedPackages).iterator(); i.hasNext();) {
  290. PackageDoc pd = (PackageDoc)i.next();
  291. ClassDoc[] allClasses = pd.allClasses();
  292. if (allClasses.length == 0) {
  293. specifiedPackages.remove(pd);
  294. } else {
  295. for (int j = 0; j < allClasses.length; j++) {
  296. addClass(allClasses[j]);
  297. }
  298. }
  299. }
  300. }
  301. /**
  302. * If filter accepts this ClassDoc,
  303. * Add it and and inner classes to classes
  304. * and add package to packages.
  305. */
  306. private void addClass(ClassDoc cd) {
  307. if (null == cd) return;
  308. ClassDocImpl impl = (ClassDocImpl) cd;
  309. if (filter.canAccess(impl.typeDec())
  310. && (!classes.contains(impl))) {
  311. impl.setIncluded(true);
  312. classes.add(impl);
  313. packages.add(impl.containingPackage());
  314. ClassDoc[] inners = impl.innerClasses();
  315. for (int i = 0; i < inners.length; i++) {
  316. addClass(inners[i]);
  317. }
  318. } // todo: flag classes not added?
  319. }
  320. /** Read all classes to find any dominates relations */
  321. private void setupDominatesRelations() {
  322. // Find just the aspects
  323. List aspects = new ArrayList();
  324. ClassDoc[] classes = classes();
  325. for (int i = 0; i < classes.length; i++) {
  326. ClassDocImpl cd = (ClassDocImpl)classes[i];
  327. if (cd.isAspect()) {
  328. aspects.add(cd);
  329. }
  330. }
  331. // Iterate over the aspects, if
  332. for (Iterator i = aspects.iterator(); i.hasNext();) {
  333. AspectDocImpl aspect1 = (AspectDocImpl)i.next();
  334. for (Iterator j = aspects.iterator(); j.hasNext();) {
  335. AspectDocImpl aspect2 = (AspectDocImpl)j.next();
  336. if (aspect1.dominates(aspect2)) {
  337. aspect1.addDominatee(aspect2);
  338. aspect2.addDominator(aspect1);
  339. }
  340. }
  341. }
  342. }
  343. /**
  344. * Ensure compiled classes are included if they pass the filter
  345. * and excluded otherwise.
  346. * todo: The set of types available includes the world plus reachable
  347. * types from there; I would like to exclude the reachable ones,
  348. * but do not know how.
  349. */
  350. private void ensureWorldInclusion() {
  351. for (Iterator i = world.getTypes().iterator(); i.hasNext();) {
  352. TypeDec td = (TypeDec)i.next();
  353. ClassDocImpl cd = ClassDocImpl.getInstance(td);
  354. boolean isIncluded = cd.isIncluded();
  355. // todo: update to consider enclosing class privileges
  356. boolean shouldInclude = filter.canAccess(td);
  357. if (shouldInclude != isIncluded) {
  358. cd.setIncluded(shouldInclude);
  359. }
  360. }
  361. }
  362. }