]> source.dussan.org Git - aspectj.git/blob
4fbdfa849b2426ab01690ad5babe467710b82976
[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 package org.aspectj.ajdt.internal.compiler.lookup;
13
14 import java.lang.reflect.Modifier;
15 import java.util.Map;
16
17 import org.aspectj.bridge.ISourceLocation;
18 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
19 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
20 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
21 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
22 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
23 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
24 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
27 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
28 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
29 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding;
30 import org.aspectj.weaver.ConcreteTypeMunger;
31 import org.aspectj.weaver.NewConstructorTypeMunger;
32 import org.aspectj.weaver.NewFieldTypeMunger;
33 import org.aspectj.weaver.NewMemberClassTypeMunger;
34 import org.aspectj.weaver.NewMethodTypeMunger;
35 import org.aspectj.weaver.ResolvedMember;
36 import org.aspectj.weaver.ResolvedType;
37 import org.aspectj.weaver.ResolvedTypeMunger;
38 import org.aspectj.weaver.UnresolvedType;
39 import org.aspectj.weaver.World;
40
41 public class EclipseTypeMunger extends ConcreteTypeMunger {
42         private ResolvedType targetTypeX;
43         // protected ReferenceBinding targetBinding = null;
44         public AbstractMethodDeclaration sourceMethod;
45         private EclipseFactory world;
46         private ISourceLocation sourceLocation;
47
48         public EclipseTypeMunger(EclipseFactory world, ResolvedTypeMunger munger, ResolvedType aspectType,
49                         AbstractMethodDeclaration sourceMethod) {
50                 super(munger, aspectType);
51                 this.world = world;
52                 this.sourceMethod = sourceMethod;
53                 // A null sourceMethod can be because of binary weaving
54                 if (sourceMethod != null) {
55                         this.sourceLocation = new EclipseSourceLocation(sourceMethod.compilationResult, sourceMethod.sourceStart,
56                                         sourceMethod.sourceEnd);
57                         // Piece of magic that tells type mungers where they came from.
58                         // Won't be persisted unless ResolvedTypeMunger.persistSourceLocation is true.
59                         munger.setSourceLocation(sourceLocation);
60
61                         // use a different ctor for type level inter type decls I think
62                         // } else {
63                         // this.sourceLocation = aspectType.getSourceLocation();
64                         // munger.setSourceLocation(sourceLocation);
65                 }
66                 // was
67                 targetTypeX = munger.getDeclaringType().resolve(world.getWorld());
68                 // targetTypeX = munger.getSignature().getDeclaringType().resolve(world.getWorld());
69                 // AMC, needed until generic and raw have distinct sigs...
70                 if (targetTypeX.isParameterizedType() || targetTypeX.isRawType()) {
71                         targetTypeX = targetTypeX.getGenericType();
72                         // targetBinding = (ReferenceBinding)world.makeTypeBinding(targetTypeX);
73                 }
74         }
75
76         public static boolean supportsKind(ResolvedTypeMunger.Kind kind) {
77                 return kind == ResolvedTypeMunger.Field || kind == ResolvedTypeMunger.Method || kind == ResolvedTypeMunger.Constructor
78                                 || kind == ResolvedTypeMunger.InnerClass;
79         }
80
81         @Override
82         public String toString() {
83                 return "(EclipseTypeMunger " + getMunger() + ")";
84         }
85
86         /**
87          * Modifies signatures of a TypeBinding through its ClassScope, i.e. adds Method|FieldBindings, plays with inheritance, ...
88          */
89         public boolean munge(SourceTypeBinding sourceType, ResolvedType onType) {
90                 ResolvedType rt = onType;
91                 if (rt.isRawType() || rt.isParameterizedType()) {
92                         rt = rt.getGenericType();
93                 }
94                 boolean isExactTargetType = rt.equals(targetTypeX);
95                 if (!isExactTargetType) {
96                         // might be the topmost implementor of an interface we care about
97                         if (munger.getKind() != ResolvedTypeMunger.Method) {
98                                 return false;
99                         }
100                         if (onType.isInterface()) {
101                                 return false;
102                         }
103                         if (!munger.needsAccessToTopmostImplementor()) {
104                                 return false;
105                         }
106                         // so we do need access, and this type could be it...
107                         if (!onType.isTopmostImplementor(targetTypeX)) {
108                                 return false;
109                         }
110                         // we are the topmost implementor of an interface type that needs munging
111                         // but we only care about public methods here (we only do this at all to
112                         // drive the JDT MethodVerifier correctly)
113                         if (!Modifier.isPublic(munger.getSignature().getModifiers())) {
114                                 return false;
115                         }
116                 }
117                 // System.out.println("munging: " + sourceType);
118                 // System.out.println("match: " + world.fromEclipse(sourceType) +
119                 // " with " + targetTypeX);
120                 if (munger.getKind() == ResolvedTypeMunger.Field) {
121                         mungeNewField(sourceType, (NewFieldTypeMunger) munger);
122                 } else if (munger.getKind() == ResolvedTypeMunger.Method) {
123                         return mungeNewMethod(sourceType, onType, (NewMethodTypeMunger) munger, isExactTargetType);
124                 } else if (munger.getKind() == ResolvedTypeMunger.Constructor) {
125                         mungeNewConstructor(sourceType, (NewConstructorTypeMunger) munger);
126                 } else if (munger.getKind() == ResolvedTypeMunger.InnerClass) {
127                         mungeNewInnerClass(sourceType, onType, (NewMemberClassTypeMunger) munger, isExactTargetType);
128                 } else {
129                         throw new RuntimeException("unimplemented: " + munger.getKind());
130                 }
131                 return true;
132         }
133
134         private boolean mungeNewMethod(SourceTypeBinding sourceType, ResolvedType onType, NewMethodTypeMunger munger,
135                         boolean isExactTargetType) {
136                 InterTypeMethodBinding binding = new InterTypeMethodBinding(world, munger, aspectType, sourceMethod);
137
138                 if (!isExactTargetType) {
139                         // we're munging an interface ITD onto a topmost implementor
140                         ResolvedMember existingMember = onType.lookupMemberIncludingITDsOnInterfaces(getSignature());
141                         if (existingMember != null) {
142                                 // already have an implementation, so don't do anything
143                                 if (onType == existingMember.getDeclaringType() && Modifier.isFinal(munger.getSignature().getModifiers())) {
144                                         // final modifier on default implementation is taken to mean that
145                                         // no-one else can provide an implementation
146                                         if (!(sourceType instanceof BinaryTypeBinding)) {
147                                                 // If sourceType is a BinaryTypeBinding, this can indicate we are re-applying the ITDs to the target
148                                                 // as we 'pull it in' to resolve something.  This means the clash here is with itself !  So if the ITD
149                                                 // was final when initially added to the target this error logic will trigger.  We can't easily
150                                                 // identify it was added via ITD, so I'm going to make this quick change to say avoid this error for 
151                                                 // BinaryTypeBindings
152                                                 CompilationUnitScope cuScope = sourceType.scope.compilationUnitScope();
153                                                 MethodBinding offendingBinding = sourceType.getExactMethod(binding.selector, binding.parameters, cuScope);
154                                                 sourceType.scope.problemReporter().finalMethodCannotBeOverridden(offendingBinding, binding);
155                                         }
156                                 }
157                                 // so that we find methods from our superinterfaces later on...
158                                 findOrCreateInterTypeMemberFinder(sourceType);
159                                 return false;
160                         }
161                 }
162
163                 // retain *only* the visibility modifiers and abstract when putting methods on an interface...
164                 if (sourceType.isInterface()) {
165                         boolean isAbstract = (binding.modifiers & ClassFileConstants.AccAbstract) != 0;
166                         binding.modifiers = (binding.modifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate));
167                         if (isAbstract) {
168                                 binding.modifiers |= ClassFileConstants.AccAbstract;
169                         }
170                 }
171                 if (munger.getSignature().isVarargsMethod()) {
172                         binding.modifiers |= ClassFileConstants.AccVarargs;
173                 }
174                 findOrCreateInterTypeMemberFinder(sourceType).addInterTypeMethod(binding);
175                 return true;
176         }
177
178         // very similar to code in AspectDeclaration
179         private boolean mungeNewInnerClass(SourceTypeBinding sourceType, ResolvedType onType, NewMemberClassTypeMunger munger,
180                         boolean isExactTargetType) {
181
182                 SourceTypeBinding aspectTypeBinding = (SourceTypeBinding) world.makeTypeBinding(aspectType);
183
184                 char[] mungerMemberTypeName = ("$" + munger.getMemberTypeName()).toCharArray();
185                 ReferenceBinding innerTypeBinding = null;
186                 for (ReferenceBinding innerType : aspectTypeBinding.memberTypes) {
187                         char[] compounded = CharOperation.concatWith(innerType.compoundName, '.');
188                         if (org.aspectj.org.eclipse.jdt.core.compiler.CharOperation.endsWith(compounded, mungerMemberTypeName)) {
189                                 innerTypeBinding = innerType;
190                                 break;
191                         }
192                 }
193                 // may be unresolved if the aspect type binding was a BinaryTypeBinding
194                 if (innerTypeBinding instanceof UnresolvedReferenceBinding) {
195                         innerTypeBinding = (ReferenceBinding)BinaryTypeBinding.resolveType(innerTypeBinding, world.getLookupEnvironment(), true);
196                 }
197                 // rb = new InterTypeMemberClassBinding(world, munger, aspectType, aspectTypeBinding, onType, munger.getMemberTypeName(),
198                 // sourceType);
199
200                 // TODO adjust modifier?
201                 // TODO deal with itd of it onto an interface
202
203                 findOrCreateInterTypeMemberClassFinder(sourceType).addInterTypeMemberType(innerTypeBinding);
204                 return true;
205         }
206
207         private void mungeNewConstructor(SourceTypeBinding sourceType, NewConstructorTypeMunger munger) {
208                 if (shouldTreatAsPublic()) {
209                         MethodBinding binding = world.makeMethodBinding(munger.getSignature(), munger.getTypeVariableAliases());
210                         findOrCreateInterTypeMemberFinder(sourceType).addInterTypeMethod(binding);
211                         TypeVariableBinding[] typeVariables = binding.typeVariables;
212                         for (int i = 0; i < typeVariables.length; i++) {
213                                 TypeVariableBinding tv = typeVariables[i];
214                                 String name = new String(tv.sourceName);
215                                 TypeVariableBinding[] tv2 = sourceMethod.binding.typeVariables;
216                                 for (int j = 0; j < tv2.length; j++) {
217                                         if (new String(tv2[j].sourceName).equals(name)) {
218                                                 typeVariables[i].declaringElement = binding;
219                                         }
220                                 }
221                         }
222                         for (int i = 0; i < typeVariables.length; i++) {
223                                 if (typeVariables[i].declaringElement == null) {
224                                         throw new RuntimeException("Declaring element not set");
225                                 }
226
227                         }
228                         // classScope.referenceContext.binding.addMethod(binding);
229                 } else {
230                         InterTypeMethodBinding binding = new InterTypeMethodBinding(world, munger, aspectType, sourceMethod);
231                         findOrCreateInterTypeMemberFinder(sourceType).addInterTypeMethod(binding);
232                 }
233
234         }
235
236         private void mungeNewField(SourceTypeBinding sourceType, NewFieldTypeMunger munger) {
237                 if (shouldTreatAsPublic() && !targetTypeX.isInterface()) {
238                         FieldBinding binding = world.makeFieldBinding(munger);
239                         findOrCreateInterTypeMemberFinder(sourceType).addInterTypeField(binding);
240                         // classScope.referenceContext.binding.addField(binding);
241                 } else {
242                         InterTypeFieldBinding binding = new InterTypeFieldBinding(world, munger, aspectType, sourceMethod);
243                         InterTypeMemberFinder finder = findOrCreateInterTypeMemberFinder(sourceType);
244                         // Downgrade this field munger if name is already 'claimed'
245                         if (finder.definesField(munger.getSignature().getName())) {
246                                 munger.version = NewFieldTypeMunger.VersionOne;
247                         }
248                         finder.addInterTypeField(binding);
249                 }
250         }
251
252         private boolean shouldTreatAsPublic() {
253                 // ??? this is where we could fairly easily choose to treat package-protected
254                 // ??? introductions like public ones when the target type and the aspect
255                 // ??? are in the same package
256                 return Modifier.isPublic(munger.getSignature().getModifiers());
257         }
258
259         private InterTypeMemberFinder findOrCreateInterTypeMemberFinder(SourceTypeBinding sourceType) {
260                 InterTypeMemberFinder finder = (InterTypeMemberFinder) sourceType.memberFinder;
261                 if (finder == null) {
262                         finder = new InterTypeMemberFinder();
263                         sourceType.memberFinder = finder;
264                         finder.sourceTypeBinding = sourceType;
265                 }
266                 return finder;
267         }
268
269         private IntertypeMemberTypeFinder findOrCreateInterTypeMemberClassFinder(SourceTypeBinding sourceType) {
270                 IntertypeMemberTypeFinder finder = (IntertypeMemberTypeFinder) sourceType.typeFinder;
271                 if (finder == null) {
272                         finder = new IntertypeMemberTypeFinder();
273                         sourceType.typeFinder = finder;
274                         finder.targetTypeBinding = sourceType;
275                         sourceType.tagBits &= ~TagBits.HasNoMemberTypes; // ensure it thinks it has one
276                 }
277                 return finder;
278         }
279
280         @Override
281         public ISourceLocation getSourceLocation() {
282                 return sourceLocation;
283         }
284
285         public void setSourceLocation(ISourceLocation sourceLocation) {
286                 this.sourceLocation = sourceLocation;
287         }
288
289         /**
290          * @return AbstractMethodDeclaration
291          */
292         public AbstractMethodDeclaration getSourceMethod() {
293                 return sourceMethod;
294         }
295
296         @Override
297         public ConcreteTypeMunger parameterizedFor(ResolvedType target) {
298                 return new EclipseTypeMunger(world, munger.parameterizedFor(target), aspectType, sourceMethod);
299         }
300
301         public ConcreteTypeMunger parameterizeWith(Map<String,UnresolvedType> m, World w) {
302                 return new EclipseTypeMunger(world, munger.parameterizeWith(m, w), aspectType, sourceMethod);
303         }
304
305 }