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.

AsmHierarchyBuilder.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Mik Kersten revisions, added additional relationships
  12. * Alexandre Vasseur support for @AJ style
  13. * ******************************************************************/
  14. package org.aspectj.ajdt.internal.core.builder;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.util.*;
  18. import org.aspectj.ajdt.internal.compiler.ast.*;
  19. import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment;
  20. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  21. import org.aspectj.asm.*;
  22. import org.aspectj.asm.internal.ProgramElement;
  23. import org.aspectj.bridge.ISourceLocation;
  24. import org.aspectj.bridge.SourceLocation;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IGenericType;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemHandler;
  31. import org.aspectj.util.LangUtil;
  32. import org.aspectj.weaver.*;
  33. import org.aspectj.weaver.patterns.*;
  34. /**
  35. * At each iteration of <CODE>processCompilationUnit</CODE> the declarations for a
  36. * particular compilation unit are added to the hierarchy passed as a a parameter.
  37. * <p>
  38. * Clients who extend this class need to ensure that they do not override any of the existing
  39. * behavior. If they do, the structure model will not be built properly and tools such as IDE
  40. * structure views and ajdoc will fail.
  41. * <p>
  42. * <b>Note:</b> this class is not considered public API and the overridable
  43. * methods are subject to change.
  44. *
  45. * @author Mik Kersten
  46. */
  47. public class AsmHierarchyBuilder extends ASTVisitor {
  48. protected AsmElementFormatter formatter = new AsmElementFormatter();
  49. /**
  50. * Reset for every compilation unit.
  51. */
  52. protected AjBuildConfig buildConfig;
  53. /**
  54. * Reset for every compilation unit.
  55. */
  56. protected Stack stack;
  57. /**
  58. * Reset for every compilation unit.
  59. */
  60. private CompilationResult currCompilationResult;
  61. /**
  62. *
  63. * @param cuDeclaration
  64. * @param buildConfig
  65. * @param structureModel hiearchy to add this unit's declarations to
  66. */
  67. public void buildStructureForCompilationUnit(CompilationUnitDeclaration cuDeclaration, IHierarchy structureModel, AjBuildConfig buildConfig) {
  68. currCompilationResult = cuDeclaration.compilationResult();
  69. LangUtil.throwIaxIfNull(currCompilationResult, "result");
  70. stack = new Stack();
  71. this.buildConfig = buildConfig;
  72. internalBuild(cuDeclaration, structureModel);
  73. // throw new RuntimeException("not implemented");
  74. }
  75. private void internalBuild(CompilationUnitDeclaration unit, IHierarchy structureModel) {
  76. LangUtil.throwIaxIfNull(structureModel, "structureModel");
  77. if (!currCompilationResult.equals(unit.compilationResult())) {
  78. throw new IllegalArgumentException("invalid unit: " + unit);
  79. }
  80. // ---- summary
  81. // add unit to package (or root if no package),
  82. // first removing any duplicate (XXX? removes children if 3 classes in same file?)
  83. // push the node on the stack
  84. // and traverse
  85. // -- create node to add
  86. final File file = new File(new String(unit.getFileName()));
  87. final IProgramElement cuNode;
  88. {
  89. // AMC - use the source start and end from the compilation unit decl
  90. int startLine = getStartLine(unit);
  91. int endLine = getEndLine(unit);
  92. SourceLocation sourceLocation
  93. = new SourceLocation(file, startLine, endLine);
  94. sourceLocation.setOffset(unit.sourceStart);
  95. cuNode = new ProgramElement(
  96. new String(file.getName()),
  97. IProgramElement.Kind.FILE_JAVA,
  98. sourceLocation,
  99. 0,
  100. "",
  101. new ArrayList());
  102. }
  103. cuNode.addChild(new ProgramElement(
  104. "import declarations",
  105. IProgramElement.Kind.IMPORT_REFERENCE,
  106. null,
  107. 0,
  108. "",
  109. new ArrayList()));
  110. final IProgramElement addToNode = genAddToNode(unit, structureModel);
  111. // -- remove duplicates before adding (XXX use them instead?)
  112. if (addToNode!=null && addToNode.getChildren()!=null) {
  113. for (ListIterator itt = addToNode.getChildren().listIterator(); itt.hasNext(); ) {
  114. IProgramElement child = (IProgramElement)itt.next();
  115. ISourceLocation childLoc = child.getSourceLocation();
  116. if (null == childLoc) {
  117. // XXX ok, packages have null source locations
  118. // signal others?
  119. } else if (childLoc.getSourceFile().equals(file)) {
  120. itt.remove();
  121. }
  122. }
  123. }
  124. // -- add and traverse
  125. addToNode.addChild(cuNode);
  126. stack.push(cuNode);
  127. unit.traverse(this, unit.scope);
  128. // -- update file map (XXX do this before traversal?)
  129. try {
  130. structureModel.addToFileMap(file.getCanonicalPath(), cuNode);
  131. } catch (IOException e) {
  132. System.err.println("IOException " + e.getMessage()
  133. + " creating path for " + file );
  134. // XXX signal IOException when canonicalizing file path
  135. }
  136. }
  137. /**
  138. * Get/create the node (package or root) to add to.
  139. */
  140. private IProgramElement genAddToNode(
  141. CompilationUnitDeclaration unit,
  142. IHierarchy structureModel) {
  143. final IProgramElement addToNode;
  144. {
  145. ImportReference currentPackage = unit.currentPackage;
  146. if (null == currentPackage) {
  147. addToNode = structureModel.getRoot();
  148. } else {
  149. String pkgName;
  150. {
  151. StringBuffer nameBuffer = new StringBuffer();
  152. final char[][] importName = currentPackage.getImportName();
  153. final int last = importName.length-1;
  154. for (int i = 0; i < importName.length; i++) {
  155. nameBuffer.append(new String(importName[i]));
  156. if (i < last) {
  157. nameBuffer.append('.');
  158. }
  159. }
  160. pkgName = nameBuffer.toString();
  161. }
  162. IProgramElement pkgNode = null;
  163. if (structureModel!=null && structureModel.getRoot()!=null && structureModel.getRoot().getChildren()!=null) {
  164. for (Iterator it = structureModel.getRoot().getChildren().iterator();
  165. it.hasNext(); ) {
  166. IProgramElement currNode = (IProgramElement)it.next();
  167. if (pkgName.equals(currNode.getName())) {
  168. pkgNode = currNode;
  169. break;
  170. }
  171. }
  172. }
  173. if (pkgNode == null) {
  174. // note packages themselves have no source location
  175. pkgNode = new ProgramElement(
  176. pkgName,
  177. IProgramElement.Kind.PACKAGE,
  178. new ArrayList()
  179. );
  180. structureModel.getRoot().addChild(pkgNode);
  181. }
  182. addToNode = pkgNode;
  183. }
  184. }
  185. return addToNode;
  186. }
  187. public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
  188. String name = new String(typeDeclaration.name);
  189. IProgramElement.Kind kind = IProgramElement.Kind.CLASS;
  190. if (typeDeclaration instanceof AspectDeclaration) kind = IProgramElement.Kind.ASPECT;
  191. else if (typeDeclaration.kind() == IGenericType.INTERFACE_DECL) kind = IProgramElement.Kind.INTERFACE;
  192. else if (typeDeclaration.kind() == IGenericType.ENUM_DECL) kind = IProgramElement.Kind.ENUM;
  193. else if (typeDeclaration.kind() == IGenericType.ANNOTATION_TYPE_DECL) kind = IProgramElement.Kind.ANNOTATION;
  194. //@AJ support
  195. if (typeDeclaration.annotations != null) {
  196. for (int i = 0; i < typeDeclaration.annotations.length; i++) {
  197. Annotation annotation = typeDeclaration.annotations[i];
  198. if (Arrays.equals(annotation.type.getTypeBindingPublic(scope).signature(),
  199. "Lorg/aspectj/lang/annotation/Aspect;".toCharArray())) {
  200. kind = IProgramElement.Kind.ASPECT;
  201. }
  202. }
  203. }
  204. IProgramElement peNode = new ProgramElement(
  205. name,
  206. kind,
  207. makeLocation(typeDeclaration),
  208. typeDeclaration.modifiers,
  209. "",
  210. new ArrayList());
  211. peNode.setSourceSignature(genSourceSignature(typeDeclaration));
  212. peNode.setFormalComment(generateJavadocComment(typeDeclaration));
  213. ((IProgramElement)stack.peek()).addChild(peNode);
  214. stack.push(peNode);
  215. return true;
  216. }
  217. public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) {
  218. stack.pop();
  219. }
  220. // ??? share impl with visit(TypeDeclaration, ..) ?
  221. public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
  222. String name = new String(memberTypeDeclaration.name);
  223. IProgramElement.Kind kind = IProgramElement.Kind.CLASS;
  224. if (memberTypeDeclaration instanceof AspectDeclaration) kind = IProgramElement.Kind.ASPECT;
  225. else if (memberTypeDeclaration.kind() == IGenericType.INTERFACE_DECL) kind = IProgramElement.Kind.INTERFACE;
  226. else if (memberTypeDeclaration.kind() == IGenericType.ENUM_DECL) kind = IProgramElement.Kind.ENUM;
  227. else if (memberTypeDeclaration.kind() == IGenericType.ANNOTATION_TYPE_DECL) kind = IProgramElement.Kind.ANNOTATION;
  228. //@AJ support
  229. if (memberTypeDeclaration.annotations != null) {
  230. for (int i = 0; i < memberTypeDeclaration.annotations.length; i++) {
  231. Annotation annotation = memberTypeDeclaration.annotations[i];
  232. if (Arrays.equals(annotation.type.getTypeBindingPublic(scope).signature(),
  233. "Lorg/aspectj/lang/annotation/Aspect;".toCharArray())) {
  234. kind = IProgramElement.Kind.ASPECT;
  235. }
  236. }
  237. }
  238. IProgramElement peNode = new ProgramElement(
  239. name,
  240. kind,
  241. makeLocation(memberTypeDeclaration),
  242. memberTypeDeclaration.modifiers,
  243. "",
  244. new ArrayList());
  245. peNode.setSourceSignature(genSourceSignature(memberTypeDeclaration));
  246. peNode.setFormalComment(generateJavadocComment(memberTypeDeclaration));
  247. ((IProgramElement)stack.peek()).addChild(peNode);
  248. stack.push(peNode);
  249. return true;
  250. }
  251. public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
  252. stack.pop();
  253. }
  254. public boolean visit(TypeDeclaration memberTypeDeclaration, BlockScope scope) {
  255. String fullName = "<undefined>";
  256. if (memberTypeDeclaration.allocation != null
  257. && memberTypeDeclaration.allocation.type != null) {
  258. // Create a name something like 'new Runnable() {..}'
  259. fullName = "new "+memberTypeDeclaration.allocation.type.toString()+"() {..}";
  260. } else if (memberTypeDeclaration.binding != null
  261. && memberTypeDeclaration.binding.constantPoolName() != null) {
  262. // If we couldn't find a nice name like 'new Runnable() {..}' then use the number after the $
  263. fullName = new String(memberTypeDeclaration.binding.constantPoolName());
  264. int dollar = fullName.indexOf('$');
  265. fullName = fullName.substring(dollar+1);
  266. }
  267. IProgramElement.Kind kind = IProgramElement.Kind.CLASS;
  268. if (memberTypeDeclaration.kind() == IGenericType.INTERFACE_DECL) kind = IProgramElement.Kind.INTERFACE;
  269. else if (memberTypeDeclaration.kind() == IGenericType.ENUM_DECL) kind = IProgramElement.Kind.ENUM;
  270. else if (memberTypeDeclaration.kind() == IGenericType.ANNOTATION_TYPE_DECL) kind = IProgramElement.Kind.ANNOTATION;
  271. //@AJ support
  272. if (memberTypeDeclaration.annotations != null) {
  273. for (int i = 0; i < memberTypeDeclaration.annotations.length; i++) {
  274. Annotation annotation = memberTypeDeclaration.annotations[i];
  275. if (Arrays.equals(annotation.type.getTypeBindingPublic(scope).signature(),
  276. "Lorg/aspectj/lang/annotation/Aspect;".toCharArray())) {
  277. kind = IProgramElement.Kind.ASPECT;
  278. break;
  279. }
  280. }
  281. }
  282. IProgramElement peNode = new ProgramElement(
  283. fullName,
  284. kind,
  285. makeLocation(memberTypeDeclaration),
  286. memberTypeDeclaration.modifiers,
  287. "",
  288. new ArrayList());
  289. peNode.setSourceSignature(genSourceSignature(memberTypeDeclaration));
  290. peNode.setFormalComment(generateJavadocComment(memberTypeDeclaration));
  291. ((IProgramElement)stack.peek()).addChild(peNode);
  292. stack.push(peNode);
  293. return true;
  294. }
  295. public void endVisit(TypeDeclaration memberTypeDeclaration, BlockScope scope) {
  296. stack.pop();
  297. }
  298. private String genSourceSignature(TypeDeclaration typeDeclaration) {
  299. StringBuffer output = new StringBuffer();
  300. typeDeclaration.printHeader(0, output);
  301. return output.toString();
  302. }
  303. private IProgramElement findEnclosingClass(Stack stack) {
  304. for (int i = stack.size()-1; i >= 0; i--) {
  305. IProgramElement pe = (IProgramElement)stack.get(i);
  306. if (pe.getKind() == IProgramElement.Kind.CLASS) {
  307. return pe;
  308. }
  309. }
  310. return (IProgramElement)stack.peek();
  311. }
  312. public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
  313. IProgramElement peNode = null;
  314. // For intertype decls, use the modifiers from the original signature, not the generated method
  315. if (methodDeclaration instanceof InterTypeDeclaration) {
  316. InterTypeDeclaration itd = (InterTypeDeclaration) methodDeclaration;
  317. ResolvedMember sig = itd.getSignature();
  318. peNode = new ProgramElement(
  319. "",
  320. IProgramElement.Kind.ERROR,
  321. makeLocation(methodDeclaration),
  322. (sig!=null?sig.getModifiers():0),
  323. "",
  324. new ArrayList());
  325. } else {
  326. peNode = new ProgramElement(
  327. "",
  328. IProgramElement.Kind.ERROR,
  329. makeLocation(methodDeclaration),
  330. methodDeclaration.modifiers,
  331. "",
  332. new ArrayList());
  333. }
  334. formatter.genLabelAndKind(methodDeclaration, peNode);
  335. genBytecodeInfo(methodDeclaration, peNode);
  336. List namedPointcuts = genNamedPointcuts(methodDeclaration);
  337. addUsesPointcutRelationsForNode(peNode, namedPointcuts, methodDeclaration);
  338. if (methodDeclaration.returnType!=null) {
  339. peNode.setCorrespondingType(methodDeclaration.returnType.toString());
  340. } else {
  341. peNode.setCorrespondingType(null);
  342. }
  343. peNode.setSourceSignature(genSourceSignature(methodDeclaration));
  344. peNode.setFormalComment(generateJavadocComment(methodDeclaration));
  345. // TODO: add return type test
  346. if (peNode.getKind().equals(IProgramElement.Kind.METHOD)) {
  347. if (peNode.toLabelString().equals("main(String[])")
  348. && peNode.getModifiers().contains(IProgramElement.Modifiers.STATIC)
  349. && peNode.getAccessibility().equals(IProgramElement.Accessibility.PUBLIC)) {
  350. ((IProgramElement)stack.peek()).setRunnable(true);
  351. }
  352. }
  353. stack.push(peNode);
  354. return true;
  355. }
  356. private void addUsesPointcutRelationsForNode(IProgramElement peNode, List namedPointcuts, MethodDeclaration declaration) {
  357. for (Iterator it = namedPointcuts.iterator(); it.hasNext();) {
  358. ReferencePointcut rp = (ReferencePointcut) it.next();
  359. ResolvedMember member = getPointcutDeclaration(rp, declaration);
  360. if (member != null) {
  361. IRelationship foreward = AsmManager.getDefault().getRelationshipMap().get(peNode.getHandleIdentifier(), IRelationship.Kind.USES_POINTCUT, "uses pointcut", false, true);
  362. foreward.addTarget(AsmManager.getDefault().getHandleProvider().createHandleIdentifier(member.getSourceLocation()));
  363. IRelationship back = AsmManager.getDefault().getRelationshipMap().get(AsmManager.getDefault().getHandleProvider().createHandleIdentifier(member.getSourceLocation()), IRelationship.Kind.USES_POINTCUT, "pointcut used by", false, true);
  364. back.addTarget(peNode.getHandleIdentifier());
  365. }
  366. }
  367. }
  368. private ResolvedMember getPointcutDeclaration(ReferencePointcut rp, MethodDeclaration declaration) {
  369. World world = ((AjLookupEnvironment)declaration.scope.environment()).factory.getWorld();
  370. TypeX onType = rp.onType;
  371. if (onType == null) {
  372. if (declaration.binding != null) {
  373. Member member = EclipseFactory.makeResolvedMember(declaration.binding);
  374. onType = member.getDeclaringType();
  375. } else {
  376. return null;
  377. }
  378. }
  379. ResolvedMember[] members = onType.getDeclaredPointcuts(world);
  380. if (members != null) {
  381. for (int i = 0; i < members.length; i++) {
  382. if (members[i].getName().equals(rp.name)) {
  383. return members[i];
  384. }
  385. }
  386. }
  387. return null;
  388. }
  389. /**
  390. * @param methodDeclaration
  391. * @return all of the named pointcuts referenced by the PCD of this declaration
  392. */
  393. private List genNamedPointcuts(MethodDeclaration methodDeclaration) {
  394. List pointcuts = new ArrayList();
  395. if (methodDeclaration instanceof AdviceDeclaration) {
  396. if (((AdviceDeclaration)methodDeclaration).pointcutDesignator != null)
  397. addAllNamed(((AdviceDeclaration)methodDeclaration).pointcutDesignator.getPointcut(), pointcuts);
  398. } else if (methodDeclaration instanceof PointcutDeclaration) {
  399. if (((PointcutDeclaration)methodDeclaration).pointcutDesignator != null)
  400. addAllNamed(((PointcutDeclaration)methodDeclaration).pointcutDesignator.getPointcut(), pointcuts);
  401. }
  402. return pointcuts;
  403. }
  404. /**
  405. * @param left
  406. * @param pointcuts accumulator for named pointcuts
  407. */
  408. private void addAllNamed(Pointcut pointcut, List pointcuts) {
  409. if (pointcut == null) return;
  410. if (pointcut instanceof ReferencePointcut) {
  411. ReferencePointcut rp = (ReferencePointcut)pointcut;
  412. pointcuts.add(rp);
  413. } else if (pointcut instanceof AndPointcut) {
  414. AndPointcut ap = (AndPointcut)pointcut;
  415. addAllNamed(ap.getLeft(), pointcuts);
  416. addAllNamed(ap.getRight(), pointcuts);
  417. } else if (pointcut instanceof OrPointcut) {
  418. OrPointcut op = (OrPointcut)pointcut;
  419. addAllNamed(op.getLeft(), pointcuts);
  420. addAllNamed(op.getRight(), pointcuts);
  421. }
  422. }
  423. private String genSourceSignature(MethodDeclaration methodDeclaration) {
  424. StringBuffer output = new StringBuffer();
  425. ASTNode.printModifiers(methodDeclaration.modifiers, output);
  426. methodDeclaration.printReturnType(0, output).append(methodDeclaration.selector).append('(');
  427. if (methodDeclaration.arguments != null) {
  428. for (int i = 0; i < methodDeclaration.arguments.length; i++) {
  429. if (i > 0) output.append(", "); //$NON-NLS-1$
  430. methodDeclaration.arguments[i].print(0, output);
  431. }
  432. }
  433. output.append(')');
  434. if (methodDeclaration.thrownExceptions != null) {
  435. output.append(" throws "); //$NON-NLS-1$
  436. for (int i = 0; i < methodDeclaration.thrownExceptions.length; i++) {
  437. if (i > 0) output.append(", "); //$NON-NLS-1$
  438. methodDeclaration.thrownExceptions[i].print(0, output);
  439. }
  440. }
  441. return output.toString();
  442. }
  443. protected void genBytecodeInfo(MethodDeclaration methodDeclaration, IProgramElement peNode) {
  444. if (methodDeclaration.binding != null) {
  445. String memberName = "";
  446. String memberBytecodeSignature = "";
  447. try {
  448. Member member = EclipseFactory.makeResolvedMember(methodDeclaration.binding);
  449. memberName = member.getName();
  450. memberBytecodeSignature = member.getSignature();
  451. } catch (BCException bce) { // bad type name
  452. memberName = "<undefined>";
  453. } catch (NullPointerException npe) {
  454. memberName = "<undefined>";
  455. }
  456. peNode.setBytecodeName(memberName);
  457. peNode.setBytecodeSignature(memberBytecodeSignature);
  458. }
  459. ((IProgramElement)stack.peek()).addChild(peNode);
  460. }
  461. public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) {
  462. stack.pop();
  463. }
  464. public boolean visit(ImportReference importRef, CompilationUnitScope scope) {
  465. int dotIndex = importRef.toString().lastIndexOf('.');
  466. String currPackageImport = "";
  467. if (dotIndex != -1) {
  468. currPackageImport = importRef.toString().substring(0, dotIndex);
  469. }
  470. if (!((ProgramElement)stack.peek()).getPackageName().equals(currPackageImport)) {
  471. IProgramElement peNode = new ProgramElement(
  472. new String(importRef.toString()),
  473. IProgramElement.Kind.IMPORT_REFERENCE,
  474. makeLocation(importRef),
  475. 0,
  476. "",
  477. new ArrayList());
  478. ProgramElement imports = (ProgramElement)((ProgramElement)stack.peek()).getChildren().get(0);
  479. imports.addChild(0, peNode);
  480. stack.push(peNode);
  481. }
  482. return true;
  483. }
  484. public void endVisit(ImportReference importRef, CompilationUnitScope scope) {
  485. int dotIndex = importRef.toString().lastIndexOf('.');
  486. String currPackageImport = "";
  487. if (dotIndex != -1) {
  488. currPackageImport = importRef.toString().substring(0, dotIndex);
  489. }
  490. if (!((ProgramElement)stack.peek()).getPackageName().equals(currPackageImport)) {
  491. stack.pop();
  492. }
  493. }
  494. public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
  495. IProgramElement peNode = null;
  496. if (fieldDeclaration.type == null) { // The field represents an enum value
  497. peNode = new ProgramElement(
  498. new String(fieldDeclaration.name),IProgramElement.Kind.ENUM_VALUE,
  499. makeLocation(fieldDeclaration), fieldDeclaration.modifiers,
  500. "", new ArrayList());
  501. peNode.setCorrespondingType(fieldDeclaration.binding.type.debugName());
  502. } else {
  503. peNode = new ProgramElement(
  504. new String(fieldDeclaration.name),IProgramElement.Kind.FIELD,
  505. makeLocation(fieldDeclaration), fieldDeclaration.modifiers,
  506. "", new ArrayList());
  507. peNode.setCorrespondingType(fieldDeclaration.type.toString());
  508. }
  509. peNode.setSourceSignature(genSourceSignature(fieldDeclaration));
  510. peNode.setFormalComment(generateJavadocComment(fieldDeclaration));
  511. ((IProgramElement)stack.peek()).addChild(peNode);
  512. stack.push(peNode);
  513. return true;
  514. }
  515. public void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope) {
  516. stack.pop();
  517. }
  518. /**
  519. * Checks if comments should be added to the model before generating.
  520. */
  521. protected String generateJavadocComment(ASTNode astNode) {
  522. if (buildConfig != null && !buildConfig.isGenerateJavadocsInModelMode()) return null;
  523. StringBuffer sb = new StringBuffer(); // !!! specify length?
  524. boolean completed = false;
  525. int startIndex = -1;
  526. if (astNode instanceof MethodDeclaration) {
  527. startIndex = ((MethodDeclaration)astNode).declarationSourceStart;
  528. } else if (astNode instanceof FieldDeclaration) {
  529. startIndex = ((FieldDeclaration)astNode).declarationSourceStart;
  530. } else if (astNode instanceof TypeDeclaration) {
  531. startIndex = ((TypeDeclaration)astNode).declarationSourceStart;
  532. }
  533. if (startIndex == -1) {
  534. return null;
  535. } else if (currCompilationResult.compilationUnit.getContents()[startIndex] == '/' // look for /**
  536. && currCompilationResult.compilationUnit.getContents()[startIndex+1] == '*'
  537. && currCompilationResult.compilationUnit.getContents()[startIndex+2] == '*') {
  538. for (int i = startIndex; i < astNode.sourceStart && !completed; i++) {
  539. char curr = currCompilationResult.compilationUnit.getContents()[i];
  540. if (curr == '/' && sb.length() > 2 && sb.charAt(sb.length()-1) == '*') completed = true; // found */
  541. sb.append(currCompilationResult.compilationUnit.getContents()[i]);
  542. }
  543. return sb.toString();
  544. } else {
  545. return null;
  546. }
  547. }
  548. /**
  549. * Doesn't print qualified allocation expressions.
  550. */
  551. protected String genSourceSignature(FieldDeclaration fieldDeclaration) {
  552. StringBuffer output = new StringBuffer();
  553. if (fieldDeclaration.type == null) { // This is an enum value
  554. output.append(fieldDeclaration.name); // ajh02: the "," or ";" has to be put on by whatever uses the sourceSignature
  555. return output.toString();
  556. } else {
  557. FieldDeclaration.printModifiers(fieldDeclaration.modifiers, output);
  558. fieldDeclaration.type.print(0, output).append(' ').append(fieldDeclaration.name);
  559. }
  560. if (fieldDeclaration.initialization != null
  561. && !(fieldDeclaration.initialization instanceof QualifiedAllocationExpression)) {
  562. output.append(" = "); //$NON-NLS-1$
  563. if (fieldDeclaration.initialization instanceof ExtendedStringLiteral) {
  564. output.append("\"<extended string literal>\"");
  565. } else {
  566. fieldDeclaration.initialization.printExpression(0, output);
  567. }
  568. }
  569. output.append(';');
  570. return output.toString();
  571. }
  572. // public boolean visit(ImportReference importRef, CompilationUnitScope scope) {
  573. // ProgramElementNode peNode = new ProgramElementNode(
  574. // new String(importRef.toString()),
  575. // ProgramElementNode.Kind.,
  576. // makeLocation(importRef),
  577. // 0,
  578. // "",
  579. // new ArrayList());
  580. // ((IProgramElement)stack.peek()).addChild(0, peNode);
  581. // stack.push(peNode);
  582. // return true;
  583. // }
  584. // public void endVisit(ImportReference importRef,CompilationUnitScope scope) {
  585. // stack.pop();
  586. // }
  587. public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
  588. if (constructorDeclaration.isDefaultConstructor) {
  589. stack.push(null); // a little wierd but does the job
  590. return true;
  591. }
  592. StringBuffer argumentsSignature = new StringBuffer();
  593. argumentsSignature.append("(");
  594. if (constructorDeclaration.arguments!=null) {
  595. for (int i = 0;i<constructorDeclaration.arguments.length;i++) {
  596. argumentsSignature.append(constructorDeclaration.arguments[i].type);
  597. if (i+1<constructorDeclaration.arguments.length) argumentsSignature.append(",");
  598. }
  599. }
  600. argumentsSignature.append(")");
  601. IProgramElement peNode = new ProgramElement(
  602. new String(constructorDeclaration.selector)+argumentsSignature,
  603. IProgramElement.Kind.CONSTRUCTOR,
  604. makeLocation(constructorDeclaration),
  605. constructorDeclaration.modifiers,
  606. "",
  607. new ArrayList());
  608. peNode.setModifiers(constructorDeclaration.modifiers);
  609. peNode.setSourceSignature(genSourceSignature(constructorDeclaration));
  610. // Fix to enable us to anchor things from ctor nodes
  611. if (constructorDeclaration.binding != null) {
  612. String memberName = "";
  613. String memberBytecodeSignature = "";
  614. try {
  615. Member member = EclipseFactory.makeResolvedMember(constructorDeclaration.binding);
  616. memberName = member.getName();
  617. memberBytecodeSignature = member.getSignature();
  618. } catch (BCException bce) { // bad type name
  619. memberName = "<undefined>";
  620. } catch (NullPointerException npe) {
  621. memberName = "<undefined>";
  622. }
  623. peNode.setBytecodeName(memberName);
  624. peNode.setBytecodeSignature(memberBytecodeSignature);
  625. }
  626. ((IProgramElement)stack.peek()).addChild(peNode);
  627. stack.push(peNode);
  628. return true;
  629. }
  630. public void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
  631. stack.pop();
  632. }
  633. private String genSourceSignature(ConstructorDeclaration constructorDeclaration) {
  634. StringBuffer output = new StringBuffer();
  635. ASTNode.printModifiers(constructorDeclaration.modifiers, output);
  636. output.append(constructorDeclaration.selector).append('(');
  637. if (constructorDeclaration.arguments != null) {
  638. for (int i = 0; i < constructorDeclaration.arguments.length; i++) {
  639. if (i > 0) output.append(", "); //$NON-NLS-1$
  640. constructorDeclaration.arguments[i].print(0, output);
  641. }
  642. }
  643. output.append(')');
  644. if (constructorDeclaration.thrownExceptions != null) {
  645. output.append(" throws "); //$NON-NLS-1$
  646. for (int i = 0; i < constructorDeclaration.thrownExceptions.length; i++) {
  647. if (i > 0) output.append(", "); //$NON-NLS-1$
  648. constructorDeclaration.thrownExceptions[i].print(0, output);
  649. }
  650. }
  651. return output.toString();
  652. }
  653. // public boolean visit(Clinit clinit, ClassScope scope) {
  654. // ProgramElementNode peNode = new ProgramElementNode(
  655. // "<clinit>",
  656. // ProgramElementNode.Kind.INITIALIZER,
  657. // makeLocation(clinit),
  658. // clinit.modifiers,
  659. // "",
  660. // new ArrayList());
  661. // ((IProgramElement)stack.peek()).addChild(peNode);
  662. // stack.push(peNode);
  663. // return false;
  664. // }
  665. // public void endVisit(Clinit clinit, ClassScope scope) {
  666. // stack.pop();
  667. // }
  668. /** This method works-around an odd traverse implementation on Initializer
  669. */
  670. private Initializer inInitializer = null;
  671. public boolean visit(Initializer initializer, MethodScope scope) {
  672. if (initializer == inInitializer) return false;
  673. inInitializer = initializer;
  674. IProgramElement peNode = new ProgramElement(
  675. "...",
  676. IProgramElement.Kind.INITIALIZER,
  677. makeLocation(initializer),
  678. initializer.modifiers,
  679. "",
  680. new ArrayList());
  681. ((IProgramElement)stack.peek()).addChild(peNode);
  682. stack.push(peNode);
  683. initializer.block.traverse(this, scope);
  684. stack.pop();
  685. return false;
  686. }
  687. // ??? handle non-existant files
  688. protected ISourceLocation makeLocation(ASTNode node) {
  689. String fileName = "";
  690. if (currCompilationResult.getFileName() != null) {
  691. fileName = new String(currCompilationResult.getFileName());
  692. }
  693. // AMC - different strategies based on node kind
  694. int startLine = getStartLine(node);
  695. int endLine = getEndLine(node);
  696. SourceLocation loc = null;
  697. if ( startLine <= endLine ) {
  698. // found a valid end line for this node...
  699. loc = new SourceLocation(new File(fileName), startLine, endLine);
  700. loc.setOffset(node.sourceStart);
  701. } else {
  702. loc = new SourceLocation(new File(fileName), startLine);
  703. loc.setOffset(node.sourceStart);
  704. }
  705. return loc;
  706. }
  707. // AMC - overloaded set of methods to get start and end lines for
  708. // various ASTNode types. They have no common ancestor in the
  709. // hierarchy!!
  710. protected int getStartLine( ASTNode n){
  711. // if ( n instanceof AbstractVariableDeclaration ) return getStartLine( (AbstractVariableDeclaration)n);
  712. // if ( n instanceof AbstractMethodDeclaration ) return getStartLine( (AbstractMethodDeclaration)n);
  713. // if ( n instanceof TypeDeclaration ) return getStartLine( (TypeDeclaration)n);
  714. return ProblemHandler.searchLineNumber(
  715. currCompilationResult.lineSeparatorPositions,
  716. n.sourceStart);
  717. }
  718. // AMC - overloaded set of methods to get start and end lines for
  719. // various ASTNode types. They have no common ancestor in the
  720. // hierarchy!!
  721. protected int getEndLine( ASTNode n){
  722. if ( n instanceof AbstractVariableDeclaration ) return getEndLine( (AbstractVariableDeclaration)n);
  723. if ( n instanceof AbstractMethodDeclaration ) return getEndLine( (AbstractMethodDeclaration)n);
  724. if ( n instanceof TypeDeclaration ) return getEndLine( (TypeDeclaration)n);
  725. return ProblemHandler.searchLineNumber(
  726. currCompilationResult.lineSeparatorPositions,
  727. n.sourceEnd);
  728. }
  729. // AMC - overloaded set of methods to get start and end lines for
  730. // various ASTNode types. They have no common ancestor in the
  731. // hierarchy!!
  732. // private int getStartLine( AbstractVariableDeclaration avd ) {
  733. // return ProblemHandler.searchLineNumber(
  734. // currCompilationResult.lineSeparatorPositions,
  735. // avd.declarationSourceStart);
  736. // }
  737. // AMC - overloaded set of methods to get start and end lines for
  738. // various ASTNode types. They have no common ancestor in the
  739. // hierarchy!!
  740. private int getEndLine( AbstractVariableDeclaration avd ){
  741. return ProblemHandler.searchLineNumber(
  742. currCompilationResult.lineSeparatorPositions,
  743. avd.declarationSourceEnd);
  744. }
  745. // AMC - overloaded set of methods to get start and end lines for
  746. // various ASTNode types. They have no common ancestor in the
  747. // hierarchy!!
  748. // private int getStartLine( AbstractMethodDeclaration amd ){
  749. // return ProblemHandler.searchLineNumber(
  750. // currCompilationResult.lineSeparatorPositions,
  751. // amd.declarationSourceStart);
  752. // }
  753. // AMC - overloaded set of methods to get start and end lines for
  754. // various ASTNode types. They have no common ancestor in the
  755. // hierarchy!!
  756. private int getEndLine( AbstractMethodDeclaration amd) {
  757. return ProblemHandler.searchLineNumber(
  758. currCompilationResult.lineSeparatorPositions,
  759. amd.declarationSourceEnd);
  760. }
  761. // AMC - overloaded set of methods to get start and end lines for
  762. // various ASTNode types. They have no common ancestor in the
  763. // hierarchy!!
  764. // private int getStartLine( TypeDeclaration td ){
  765. // return ProblemHandler.searchLineNumber(
  766. // currCompilationResult.lineSeparatorPositions,
  767. // td.declarationSourceStart);
  768. // }
  769. // AMC - overloaded set of methods to get start and end lines for
  770. // various ASTNode types. They have no common ancestor in the
  771. // hierarchy!!
  772. private int getEndLine( TypeDeclaration td){
  773. return ProblemHandler.searchLineNumber(
  774. currCompilationResult.lineSeparatorPositions,
  775. td.declarationSourceEnd);
  776. }
  777. }