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.

InterTypeConstructorDeclaration.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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 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. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  15. import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
  16. import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
  17. import org.aspectj.ajdt.internal.compiler.lookup.InterTypeScope;
  18. import org.aspectj.bridge.ISourceLocation;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  20. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CastExpression;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NullLiteral;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
  34. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  35. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  36. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
  37. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
  38. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  39. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
  40. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  41. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
  42. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
  43. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
  44. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  45. import org.aspectj.weaver.AjAttribute;
  46. import org.aspectj.weaver.AjcMemberMaker;
  47. import org.aspectj.weaver.Constants;
  48. import org.aspectj.weaver.Member;
  49. import org.aspectj.weaver.NameMangler;
  50. import org.aspectj.weaver.NewConstructorTypeMunger;
  51. import org.aspectj.weaver.ResolvedMember;
  52. import org.aspectj.weaver.ResolvedMemberImpl;
  53. import org.aspectj.weaver.ResolvedType;
  54. import org.aspectj.weaver.Shadow;
  55. import org.aspectj.weaver.UnresolvedType;
  56. /**
  57. * An inter-type constructor declaration.
  58. *
  59. * This will generate two implementation methods in the aspect, the main one for the body of the constructor, and an additional
  60. * <code>preMethod</code> for the code that runs before the super constructor is called.
  61. *
  62. * @author Jim Hugunin
  63. */
  64. public class InterTypeConstructorDeclaration extends InterTypeDeclaration {
  65. private static final String SUPPRESSAJWARNINGS = "Lorg/aspectj/lang/annotation/SuppressAjWarnings;";
  66. private static final String NOEXPLICITCONSTRUCTORCALL = "noExplicitConstructorCall";
  67. private MethodDeclaration preMethod;
  68. private ExplicitConstructorCall explicitConstructorCall = null;
  69. public InterTypeConstructorDeclaration(CompilationResult result, TypeReference onType) {
  70. super(result, onType);
  71. }
  72. public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
  73. if (ignoreFurtherInvestigation)
  74. return;
  75. parser.parse(this, unit);
  76. }
  77. protected char[] getPrefix() {
  78. return (NameMangler.ITD_PREFIX + "interConstructor$").toCharArray();
  79. }
  80. public void resolve(ClassScope upperScope) {
  81. if (munger == null || binding == null)
  82. ignoreFurtherInvestigation = true;
  83. if (ignoreFurtherInvestigation)
  84. return;
  85. explicitConstructorCall = null;
  86. if (statements != null && statements.length > 0 && statements[0] instanceof ExplicitConstructorCall) {
  87. explicitConstructorCall = (ExplicitConstructorCall) statements[0];
  88. statements = AstUtil.remove(0, statements);
  89. }
  90. preMethod = makePreMethod(upperScope, explicitConstructorCall);
  91. binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
  92. this.arguments = AstUtil.insert(AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding), this.arguments);
  93. super.resolve(upperScope);
  94. // after annotations have been resolved...
  95. if (explicitConstructorCall == null) {
  96. raiseNoFieldInitializersWarning();
  97. }
  98. }
  99. /**
  100. * Warning added in response to PR 62606 - if an ITD constructor does not make an explicit constructor call then field
  101. * initializers in the target class will not be executed leading to unexpected behaviour.
  102. */
  103. private void raiseNoFieldInitializersWarning() {
  104. if (suppressingNoExplicitConstructorCall())
  105. return;
  106. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
  107. ISourceLocation location = new EclipseSourceLocation(scope.problemReporter().referenceContext.compilationResult(),
  108. sourceStart(), sourceEnd());
  109. world.getWorld().getLint().noExplicitConstructorCall.signal(null, location);
  110. }
  111. /**
  112. * true iff constructor has @SuppressAjWarnings or @SuppressAjWarnings("xyz,noExplicitConstructorCall,def,...")
  113. *
  114. * @return
  115. */
  116. private boolean suppressingNoExplicitConstructorCall() {
  117. if (this.annotations == null)
  118. return false;
  119. for (int i = 0; i < this.annotations.length; i++) {
  120. if (new String(this.annotations[i].resolvedType.signature()).equals(SUPPRESSAJWARNINGS)) {
  121. if (this.annotations[i] instanceof MarkerAnnotation) {
  122. return true;
  123. } else if (this.annotations[i] instanceof SingleMemberAnnotation) {
  124. SingleMemberAnnotation sma = (SingleMemberAnnotation) this.annotations[i];
  125. if (sma.memberValue instanceof ArrayInitializer) {
  126. ArrayInitializer memberValue = (ArrayInitializer) sma.memberValue;
  127. for (int j = 0; j < memberValue.expressions.length; j++) {
  128. if (memberValue.expressions[j] instanceof StringLiteral) {
  129. StringLiteral val = (StringLiteral) memberValue.expressions[j];
  130. if (new String(val.source()).equals(NOEXPLICITCONSTRUCTORCALL))
  131. return true;
  132. }
  133. }
  134. }
  135. }
  136. }
  137. }
  138. return false;
  139. }
  140. private MethodDeclaration makePreMethod(ClassScope scope, ExplicitConstructorCall explicitConstructorCall) {
  141. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
  142. UnresolvedType aspectTypeX = world.fromBinding(binding.declaringClass);
  143. UnresolvedType targetTypeX = world.fromBinding(onTypeBinding);
  144. ArrayBinding objectArrayBinding = scope.createArrayType(scope.getJavaLangObject(), 1);
  145. MethodDeclaration pre = new MethodDeclaration(compilationResult);
  146. pre.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
  147. pre.returnType = AstUtil.makeTypeReference(objectArrayBinding);
  148. pre.selector = NameMangler.postIntroducedConstructor(aspectTypeX, targetTypeX).toCharArray();
  149. pre.arguments = AstUtil.copyArguments(this.arguments);
  150. // XXX should do exceptions
  151. pre.scope = new MethodScope(scope, pre, true);
  152. // ??? do we need to do anything with scope???
  153. // Use the factory to build a semi-correct resolvedmember - then patch it up with
  154. // reset calls. This is SAFE
  155. ResolvedMemberImpl preIntroducedConstructorRM = world.makeResolvedMember(binding);
  156. preIntroducedConstructorRM.resetName(NameMangler.preIntroducedConstructor(aspectTypeX, targetTypeX));
  157. preIntroducedConstructorRM.resetModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
  158. preIntroducedConstructorRM.resetReturnTypeToObjectArray();
  159. pre.binding = world.makeMethodBinding(preIntroducedConstructorRM);
  160. pre.bindArguments();
  161. pre.bindThrownExceptions();
  162. if (explicitConstructorCall == null) {
  163. pre.statements = new Statement[] {};
  164. } else {
  165. pre.statements = new Statement[] { explicitConstructorCall };
  166. }
  167. InterTypeScope newParent = new InterTypeScope(scope, onTypeBinding);
  168. pre.scope.parent = newParent;
  169. pre.resolveStatements(); // newParent);
  170. int nParams = pre.arguments.length;
  171. MethodBinding explicitConstructor = null;
  172. if (explicitConstructorCall != null) {
  173. explicitConstructor = explicitConstructorCall.binding;
  174. // If it is null then we are going to report something else is wrong with this code!
  175. if (explicitConstructor != null && explicitConstructor.alwaysNeedsAccessMethod()) {
  176. explicitConstructor = explicitConstructor.getAccessMethod(true);
  177. }
  178. }
  179. int nExprs;
  180. if (explicitConstructor == null)
  181. nExprs = 0;
  182. else
  183. nExprs = explicitConstructor.parameters.length;
  184. ArrayInitializer init = new ArrayInitializer();
  185. init.expressions = new Expression[nExprs + nParams];
  186. int index = 0;
  187. for (int i = 0; i < nExprs; i++) {
  188. if (i >= (explicitConstructorCall.arguments == null ? 0 : explicitConstructorCall.arguments.length)) {
  189. init.expressions[index++] = new NullLiteral(0, 0);
  190. continue;
  191. }
  192. Expression arg = explicitConstructorCall.arguments[i];
  193. ResolvedMember conversionMethod = AjcMemberMaker.toObjectConversionMethod(world
  194. .fromBinding(explicitConstructorCall.binding.parameters[i]));
  195. if (conversionMethod != null) {
  196. arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod), new CastExpression(new NullLiteral(0,
  197. 0), AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
  198. new Expression[] { arg });
  199. }
  200. init.expressions[index++] = arg;
  201. }
  202. for (int i = 0; i < nParams; i++) {
  203. LocalVariableBinding binding = pre.arguments[i].binding;
  204. Expression arg = AstUtil.makeResolvedLocalVariableReference(binding);
  205. ResolvedMember conversionMethod = AjcMemberMaker.toObjectConversionMethod(world.fromBinding(binding.type));
  206. if (conversionMethod != null) {
  207. arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod), new CastExpression(new NullLiteral(0,
  208. 0), AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
  209. new Expression[] { arg });
  210. }
  211. init.expressions[index++] = arg;
  212. }
  213. init.binding = objectArrayBinding;
  214. ArrayAllocationExpression newArray = new ArrayAllocationExpression();
  215. newArray.initializer = init;
  216. newArray.type = AstUtil.makeTypeReference(scope.getJavaLangObject());
  217. newArray.dimensions = new Expression[1];
  218. newArray.constant = Constant.NotAConstant;
  219. pre.statements = new Statement[] { new ReturnStatement(newArray, 0, 0), };
  220. return pre;
  221. }
  222. public EclipseTypeMunger build(ClassScope classScope) {
  223. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
  224. resolveOnType(classScope);
  225. if (ignoreFurtherInvestigation)
  226. return null;
  227. binding = classScope.referenceContext.binding.resolveTypesFor(binding);
  228. if (isTargetAnnotation(classScope, "constructor"))
  229. return null; // Error message output in isTargetAnnotation
  230. if (isTargetEnum(classScope, "constructor"))
  231. return null; // Error message output in isTargetEnum
  232. if (onTypeBinding.isInterface()) {
  233. classScope.problemReporter().signalError(sourceStart, sourceEnd, "can't define constructors on interfaces");
  234. ignoreFurtherInvestigation = true;
  235. return null;
  236. }
  237. if (onTypeBinding.isNestedType()) {
  238. classScope.problemReporter().signalError(sourceStart, sourceEnd,
  239. "can't define constructors on nested types (compiler limitation)");
  240. ignoreFurtherInvestigation = true;
  241. return null;
  242. }
  243. ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding);
  244. ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
  245. if (interTypeScope == null)
  246. return null; // We encountered a problem building the scope, don't continue - error already reported
  247. // This signature represents what we want consumers of the targetted type to 'see'
  248. ResolvedMemberImpl signature = world.makeResolvedMemberForITD(binding, onTypeBinding, interTypeScope.getRecoveryAliases());
  249. signature.resetKind(Member.CONSTRUCTOR);
  250. signature.resetName("<init>");
  251. int resetModifiers = declaredModifiers;
  252. if (binding.isVarargs())
  253. resetModifiers = resetModifiers | Constants.ACC_VARARGS;
  254. signature.resetModifiers(resetModifiers);
  255. ResolvedMember syntheticInterMember = AjcMemberMaker.interConstructor(declaringTypeX, signature, aspectType);
  256. NewConstructorTypeMunger myMunger = new NewConstructorTypeMunger(signature, syntheticInterMember, null, null,
  257. typeVariableAliases);
  258. setMunger(myMunger);
  259. myMunger.check(world.getWorld());
  260. this.selector = binding.selector = NameMangler.postIntroducedConstructor(world.fromBinding(binding.declaringClass),
  261. declaringTypeX).toCharArray();
  262. return new EclipseTypeMunger(world, myMunger, aspectType, this);
  263. }
  264. private AjAttribute makeAttribute(EclipseFactory world) {
  265. if (explicitConstructorCall != null && (explicitConstructorCall.binding != null)
  266. && !(explicitConstructorCall.binding instanceof ProblemMethodBinding)) {
  267. MethodBinding explicitConstructor = explicitConstructorCall.binding;
  268. if (explicitConstructor.alwaysNeedsAccessMethod()) {
  269. explicitConstructor = explicitConstructor.getAccessMethod(true);
  270. }
  271. if (explicitConstructor instanceof ParameterizedMethodBinding) {
  272. explicitConstructor = explicitConstructor.original();
  273. }
  274. ((NewConstructorTypeMunger) munger).setExplicitConstructor(world.makeResolvedMember(explicitConstructor));
  275. } else {
  276. ((NewConstructorTypeMunger) munger).setExplicitConstructor(new ResolvedMemberImpl(Member.CONSTRUCTOR, world
  277. .fromBinding(onTypeBinding.superclass()), 0, UnresolvedType.VOID, "<init>", UnresolvedType.NONE));
  278. }
  279. return new AjAttribute.TypeMunger(munger);
  280. }
  281. public void generateCode(ClassScope classScope, ClassFile classFile) {
  282. if (ignoreFurtherInvestigation)
  283. return;
  284. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
  285. classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute(world)));
  286. super.generateCode(classScope, classFile);
  287. // classFile.codeStream.generateAttributes &= ~ClassFileConstants.ATTR_VARS;
  288. preMethod.generateCode(classScope, classFile);
  289. }
  290. protected Shadow.Kind getShadowKindForBody() {
  291. return Shadow.ConstructorExecution;
  292. }
  293. }