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.

InterTypeMemberFinder.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /* *******************************************************************
  2. * Copyright (c) 2002,2005 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. * PARC initial implementation
  11. * Andy Clement - upgrade to support fields targetting generic types
  12. * ******************************************************************/
  13. package org.aspectj.ajdt.internal.compiler.lookup;
  14. import java.lang.reflect.Modifier;
  15. import java.util.ArrayList;
  16. import java.util.Arrays;
  17. import java.util.HashSet;
  18. import java.util.List;
  19. import java.util.Set;
  20. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  21. import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.IMemberFinder;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
  34. /**
  35. * The member finder looks after intertype declared members on a type, there is one member finder per type that was hit by an ITD.
  36. */
  37. public class InterTypeMemberFinder implements IMemberFinder {
  38. private List<FieldBinding> interTypeFields = new ArrayList<>();
  39. private List<MethodBinding> interTypeMethods = new ArrayList<>();
  40. public SourceTypeBinding sourceTypeBinding;
  41. @Override
  42. public FieldBinding getField(SourceTypeBinding sourceTypeBinding, char[] fieldName, InvocationSite site, Scope scope) {
  43. FieldBinding retField = sourceTypeBinding.getFieldBase(fieldName, true); // XXX may need to get the correct value for second
  44. // parameter in the future (see #55341)
  45. if (interTypeFields.isEmpty()) {
  46. return retField;
  47. }
  48. int fieldLength = fieldName.length;
  49. for (FieldBinding field : interTypeFields) {
  50. if (field.name.length == fieldLength && CharOperation.prefixEquals(field.name, fieldName)) {
  51. retField = resolveConflicts(sourceTypeBinding, retField, field, site, scope);
  52. }
  53. }
  54. return retField;
  55. }
  56. private FieldBinding resolveConflicts(SourceTypeBinding sourceTypeBinding, FieldBinding retField, FieldBinding field,
  57. InvocationSite site, Scope scope) {
  58. if (retField == null) {
  59. return field;
  60. }
  61. if (site != null) {
  62. if (!field.canBeSeenBy(sourceTypeBinding, site, scope)) {
  63. return retField;
  64. }
  65. if (!retField.canBeSeenBy(sourceTypeBinding, site, scope)) {
  66. return field;
  67. }
  68. }
  69. // XXX need dominates check on aspects
  70. return new ProblemFieldBinding(retField.declaringClass, retField.name, IProblem.AmbiguousField);// ProblemReporter.Ambiguous);
  71. }
  72. // private void reportConflicts(SourceTypeBinding sourceTypeBinding,
  73. // MethodBinding m1, MethodBinding m2)
  74. // {
  75. // if (m1 == m2) {
  76. // System.err.println("odd that we're ecomparing the same: " + m1);
  77. // return;
  78. // }
  79. //
  80. // if (!m1.areParametersEqual(m2)) return;
  81. // if (m1 instanceof InterTypeMethodBinding) {
  82. // if (m2 instanceof InterTypeMethodBinding) {
  83. // reportConflictsBoth(sourceTypeBinding,
  84. // (InterTypeMethodBinding)m1,
  85. // (InterTypeMethodBinding)m2);
  86. // } else {
  87. // reportConflictsOne(sourceTypeBinding,
  88. // (InterTypeMethodBinding)m1,
  89. // m2);
  90. // }
  91. // } else if (m2 instanceof InterTypeMethodBinding) {
  92. // reportConflictsOne(sourceTypeBinding,
  93. // (InterTypeMethodBinding)m2,
  94. // m1);
  95. // } else {
  96. // reportConflictsNone(sourceTypeBinding,
  97. // m2,
  98. // m1);
  99. // }
  100. // }
  101. // private void reportConflicts(
  102. // SourceTypeBinding sourceTypeBinding,
  103. // MethodBinding m1,
  104. // MethodBinding m2)
  105. // {
  106. // //System.err.println("compare: " + m1 + " with " + m2);
  107. //
  108. // if (m1 == m2) {
  109. // System.err.println("odd that we're ecomparing the same: " + m1);
  110. // return;
  111. // }
  112. //
  113. // if (!m1.areParametersEqual(m2)) return;
  114. //
  115. // //System.err.println("t1: " + getTargetType(m1) + ", " + getTargetType(m2));
  116. //
  117. // if (getTargetType(m1) != getTargetType(m2)) return;
  118. //
  119. // if (m1.declaringClass == m2.declaringClass) {
  120. // duplicateMethodBinding(m1, m2);
  121. // return;
  122. // }
  123. //
  124. //
  125. // if (m1.isPublic() || m2.isPublic()) {
  126. // duplicateMethodBinding(m1, m2);
  127. // return;
  128. // }
  129. //
  130. // // handle the wierd case where the aspect is a subtype of the target
  131. // if (m2.isProtected()) {
  132. // if (m2.declaringClass.isSuperclassOf(m1.declaringClass)) {
  133. // duplicateMethodBinding(m1, m2);
  134. // }
  135. // // don't return because we also want to do the package test
  136. // }
  137. //
  138. // if (!m1.isPrivate() || !m2.isPrivate()) {
  139. // // at least package visible
  140. // if (m1.declaringClass.getPackage() == m2.declaringClass.getPackage()) {
  141. // duplicateMethodBinding(m1, m2);
  142. // }
  143. // return;
  144. // }
  145. //
  146. // //XXX think about inner types some day
  147. // }
  148. // //
  149. private boolean isVisible(MethodBinding m1, ReferenceBinding s) {
  150. if (m1.declaringClass == s) {
  151. return true;
  152. }
  153. if (m1.isPublic()) {
  154. return true;
  155. }
  156. // don't need to handle protected
  157. // if (m1.isProtected()) {
  158. if (!m1.isPrivate()) {
  159. // at least package visible
  160. return (m1.declaringClass.getPackage() == s.getPackage());
  161. }
  162. return false;
  163. }
  164. //
  165. // private void duplicateMethodBinding(MethodBinding m1, MethodBinding m2) {
  166. // ReferenceBinding t1 = m1.declaringClass;
  167. // ReferenceBinding t2 = m2.declaringClass;
  168. //
  169. //
  170. //
  171. //
  172. //
  173. //
  174. // if (!(t1 instanceof SourceTypeBinding) || !(t2 instanceof SourceTypeBinding)) {
  175. // throw new RuntimeException("unimplemented");
  176. // }
  177. //
  178. // SourceTypeBinding s1 = (SourceTypeBinding)t1;
  179. // SourceTypeBinding s2 = (SourceTypeBinding)t2;
  180. //
  181. // if (m1.sourceMethod() != null) {
  182. // s1.scope.problemReporter().duplicateMethodInType(s2, m1.sourceMethod());
  183. // }
  184. // if (m2.sourceMethod() != null) {
  185. // s2.scope.problemReporter().duplicateMethodInType(s1, m2.sourceMethod());
  186. // }
  187. // }
  188. // private void reportConflictsNone(
  189. // SourceTypeBinding sourceTypeBinding,
  190. // MethodBinding m2,
  191. // MethodBinding m1)
  192. // {
  193. // throw new RuntimeException("not possible");
  194. // }
  195. // ReferenceBinding t1 = getDeclaringClass(m1);
  196. // //.declaringClass;
  197. // ReferenceBinding t2 = getDeclaringClass(m2);
  198. // //.declaringClass;
  199. //
  200. // if (t1 == t2) {
  201. // AbstractMethodDeclaration methodDecl = m2.sourceMethod(); // cannot be retrieved after binding is lost
  202. // System.err.println("duplicate: " + t1 + ", " + t2);
  203. // sourceTypeBinding.scope.problemReporter().duplicateMethodInType(sourceTypeBinding, methodDecl);
  204. // methodDecl.binding = null;
  205. // //methods[m] = null; //XXX duplicate problem reports
  206. // return;
  207. // }
  208. //
  209. // if (!(t1 instanceof SourceTypeBinding) || !(t2 instanceof SourceTypeBinding)) {
  210. // throw new RuntimeException("unimplemented");
  211. // }
  212. //
  213. // SourceTypeBinding s1 = (SourceTypeBinding)t1;
  214. // SourceTypeBinding s2 = (SourceTypeBinding)t2;
  215. //
  216. //
  217. // if (m1.canBeSeenBy(s1, null, s2.scope) || m2.canBeSeenBy(s2, null, s1.scope)) {
  218. // s1.scope.problemReporter().duplicateMethodInType(s2, m1.sourceMethod());
  219. // s2.scope.problemReporter().duplicateMethodInType(s1, m2.sourceMethod());
  220. // }
  221. // }
  222. // private ReferenceBinding getTargetType(MethodBinding m2) {
  223. // if (m2 instanceof InterTypeMethodBinding) {
  224. // return ((InterTypeMethodBinding)m2).getTargetType();
  225. // }
  226. //
  227. // return m2.declaringClass;
  228. // }
  229. // find all of my methods, including ITDs
  230. // PLUS: any public ITDs made on interfaces that I implement
  231. @Override
  232. public MethodBinding[] methods(SourceTypeBinding sourceTypeBinding) {
  233. MethodBinding[] orig = sourceTypeBinding.methodsBase();
  234. // if (interTypeMethods.isEmpty()) return orig;
  235. List<MethodBinding> ret = new ArrayList<>(Arrays.asList(orig));
  236. for (MethodBinding method : interTypeMethods) {
  237. ret.add(method);
  238. }
  239. ReferenceBinding[] interfaces = sourceTypeBinding.superInterfaces();
  240. for (ReferenceBinding anInterface : interfaces) {
  241. if (anInterface instanceof SourceTypeBinding) {
  242. SourceTypeBinding intSTB = (SourceTypeBinding) anInterface;
  243. addPublicITDSFrom(intSTB, ret);
  244. }
  245. }
  246. if (ret.isEmpty()) {
  247. return Binding.NO_METHODS;
  248. }
  249. return ret.toArray(new MethodBinding[ret.size()]);
  250. }
  251. private void addPublicITDSFrom(SourceTypeBinding anInterface, List<MethodBinding> accumulator) {
  252. if (anInterface.memberFinder != null) {
  253. InterTypeMemberFinder finder = (InterTypeMemberFinder) anInterface.memberFinder;
  254. for (MethodBinding aBinding: finder.interTypeMethods) {
  255. if (Modifier.isPublic(aBinding.modifiers)) {
  256. accumulator.add(aBinding);
  257. }
  258. }
  259. }
  260. ReferenceBinding superType = anInterface.superclass;
  261. if (superType instanceof SourceTypeBinding && superType.isInterface()) {
  262. addPublicITDSFrom((SourceTypeBinding) superType, accumulator);
  263. }
  264. }
  265. // XXX conflicts
  266. @Override
  267. public MethodBinding[] getMethods(SourceTypeBinding sourceTypeBinding, char[] selector) {
  268. // System.err.println("getMethods: " + new String(sourceTypeBinding.signature()) +
  269. // ", " + new String(selector));
  270. MethodBinding[] orig = sourceTypeBinding.getMethodsBase(selector);
  271. if (interTypeMethods.isEmpty()) {
  272. return orig;
  273. }
  274. Set<MethodBinding> ret = new HashSet<>(Arrays.asList(orig));
  275. // System.err.println("declared method: " + ret + " inters = " + interTypeMethods);
  276. for (MethodBinding method : interTypeMethods) {
  277. if (CharOperation.equals(selector, method.selector)) {
  278. ret.add(method);
  279. }
  280. }
  281. if (ret.isEmpty()) {
  282. return Binding.NO_METHODS;
  283. }
  284. // System.err.println("method: " + ret);
  285. // check for conflicts
  286. // int len = ret.size();
  287. // if (len > 1) {
  288. // for (int i=0; i <len; i++) {
  289. // MethodBinding m1 = (MethodBinding)ret.get(i);
  290. // for (int j=i+1; j < len; j++) {
  291. // MethodBinding m2 = (MethodBinding)ret.get(j);
  292. // //reportConflicts(sourceTypeBinding, m1, m2);
  293. // }
  294. // }
  295. // }
  296. // System.err.println("got methods: " + ret + " on " + sourceTypeBinding);
  297. return ret.toArray(new MethodBinding[ret.size()]);
  298. }
  299. @Override
  300. public MethodBinding getExactMethod(SourceTypeBinding sourceTypeBinding, char[] selector, TypeBinding[] argumentTypes,
  301. CompilationUnitScope refScope) {
  302. MethodBinding ret = sourceTypeBinding.getExactMethodBase(selector, argumentTypes, refScope);
  303. // An intertype declaration may override an inherited member (Bug#50776)
  304. for (MethodBinding im : interTypeMethods) {
  305. if (matches(im, selector, argumentTypes)) {
  306. return im;
  307. }
  308. }
  309. return ret;
  310. }
  311. // if (isVisible(im, sourceTypeBinding)) {
  312. // if (ret == null) {
  313. // ret = im;
  314. // } else {
  315. // ret = resolveOverride(ret, im);
  316. // }
  317. // }
  318. // }
  319. // }
  320. // return ret;
  321. // }
  322. // private MethodBinding resolveOverride(MethodBinding m1, MethodBinding m2) {
  323. // ReferenceBinding t1 = getTargetType(m1);
  324. // ReferenceBinding t2 = getTargetType(m2);
  325. // if (t1 == t2) {
  326. // //XXX also need a test for completely matching sigs
  327. // if (m1.isAbstract()) return m2;
  328. // else if (m2.isAbstract()) return m1;
  329. //
  330. //
  331. // if (m1 instanceof InterTypeMethodBinding) {
  332. // //XXX need to handle dominates here
  333. // EclipseWorld world = EclipseWorld.fromScopeLookupEnvironment(sourceTypeBinding.scope);
  334. // int cmp = compareAspectPrecedence(world.fromEclipse(m1.declaringClass),
  335. // world.fromEclipse(m2.declaringClass));
  336. // if (cmp < 0) return m2;
  337. // else if (cmp > 0) return m1;
  338. // }
  339. //
  340. // duplicateMethodBinding(m1, m2);
  341. // return null;
  342. // }
  343. // if (t1.isSuperclassOf(t2)) {
  344. // return m2;
  345. // }
  346. // if (t2.isSuperclassOf(t1)) {
  347. // return m1;
  348. // }
  349. //
  350. // duplicateMethodBinding(m1, m2);
  351. // return null;
  352. // }
  353. // private int compareAspectPrecedence(ResolvedType a1, ResolvedType a2) {
  354. // World world = a1.getWorld();
  355. // int ret = world.compareByDominates(a1, a2);
  356. // if (ret == 0) {
  357. // if (a1.isAssignableFrom(a2)) return -1;
  358. // if (a2.isAssignableFrom(a1)) return +1;
  359. // }
  360. // return ret;
  361. // }
  362. //
  363. public static boolean matches(MethodBinding m1, MethodBinding m2) {
  364. return matches(m1, m2.selector, m2.parameters);
  365. // &&
  366. // (isVisible(m1, m2.declaringClass) || isVisible(m2, m1.declaringClass));
  367. }
  368. public static boolean matches2(MethodBinding newBinding, MethodBinding existingBinding) {
  369. if (!CharOperation.equals(existingBinding.selector, newBinding.selector)) {
  370. return false;
  371. }
  372. int argCount = existingBinding.parameters.length;
  373. if (newBinding.parameters.length != argCount) {
  374. return false;
  375. }
  376. TypeBinding[] toMatch = newBinding.parameters;
  377. boolean matches = true;
  378. for (int p = 0; p < argCount; p++) {
  379. if (toMatch[p] != existingBinding.parameters[p]) {
  380. matches = false;
  381. break;
  382. }
  383. }
  384. if (!matches) {
  385. // could be due to generics differences. For example:
  386. // existingBinding is <T extends Foo> T bar(T t)
  387. // newBinding is <T extends Foo> T bar(T t)
  388. // the '==' check isn't going to pass, we need to do a deeper check
  389. TypeVariableBinding[] existingTVBs = existingBinding.typeVariables;
  390. TypeVariableBinding[] newTVBs = newBinding.typeVariables;
  391. if (existingTVBs.length != 0 && existingTVBs.length == newTVBs.length) {
  392. // Check them
  393. boolean genericsMatch = true;
  394. for (int t = 0, max = existingTVBs.length; t < max; t++) {
  395. char[] existingSig = existingTVBs[t].genericSignature();
  396. char[] newSig = newTVBs[t].genericSignature();
  397. if (!CharOperation.equals(existingSig, newSig)) {
  398. genericsMatch = false;
  399. break;
  400. }
  401. }
  402. if (genericsMatch) {
  403. for (int a = 0; a < argCount; a++) {
  404. char[] existingSig = existingBinding.parameters[a].genericTypeSignature();
  405. char[] newSig = toMatch[a].genericTypeSignature();
  406. if (!CharOperation.equals(existingSig, newSig)) {
  407. genericsMatch = false;
  408. break;
  409. }
  410. }
  411. }
  412. if (genericsMatch) {
  413. matches = true;
  414. }
  415. }
  416. }
  417. return matches;
  418. }
  419. private static boolean matches(MethodBinding method, char[] selector, TypeBinding[] argumentTypes) {
  420. if (!CharOperation.equals(selector, method.selector)) {
  421. return false;
  422. }
  423. int argCount = argumentTypes.length;
  424. if (method.parameters.length != argCount) {
  425. return false;
  426. }
  427. TypeBinding[] toMatch = method.parameters;
  428. for (int p = 0; p < argCount; p++) {
  429. if (toMatch[p] != argumentTypes[p]) {
  430. return false;
  431. }
  432. }
  433. return true;
  434. }
  435. public void addInterTypeField(FieldBinding binding) {
  436. // System.err.println("adding: " + binding + " to " + this);
  437. interTypeFields.add(binding);
  438. }
  439. public void addInterTypeMethod(MethodBinding binding) {
  440. // check for conflicts with existing methods, should really check type as well...
  441. // System.err.println("adding: " + binding + " to " + sourceTypeBinding);
  442. // pr284862 - this can leave a broken EclipseResolvedMember with an orphan method binding inside...ought to repair it
  443. if (isVisible(binding, sourceTypeBinding)) {
  444. MethodBinding[] baseMethods = sourceTypeBinding.methods;
  445. for (int i = 0, len = baseMethods.length; i < len; i++) {
  446. MethodBinding b = baseMethods[i];
  447. sourceTypeBinding.resolveTypesFor(b); // this will return fast if its already been done.
  448. if (matches2(binding, b)) {
  449. // this always means we should remove the existing method
  450. if (b.sourceMethod() != null) {
  451. b.sourceMethod().binding = null;
  452. }
  453. sourceTypeBinding.removeMethod(i);
  454. // System.err.println(" left: " + Arrays.asList(sourceTypeBinding.methods));
  455. break;
  456. }
  457. }
  458. }
  459. interTypeMethods.add(binding);
  460. }
  461. /**
  462. * @param name the name of the field
  463. * @return true if already know about an intertype field declaration for that field
  464. */
  465. public boolean definesField(String name) {
  466. List<FieldBinding> l = interTypeFields;
  467. if (l.size() > 0) {
  468. char[] nameChars = name.toCharArray();
  469. for (int i = 0; i < l.size(); i++) {
  470. FieldBinding fieldBinding = interTypeFields.get(i);
  471. if (CharOperation.equals(fieldBinding.name, nameChars)) {
  472. return true;
  473. }
  474. }
  475. }
  476. return false;
  477. }
  478. }