]> source.dussan.org Git - aspectj.git/blob
2586eec95186df281bf348eff2087ee8d134de5d
[aspectj.git] /
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
13
14 package org.aspectj.ajdt.internal.compiler.ast;
15
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;
27
28 /**
29  * An inter-type constructor declaration.
30  * 
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.
34  * 
35  * @author Jim Hugunin
36  */
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;
42         
43         public InterTypeConstructorDeclaration(CompilationResult result, TypeReference onType) {
44                 super(result, onType);
45         }
46         
47         public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
48                 if (ignoreFurtherInvestigation)
49                         return;
50             parser.parse(this, unit); 
51         }
52         
53         protected char[] getPrefix() {
54                 return (NameMangler.ITD_PREFIX + "interConstructor$").toCharArray();
55         }
56
57         public void resolve(ClassScope upperScope) {
58                 if (munger == null || binding == null) ignoreFurtherInvestigation = true;
59                 if (ignoreFurtherInvestigation) return;
60
61                 explicitConstructorCall = null;
62                 if (statements != null && statements.length > 0 && 
63                         statements[0] instanceof ExplicitConstructorCall)
64                 {
65                         explicitConstructorCall = (ExplicitConstructorCall) statements[0];
66                         statements = AstUtil.remove(0, statements);
67                 }
68                 
69                 preMethod = makePreMethod(upperScope, explicitConstructorCall);
70                 
71                 binding.parameters  = AstUtil.insert(onTypeBinding, binding.parameters);
72                 this.arguments = AstUtil.insert(
73                         AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding),
74                         this.arguments);
75                         
76                 super.resolve(upperScope);
77                 
78                 // after annotations have been resolved...
79                 if (explicitConstructorCall == null) {
80                         raiseNoFieldInitializersWarning();
81                 }
82         }
83
84         /**
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.
87          */
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);
95         }
96         
97         /**
98          * true iff constructor has @SuppressAjWarnings or @SuppressAjWarnings("xyz,noExplicitConstructorCall,def,...")
99          * @return
100          */
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) {
106                                         return true;
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;
115                                                         }
116                                                 }
117                                         }
118                                 }
119                         }
120                 }
121                 return false;
122         }
123         
124         private MethodDeclaration makePreMethod(ClassScope scope, 
125                                                                                         ExplicitConstructorCall explicitConstructorCall)
126         {
127                 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
128                 
129                 UnresolvedType aspectTypeX = world.fromBinding(binding.declaringClass);
130                 UnresolvedType targetTypeX = world.fromBinding(onTypeBinding);
131                 
132                 ArrayBinding objectArrayBinding = scope.createArrayType(scope.getJavaLangObject(), 1);
133                 
134                 
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();
139                 
140                 
141                 pre.arguments = AstUtil.copyArguments(this.arguments);
142                 
143                 //XXX should do exceptions
144                 
145                 pre.scope = new MethodScope(scope, pre, true);
146                 //??? do we need to do anything with scope???
147                 
148                 
149
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();
156                 
157                 pre.binding = world.makeMethodBinding(preIntroducedConstructorRM);
158                 
159                 pre.bindArguments();
160                 pre.bindThrownExceptions();
161                 
162                 
163                 if (explicitConstructorCall == null) {
164                         pre.statements = new Statement[] {};
165                 } else {
166                         pre.statements = new Statement[] {
167                                 explicitConstructorCall
168                         };
169                 }
170                 
171                 InterTypeScope newParent =
172                         new InterTypeScope(scope, onTypeBinding);
173                 pre.scope.parent = newParent;
174
175                 pre.resolveStatements(); //newParent);
176                 
177                 
178                 
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);
186                         }
187                 }
188                 
189                 int nExprs;
190                 if (explicitConstructor == null) nExprs = 0;
191                 else nExprs = explicitConstructor.parameters.length;
192                 
193                 
194                 ArrayInitializer init = new ArrayInitializer();
195                 init.expressions = new Expression[nExprs + nParams];
196                 int index = 0;
197                 for (int i=0; i < nExprs; i++) {
198                         if (i >= explicitConstructorCall.arguments.length) {
199                                 init.expressions[index++] = new NullLiteral(0, 0);
200                                 continue;
201                         }
202                         
203                         
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 });
212                         }
213                         init.expressions[index++] = arg;
214                 }
215                 
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 });
226                         }
227                         init.expressions[index++] = arg;
228                 }
229                 
230                 init.binding =objectArrayBinding;
231                 
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;
237                 
238
239                 
240                 
241                 pre.statements = new Statement[] {
242                         new ReturnStatement(newArray, 0, 0),
243                 };
244                 return pre;
245         }
246
247
248
249
250
251           
252         public EclipseTypeMunger build(ClassScope classScope) {
253                 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
254                 
255                 resolveOnType(classScope);
256                 if (ignoreFurtherInvestigation) return null;
257                 
258                 binding = classScope.referenceContext.binding.resolveTypesFor(binding);
259                                 
260                 if (isTargetAnnotation(classScope,"constructor")) return null; // Error message output in isTargetAnnotation
261                 if (isTargetEnum(classScope,"constructor")) return null;       // Error message output in isTargetEnum
262                 
263                 if (onTypeBinding.isInterface()) {
264                         classScope.problemReporter().signalError(sourceStart, sourceEnd,
265                                                         "can't define constructors on interfaces");
266                         ignoreFurtherInvestigation = true;
267                         return null;
268                 }
269                 
270                 if (onTypeBinding.isNestedType()) {
271                         classScope.problemReporter().signalError(sourceStart, sourceEnd,
272                                 "can't define constructors on nested types (compiler limitation)");
273                         ignoreFurtherInvestigation = true;
274                         return null;
275                 }       
276                 
277                 ResolvedType declaringTypeX = world.fromEclipse(onTypeBinding);
278                 ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
279                 
280                 if (interTypeScope==null) return null; // We encountered a problem building the scope, don't continue - error already reported
281
282                 
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);
290                 
291                 ResolvedMember syntheticInterMember =
292                         AjcMemberMaker.interConstructor(declaringTypeX,  signature, aspectType);
293                 
294                 NewConstructorTypeMunger myMunger = 
295                         new NewConstructorTypeMunger(signature, syntheticInterMember, null, null,typeVariableAliases);
296                 setMunger(myMunger);
297                 myMunger.check(world.getWorld());
298                 
299                 this.selector = binding.selector =
300                         NameMangler.postIntroducedConstructor(
301                                 world.fromBinding(binding.declaringClass),
302                                 declaringTypeX).toCharArray();
303                 
304                 return new EclipseTypeMunger(world, myMunger, aspectType, this);
305         }
306         
307         
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);
313                         }
314                         
315                         ((NewConstructorTypeMunger)munger).setExplicitConstructor(
316                                 world.makeResolvedMember(explicitConstructor));
317                 } else {
318                         ((NewConstructorTypeMunger)munger).setExplicitConstructor(
319                                 new ResolvedMemberImpl(Member.CONSTRUCTOR, 
320                                         world.fromBinding(onTypeBinding.superclass()),
321                                         0, ResolvedType.VOID, "<init>", UnresolvedType.NONE));
322                 }
323                 return new AjAttribute.TypeMunger(munger);
324         }
325         
326         
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);
332                 
333                 preMethod.generateCode(classScope, classFile);
334         }
335         protected Shadow.Kind getShadowKindForBody() {
336                 return Shadow.ConstructorExecution;
337         }
338         
339 }