1 /* *******************************************************************
2 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
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
10 * PARC initial implementation
11 * ******************************************************************/
14 package org.aspectj.ajdt.internal.compiler.ast;
16 import java.lang.reflect.Modifier;
17 import org.aspectj.ajdt.internal.compiler.lookup.*;
18 import org.aspectj.bridge.ISourceLocation;
19 import org.aspectj.weaver.*;
20 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
21 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
22 import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
23 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
24 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
29 * An inter-type constructor declaration.
31 * This will generate two implementation methods in the aspect, the main one for the body
32 * of the constructor, and an additional <code>preMethod</code> for the code that
33 * runs before the super constructor is called.
37 public class InterTypeConstructorDeclaration extends InterTypeDeclaration {
38 private static final String SUPPRESSAJWARNINGS = "Lorg/aspectj/lang/annotation/SuppressAjWarnings;";
39 private static final String NOEXPLICITCONSTRUCTORCALL = "noExplicitConstructorCall";
40 private MethodDeclaration preMethod;
41 private ExplicitConstructorCall explicitConstructorCall = null;
43 public InterTypeConstructorDeclaration(CompilationResult result, TypeReference onType) {
44 super(result, onType);
47 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
48 if (ignoreFurtherInvestigation)
50 parser.parse(this, unit);
53 protected char[] getPrefix() {
54 return (NameMangler.ITD_PREFIX + "interConstructor$").toCharArray();
57 public void resolve(ClassScope upperScope) {
58 if (munger == null || binding == null) ignoreFurtherInvestigation = true;
59 if (ignoreFurtherInvestigation) return;
61 explicitConstructorCall = null;
62 if (statements != null && statements.length > 0 &&
63 statements[0] instanceof ExplicitConstructorCall)
65 explicitConstructorCall = (ExplicitConstructorCall) statements[0];
66 statements = AstUtil.remove(0, statements);
69 preMethod = makePreMethod(upperScope, explicitConstructorCall);
71 binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
72 this.arguments = AstUtil.insert(
73 AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding),
76 super.resolve(upperScope);
78 // after annotations have been resolved...
79 if (explicitConstructorCall == null) {
80 raiseNoFieldInitializersWarning();
85 * Warning added in response to PR 62606 - if an ITD constructor does not make an explicit constructor
86 * call then field initializers in the target class will not be executed leading to unexpected behaviour.
88 private void raiseNoFieldInitializersWarning() {
89 if (suppressingNoExplicitConstructorCall()) return;
90 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
91 ISourceLocation location =
92 new EclipseSourceLocation(scope.problemReporter().referenceContext.compilationResult(),
93 sourceStart(),sourceEnd());
94 world.getWorld().getLint().noExplicitConstructorCall.signal(null, location);
98 * true iff constructor has @SuppressAjWarnings or @SuppressAjWarnings("xyz,noExplicitConstructorCall,def,...")
101 private boolean suppressingNoExplicitConstructorCall() {
102 if (this.annotations == null) return false;
103 for (int i = 0; i < this.annotations.length; i++) {
104 if (new String(this.annotations[i].resolvedType.signature()).equals(SUPPRESSAJWARNINGS)) {
105 if (this.annotations[i] instanceof MarkerAnnotation) {
107 } else if (this.annotations[i] instanceof SingleMemberAnnotation){
108 SingleMemberAnnotation sma = (SingleMemberAnnotation) this.annotations[i];
109 if (sma.memberValue instanceof ArrayInitializer) {
110 ArrayInitializer memberValue = (ArrayInitializer) sma.memberValue;
111 for (int j = 0; j < memberValue.expressions.length; j++) {
112 if (memberValue.expressions[j] instanceof StringLiteral) {
113 StringLiteral val = (StringLiteral) memberValue.expressions[j];
114 if (new String(val.source()).equals(NOEXPLICITCONSTRUCTORCALL)) return true;
124 private MethodDeclaration makePreMethod(ClassScope scope,
125 ExplicitConstructorCall explicitConstructorCall)
127 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
129 UnresolvedType aspectTypeX = world.fromBinding(binding.declaringClass);
130 UnresolvedType targetTypeX = world.fromBinding(onTypeBinding);
132 ArrayBinding objectArrayBinding = scope.createArrayType(scope.getJavaLangObject(), 1);
135 MethodDeclaration pre = new MethodDeclaration(compilationResult);
136 pre.modifiers = AccPublic | AccStatic;
137 pre.returnType = AstUtil.makeTypeReference(objectArrayBinding);
138 pre.selector = NameMangler.postIntroducedConstructor(aspectTypeX, targetTypeX).toCharArray();
141 pre.arguments = AstUtil.copyArguments(this.arguments);
143 //XXX should do exceptions
145 pre.scope = new MethodScope(scope, pre, true);
146 //??? do we need to do anything with scope???
150 // Use the factory to build a semi-correct resolvedmember - then patch it up with
151 // reset calls. This is SAFE
152 ResolvedMember preIntroducedConstructorRM = world.makeResolvedMember(binding);
153 preIntroducedConstructorRM.resetName(NameMangler.preIntroducedConstructor(aspectTypeX, targetTypeX));
154 preIntroducedConstructorRM.resetModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
155 preIntroducedConstructorRM.resetReturnTypeToObjectArray();
157 pre.binding = world.makeMethodBinding(preIntroducedConstructorRM);
160 pre.bindThrownExceptions();
163 if (explicitConstructorCall == null) {
164 pre.statements = new Statement[] {};
166 pre.statements = new Statement[] {
167 explicitConstructorCall
171 InterTypeScope newParent =
172 new InterTypeScope(scope, onTypeBinding);
173 pre.scope.parent = newParent;
175 pre.resolveStatements(); //newParent);
179 int nParams = pre.arguments.length;
180 MethodBinding explicitConstructor = null;
181 if (explicitConstructorCall != null) {
182 explicitConstructor = explicitConstructorCall.binding;
183 // If it is null then we are going to report something else is wrong with this code!
184 if (explicitConstructor!=null && explicitConstructor.alwaysNeedsAccessMethod()) {
185 explicitConstructor = explicitConstructor.getAccessMethod(true);
190 if (explicitConstructor == null) nExprs = 0;
191 else nExprs = explicitConstructor.parameters.length;
194 ArrayInitializer init = new ArrayInitializer();
195 init.expressions = new Expression[nExprs + nParams];
197 for (int i=0; i < nExprs; i++) {
198 if (i >= explicitConstructorCall.arguments.length) {
199 init.expressions[index++] = new NullLiteral(0, 0);
204 Expression arg = explicitConstructorCall.arguments[i];
205 ResolvedMember conversionMethod =
206 AjcMemberMaker.toObjectConversionMethod(world.fromBinding(explicitConstructorCall.binding.parameters[i]));
207 if (conversionMethod != null) {
208 arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod),
209 new CastExpression(new NullLiteral(0, 0),
210 AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
211 new Expression[] {arg });
213 init.expressions[index++] = arg;
216 for (int i=0; i < nParams; i++) {
217 LocalVariableBinding binding = pre.arguments[i].binding;
218 Expression arg = AstUtil.makeResolvedLocalVariableReference(binding);
219 ResolvedMember conversionMethod =
220 AjcMemberMaker.toObjectConversionMethod(world.fromBinding(binding.type));
221 if (conversionMethod != null) {
222 arg = new KnownMessageSend(world.makeMethodBindingForCall(conversionMethod),
223 new CastExpression(new NullLiteral(0, 0),
224 AstUtil.makeTypeReference(world.makeTypeBinding(AjcMemberMaker.CONVERSIONS_TYPE))),
225 new Expression[] {arg });
227 init.expressions[index++] = arg;
230 init.binding =objectArrayBinding;
232 ArrayAllocationExpression newArray = new ArrayAllocationExpression();
233 newArray.initializer = init;
234 newArray.type = AstUtil.makeTypeReference(scope.getJavaLangObject());
235 newArray.dimensions = new Expression[1];
236 newArray.constant = NotAConstant;
241 pre.statements = new Statement[] {
242 new ReturnStatement(newArray, 0, 0),
252 public EclipseTypeMunger build(ClassScope classScope) {
253 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
255 resolveOnType(classScope);
256 if (ignoreFurtherInvestigation) return null;
258 binding = classScope.referenceContext.binding.resolveTypesFor(binding);
260 if (isTargetAnnotation(classScope,"constructor")) return null; // Error message output in isTargetAnnotation
261 if (isTargetEnum(classScope,"constructor")) return null; // Error message output in isTargetEnum
263 if (onTypeBinding.isInterface()) {
264 classScope.problemReporter().signalError(sourceStart, sourceEnd,
265 "can't define constructors on interfaces");
266 ignoreFurtherInvestigation = true;
270 if (onTypeBinding.isNestedType()) {
271 classScope.problemReporter().signalError(sourceStart, sourceEnd,
272 "can't define constructors on nested types (compiler limitation)");
273 ignoreFurtherInvestigation = true;
277 ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding);
278 ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
280 if (interTypeScope==null) return null; // We encountered a problem building the scope, don't continue - error already reported
283 // This signature represents what we want consumers of the targetted type to 'see'
284 ResolvedMember signature = world.makeResolvedMemberForITD(binding,onTypeBinding,interTypeScope.getRecoveryAliases());
285 signature.resetKind(Member.CONSTRUCTOR);
286 signature.resetName("<init>");
287 int resetModifiers = declaredModifiers;
288 if (binding.isVarargs()) resetModifiers = resetModifiers | Constants.ACC_VARARGS;
289 signature.resetModifiers(resetModifiers);
291 ResolvedMember syntheticInterMember =
292 AjcMemberMaker.interConstructor(declaringTypeX, signature, aspectType);
294 NewConstructorTypeMunger myMunger =
295 new NewConstructorTypeMunger(signature, syntheticInterMember, null, null,typeVariableAliases);
297 myMunger.check(world.getWorld());
299 this.selector = binding.selector =
300 NameMangler.postIntroducedConstructor(
301 world.fromBinding(binding.declaringClass),
302 declaringTypeX).toCharArray();
304 return new EclipseTypeMunger(world, myMunger, aspectType, this);
308 private AjAttribute makeAttribute(EclipseFactory world) {
309 if (explicitConstructorCall != null && (explicitConstructorCall.binding!=null) && !(explicitConstructorCall.binding instanceof ProblemMethodBinding)) {
310 MethodBinding explicitConstructor = explicitConstructorCall.binding;
311 if (explicitConstructor.alwaysNeedsAccessMethod()) {
312 explicitConstructor = explicitConstructor.getAccessMethod(true);
315 ((NewConstructorTypeMunger)munger).setExplicitConstructor(
316 world.makeResolvedMember(explicitConstructor));
318 ((NewConstructorTypeMunger)munger).setExplicitConstructor(
319 new ResolvedMemberImpl(Member.CONSTRUCTOR,
320 world.fromBinding(onTypeBinding.superclass()),
321 0, ResolvedType.VOID, "<init>", UnresolvedType.NONE));
323 return new AjAttribute.TypeMunger(munger);
327 public void generateCode(ClassScope classScope, ClassFile classFile) {
328 if (ignoreFurtherInvestigation) return;
329 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
330 classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute(world)));
331 super.generateCode(classScope, classFile);
333 preMethod.generateCode(classScope, classFile);
335 protected Shadow.Kind getShadowKindForBody() {
336 return Shadow.ConstructorExecution;