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.

AccessForInlineVisitor.java 12KB

13 years ago
12 years ago
19 years ago
13 years ago
13 years ago
13 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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 Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. //import java.util.Arrays;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  17. import org.aspectj.ajdt.internal.compiler.lookup.InlineAccessFieldBinding;
  18. import org.aspectj.ajdt.internal.compiler.lookup.InterTypeFieldBinding;
  19. import org.aspectj.ajdt.internal.compiler.lookup.InterTypeMethodBinding;
  20. import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedFieldBinding;
  21. import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler;
  22. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AssertStatement;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldReference;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ThisReference;
  34. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  35. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
  36. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
  37. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
  38. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  39. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
  40. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
  41. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding;
  42. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  43. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  44. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
  45. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
  46. import org.aspectj.weaver.AjcMemberMaker;
  47. import org.aspectj.weaver.ResolvedMember;
  48. /**
  49. * Walks the body of around advice
  50. *
  51. * Makes sure that all member accesses are to public members. Will convert to use access methods when needed to ensure that. This
  52. * makes it much simpler (and more modular) to inline the body of an around.
  53. *
  54. * ??? constructors are handled different and require access to the target type. changes to
  55. * org.eclipse.jdt.internal.compiler.ast.AllocationExpression would be required to fix this issue.
  56. *
  57. * @author Jim Hugunin
  58. */
  59. public class AccessForInlineVisitor extends ASTVisitor {
  60. PrivilegedHandler handler;
  61. AspectDeclaration inAspect;
  62. EclipseFactory world; // alias for inAspect.world
  63. private Map<TypeBinding, Map<FieldBinding, ResolvedMember>> alreadyProcessedReceivers = new HashMap<>();
  64. // set to true for ClassLiteralAccess and AssertStatement
  65. // ??? A better answer would be to transform these into inlinable forms
  66. public boolean isInlinable = true;
  67. public AccessForInlineVisitor(AspectDeclaration inAspect, PrivilegedHandler handler) {
  68. this.inAspect = inAspect;
  69. this.world = inAspect.factory;
  70. this.handler = handler;
  71. }
  72. public void endVisit(SingleNameReference ref, BlockScope scope) {
  73. if (ref.binding instanceof FieldBinding) {
  74. ref.binding = getAccessibleField((FieldBinding) ref.binding, ref.actualReceiverType);
  75. }
  76. }
  77. public void endVisit(QualifiedNameReference ref, BlockScope scope) {
  78. if (ref.binding instanceof FieldBinding) {
  79. ref.binding = getAccessibleField((FieldBinding) ref.binding, ref.actualReceiverType);
  80. }
  81. if (ref.otherBindings != null && ref.otherBindings.length > 0) {
  82. TypeBinding receiverType;
  83. if (ref.binding instanceof FieldBinding) {
  84. receiverType = ((FieldBinding) ref.binding).type;
  85. } else if (ref.binding instanceof VariableBinding) {
  86. receiverType = ((VariableBinding) ref.binding).type;
  87. } else {
  88. // !!! understand and fix this case later
  89. receiverType = ref.otherBindings[0].declaringClass;
  90. }
  91. boolean cont = true; // don't continue if we come across a problem
  92. for (int i = 0, len = ref.otherBindings.length; i < len && cont; i++) {
  93. FieldBinding binding = ref.otherBindings[i];
  94. ref.otherBindings[i] = getAccessibleField(binding, receiverType);
  95. if (!(binding instanceof ProblemFieldBinding) && binding != null)
  96. receiverType = binding.type; // TODO Why is this sometimes null?
  97. else
  98. cont = false;
  99. }
  100. }
  101. }
  102. public void endVisit(FieldReference ref, BlockScope scope) {
  103. ref.binding = getAccessibleField(ref.binding, ref.actualReceiverType);
  104. }
  105. public void endVisit(MessageSend send, BlockScope scope) {
  106. if (send instanceof Proceed)
  107. return;
  108. if (send.binding == null || !send.binding.isValidBinding())
  109. return;
  110. if (send.isSuperAccess() && !send.binding.isStatic()) {
  111. send.receiver = new ThisReference(send.sourceStart, send.sourceEnd);
  112. // send.arguments = AstUtil.insert(new ThisReference(send.sourceStart, send.sourceEnd), send.arguments);
  113. MethodBinding superAccessBinding = getSuperAccessMethod(send.binding);
  114. AstUtil.replaceMethodBinding(send, superAccessBinding);
  115. } else if (!isPublic(send.binding) && !isCloneMethod(send.binding)) {
  116. send.syntheticAccessor = getAccessibleMethod(send.binding, send.actualReceiverType);
  117. }
  118. }
  119. private boolean isCloneMethod(MethodBinding binding) {
  120. return (CharOperation.equals(binding.selector, TypeConstants.CLONE)) &&
  121. (CharOperation.equals(binding.declaringClass.compoundName, TypeConstants.JAVA_LANG_OBJECT));
  122. }
  123. public void endVisit(AllocationExpression send, BlockScope scope) {
  124. if (send.binding == null || !send.binding.isValidBinding())
  125. return;
  126. // XXX TBD
  127. if (isPublic(send.binding))
  128. return;
  129. makePublic(send.binding.declaringClass);
  130. send.binding = handler.getPrivilegedAccessMethod(send.binding, send);
  131. }
  132. public void endVisit(QualifiedTypeReference ref, BlockScope scope) {
  133. makePublic(ref.resolvedType); // getTypeBinding(scope)); //??? might be trouble
  134. }
  135. public void endVisit(SingleTypeReference ref, BlockScope scope) {
  136. makePublic(ref.resolvedType); // getTypeBinding(scope)); //??? might be trouble
  137. }
  138. private FieldBinding getAccessibleField(FieldBinding binding, TypeBinding receiverType) {
  139. // System.err.println("checking field: " + binding);
  140. if (binding == null || !binding.isValidBinding())
  141. return binding;
  142. makePublic(receiverType);
  143. if (isPublic(binding))
  144. return binding;
  145. if (binding instanceof PrivilegedFieldBinding)
  146. return binding;
  147. if (binding instanceof InterTypeFieldBinding)
  148. return binding;
  149. if (binding.isPrivate() && binding.declaringClass != inAspect.binding) {
  150. binding.modifiers = AstUtil.makePackageVisible(binding.modifiers);
  151. }
  152. // Avoid repeatedly building ResolvedMembers by using info on any done previously in this visitor
  153. Map<FieldBinding, ResolvedMember> alreadyResolvedMembers = alreadyProcessedReceivers.computeIfAbsent(receiverType, k -> new HashMap<>());
  154. ResolvedMember m = alreadyResolvedMembers.get(binding);
  155. if (m == null) {
  156. m = world.makeResolvedMember(binding, receiverType);
  157. alreadyResolvedMembers.put(binding, m);
  158. }
  159. if (inAspect.accessForInline.containsKey(m)) {
  160. return (FieldBinding) inAspect.accessForInline.get(m);
  161. }
  162. FieldBinding ret = new InlineAccessFieldBinding(inAspect, binding, m);
  163. inAspect.accessForInline.put(m, ret);
  164. return ret;
  165. }
  166. private MethodBinding getAccessibleMethod(MethodBinding binding, TypeBinding receiverType) {
  167. if (!binding.isValidBinding())
  168. return binding;
  169. makePublic(receiverType); // ???
  170. if (isPublic(binding))
  171. return binding;
  172. if (binding instanceof InterTypeMethodBinding)
  173. return binding;
  174. if (binding instanceof ParameterizedMethodBinding) { // pr124999
  175. binding = binding.original();
  176. }
  177. ResolvedMember m = null;
  178. if (binding.isPrivate() && binding.declaringClass != inAspect.binding) {
  179. // does this always mean that the aspect is an inner aspect of the bindings
  180. // declaring class? After all, the field is private but we can see it from
  181. // where we are.
  182. binding.modifiers = AstUtil.makePackageVisible(binding.modifiers);
  183. m = world.makeResolvedMember(binding);
  184. } else {
  185. // Sometimes receiverType and binding.declaringClass are *not* the same.
  186. // Sometimes receiverType is a subclass of binding.declaringClass. In these situations
  187. // we want the generated inline accessor to call the method on the subclass (at
  188. // runtime this will be satisfied by the super).
  189. m = world.makeResolvedMember(binding, receiverType);
  190. }
  191. if (inAspect.accessForInline.containsKey(m))
  192. return (MethodBinding) inAspect.accessForInline.get(m);
  193. MethodBinding ret = world.makeMethodBinding(AjcMemberMaker.inlineAccessMethodForMethod(inAspect.typeX, m));
  194. inAspect.accessForInline.put(m, ret);
  195. return ret;
  196. }
  197. static class SuperAccessMethodPair {
  198. public ResolvedMember originalMethod;
  199. public MethodBinding accessMethod;
  200. public SuperAccessMethodPair(ResolvedMember originalMethod, MethodBinding accessMethod) {
  201. this.originalMethod = originalMethod;
  202. this.accessMethod = accessMethod;
  203. }
  204. }
  205. private MethodBinding getSuperAccessMethod(MethodBinding binding) {
  206. ResolvedMember m = world.makeResolvedMember(binding);
  207. ResolvedMember superAccessMember = AjcMemberMaker.superAccessMethod(inAspect.typeX, m);
  208. if (inAspect.superAccessForInline.containsKey(superAccessMember)) {
  209. return inAspect.superAccessForInline.get(superAccessMember).accessMethod;
  210. }
  211. MethodBinding ret = world.makeMethodBinding(superAccessMember);
  212. inAspect.superAccessForInline.put(superAccessMember, new SuperAccessMethodPair(m, ret));
  213. return ret;
  214. }
  215. private boolean isPublic(FieldBinding fieldBinding) {
  216. // these are always effectively public to the inliner
  217. if (fieldBinding instanceof InterTypeFieldBinding)
  218. return true;
  219. return fieldBinding.isPublic();
  220. }
  221. private boolean isPublic(MethodBinding methodBinding) {
  222. // these are always effectively public to the inliner
  223. if (methodBinding instanceof InterTypeMethodBinding)
  224. return true;
  225. return methodBinding.isPublic();
  226. }
  227. private void makePublic(TypeBinding binding) {
  228. if (binding == null || !binding.isValidBinding())
  229. return; // has already produced an error
  230. if (binding instanceof ReferenceBinding) {
  231. ReferenceBinding rb = (ReferenceBinding) binding;
  232. if (!rb.isPublic()) {
  233. try {
  234. if (rb instanceof ParameterizedTypeBinding) {
  235. rb = (ReferenceBinding) rb.erasure();
  236. }
  237. } catch (Throwable t) { // TODO remove post 1.7.0
  238. t.printStackTrace();
  239. }
  240. handler.notePrivilegedTypeAccess(rb, null); // ???
  241. }
  242. } else if (binding instanceof ArrayBinding) {
  243. makePublic(((ArrayBinding) binding).leafComponentType);
  244. } else {
  245. return;
  246. }
  247. }
  248. public void endVisit(AssertStatement assertStatement, BlockScope scope) {
  249. isInlinable = false;
  250. }
  251. public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) {
  252. isInlinable = false;
  253. }
  254. public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
  255. // we don't want to transform any local anonymous classes as they won't be inlined
  256. return false;
  257. }
  258. }