001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.support.reflect.reference;
019:
020: import java.lang.annotation.Annotation;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.Method;
023: import java.lang.reflect.Modifier;
024: import java.util.ArrayList;
025: import java.util.List;
026: import java.util.Set;
027: import java.util.TreeSet;
028:
029: import spoon.reflect.declaration.CtClass;
030: import spoon.reflect.declaration.CtExecutable;
031: import spoon.reflect.declaration.CtMethod;
032: import spoon.reflect.declaration.CtSimpleType;
033: import spoon.reflect.declaration.CtType;
034: import spoon.reflect.declaration.ModifierKind;
035: import spoon.reflect.reference.CtExecutableReference;
036: import spoon.reflect.reference.CtTypeReference;
037: import spoon.reflect.visitor.CtVisitor;
038: import spoon.support.util.RtHelper;
039:
040: public class CtExecutableReferenceImpl<T> extends CtReferenceImpl
041: implements CtExecutableReference<T> {
042: private static final long serialVersionUID = 1L;
043:
044: boolean stat = false;
045:
046: List<CtTypeReference<?>> actualTypeArguments = new ArrayList<CtTypeReference<?>>();
047:
048: CtTypeReference<?> declaringType;
049:
050: List<CtTypeReference<?>> parametersTypes = new ArrayList<CtTypeReference<?>>();
051:
052: CtTypeReference<T> type;
053:
054: public CtExecutableReferenceImpl() {
055: super ();
056: }
057:
058: public void accept(CtVisitor visitor) {
059: visitor.visitCtExecutableReference(this );
060: }
061:
062: public List<CtTypeReference<?>> getActualTypeArguments() {
063: return actualTypeArguments;
064: }
065:
066: public boolean isConstructor() {
067: return getSimpleName().equals("<init>");
068: }
069:
070: @Override
071: public <A extends Annotation> A getAnnotation(
072: Class<A> annotationType) {
073: A annotation = super .getAnnotation(annotationType);
074: if (annotation != null) {
075: return annotation;
076: }
077: // use reflection
078: Class<?> c = getDeclaringType().getActualClass();
079: for (Method m : RtHelper.getAllMethods(c)) {
080: if (!getSimpleName().equals(m.getName())) {
081: continue;
082: }
083: if (getParameterTypes().size() != m.getParameterTypes().length) {
084: continue;
085: }
086: int i = 0;
087: for (Class<?> t : m.getParameterTypes()) {
088: if (t != getParameterTypes().get(i).getActualClass()) {
089: break;
090: }
091: i++;
092: }
093: if (i == getParameterTypes().size()) {
094: m.setAccessible(true);
095: return m.getAnnotation(annotationType);
096: }
097: }
098: return null;
099: }
100:
101: @Override
102: public Annotation[] getAnnotations() {
103: Annotation[] annotations = super .getAnnotations();
104: if (annotations != null) {
105: return annotations;
106: }
107: // use reflection
108: Class<?> c = getDeclaringType().getActualClass();
109: for (Method m : RtHelper.getAllMethods(c)) {
110: if (!getSimpleName().equals(m.getName())) {
111: continue;
112: }
113: if (getParameterTypes().size() != m.getParameterTypes().length) {
114: continue;
115: }
116: int i = 0;
117: for (Class<?> t : m.getParameterTypes()) {
118: if (t != getParameterTypes().get(i).getActualClass()) {
119: break;
120: }
121: i++;
122: }
123: if (i == getParameterTypes().size()) {
124: m.setAccessible(true);
125: return m.getAnnotations();
126: }
127: }
128: return null;
129: }
130:
131: @SuppressWarnings("unchecked")
132: public CtExecutable<T> getDeclaration() {
133: CtType<?> typeDecl = (CtType<?>) getDeclaringType()
134: .getDeclaration();
135: if (typeDecl == null) {
136: return null;
137: }
138:
139: CtExecutable<?> ret = typeDecl.getMethod(getSimpleName(),
140: parametersTypes.toArray(new CtTypeReference<?>[0]));
141: if ((ret == null) && (typeDecl instanceof CtClass)
142: && (getSimpleName().equals("<init>"))) {
143: try {
144: return (CtExecutable<T>) ((CtClass<?>) typeDecl)
145: .getConstructor(parametersTypes
146: .toArray(new CtTypeReference<?>[0]));
147: } catch (ClassCastException e) {
148: e.printStackTrace();
149: }
150: }
151: return (CtExecutable<T>) ret;
152: }
153:
154: public CtTypeReference<?> getDeclaringType() {
155: return declaringType;
156: }
157:
158: public List<CtTypeReference<?>> getParameterTypes() {
159: return parametersTypes;
160: }
161:
162: public CtTypeReference<T> getType() {
163: return type;
164: }
165:
166: @SuppressWarnings("unchecked")
167: public <S extends T> CtExecutableReference<S> getOverridingExecutable(
168: CtTypeReference<?> subType) {
169: if ((subType == null) || subType.equals(getDeclaringType())) {
170: return null;
171: }
172: CtSimpleType<?> t = subType.getDeclaration();
173: if (t == null) {
174: return null;
175: }
176: if (!(t instanceof CtClass)) {
177: return null;
178: }
179: CtClass<?> c = (CtClass<?>) t;
180: for (CtMethod<?> m : c.getMethods()) {
181: if (m.getReference().isOverriding(this )) {
182: return (CtExecutableReference<S>) m.getReference();
183: }
184: }
185: return getOverridingExecutable(c.getSuperclass());
186: }
187:
188: public boolean isOverriding(CtExecutableReference<?> executable) {
189: if (!this .getDeclaringType().isSubtypeOf(
190: executable.getDeclaringType())) {
191: return false;
192: }
193: if (!getSimpleName().equals(executable.getSimpleName())) {
194: return false;
195: }
196: List<CtTypeReference<?>> l1 = this .getParameterTypes();
197: List<CtTypeReference<?>> l2 = executable.getParameterTypes();
198: if (l1.size() != l2.size()) {
199: return false;
200: }
201: for (int i = 0; i < l1.size(); i++) {
202: if (!l1.get(i).isAssignableFrom(l2.get(i))) {
203: return false;
204: }
205: }
206: return true;
207: }
208:
209: public void setActualTypeArguments(
210: List<CtTypeReference<?>> actualTypeArguments) {
211: this .actualTypeArguments = actualTypeArguments;
212: }
213:
214: public void setDeclaringType(CtTypeReference<?> declaringType) {
215: this .declaringType = declaringType;
216: }
217:
218: public void setParameterTypes(
219: List<CtTypeReference<?>> parameterTypes) {
220: this .parametersTypes = parameterTypes;
221: }
222:
223: public void setType(CtTypeReference<T> type) {
224: this .type = type;
225: }
226:
227: public Method getActualMethod() {
228: for (Method m : getDeclaringType().getActualClass()
229: .getDeclaredMethods()) {
230: if (!m.getName().equals(getSimpleName())) {
231: continue;
232: }
233: if (m.getParameterTypes().length != getParameterTypes()
234: .size()) {
235: continue;
236: }
237: boolean matches = true;
238: for (int i = 0; i < m.getParameterTypes().length; i++) {
239: if (m.getParameterTypes()[i] != getParameterTypes()
240: .get(i).getActualClass()) {
241: matches = false;
242: break;
243: }
244: }
245: if (matches) {
246: return m;
247: }
248: }
249: return null;
250: }
251:
252: public Constructor<?> getActualConstructor() {
253: for (Constructor<?> c : getDeclaringType().getActualClass()
254: .getDeclaredConstructors()) {
255: if (c.getParameterTypes().length != getParameterTypes()
256: .size()) {
257: continue;
258: }
259: boolean matches = true;
260: for (int i = 0; i < c.getParameterTypes().length; i++) {
261: if (c.getParameterTypes()[i] != getParameterTypes()
262: .get(i).getActualClass()) {
263: matches = false;
264: break;
265: }
266: }
267: if (matches) {
268: return c;
269: }
270: }
271: return null;
272: }
273:
274: public boolean isStatic() {
275: return stat;
276: // CtExecutable<?> e = getDeclaration();
277: // if (e != null) {
278: // return e.getModifiers().contains(ModifierKind.STATIC);
279: // }
280: // try {
281: // Class declaringClass = Class.forName(getDeclaringType()
282: // .getQualifiedName());
283: //
284: // List<CtTypeReference<?>> paramsRef = getParameterTypes();
285: //
286: // for (Method m : declaringClass.getMethods()) {
287: // if (m.getName().equals(getSimpleName())) {
288: // int count = 0;
289: // int i = 0;
290: // Class[] params = m.getParameterTypes();
291: // for (; i < params.length && i < paramsRef.size()
292: // && i == count; i++) {
293: // if (params[i] == paramsRef.get((i)).getActualClass()) {
294: // count++;
295: // }
296: // }
297: //
298: // if (count == i) {
299: // return Modifier.isStatic(m.getModifiers());
300: // } else {
301: // if (count == params.length - 1) {
302: // for (; i < paramsRef.size() && i == count + 1; i++) {
303: // if (paramsRef.get(i).getActualClass() == params[params.length - 1]
304: // .getComponentType())
305: // count++;
306: // }
307: // if (i == count + 1)
308: // return Modifier.isStatic(m.getModifiers());
309: // }
310: // }
311: // }
312: // }
313: // } catch (Exception e1) {
314: // e1.printStackTrace();
315: // }
316: //
317: // return false;
318: }
319:
320: public void setStatic(boolean b) {
321: this .stat = b;
322: }
323:
324: public boolean isFinal() {
325: CtExecutable<T> e = getDeclaration();
326: if (e != null) {
327: return e.hasModifier(ModifierKind.FINAL);
328: }
329: Method m = getActualMethod();
330: if (m != null) {
331: return Modifier.isFinal(m.getModifiers());
332: }
333: return false;
334: }
335:
336: public Set<ModifierKind> getModifiers() {
337: CtExecutable<T> e = getDeclaration();
338: if (e != null) {
339: return e.getModifiers();
340: }
341: Method m = getActualMethod();
342: if (m != null) {
343: return RtHelper.getModifiers(m.getModifiers());
344: }
345: Constructor<?> c = getActualConstructor();
346: if (c != null) {
347: return RtHelper.getModifiers(c.getModifiers());
348: }
349: return new TreeSet<ModifierKind>();
350: }
351:
352: public CtExecutableReference<?> getOverridingExecutable() {
353: CtTypeReference<?> st = getDeclaringType().getSuperclass();
354: CtTypeReference<Object> objectType = getFactory().Type()
355: .createReference(Object.class);
356: if (st == null) {
357: return getOverloadedExecutable(objectType, objectType);
358: }
359: return getOverloadedExecutable(st, objectType);
360: }
361:
362: private CtExecutableReference<?> getOverloadedExecutable(
363: CtTypeReference<?> t, CtTypeReference<Object> objectType) {
364: if (t == null) {
365: return null;
366: }
367: for (CtExecutableReference<?> e : t.getDeclaredExecutables()) {
368: if (this .isOverriding(e)) {
369: return e;
370: }
371: }
372: if (t.equals(objectType)) {
373: return null;
374: }
375: CtTypeReference<?> st = t.getSuperclass();
376: if (st == null) {
377: return getOverloadedExecutable(objectType, objectType);
378: }
379: return getOverloadedExecutable(t.getSuperclass(), objectType);
380: }
381: }
|