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.

Ajc164Tests.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*******************************************************************************
  2. * Copyright (c) 2008 Contributors
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * Andy Clement - initial API and implementation
  10. *******************************************************************************/
  11. package org.aspectj.systemtest.ajc164;
  12. import java.io.File;
  13. import java.io.PrintWriter;
  14. import java.util.ArrayList;
  15. import java.util.Collections;
  16. import java.util.Comparator;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import junit.framework.Test;
  20. import org.aspectj.apache.bcel.classfile.JavaClass;
  21. import org.aspectj.apache.bcel.classfile.LocalVariable;
  22. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  23. import org.aspectj.apache.bcel.classfile.Method;
  24. import org.aspectj.apache.bcel.util.ClassPath;
  25. import org.aspectj.apache.bcel.util.SyntheticRepository;
  26. import org.aspectj.asm.AsmManager;
  27. import org.aspectj.asm.IHierarchy;
  28. import org.aspectj.asm.IProgramElement;
  29. import org.aspectj.asm.IRelationship;
  30. import org.aspectj.testing.XMLBasedAjcTestCase;
  31. public class Ajc164Tests extends org.aspectj.testing.XMLBasedAjcTestCase {
  32. public void testAnnoStyleLong_pr266564() {
  33. runTest("annotation style long");
  34. }
  35. public void testAnnoStyleLong_pr266564_2() {
  36. runTest("annotation style long - 2");
  37. }
  38. public void testUnusedPrivateWarning_pr266420() {
  39. runTest("unused private warning");
  40. }
  41. public void testUnusedPrivateWarning_pr266420_2() {
  42. runTest("unused private warning - 2");
  43. }
  44. public void testUnusedPrivateWarning_pr266420_3() {
  45. runTest("unused private warning - 3");
  46. }
  47. /**
  48. * This test program can be used to compare handles for faulted in binary aspects with handles that would be used if the aspect
  49. * was available as source. There are two compile steps in the xml for the test - commenting out the first will allow the source
  50. * handles to be seen, leaving it in will switch to binary. Effectively the only difference should be that in the binary case
  51. * the handles are prefixed 'binaries'.
  52. */
  53. public void testItdsAspectPathModel_pr265729_1() {
  54. runTest("aspectpath model");
  55. AsmManager model = AsmManager.lastActiveStructureModel;
  56. IHierarchy top = model.getHierarchy();
  57. printModel(model);
  58. IProgramElement ipe = null;
  59. // ITD METHOD
  60. // should be the ITD method from the binary aspect:
  61. // public Color Orange.getColor() { return Color.orange; }
  62. ipe = top.findElementForType("demo", "Orange");
  63. assertNotNull(ipe);
  64. assertEquals("<demo{Orange.java[Orange", ipe.getHandleIdentifier());
  65. IRelationship ir = (IRelationship) model.getRelationshipMap().get(ipe).get(0);
  66. String itdMethodHandle = (String) ir.getTargets().get(0);
  67. // handle when all source: <{Aspect.java}Aspect)Orange.getColor
  68. assertEquals("/binaries<{Aspect.java}Aspect)Orange.getColor", itdMethodHandle);
  69. IProgramElement itdpe = model.getHierarchy().findElementForHandle(itdMethodHandle);
  70. assertEquals("java.awt.Color", itdpe.getCorrespondingType(true));
  71. // ITD FIELD
  72. // should be the ITD field from the binary aspect:
  73. // public Color Strawberry.color
  74. ipe = top.findElementForType("demo", "Strawberry");
  75. assertNotNull(ipe);
  76. assertEquals("<demo{Strawberry.java[Strawberry", ipe.getHandleIdentifier());
  77. ir = (IRelationship) model.getRelationshipMap().get(ipe).get(0);
  78. String itdFieldHandle = (String) ir.getTargets().get(0);
  79. // source handle <{Aspect.java}Aspect)Strawberry.color
  80. assertEquals("/binaries<{Aspect.java}Aspect)Strawberry.color", itdFieldHandle);
  81. IProgramElement itdfpe = model.getHierarchy().findElementForHandle(itdMethodHandle);
  82. assertEquals("java.awt.Color", itdfpe.getCorrespondingType(true));
  83. // ITD CONSTRUCTOR
  84. // /binaries< Aspect.java}Aspect)java.awt.Color demo.Strawberry.color
  85. ipe = top.findElementForType("demo", "Fruit");
  86. assertNotNull(ipe);
  87. assertEquals("<demo{Fruit.java[Fruit", ipe.getHandleIdentifier());
  88. ir = (IRelationship) model.getRelationshipMap().get(ipe).get(0);
  89. String itdCtorHandle = (String) ir.getTargets().get(0);
  90. // source handle <{Aspect.java}Aspect)Fruit.Fruit_new)QColor;)QString;
  91. assertEquals("/binaries<{Aspect.java}Aspect)Fruit.Fruit_new)QColor;)QString;", itdCtorHandle);
  92. IProgramElement itdcpe = model.getHierarchy().findElementForHandle(itdCtorHandle);
  93. List ptypes = itdcpe.getParameterTypes();
  94. assertEquals("java.awt.Color", new String((char[]) ptypes.get(0)));
  95. assertEquals("java.lang.String", new String((char[]) ptypes.get(1)));
  96. }
  97. private void printModel(AsmManager model) {
  98. try {
  99. model.dumptree(model.getHierarchy().getRoot(), 0);
  100. model.dumprels(new PrintWriter(System.out));
  101. } catch (Exception e) {
  102. }
  103. }
  104. public void testGenericsAopXml_pr266220() {
  105. runTest("generics and aop.xml");
  106. }
  107. public void testOptimizingIf_pr266165_1() {
  108. runTest("optimizing if for constant reference - 1");
  109. }
  110. public void testOptimizingIf_pr266165_2() {
  111. runTest("optimizing if for constant reference - 2");
  112. }
  113. public void testOptimizingIf_pr266165_3() {
  114. runTest("optimizing if for constant reference - 3");
  115. }
  116. public void testOptimizingIf_pr266165_4() {
  117. runTest("optimizing if for constant reference - 4");
  118. }
  119. // public void testAnnoInherited_pr265695() {
  120. // runTest("anno inherited");
  121. // }
  122. //
  123. // public void testAnnoInherited_pr265695_2() {
  124. // runTest("new syntax for inherited anno - 1");
  125. // }
  126. //
  127. // public void testAnnoInherited_pr265695_3() {
  128. // runTest("new syntax for inherited anno - 3");
  129. // }
  130. public void testParserProblemSubArrayPatterns_pr148508() {
  131. runTest("parser problem for array subtypes");
  132. }
  133. public void testVarargs_pr265418() {
  134. runTest("varargs");
  135. }
  136. public void testIncorrectDateResolution_pr265360() {
  137. runTest("incorrect resolution of Date");
  138. }
  139. public void testDualPreClinit_pr233032() {
  140. runTest("dual preClinit");
  141. }
  142. public void testHandles_pr263310() {
  143. runTest("inner handles");
  144. IHierarchy top = AsmManager.lastActiveStructureModel.getHierarchy();
  145. IProgramElement ipe = null;
  146. ipe = findElementAtLine(top.getRoot(), 13);
  147. assertEquals("<p{HandleTestingAspect.java}HandleTestingAspect[InnerClass}InnerInnerAspect|1", ipe.getHandleIdentifier());
  148. // ipe = findElementAtLine(top.getRoot(), 29);
  149. // assertEquals("<x*OverrideOptions.aj}OverrideOptions&around!2",
  150. // ipe.getHandleIdentifier());
  151. }
  152. public void testHandles_pr263666() {
  153. runTest("around advice handles");
  154. IHierarchy top = AsmManager.lastActiveStructureModel.getHierarchy();
  155. IProgramElement ipe = null;
  156. ipe = findElementAtLine(top.getRoot(), 22);
  157. assertEquals("<x*OverrideOptions.aj}OverrideOptions&around", ipe.getHandleIdentifier());
  158. ipe = findElementAtLine(top.getRoot(), 29);
  159. assertEquals("<x*OverrideOptions.aj}OverrideOptions&around!2", ipe.getHandleIdentifier());
  160. }
  161. // Only one of two aspects named
  162. public void testAopConfig1() {
  163. runTest("aop config - 1");
  164. }
  165. // Only one of two aspects named - and named one is scoped to only affect
  166. // one type
  167. public void testAopConfig2() {
  168. runTest("aop config - 2");
  169. }
  170. // Invalid scope specified - cannot be parsed as type pattern
  171. public void testAopConfig3() {
  172. runTest("aop config - 3");
  173. }
  174. public void testAjcThisNotRead() {
  175. runTest("ajcthis not read");
  176. }
  177. public void testRecursiveCflow() {
  178. runTest("recursive cflow");
  179. }
  180. public void testAnnoDecprecedence_pr256779() {
  181. runTest("anno decprecedence");
  182. }
  183. //
  184. public void testBrokenLVT_pr194314_1() throws Exception {
  185. runTest("broken lvt - 1");
  186. Method m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "Service"), "method_aroundBody1$advice");
  187. if (m.getLocalVariableTable() == null) {
  188. fail("Local variable table should not be null");
  189. }
  190. // Method:
  191. // private static final void method_aroundBody1$advice(Service, long,
  192. // JoinPoint, ServiceInterceptor, ProceedingJoinPoint);
  193. LocalVariable[] lvt = m.getLocalVariableTable().getLocalVariableTable();
  194. assertEquals(7, lvt.length); // no aroundClosure compared to second
  195. // version of this test
  196. assertEquals("LService; this(0) start=0 len=86", stringify(m.getLocalVariableTable(), 0));
  197. assertEquals("J l(1) start=0 len=86", stringify(m.getLocalVariableTable(), 1));
  198. assertEquals("Lorg/aspectj/lang/JoinPoint; thisJoinPoint(3) start=0 len=86", stringify(m.getLocalVariableTable(), 2));
  199. assertEquals("LServiceInterceptor; ajc$aspectInstance(4) start=0 len=86", stringify(m.getLocalVariableTable(), 3));
  200. assertEquals("Lorg/aspectj/lang/ProceedingJoinPoint; pjp(5) start=0 len=86", stringify(m.getLocalVariableTable(), 4));
  201. assertEquals("[Ljava/lang/Object; args(6) start=9 len=77", stringify(m.getLocalVariableTable(), 5));
  202. assertEquals("J id(7) start=21 len=65", stringify(m.getLocalVariableTable(), 6));
  203. }
  204. public void testBrokenLVT_pr194314_2() throws Exception {
  205. runTest("broken lvt - 2");
  206. Method m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "Service"), "method_aroundBody1$advice");
  207. if (m.getLocalVariableTable() == null) {
  208. fail("Local variable table should not be null");
  209. }
  210. System.out.println(m.getLocalVariableTable());
  211. LocalVariable[] lvt = m.getLocalVariableTable().getLocalVariableTable();
  212. assertEquals(8, lvt.length);
  213. // private static final void method_aroundBody1$advice(Service, long,
  214. // JoinPoint, ServiceInterceptorCodeStyle, AroundClosure,
  215. // JoinPoint);
  216. assertEquals("LService; this(0) start=0 len=68", stringify(m.getLocalVariableTable(), 0));
  217. assertEquals("J l(1) start=0 len=68", stringify(m.getLocalVariableTable(), 1));
  218. assertEquals("Lorg/aspectj/lang/JoinPoint; thisJoinPoint(3) start=0 len=68", stringify(m.getLocalVariableTable(), 2));
  219. assertEquals("LServiceInterceptorCodeStyle; ajc$aspectInstance(4) start=0 len=68", stringify(m.getLocalVariableTable(), 3));
  220. assertEquals("Lorg/aspectj/runtime/internal/AroundClosure; ajc$aroundClosure(5) start=0 len=68", stringify(m
  221. .getLocalVariableTable(), 4));
  222. assertEquals("Lorg/aspectj/lang/JoinPoint; thisJoinPoint(6) start=0 len=68", stringify(m.getLocalVariableTable(), 5));
  223. assertEquals("[Ljava/lang/Object; args(7) start=9 len=59", stringify(m.getLocalVariableTable(), 6));
  224. assertEquals("J id(8) start=21 len=47", stringify(m.getLocalVariableTable(), 7));
  225. }
  226. /**
  227. * This test checks that local variable table for the interMethodDispatcher is built correctly, for the related code see
  228. * IntertypeMethodDeclaration.generateDispatchMethod(). It checks non-static and static ITDs. Once the information here is
  229. * correct then around advice on ITDs can also be correct.
  230. */
  231. public void testBrokenLVT_pr194314_3() throws Exception {
  232. runTest("broken lvt - 3");
  233. // Check intermethoddispatchers have the lvts correct
  234. // first ITD: public void I.foo(String s,int i,String[] ss) {}
  235. Method m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "X"), "ajc$interMethodDispatch1$X$I$foo");
  236. LocalVariableTable lvt = m.getLocalVariableTable();
  237. assertNotNull(lvt);
  238. assertEquals("LI; ajc$this_(0) start=0 len=10", stringify(lvt, 0));
  239. assertEquals("Ljava/lang/String; s(1) start=0 len=10", stringify(lvt, 1));
  240. assertEquals("I i(2) start=0 len=10", stringify(lvt, 2));
  241. assertEquals("[Ljava/lang/String; ss(3) start=0 len=10", stringify(lvt, 3));
  242. // second ITD: public void I.fooStatic(Long l,int i,String[] ss) {}
  243. m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "X"), "ajc$interMethodDispatch1$X$C$fooStatic");
  244. lvt = m.getLocalVariableTable();
  245. assertNotNull(lvt);
  246. assertEquals("J l(0) start=0 len=7", stringify(lvt, 0));
  247. assertEquals("I i(2) start=0 len=7", stringify(lvt, 1));
  248. assertEquals("[Ljava/lang/String; ss(3) start=0 len=7", stringify(lvt, 2));
  249. // Now let's check the around advice on the calls to those ITDs
  250. // non-static:
  251. m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "C"), "foo_aroundBody1$advice");
  252. lvt = m.getLocalVariableTable();
  253. assertNotNull(lvt);
  254. assertEquals("LC; this(0) start=0 len=0", stringify(lvt, 0));
  255. assertEquals("LI; target(1) start=0 len=0", stringify(lvt, 1));
  256. assertEquals("Ljava/lang/String; s(2) start=0 len=0", stringify(lvt, 2));
  257. assertEquals("I i(3) start=0 len=0", stringify(lvt, 3));
  258. assertEquals("[Ljava/lang/String; ss(4) start=0 len=0", stringify(lvt, 4));
  259. assertEquals("LX; ajc$aspectInstance(5) start=0 len=0", stringify(lvt, 5));
  260. assertEquals("Lorg/aspectj/runtime/internal/AroundClosure; ajc$aroundClosure(6) start=0 len=0", stringify(lvt, 6));
  261. // static:
  262. m = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "C"), "fooStatic_aroundBody3$advice");
  263. lvt = m.getLocalVariableTable();
  264. assertNotNull(lvt);
  265. assertEquals("LC; this(0) start=0 len=0", stringify(lvt, 0));
  266. assertEquals("J l(1) start=0 len=0", stringify(lvt, 1));
  267. assertEquals("I i(3) start=0 len=0", stringify(lvt, 2));
  268. assertEquals("[Ljava/lang/String; ss(4) start=0 len=0", stringify(lvt, 3));
  269. assertEquals("LX; ajc$aspectInstance(5) start=0 len=0", stringify(lvt, 4));
  270. assertEquals("Lorg/aspectj/runtime/internal/AroundClosure; ajc$aroundClosure(6) start=0 len=0", stringify(lvt, 5));
  271. }
  272. // Single piece of advice on before execution of a method with a this and a
  273. // parameter
  274. public void testDebuggingBeforeAdvice_pr262509() {
  275. runTest("debugging before advice");
  276. Method method = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "Foo"), "foo");
  277. assertEquals("LFoo; this(0) start=0 len=13", stringify(method.getLocalVariableTable(), 0));
  278. assertEquals("LBar; bar(1) start=0 len=13", stringify(method.getLocalVariableTable(), 1));
  279. }
  280. // Single piece of advice on before execution of a method with a this and a
  281. // parameter and other various locals within it
  282. public void testDebuggingBeforeAdvice_pr262509_2() {
  283. // Compile with -preserveAllLocals
  284. runTest("debugging before advice - 2");
  285. Method method = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "Foo2"), "foo");
  286. // System.out.println(stringify(method.getLocalVariableTable()));
  287. List l = sortedLocalVariables(method.getLocalVariableTable());
  288. assertEquals("LBar; bar(1) start=0 len=34", stringify(l, 0));
  289. assertEquals("Ljava/lang/Exception; e(3) start=29 len=4", stringify(l, 1));
  290. assertEquals("LFoo2; this(0) start=0 len=34", stringify(l, 4));
  291. assertEquals("Ljava/lang/String; s(2) start=15 len=19", stringify(l, 2));
  292. assertEquals("Ljava/lang/String; s2(3) start=18 len=10", stringify(l, 3));
  293. }
  294. /**
  295. * Sort it by name then start position
  296. */
  297. private List sortedLocalVariables(LocalVariableTable lvt) {
  298. List l = new ArrayList();
  299. StringBuffer sb = new StringBuffer();
  300. LocalVariable lv[] = lvt.getLocalVariableTable();
  301. for (int i = 0; i < lv.length; i++) {
  302. LocalVariable lvEntry = lv[i];
  303. l.add(lvEntry);
  304. }
  305. Collections.sort(l, new MyComparator());
  306. return l;
  307. }
  308. private static class MyComparator implements Comparator {
  309. public int compare(Object o1, Object o2) {
  310. LocalVariable l1 = (LocalVariable) o1;
  311. LocalVariable l2 = (LocalVariable) o2;
  312. if (l1.getName().equals(l2.getName())) {
  313. return l1.getStartPC() - l2.getStartPC();
  314. } else {
  315. return l1.getName().compareTo(l2.getName());
  316. }
  317. }
  318. }
  319. // Two pieces of advice on before execution of a method with a this and a
  320. // parameter and another local within it
  321. public void testDebuggingBeforeAdvice_pr262509_3() {
  322. // Compile with -preserveAllLocals
  323. runTest("debugging before advice - 3");
  324. Method method = getMethodFromClass(getClassFrom(ajc.getSandboxDirectory(), "Foo3"), "foo");
  325. System.out.println(stringify(method.getLocalVariableTable()));
  326. assertEquals("LFoo3; this(0) start=0 len=35", stringify(method.getLocalVariableTable(), 0));
  327. assertEquals("LBar; bar(1) start=0 len=35", stringify(method.getLocalVariableTable(), 1));
  328. assertEquals("Ljava/lang/Exception; e(2) start=30 len=4", stringify(method.getLocalVariableTable(), 2));
  329. }
  330. public void testRogueErrors_pr246393_1() {
  331. runTest("rogue errors - 1");
  332. }
  333. // public void testNameClash_pr262257() {
  334. // runTest("name clash");
  335. // fail("incomplete");
  336. // }
  337. public void testCompilingSpring_pr260384() {
  338. runTest("compiling spring");
  339. }
  340. public void testCompilingSpring_pr260384_2() {
  341. runTest("compiling spring - 2");
  342. }
  343. public void testCompilingSpring_pr260384_3() {
  344. runTest("compiling spring - 3");
  345. }
  346. public void testCompilingSpring_pr260384_4() {
  347. runTest("compiling spring - 4");
  348. }
  349. public void testAtAspectJDecp_pr164016() {
  350. runTest("ataspectj decp 164016");
  351. }
  352. public void testAtAspectJDecp_pr258788() {
  353. runTest("ataspectj decp 258788");
  354. }
  355. // ---
  356. public static Test suite() {
  357. return XMLBasedAjcTestCase.loadSuite(Ajc164Tests.class);
  358. }
  359. protected File getSpecFile() {
  360. return new File("../tests/src/org/aspectj/systemtest/ajc164/ajc164.xml");
  361. }
  362. private SyntheticRepository createRepos(File cpentry) {
  363. ClassPath cp = new ClassPath(cpentry + File.pathSeparator + System.getProperty("java.class.path"));
  364. return SyntheticRepository.getInstance(cp);
  365. }
  366. private JavaClass getClassFrom(File where, String clazzname) {
  367. try {
  368. SyntheticRepository repos = createRepos(where);
  369. return repos.loadClass(clazzname);
  370. } catch (ClassNotFoundException cnfe) {
  371. throw new RuntimeException("Failed to find class " + clazzname + " at " + where.toString());
  372. }
  373. }
  374. private Method getMethodFromClass(JavaClass clazz, String methodName) {
  375. Method[] meths = clazz.getMethods();
  376. for (int i = 0; i < meths.length; i++) {
  377. Method method = meths[i];
  378. if (method.getName().equals(methodName)) {
  379. return meths[i];
  380. }
  381. }
  382. return null;
  383. }
  384. private String stringify(LocalVariableTable lvt, int slotIndex) {
  385. LocalVariable lv[] = lvt.getLocalVariableTable();
  386. LocalVariable lvEntry = lv[slotIndex];
  387. StringBuffer sb = new StringBuffer();
  388. sb.append(lvEntry.getSignature()).append(" ").append(lvEntry.getName()).append("(").append(lvEntry.getIndex()).append(
  389. ") start=").append(lvEntry.getStartPC()).append(" len=").append(lvEntry.getLength());
  390. return sb.toString();
  391. }
  392. private String stringify(List l, int slotIndex) {
  393. LocalVariable lvEntry = (LocalVariable) l.get(slotIndex);
  394. StringBuffer sb = new StringBuffer();
  395. sb.append(lvEntry.getSignature()).append(" ").append(lvEntry.getName()).append("(").append(lvEntry.getIndex()).append(
  396. ") start=").append(lvEntry.getStartPC()).append(" len=").append(lvEntry.getLength());
  397. return sb.toString();
  398. }
  399. private String stringify(LocalVariableTable lvt) {
  400. StringBuffer sb = new StringBuffer();
  401. sb.append("LocalVariableTable. Entries=#" + lvt.getTableLength()).append("\n");
  402. LocalVariable lv[] = lvt.getLocalVariableTable();
  403. for (int i = 0; i < lv.length; i++) {
  404. LocalVariable lvEntry = lv[i];
  405. sb.append(lvEntry.getSignature()).append(" ").append(lvEntry.getName()).append("(").append(lvEntry.getIndex()).append(
  406. ") start=").append(lvEntry.getStartPC()).append(" len=").append(lvEntry.getLength()).append("\n");
  407. }
  408. return sb.toString();
  409. }
  410. private IProgramElement findElementAtLine(IProgramElement whereToLook, int line) {
  411. if (whereToLook == null) {
  412. return null;
  413. }
  414. if (whereToLook.getSourceLocation() != null && whereToLook.getSourceLocation().getLine() == line) {
  415. return whereToLook;
  416. }
  417. List kids = whereToLook.getChildren();
  418. for (Iterator iterator = kids.iterator(); iterator.hasNext();) {
  419. IProgramElement object = (IProgramElement) iterator.next();
  420. if (object.getSourceLocation() != null && object.getSourceLocation().getLine() == line) {
  421. return object;
  422. }
  423. IProgramElement gotSomething = findElementAtLine(object, line);
  424. if (gotSomething != null) {
  425. return gotSomething;
  426. }
  427. }
  428. return null;
  429. }
  430. }