1 /* *******************************************************************
2 * Copyright (c) 2010 Contributors
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 * Andy Clement - SpringSource
11 * ******************************************************************/
12 package org.aspectj.ajdt.internal.compiler.ast;
14 import java.lang.reflect.Modifier;
15 import java.util.Collections;
17 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
18 import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceLocation;
19 import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
20 import org.aspectj.ajdt.internal.compiler.lookup.InterTypeScope;
21 import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
22 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
23 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
24 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
25 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
26 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
27 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
28 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
29 import org.aspectj.weaver.AjAttribute;
30 import org.aspectj.weaver.NewMemberClassTypeMunger;
31 import org.aspectj.weaver.ResolvedType;
32 import org.aspectj.weaver.ResolvedTypeMunger;
35 * Represents an intertype member class declaration.
37 * @author Andy Clement
40 public class IntertypeMemberClassDeclaration extends TypeDeclaration {
42 // The target type for this inner class
43 private TypeReference onType;
44 private ReferenceBinding onTypeResolvedBinding;
45 private NewMemberClassTypeMunger newMemberClassTypeMunger;
46 protected InterTypeScope interTypeScope;
47 // When set to true, the scope hierarchy for the field/method declaration has been correctly modified to include an intertype
48 // scope which resolves things relative to the targeted type.
49 private boolean scopeSetup = false;
51 public IntertypeMemberClassDeclaration(CompilationResult compilationResult) {
52 super(compilationResult);
55 public ResolvedTypeMunger getMunger() {
56 return newMemberClassTypeMunger;
60 public void resolve(ClassScope aspectScope) {
61 resolveOnType(aspectScope);
63 super.resolve(aspectScope);
67 public void resolve() {
72 public void resolve(BlockScope blockScope) {
73 throw new IllegalStateException();
77 public void resolve(CompilationUnitScope upperScope) {
78 throw new IllegalStateException();
81 @SuppressWarnings("unchecked")
83 protected void generateAttributes(ClassFile classFile) {
84 // classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
85 super.generateAttributes(classFile);
88 public AjAttribute getAttribute() {
89 // if there were problems then there is nothing to return
90 if (newMemberClassTypeMunger == null) {
93 return new AjAttribute.TypeMunger(newMemberClassTypeMunger);
97 * Called just before the compiler is going to start resolving elements of a declaration, this method adds an intertype scope so
98 * that elements of the type targeted by the ITD can be resolved. For example, if type variables are referred to in the ontype
99 * for the ITD, they have to be resolved against the ontype, not the aspect containing the ITD.
101 public void ensureScopeSetup() {
103 return; // don't do it again
105 ClassScope scope = this.scope;
107 // TODO [inner] ton of stuff related to parameterization support
109 // if (ot instanceof ParameterizedQualifiedTypeReference) { // pr132349
110 // ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
111 // if (pref.typeArguments != null && pref.typeArguments.length != 0) {
112 // boolean usingNonTypeVariableInITD = false;
113 // // Check if any of them are not type variables
114 // for (int i = 0; i < pref.typeArguments.length; i++) {
115 // TypeReference[] refs = pref.typeArguments[i];
116 // for (int j = 0; refs != null && j < refs.length; j++) {
117 // TypeBinding tb = refs[j].getTypeBindingPublic(scope.parent);
118 // if (!tb.isTypeVariable() && !(tb instanceof ProblemReferenceBinding)) {
119 // usingNonTypeVariableInITD = true;
124 // if (usingNonTypeVariableInITD) {
125 // scope.problemReporter().signalError(sourceStart, sourceEnd,
126 // "Cannot make inter-type declarations on parameterized types");
127 // // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
128 // this.arguments = null;
129 // this.returnType = new SingleTypeReference(TypeReference.VOID, 0L);
131 // this.ignoreFurtherInvestigation = true;
132 // ReferenceBinding closestMatch = null;
133 // rb = new ProblemReferenceBinding(ot.getParameterizedTypeName(), closestMatch, 0);
140 // // Work out the real base type
141 // if (onType instanceof ParameterizedSingleTypeReference) {
142 // ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) ot;
143 // long pos = (((long) pref.sourceStart) << 32) | pref.sourceEnd;
144 // ot = new SingleTypeReference(pref.token, pos);
145 // } else if (ot instanceof ParameterizedQualifiedTypeReference) {
146 // ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
147 // long pos = (((long) pref.sourceStart) << 32) | pref.sourceEnd;
148 // ot = new QualifiedTypeReference(pref.tokens, new long[] { pos });// SingleTypeReference(pref.Quatoken,pos);
153 // rb = (ReferenceBinding) ot.getTypeBindingPublic(scope.parent);
156 // pr203646 - if we have ended up with the raw type, get back to the underlying generic one.
157 // if (rb.isRawType() && rb.isMemberType()) {
158 // // if the real target type used a type variable alias then we can do this OK, but need to switch things around, we want
159 // // the generic type
160 // rb = ((RawTypeBinding) rb).type;
163 // if (rb instanceof TypeVariableBinding) {
164 // scope.problemReporter().signalError(sourceStart, sourceEnd,
165 // "Cannot make inter-type declarations on type variables, use an interface and declare parents");
166 // // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
167 // this.arguments = null;
168 // this.returnType = new SingleTypeReference(TypeReference.VOID, 0L);
170 // this.ignoreFurtherInvestigation = true;
171 // ReferenceBinding closestMatch = null;
172 // if (((TypeVariableBinding) rb).firstBound != null) {
173 // closestMatch = ((TypeVariableBinding) rb).firstBound.enclosingType();
175 // rb = new ProblemReferenceBinding(rb.compoundName, closestMatch, 0);
178 // if resolution failed, give up - someone else is going to report an error
179 // if (rb instanceof ProblemReferenceBinding) {
183 interTypeScope = new InterTypeScope(scope.parent, onTypeResolvedBinding, Collections.emptyList());
184 // FIXME asc verify the choice of lines here...
185 // Two versions of this next line.
186 // First one tricks the JDT variable processing code so that it won't complain if
187 // you refer to a type variable from a static ITD - it *is* a problem and it *will* be caught, but later and
188 // by the AJDT code so we can put out a much nicer message.
189 // scope.isStatic = (typeVariableAliases != null ? false : Modifier.isStatic(declaredModifiers));
190 // this is the original version in case tricking the JDT causes grief (if you reinstate this variant, you
191 // will need to change the expected messages output for some of the generic ITD tests)
192 // scope.isStatic = Modifier.isStatic(declaredModifiers);
193 scope.parent = interTypeScope;
197 public void setOnType(TypeReference onType) {
198 this.onType = onType;
201 private void resolveOnType(ClassScope cuScope) {
202 if (onType == null || onTypeResolvedBinding != null) {
204 } // error reported elsewhere.
206 onTypeResolvedBinding = (ReferenceBinding) onType.getTypeBindingPublic(cuScope);
207 if (!onTypeResolvedBinding.isValidBinding()) {
208 cuScope.problemReporter().invalidType(onType, onTypeResolvedBinding);
209 ignoreFurtherInvestigation = true;
213 public EclipseTypeMunger build(ClassScope classScope) {
214 EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(classScope);
215 resolveOnType(classScope);
218 if (ignoreFurtherInvestigation) {
222 if (onTypeResolvedBinding.isInterface() || onTypeResolvedBinding.isEnum() || onTypeResolvedBinding.isAnnotationType()) {
223 scope.problemReporter().signalError(
226 "Cannot declare new member type on '" + onType.toString()
227 + "'. New member types can only be specified on classes (compiler limitation)");
231 if (!Modifier.isStatic(modifiers)) {
232 scope.problemReporter().signalError(sourceStart, sourceEnd,
233 "Intertype declared member types can only be static (compiler limitation)");
237 ResolvedType declaringType = world.fromBinding(onTypeResolvedBinding).resolve(world.getWorld());
238 if (declaringType.isRawType() || declaringType.isParameterizedType()) {
239 declaringType = declaringType.getGenericType();
242 if (interTypeScope == null) {
243 return null; // We encountered a problem building the scope, don't continue - error already reported
246 // TODO [inner] use the interTypeScope.getRecoveryAliases
247 // TODO [inner] should mark it in the aspect as unreachable - it is not to be considered part of the aspect
248 newMemberClassTypeMunger = new NewMemberClassTypeMunger(declaringType, new String(this.name));
249 newMemberClassTypeMunger.setSourceLocation(new EclipseSourceLocation(compilationResult, sourceStart, sourceEnd));
250 ResolvedType aspectType = world.fromEclipse(classScope.referenceContext.binding);
251 return new EclipseTypeMunger(world, newMemberClassTypeMunger, aspectType, null);