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 * ******************************************************************/
13 package org.aspectj.ajdt.internal.compiler.ast;
15 import java.lang.reflect.Modifier;
17 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
18 import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
19 import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter;
20 import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
21 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
22 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
23 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
24 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
27 import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
28 import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Opcodes;
29 import org.aspectj.org.eclipse.jdt.internal.compiler.flow.FlowContext;
30 import org.aspectj.org.eclipse.jdt.internal.compiler.flow.FlowInfo;
31 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
32 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
33 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
34 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
42 import org.aspectj.weaver.AjAttribute;
43 import org.aspectj.weaver.AjcMemberMaker;
44 import org.aspectj.weaver.Constants;
45 import org.aspectj.weaver.NameMangler;
46 import org.aspectj.weaver.NewMethodTypeMunger;
47 import org.aspectj.weaver.ResolvedMember;
48 import org.aspectj.weaver.ResolvedMemberImpl;
49 import org.aspectj.weaver.ResolvedType;
50 import org.aspectj.weaver.Shadow;
51 import org.aspectj.weaver.UnresolvedType;
54 * An inter-type method declaration.
58 public class InterTypeMethodDeclaration extends InterTypeDeclaration {
59 public InterTypeMethodDeclaration(CompilationResult result, TypeReference onType) {
60 super(result, onType);
64 public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
65 if (ignoreFurtherInvestigation)
67 if (!Modifier.isAbstract(declaredModifiers)) {
68 parser.parse(this, unit);
73 protected char[] getPrefix() {
74 return (NameMangler.ITD_PREFIX + "interMethod$").toCharArray();
77 public boolean isFinal() {
78 return (declaredModifiers & ClassFileConstants.AccFinal) != 0;
81 // public boolean isAbstract() {
82 // boolean b = (declaredModifiers & ClassFileConstants.AccAbstract) != 0;
83 // return b;//super.isAbstract();
87 public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) {
88 if (Modifier.isAbstract(declaredModifiers))
91 super.analyseCode(classScope, flowContext, flowInfo);
95 public void resolve(ClassScope upperScope) {
97 ignoreFurtherInvestigation = true;
99 ignoreFurtherInvestigation = true;
100 if (ignoreFurtherInvestigation)
103 if (!Modifier.isStatic(declaredModifiers)) {
104 this.arguments = AstUtil.insert(AstUtil.makeFinalArgument("ajc$this_".toCharArray(), onTypeBinding), this.arguments);
105 binding.parameters = AstUtil.insert(onTypeBinding, binding.parameters);
107 // If the inserted argument is a generic type, we should include the associated type variables to ensure
108 // the generated signature is correct (it will be checked by eclipse when this type is consumed in binary form).
109 TypeVariableBinding onTypeTVBs[] = onTypeBinding.typeVariables();
110 if (onTypeTVBs!=null && onTypeTVBs.length!=0) {
111 // The type parameters don't seem to need to be correct
112 // TypeParameter tp = new TypeParameter();
113 // tp.binding = tvb[0];
114 // tp.name = tvb[0].sourceName;
115 // this.typeParameters = AstUtil.insert(tp,this.typeParameters);
116 binding.typeVariables = AstUtil.insert(onTypeBinding.typeVariables(), binding.typeVariables);
120 super.resolve(upperScope);
124 public void resolveStatements() {
125 checkAndSetModifiersForMethod();
126 if ((modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
127 if ((declaredModifiers & ClassFileConstants.AccAbstract) == 0)
128 scope.problemReporter().methodNeedBody(this);
130 // the method HAS a body --> abstract native modifiers are forbiden
131 if (((declaredModifiers & ClassFileConstants.AccAbstract) != 0))
132 scope.problemReporter().methodNeedingNoBody(this);
135 // XXX AMC we need to do this, but I'm not 100% comfortable as I don't
136 // know why the return type is wrong in this case. Also, we don't seem to need
137 // to do it for args...
138 if (munger.getSignature().getReturnType().isRawType()) {
139 if (!binding.returnType.isRawType()) {
140 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
141 binding.returnType = world.makeTypeBinding(munger.getSignature().getReturnType());
145 // check @Override annotation - based on MethodDeclaration.resolveStatements() @Override processing
147 if (this.binding == null)
149 if (this.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5)
151 boolean hasOverrideAnnotation = (this.binding.tagBits & TagBits.AnnotationOverride) != 0;
154 if (hasOverrideAnnotation) {
156 // Work out the real method binding that we can use for comparison
157 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
158 MethodBinding realthing = world.makeMethodBinding(munger.getSignature(), munger.getTypeVariableAliases());
160 boolean reportError = true;
161 // Go up the hierarchy, looking for something we override
162 ReferenceBinding supertype = onTypeBinding.superclass();
163 while (supertype != null && reportError) {
164 MethodBinding[] possibles = supertype.getMethods(declaredSelector);
165 for (int i = 0; i < possibles.length; i++) {
166 MethodBinding mb = possibles[i];
168 boolean couldBeMatch = true;
169 if (mb.parameters.length != realthing.parameters.length)
170 couldBeMatch = false;
172 for (int j = 0; j < mb.parameters.length && couldBeMatch; j++) {
173 if (!mb.parameters[j].equals(realthing.parameters[j]))
174 couldBeMatch = false;
177 // return types compatible? (allow for covariance)
178 if (couldBeMatch && !returnType.resolvedType.isCompatibleWith(mb.returnType))
179 couldBeMatch = false;
183 supertype = supertype.superclass(); // superclass of object is null
185 // If we couldn't find something we override, report the error
187 ((AjProblemReporter) this.scope.problemReporter()).itdMethodMustOverride(this, realthing);
191 if (!Modifier.isAbstract(declaredModifiers))
192 super.resolveStatements();
193 if (Modifier.isStatic(declaredModifiers)) {
194 // Check the target for ITD is not an interface
195 if (onTypeBinding.isInterface()) {
196 scope.problemReporter().signalError(sourceStart, sourceEnd, "methods in interfaces cannot be declared static");
202 public EclipseTypeMunger build(ClassScope classScope) {
203 EclipseFactory factory = EclipseFactory.fromScopeLookupEnvironment(classScope);
205 resolveOnType(classScope);
206 if (ignoreFurtherInvestigation)
209 binding = classScope.referenceContext.binding.resolveTypesFor(binding);
210 if (binding == null) {
211 // if binding is null, we failed to find a type used in the method params, this error
212 // has already been reported.
213 this.ignoreFurtherInvestigation = true;
215 throw new AbortCompilationUnit(compilationResult, null);
218 if (isTargetAnnotation(classScope, "method"))
219 return null; // Error message output in isTargetAnnotation
220 if (isTargetEnum(classScope, "method"))
221 return null; // Error message output in isTargetEnum
223 if (interTypeScope == null)
224 return null; // We encountered a problem building the scope, don't continue - error already reported
226 // This signature represents what we want consumers of the targetted type to 'see'
227 // must use the factory method to build it since there may be typevariables from the binding
228 // referred to in the parameters/returntype
229 ResolvedMemberImpl sig = factory.makeResolvedMemberForITD(binding, onTypeBinding, interTypeScope.getRecoveryAliases());
230 sig.resetName(new String(declaredSelector));
231 int resetModifiers = declaredModifiers;
232 if (binding.isVarargs())
233 resetModifiers = resetModifiers | Constants.ACC_VARARGS;
234 sig.resetModifiers(resetModifiers);
235 NewMethodTypeMunger myMunger = new NewMethodTypeMunger(sig, null, typeVariableAliases);
237 ResolvedType aspectType = factory.fromEclipse(classScope.referenceContext.binding);
238 ResolvedMember me = myMunger.getInterMethodBody(aspectType);
239 this.selector = binding.selector = me.getName().toCharArray();
240 return new EclipseTypeMunger(factory, myMunger, aspectType, this);
243 private AjAttribute makeAttribute() {
244 return new AjAttribute.TypeMunger(munger);
248 public void generateCode(ClassScope classScope, ClassFile classFile) {
249 if (ignoreFurtherInvestigation) {
250 // System.err.println("no code for " + this);
254 classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
256 if (!Modifier.isAbstract(declaredModifiers)) {
257 super.generateCode(classScope, classFile); // this makes the interMethodBody
260 // annotations on the ITD declaration get put on this method
261 generateDispatchMethod(classScope, classFile);
264 public void generateDispatchMethod(ClassScope classScope, ClassFile classFile) {
265 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
267 UnresolvedType aspectType = world.fromBinding(classScope.referenceContext.binding);
268 ResolvedMember signature = munger.getSignature();
270 ResolvedMember dispatchMember = AjcMemberMaker.interMethodDispatcher(signature, aspectType);
271 MethodBinding dispatchBinding = world.makeMethodBinding(dispatchMember, munger.getTypeVariableAliases(), munger
272 .getSignature().getDeclaringType());
273 MethodBinding introducedMethod = world.makeMethodBinding(AjcMemberMaker.interMethod(signature, aspectType, onTypeBinding
274 .isInterface()), munger.getTypeVariableAliases());
276 classFile.generateMethodInfoHeader(dispatchBinding);
277 int methodAttributeOffset = classFile.contentsOffset;
279 // Watch out! We are passing in 'binding' here (instead of dispatchBinding) so that
280 // the dispatch binding attributes will include the annotations from the 'binding'.
281 // There is a chance that something else on the binding (e.g. throws clause) might
282 // damage the attributes generated for the dispatch binding.
283 int attributeNumber = classFile.generateMethodInfoAttributes(binding, makeEffectiveSignatureAttribute(signature,
284 Shadow.MethodCall, false));
285 int codeAttributeOffset = classFile.contentsOffset;
286 classFile.generateCodeAttributeHeader();
287 CodeStream codeStream = classFile.codeStream;
288 codeStream.reset(this, classFile);
289 codeStream.initializeMaxLocals(dispatchBinding);
291 Argument[] itdArgs = this.arguments;
292 if (itdArgs != null) {
293 for (int a = 0; a < itdArgs.length; a++) {
294 LocalVariableBinding lvb = itdArgs[a].binding;
295 LocalVariableBinding lvbCopy = new LocalVariableBinding(lvb.name, lvb.type, lvb.modifiers, true);
296 // e37: have to create a declaration so that the check in ClassFile (line 2538) won't skip it
297 lvbCopy.declaration = new LocalDeclaration(itdArgs[a].name,0,0);
298 codeStream.record(lvbCopy);
299 lvbCopy.recordInitializationStartPC(0);
300 lvbCopy.resolvedPosition = lvb.resolvedPosition;
304 MethodBinding methodBinding = introducedMethod;
305 TypeBinding[] parameters = methodBinding.parameters;
306 int length = parameters.length;
307 int resolvedPosition;
308 if (methodBinding.isStatic())
309 resolvedPosition = 0;
311 codeStream.aload_0();
312 resolvedPosition = 1;
314 for (int i = 0; i < length; i++) {
315 codeStream.load(parameters[i], resolvedPosition);
316 if ((parameters[i] == TypeBinding.DOUBLE) || (parameters[i] == TypeBinding.LONG))
317 resolvedPosition += 2;
322 if (methodBinding.isStatic())
323 codeStream.invoke(Opcodes.OPC_invokestatic,methodBinding,null);
325 if (methodBinding.declaringClass.isInterface()) {
326 codeStream.invoke(Opcodes.OPC_invokeinterface, methodBinding, null);
328 codeStream.invoke(Opcodes.OPC_invokevirtual, methodBinding, null);
331 AstUtil.generateReturn(dispatchBinding.returnType, codeStream);
333 // tag the local variables as used throughout the method
334 if (itdArgs != null && codeStream.locals != null) {
335 for (int a = 0; a < itdArgs.length; a++) {
336 if (codeStream.locals[a] != null) {
337 codeStream.locals[a].recordInitializationEndPC(codeStream.position);
341 classFile.completeCodeAttribute(codeAttributeOffset);
343 classFile.completeMethodInfo(binding,methodAttributeOffset, attributeNumber);
347 protected Shadow.Kind getShadowKindForBody() {
348 return Shadow.MethodExecution;
351 // XXX this code is copied from MethodScope, with a few adjustments for ITDs...
352 private void checkAndSetModifiersForMethod() {
354 // for reported problems, we want the user to see the declared selector
355 char[] realSelector = this.selector;
356 this.selector = declaredSelector;
358 final ReferenceBinding declaringClass = this.binding.declaringClass;
359 if ((declaredModifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0)
360 scope.problemReporter().duplicateModifierForMethod(onTypeBinding, this);
362 // after this point, tests on the 16 bits reserved.
363 int realModifiers = declaredModifiers & ExtraCompilerModifiers.AccJustFlag;
365 // check for abnormal modifiers
366 int unexpectedModifiers = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected
367 | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal
368 | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp);
369 if ((realModifiers & unexpectedModifiers) != 0) {
370 scope.problemReporter().illegalModifierForMethod(this);
371 declaredModifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~unexpectedModifiers;
374 // check for incompatible modifiers in the visibility bits, isolate the visibility bits
375 int accessorBits = realModifiers
376 & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate);
377 if ((accessorBits & (accessorBits - 1)) != 0) {
378 scope.problemReporter().illegalVisibilityModifierCombinationForMethod(onTypeBinding, this);
380 // need to keep the less restrictive so disable Protected/Private as necessary
381 if ((accessorBits & ClassFileConstants.AccPublic) != 0) {
382 if ((accessorBits & ClassFileConstants.AccProtected) != 0)
383 declaredModifiers &= ~ClassFileConstants.AccProtected;
384 if ((accessorBits & ClassFileConstants.AccPrivate) != 0)
385 declaredModifiers &= ~ClassFileConstants.AccPrivate;
386 } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) {
387 declaredModifiers &= ~ClassFileConstants.AccPrivate;
391 // check for modifiers incompatible with abstract modifier
392 if ((declaredModifiers & ClassFileConstants.AccAbstract) != 0) {
393 int incompatibleWithAbstract = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal
394 | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp;
395 if ((declaredModifiers & incompatibleWithAbstract) != 0)
396 scope.problemReporter().illegalAbstractModifierCombinationForMethod(onTypeBinding, this);
397 if (!onTypeBinding.isAbstract())
398 scope.problemReporter().abstractMethodInAbstractClass((SourceTypeBinding) onTypeBinding, this);
402 * DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) // methods from a
403 * final class are final : 8.4.3.3 if (methodBinding.declaringClass.isFinal()) modifiers |= AccFinal;
405 // native methods cannot also be tagged as strictfp
406 if ((declaredModifiers & ClassFileConstants.AccNative) != 0 && (declaredModifiers & ClassFileConstants.AccStrictfp) != 0)
407 scope.problemReporter().nativeMethodsCannotBeStrictfp(onTypeBinding, this);
409 // static members are only authorized in a static member or top level type
410 if (((realModifiers & ClassFileConstants.AccStatic) != 0) && declaringClass.isNestedType() && !declaringClass.isStatic())
411 scope.problemReporter().unexpectedStaticModifierForMethod(onTypeBinding, this);
413 // restore the true selector now that any problems have been reported
414 this.selector = realSelector;