1 /*
2  * Copyright 2014 - 2020 Rafael Winterhalter
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.bytebuddy.description.method;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.CachedReturnPlugin;
20 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21 import net.bytebuddy.description.ByteCodeElement;
22 import net.bytebuddy.description.ModifierReviewable;
23 import net.bytebuddy.description.NamedElement;
24 import net.bytebuddy.description.annotation.AnnotationDescription;
25 import net.bytebuddy.description.annotation.AnnotationList;
26 import net.bytebuddy.description.annotation.AnnotationSource;
27 import net.bytebuddy.description.type.TypeDefinition;
28 import net.bytebuddy.description.type.TypeDescription;
29 import net.bytebuddy.description.type.TypeList;
30 import net.bytebuddy.implementation.bytecode.StackSize;
31 import net.bytebuddy.matcher.ElementMatcher;
32
33 import java.lang.annotation.Annotation;
34 import java.lang.reflect.*;
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37 import java.util.AbstractList;
38 import java.util.Collections;
39 import java.util.List;
40
41 /**
42  * Description of the parameter of a Java method or constructor.
43  */

44 public interface ParameterDescription extends AnnotationSource,
45         NamedElement.WithRuntimeName,
46         NamedElement.WithOptionalName,
47         ModifierReviewable.ForParameterDescription,
48         ByteCodeElement.TypeDependant<ParameterDescription.InDefinedShape, ParameterDescription.Token> {
49
50     /**
51      * The prefix for names of an unnamed parameter.
52      */

53     String NAME_PREFIX = "arg";
54
55     /**
56      * Returns the type of this parameter.
57      *
58      * @return The type of this parameter.
59      */

60     TypeDescription.Generic getType();
61
62     /**
63      * Returns the method that declares this parameter.
64      *
65      * @return The method that declares this parameter.
66      */

67     MethodDescription getDeclaringMethod();
68
69     /**
70      * Returns this parameter's index.
71      *
72      * @return The index of this parameter.
73      */

74     int getIndex();
75
76     /**
77      * Checks if this parameter has an explicit modifier. A parameter without a modifier is simply treated as
78      * if it had a modifier of zero.
79      *
80      * @return {@code trueif this parameter defines explicit modifiers.
81      */

82     boolean hasModifiers();
83
84     /**
85      * Returns the offset to the parameter value within the local method variable.
86      *
87      * @return The offset of this parameter's value.
88      */

89     int getOffset();
90
91     /**
92      * Represents a parameter description in its generic shape, i.e. in the shape it is defined by a generic or raw type.
93      */

94     interface InGenericShape extends ParameterDescription {
95
96         /**
97          * {@inheritDoc}
98          */

99         MethodDescription.InGenericShape getDeclaringMethod();
100     }
101
102     /**
103      * Represents a parameter in its defined shape, i.e. in the form it is defined by a class without its type variables being resolved.
104      */

105     interface InDefinedShape extends ParameterDescription {
106
107         /**
108          * {@inheritDoc}
109          */

110         MethodDescription.InDefinedShape getDeclaringMethod();
111
112         /**
113          * An abstract base implementation of a parameter description in its defined shape.
114          */

115         abstract class AbstractBase extends ParameterDescription.AbstractBase implements InDefinedShape {
116
117             /**
118              * {@inheritDoc}
119              */

120             public InDefinedShape asDefined() {
121                 return this;
122             }
123         }
124     }
125
126     /**
127      * A base implementation of a method parameter description.
128      */

129     abstract class AbstractBase extends ModifierReviewable.AbstractBase implements ParameterDescription {
130
131         /**
132          * {@inheritDoc}
133          */

134         public String getName() {
135             return NAME_PREFIX.concat(String.valueOf(getIndex()));
136         }
137
138         /**
139          * {@inheritDoc}
140          */

141         public String getInternalName() {
142             return getName();
143         }
144
145         /**
146          * {@inheritDoc}
147          */

148         public String getActualName() {
149             return isNamed()
150                     ? getName()
151                     : EMPTY_NAME;
152         }
153
154         /**
155          * {@inheritDoc}
156          */

157         public int getModifiers() {
158             return EMPTY_MASK;
159         }
160
161         /**
162          * {@inheritDoc}
163          */

164         public int getOffset() {
165             TypeList parameterType = getDeclaringMethod().getParameters().asTypeList().asErasures();
166             int offset = getDeclaringMethod().isStatic()
167                     ? StackSize.ZERO.getSize()
168                     : StackSize.SINGLE.getSize();
169             for (int i = 0; i < getIndex(); i++) {
170                 offset += parameterType.get(i).getStackSize().getSize();
171             }
172             return offset;
173         }
174
175         /**
176          * {@inheritDoc}
177          */

178         public Token asToken(ElementMatcher<? super TypeDescription> matcher) {
179             return new Token(getType().accept(new TypeDescription.Generic.Visitor.Substitutor.ForDetachment(matcher)),
180                     getDeclaredAnnotations(),
181                     isNamed()
182                             ? getName()
183                             : Token.NO_NAME,
184                     hasModifiers()
185                             ? (Integer) getModifiers()
186                             : Token.NO_MODIFIERS);
187         }
188
189         @Override
190         @CachedReturnPlugin.Enhance
191         public int hashCode() {
192             return getDeclaringMethod().hashCode() ^ getIndex();
193         }
194
195         @Override
196         public boolean equals(Object other) {
197             if (this == other) {
198                 return true;
199             } else if (!(other instanceof ParameterDescription)) {
200                 return false;
201             }
202             ParameterDescription parameterDescription = (ParameterDescription) other;
203             return getDeclaringMethod().equals(parameterDescription.getDeclaringMethod()) && getIndex() == parameterDescription.getIndex();
204         }
205
206         @Override
207         public String toString() {
208             StringBuilder stringBuilder = new StringBuilder(Modifier.toString(getModifiers()));
209             if (getModifiers() != EMPTY_MASK) {
210                 stringBuilder.append(' ');
211             }
212             stringBuilder.append(isVarArgs()
213                     ? getType().asErasure().getName().replaceFirst("\\[\\]$""...")
214                     : getType().asErasure().getName());
215             return stringBuilder.append(' ').append(getName()).toString();
216         }
217     }
218
219     /**
220      * Description of a loaded parameter with support for the information exposed by {@code java.lang.reflect.Parameter}.
221      *
222      * @param <T> The type of the {@code java.lang.reflect.Executable} that this list represents.
223      */

224     abstract class ForLoadedParameter<T extends AccessibleObject> extends InDefinedShape.AbstractBase {
225
226         /**
227          * A dispatcher for reading properties from {@code java.lang.reflect.Executable} instances.
228          */

229         private static final Dispatcher DISPATCHER = AccessController.doPrivileged(Dispatcher.CreationAction.INSTANCE);
230
231         /**
232          * The {@code java.lang.reflect.Executable} for which the parameter types are described.
233          */

234         protected final T executable;
235
236         /**
237          * The parameter's index.
238          */

239         protected final int index;
240
241         /**
242          * The parameter annotation source to query.
243          */

244         protected final ParameterAnnotationSource parameterAnnotationSource;
245
246         /**
247          * Creates a new description for a loaded parameter.
248          *
249          * @param executable                The {@code java.lang.reflect.Executable} for which the parameter types are described.
250          * @param index                     The parameter's index.
251          * @param parameterAnnotationSource The parameter annotation source to query.
252          */

253         protected ForLoadedParameter(T executable, int index, ParameterAnnotationSource parameterAnnotationSource) {
254             this.executable = executable;
255             this.index = index;
256             this.parameterAnnotationSource = parameterAnnotationSource;
257         }
258
259         /**
260          * {@inheritDoc}
261          */

262         public String getName() {
263             return DISPATCHER.getName(executable, index);
264         }
265
266         /**
267          * {@inheritDoc}
268          */

269         public int getIndex() {
270             return index;
271         }
272
273         /**
274          * {@inheritDoc}
275          */

276         public boolean isNamed() {
277             return DISPATCHER.isNamePresent(executable, index);
278         }
279
280         /**
281          * {@inheritDoc}
282          */

283         public int getModifiers() {
284             return DISPATCHER.getModifiers(executable, index);
285         }
286
287         /**
288          * {@inheritDoc}
289          */

290         public boolean hasModifiers() {
291             // Rational: If a parameter is not named despite the information being attached,
292             // it is synthetic, i.e. it has non-default modifiers.
293             return isNamed() || getModifiers() != EMPTY_MASK;
294         }
295
296         /**
297          * A source for querying parameter annotations.
298          */

299         public interface ParameterAnnotationSource {
300
301             /**
302              * Returns the parameter annotations represented by this source.
303              *
304              * @return The parameter annotations as an array indexed by parameter index.
305              */

306             Annotation[][] getParameterAnnotations();
307
308             /**
309              * A source for a loaded constructor.
310              */

311             @HashCodeAndEqualsPlugin.Enhance
312             class ForLoadedConstructor implements ParameterAnnotationSource {
313
314                 /**
315                  * The constructor to query for annotations.
316                  */

317                 private final Constructor<?> constructor;
318
319                 /**
320                  * Creates a new parameter annotation source for a constructor.
321                  *
322                  * @param constructor The constructor to query for annotations.
323                  */

324                 public ForLoadedConstructor(Constructor<?> constructor) {
325                     this.constructor = constructor;
326                 }
327
328                 /**
329                  * {@inheritDoc}
330                  */

331                 public Annotation[][] getParameterAnnotations() {
332                     return constructor.getParameterAnnotations();
333                 }
334             }
335
336             /**
337              * A source for a loaded method.
338              */

339             @HashCodeAndEqualsPlugin.Enhance
340             class ForLoadedMethod implements ParameterAnnotationSource {
341
342                 /**
343                  * The method to query for annotations.
344                  */

345                 private final Method method;
346
347                 /**
348                  * Creates a new parameter annpotation source for a method.
349                  *
350                  * @param method The method to query for annotations.
351                  */

352                 public ForLoadedMethod(Method method) {
353                     this.method = method;
354                 }
355
356                 /**
357                  * {@inheritDoc}
358                  */

359                 public Annotation[][] getParameterAnnotations() {
360                     return method.getParameterAnnotations();
361                 }
362             }
363         }
364
365         /**
366          * A dispatcher creating parameter descriptions based on the API that is available for the current JVM.
367          */

368         protected interface Dispatcher {
369
370             /**
371              * Returns the given parameter's modifiers.
372              *
373              * @param executable The executable to introspect.
374              * @param index      The parameter's index.
375              * @return The parameter's modifiers.
376              */

377             int getModifiers(AccessibleObject executable, int index);
378
379             /**
380              * Returns {@code trueif the given parameter has an explicit name.
381              *
382              * @param executable The parameter to introspect.
383              * @param index      The parameter's index.
384              * @return {@code trueif the given parameter has an explicit name.
385              */

386             boolean isNamePresent(AccessibleObject executable, int index);
387
388             /**
389              * Returns the given parameter's implicit or explicit name.
390              *
391              * @param executable The parameter to introspect.
392              * @param index      The parameter's index.
393              * @return The parameter's name.
394              */

395             String getName(AccessibleObject executable, int index);
396
397             /**
398              * A creation action for a dispatcher.
399              */

400             enum CreationAction implements PrivilegedAction<Dispatcher> {
401
402                 /**
403                  * The singleton instance.
404                  */

405                 INSTANCE;
406
407                 /**
408                  * {@inheritDoc}
409                  */

410                 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback")
411                 public Dispatcher run() {
412                     try {
413                         Class<?> executableType = Class.forName("java.lang.reflect.Executable");
414                         Class<?> parameterType = Class.forName("java.lang.reflect.Parameter");
415                         return new Dispatcher.ForJava8CapableVm(executableType.getMethod("getParameters"),
416                                 parameterType.getMethod("getName"),
417                                 parameterType.getMethod("isNamePresent"),
418                                 parameterType.getMethod("getModifiers"));
419                     } catch (Exception ignored) {
420                         return Dispatcher.ForLegacyVm.INSTANCE;
421                     }
422                 }
423             }
424
425             /**
426              * A dispatcher for VMs that support the {@code java.lang.reflect.Parameter} API for Java 8+.
427              */

428             @HashCodeAndEqualsPlugin.Enhance
429             class ForJava8CapableVm implements Dispatcher {
430
431                 /**
432                  * An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call.
433                  */

434                 private static final Object[] NO_ARGUMENTS = new Object[0];
435
436                 /**
437                  * A reference to {@code java.lang.reflect.Executable#getParameters}.
438                  */

439                 private final Method getParameters;
440
441                 /**
442                  * A reference to {@code java.lang.reflect.Parameter#getName}.
443                  */

444                 private final Method getName;
445
446                 /**
447                  * A reference to {@code java.lang.reflect.Parameter#isNamePresent}.
448                  */

449                 private final Method isNamePresent;
450
451                 /**
452                  * A reference to {@code java.lang.reflect.Parameter#getModifiers}.
453                  */

454                 private final Method getModifiers;
455
456                 /**
457                  * Creates a new dispatcher for a modern VM.
458                  *
459                  * @param getParameters A reference to {@code java.lang.reflect.Executable#getTypeArguments}.
460                  * @param getName       A reference to {@code java.lang.reflect.Parameter#getName}.
461                  * @param isNamePresent A reference to {@code java.lang.reflect.Parameter#isNamePresent}.
462                  * @param getModifiers  A reference to {@code java.lang.reflect.Parameter#getModifiers}.
463                  */

464                 protected ForJava8CapableVm(Method getParameters, Method getName, Method isNamePresent, Method getModifiers) {
465                     this.getParameters = getParameters;
466                     this.getName = getName;
467                     this.isNamePresent = isNamePresent;
468                     this.getModifiers = getModifiers;
469                 }
470
471                 /**
472                  * {@inheritDoc}
473                  */

474                 public int getModifiers(AccessibleObject executable, int index) {
475                     try {
476                         return (Integer) getModifiers.invoke(getParameter(executable, index), NO_ARGUMENTS);
477                     } catch (IllegalAccessException exception) {
478                         throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#getModifiers", exception);
479                     } catch (InvocationTargetException exception) {
480                         throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#getModifiers", exception.getCause());
481                     }
482                 }
483
484                 /**
485                  * {@inheritDoc}
486                  */

487                 public boolean isNamePresent(AccessibleObject executable, int index) {
488                     try {
489                         return (Boolean) isNamePresent.invoke(getParameter(executable, index), NO_ARGUMENTS);
490                     } catch (IllegalAccessException exception) {
491                         throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#isNamePresent", exception);
492                     } catch (InvocationTargetException exception) {
493                         throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#isNamePresent", exception.getCause());
494                     }
495                 }
496
497                 /**
498                  * {@inheritDoc}
499                  */

500                 public String getName(AccessibleObject executable, int index) {
501                     try {
502                         return (String) getName.invoke(getParameter(executable, index), NO_ARGUMENTS);
503                     } catch (IllegalAccessException exception) {
504                         throw new IllegalStateException("Cannot access java.lang.reflect.Parameter#getName", exception);
505                     } catch (InvocationTargetException exception) {
506                         throw new IllegalStateException("Error invoking java.lang.reflect.Parameter#getName", exception.getCause());
507                     }
508                 }
509
510                 /**
511                  * Returns the {@code java.lang.reflect.Parameter} of an executable at a given index.
512                  *
513                  * @param executable The executable for which a parameter should be read.
514                  * @param index      The index of the parameter.
515                  * @return The parameter for the given index.
516                  */

517                 private Object getParameter(AccessibleObject executable, int index) {
518                     try {
519                         return Array.get(getParameters.invoke(executable, NO_ARGUMENTS), index);
520                     } catch (IllegalAccessException exception) {
521                         throw new IllegalStateException("Cannot access java.lang.reflect.Executable#getParameters", exception);
522                     } catch (InvocationTargetException exception) {
523                         throw new IllegalStateException("Error invoking java.lang.reflect.Executable#getParameters", exception.getCause());
524                     }
525                 }
526             }
527
528             /**
529              * A dispatcher for a legacy VM that does not know the {@code java.lang.reflect.Parameter} type that only throws
530              * exceptions on any property extraction.
531              */

532             enum ForLegacyVm implements Dispatcher {
533
534                 /**
535                  * The singleton instance.
536                  */

537                 INSTANCE;
538
539                 /**
540                  * {@inheritDoc}
541                  */

542                 public int getModifiers(AccessibleObject executable, int index) {
543                     throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
544                 }
545
546                 /**
547                  * {@inheritDoc}
548                  */

549                 public boolean isNamePresent(AccessibleObject executable, int index) {
550                     throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
551                 }
552
553                 /**
554                  * {@inheritDoc}
555                  */

556                 public String getName(AccessibleObject executable, int index) {
557                     throw new UnsupportedOperationException("Cannot dispatch method for java.lang.reflect.Parameter");
558                 }
559             }
560         }
561
562         /**
563          * A description of a loaded {@link Method} parameter for a modern VM.
564          */

565         protected static class OfMethod extends ForLoadedParameter<Method> {
566
567             /**
568              * Creates a new description for a loaded method.
569              *
570              * @param method                    The method for which a parameter is represented.
571              * @param index                     The index of the parameter.
572              * @param parameterAnnotationSource The parameter annotation source to query.
573              */

574             protected OfMethod(Method method, int index, ParameterAnnotationSource parameterAnnotationSource) {
575                 super(method, index, parameterAnnotationSource);
576             }
577
578             /**
579              * {@inheritDoc}
580              */

581             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
582             public MethodDescription.InDefinedShape getDeclaringMethod() {
583                 return new MethodDescription.ForLoadedMethod(executable);
584             }
585
586             /**
587              * {@inheritDoc}
588              */

589             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
590             public TypeDescription.Generic getType() {
591                 if (TypeDescription.AbstractBase.RAW_TYPES) {
592                     return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(executable.getParameterTypes()[index]);
593                 }
594                 return new TypeDescription.Generic.LazyProjection.OfMethodParameter(executable, index, executable.getParameterTypes());
595             }
596
597             /**
598              * {@inheritDoc}
599              */

600             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
601             public AnnotationList getDeclaredAnnotations() {
602                 return new AnnotationList.ForLoadedAnnotations(parameterAnnotationSource.getParameterAnnotations()[index]);
603             }
604         }
605
606         /**
607          * A description of a loaded {@link Constructor} parameter for a modern VM.
608          */

609         protected static class OfConstructor extends ForLoadedParameter<Constructor<?>> {
610
611             /**
612              * Creates a new description for a loaded constructor.
613              *
614              * @param constructor               The constructor for which a parameter is represented.
615              * @param index                     The index of the parameter.
616              * @param parameterAnnotationSource The parameter annotation source to query.
617              */

618             protected OfConstructor(Constructor<?> constructor, int index, ParameterAnnotationSource parameterAnnotationSource) {
619                 super(constructor, index, parameterAnnotationSource);
620             }
621
622             /**
623              * {@inheritDoc}
624              */

625             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
626             public MethodDescription.InDefinedShape getDeclaringMethod() {
627                 return new MethodDescription.ForLoadedConstructor(executable);
628             }
629
630             /**
631              * {@inheritDoc}
632              */

633             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
634             public TypeDescription.Generic getType() {
635                 if (TypeDescription.AbstractBase.RAW_TYPES) {
636                     return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(executable.getParameterTypes()[index]);
637                 }
638                 return new TypeDescription.Generic.LazyProjection.OfConstructorParameter(executable, index, executable.getParameterTypes());
639             }
640
641             /**
642              * {@inheritDoc}
643              */

644             @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST", justification = "The implicit field type casting is not understood by Findbugs")
645             public AnnotationList getDeclaredAnnotations() {
646                 Annotation[][] annotation = parameterAnnotationSource.getParameterAnnotations();
647                 MethodDescription.InDefinedShape declaringMethod = getDeclaringMethod();
648                 if (annotation.length != declaringMethod.getParameters().size() && declaringMethod.getDeclaringType().isInnerClass()) {
649                     return index == 0
650                             ? new AnnotationList.Empty()
651                             : new AnnotationList.ForLoadedAnnotations(annotation[index - 1]);
652                 } else {
653                     return new AnnotationList.ForLoadedAnnotations(annotation[index]);
654                 }
655             }
656         }
657
658         /**
659          * Description of a loaded method's parameter on a virtual machine where {@code java.lang.reflect.Parameter}
660          * is not available.
661          */

662         protected static class OfLegacyVmMethod extends InDefinedShape.AbstractBase {
663
664             /**
665              * The method that declares this parameter.
666              */

667             private final Method method;
668
669             /**
670              * The index of this parameter.
671              */

672             private final int index;
673
674             /**
675              * The type erasures of the represented method.
676              */

677             private final Class<?>[] parameterType;
678
679             /**
680              * The parameter annotation source to query.
681              */

682             private final ParameterAnnotationSource parameterAnnotationSource;
683
684             /**
685              * Creates a legacy representation of a method's parameter.
686              *
687              * @param method                    The method that declares this parameter.
688              * @param index                     The index of this parameter.
689              * @param parameterType             The type erasures of the represented method.
690              * @param parameterAnnotationSource The parameter annotation source to query.
691              */

692             protected OfLegacyVmMethod(Method method, int index, Class<?>[] parameterType, ParameterAnnotationSource parameterAnnotationSource) {
693                 this.method = method;
694                 this.index = index;
695                 this.parameterType = parameterType;
696                 this.parameterAnnotationSource = parameterAnnotationSource;
697             }
698
699             /**
700              * {@inheritDoc}
701              */

702             public TypeDescription.Generic getType() {
703                 if (TypeDescription.AbstractBase.RAW_TYPES) {
704                     return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(parameterType[index]);
705                 }
706                 return new TypeDescription.Generic.LazyProjection.OfMethodParameter(method, index, parameterType);
707             }
708
709             /**
710              * {@inheritDoc}
711              */

712             public MethodDescription.InDefinedShape getDeclaringMethod() {
713                 return new MethodDescription.ForLoadedMethod(method);
714             }
715
716             /**
717              * {@inheritDoc}
718              */

719             public int getIndex() {
720                 return index;
721             }
722
723             /**
724              * {@inheritDoc}
725              */

726             public boolean isNamed() {
727                 return false;
728             }
729
730             /**
731              * {@inheritDoc}
732              */

733             public boolean hasModifiers() {
734                 return false;
735             }
736
737             /**
738              * {@inheritDoc}
739              */

740             public AnnotationList getDeclaredAnnotations() {
741                 return new AnnotationList.ForLoadedAnnotations(parameterAnnotationSource.getParameterAnnotations()[index]);
742             }
743         }
744
745         /**
746          * Description of a loaded constructor's parameter on a virtual machine where {@code java.lang.reflect.Parameter}
747          * is not available.
748          */

749         protected static class OfLegacyVmConstructor extends InDefinedShape.AbstractBase {
750
751             /**
752              * The method that declares this parameter.
753              */

754             private final Constructor<?> constructor;
755
756             /**
757              * The index of this parameter.
758              */

759             private final int index;
760
761             /**
762              * The type erasures of the represented method.
763              */

764             private final Class<?>[] parameterType;
765
766             /**
767              * The parameter annotation source to query.
768              */

769             private final ParameterAnnotationSource parameterAnnotationSource;
770
771             /**
772              * Creates a legacy representation of a method's parameter.
773              *
774              * @param constructor               The constructor that declares this parameter.
775              * @param index                     The index of this parameter.
776              * @param parameterType             The type erasures of the represented method.
777              * @param parameterAnnotationSource The parameter annotation source to query.
778              */

779             protected OfLegacyVmConstructor(Constructor<?> constructor, int index, Class<?>[] parameterType, ParameterAnnotationSource parameterAnnotationSource) {
780                 this.constructor = constructor;
781                 this.index = index;
782                 this.parameterType = parameterType;
783                 this.parameterAnnotationSource = parameterAnnotationSource;
784             }
785
786             /**
787              * {@inheritDoc}
788              */

789             public TypeDescription.Generic getType() {
790                 if (TypeDescription.AbstractBase.RAW_TYPES) {
791                     return TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(parameterType[index]);
792                 }
793                 return new TypeDescription.Generic.LazyProjection.OfConstructorParameter(constructor, index, parameterType);
794             }
795
796             /**
797              * {@inheritDoc}
798              */

799             public MethodDescription.InDefinedShape getDeclaringMethod() {
800                 return new MethodDescription.ForLoadedConstructor(constructor);
801             }
802
803             /**
804              * {@inheritDoc}
805              */

806             public int getIndex() {
807                 return index;
808             }
809
810             /**
811              * {@inheritDoc}
812              */

813             public boolean isNamed() {
814                 return false;
815             }
816
817             /**
818              * {@inheritDoc}
819              */

820             public boolean hasModifiers() {
821                 return false;
822             }
823
824             /**
825              * {@inheritDoc}
826              */

827             public AnnotationList getDeclaredAnnotations() {
828                 MethodDescription.InDefinedShape declaringMethod = getDeclaringMethod();
829                 Annotation[][] parameterAnnotation = parameterAnnotationSource.getParameterAnnotations();
830                 if (parameterAnnotation.length != declaringMethod.getParameters().size() && declaringMethod.getDeclaringType().isInnerClass()) {
831                     return index == 0
832                             ? new AnnotationList.Empty()
833                             : new AnnotationList.ForLoadedAnnotations(parameterAnnotation[index - 1]);
834                 } else {
835                     return new AnnotationList.ForLoadedAnnotations(parameterAnnotation[index]);
836                 }
837             }
838         }
839     }
840
841     /**
842      * A latent description of a parameter that is not attached to a method or constructor.
843      */

844     class Latent extends InDefinedShape.AbstractBase {
845
846         /**
847          * The method that is declaring the parameter.
848          */

849         private final MethodDescription.InDefinedShape declaringMethod;
850
851         /**
852          * The type of the parameter.
853          */

854         private final TypeDescription.Generic parameterType;
855
856         /**
857          * The annotations of the parameter.
858          */

859         private final List<? extends AnnotationDescription> declaredAnnotations;
860
861         /**
862          * The name of the parameter or {@code nullif no name is explicitly defined.
863          */

864         private final String name;
865
866         /**
867          * The modifiers of the parameter or {@code nullif no modifiers are explicitly defined.
868          */

869         private final Integer modifiers;
870
871         /**
872          * The index of the parameter.
873          */

874         private final int index;
875
876         /**
877          * The parameter's offset in the local method variables array.
878          */

879         private final int offset;
880
881         /**
882          * Creates a latent parameter description. All provided types are attached to this instance before they are returned.
883          *
884          * @param declaringMethod The method that is declaring the parameter.
885          * @param token           The token describing the shape of the parameter.
886          * @param index           The index of the parameter.
887          * @param offset          The parameter's offset in the local method variables array.
888          */

889         public Latent(MethodDescription.InDefinedShape declaringMethod, Token token, int index, int offset) {
890             this(declaringMethod,
891                     token.getType(),
892                     token.getAnnotations(),
893                     token.getName(),
894                     token.getModifiers(),
895                     index,
896                     offset);
897         }
898
899         /**
900          * Creates a new latent parameter descriptions for a parameter without explicit meta data or annotations.
901          *
902          * @param declaringMethod The method declaring this parameter.
903          * @param parameterType   The type of the parameter.
904          * @param index           The index of the parameter.
905          * @param offset          The offset of the parameter.
906          */

907         public Latent(MethodDescription.InDefinedShape declaringMethod,
908                       TypeDescription.Generic parameterType,
909                       int index,
910                       int offset) {
911             this(declaringMethod,
912                     parameterType,
913                     Collections.<AnnotationDescription>emptyList(),
914                     Token.NO_NAME,
915                     Token.NO_MODIFIERS,
916                     index,
917                     offset);
918         }
919
920         /**
921          * Creates a latent parameter description. All provided types are attached to this instance before they are returned.
922          *
923          * @param declaringMethod     The method that is declaring the parameter.
924          * @param parameterType       The parameter's type.
925          * @param declaredAnnotations The annotations of the parameter.
926          * @param name                The name of the parameter or {@code nullif no name is explicitly defined.
927          * @param modifiers           The modifiers of the parameter or {@code nullif no modifiers are explicitly defined.
928          * @param index               The index of the parameter.
929          * @param offset              The parameter's offset in the local method variables array.
930          */

931         public Latent(MethodDescription.InDefinedShape declaringMethod,
932                       TypeDescription.Generic parameterType,
933                       List<? extends AnnotationDescription> declaredAnnotations,
934                       String name,
935                       Integer modifiers,
936                       int index,
937                       int offset) {
938             this.declaringMethod = declaringMethod;
939             this.parameterType = parameterType;
940             this.declaredAnnotations = declaredAnnotations;
941             this.name = name;
942             this.modifiers = modifiers;
943             this.index = index;
944             this.offset = offset;
945         }
946
947         /**
948          * {@inheritDoc}
949          */

950         public TypeDescription.Generic getType() {
951             return parameterType.accept(TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(this));
952         }
953
954         /**
955          * {@inheritDoc}
956          */

957         public MethodDescription.InDefinedShape getDeclaringMethod() {
958             return declaringMethod;
959         }
960
961         /**
962          * {@inheritDoc}
963          */

964         public int getIndex() {
965             return index;
966         }
967
968         /**
969          * {@inheritDoc}
970          */

971         public int getOffset() {
972             return offset;
973         }
974
975         /**
976          * {@inheritDoc}
977          */

978         public boolean isNamed() {
979             return name != null;
980         }
981
982         /**
983          * {@inheritDoc}
984          */

985         public boolean hasModifiers() {
986             return modifiers != null;
987         }
988
989         /**
990          * {@inheritDoc}
991          */

992         public String getName() {
993             return isNamed()
994                     ? name
995                     : super.getName();
996         }
997
998         /**
999          * {@inheritDoc}
1000          */

1001         public int getModifiers() {
1002             return hasModifiers()
1003                     ? modifiers
1004                     : super.getModifiers();
1005         }
1006
1007         /**
1008          * {@inheritDoc}
1009          */

1010         public AnnotationList getDeclaredAnnotations() {
1011             return new AnnotationList.Explicit(declaredAnnotations);
1012         }
1013     }
1014
1015     /**
1016      * <p>
1017      * A parameter description that represents a given parameter but with a substituted parameter type.
1018      * </p>
1019      * <p>
1020      * <b>Note</b>: The supplied visitor must assure to not substitute
1021      * </p>
1022      */

1023     class TypeSubstituting extends AbstractBase implements InGenericShape {
1024
1025         /**
1026          * The method that declares this type-substituted parameter.
1027          */

1028         private final MethodDescription.InGenericShape declaringMethod;
1029
1030         /**
1031          * The represented parameter.
1032          */

1033         private final ParameterDescription parameterDescription;
1034
1035         /**
1036          * A visitor that is applied to the parameter type.
1037          */

1038         private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
1039
1040         /**
1041          * Creates a new type substituting parameter.
1042          *
1043          * @param declaringMethod      The method that declares this type-substituted parameter.
1044          * @param parameterDescription The represented parameter.
1045          * @param visitor              A visitor that is applied to the parameter type.
1046          */

1047         public TypeSubstituting(MethodDescription.InGenericShape declaringMethod,
1048                                 ParameterDescription parameterDescription,
1049                                 TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
1050             this.declaringMethod = declaringMethod;
1051             this.parameterDescription = parameterDescription;
1052             this.visitor = visitor;
1053         }
1054
1055         /**
1056          * {@inheritDoc}
1057          */

1058         public TypeDescription.Generic getType() {
1059             return parameterDescription.getType().accept(visitor);
1060         }
1061
1062         /**
1063          * {@inheritDoc}
1064          */

1065         public MethodDescription.InGenericShape getDeclaringMethod() {
1066             return declaringMethod;
1067         }
1068
1069         /**
1070          * {@inheritDoc}
1071          */

1072         public int getIndex() {
1073             return parameterDescription.getIndex();
1074         }
1075
1076         /**
1077          * {@inheritDoc}
1078          */

1079         public boolean isNamed() {
1080             return parameterDescription.isNamed();
1081         }
1082
1083         /**
1084          * {@inheritDoc}
1085          */

1086         public boolean hasModifiers() {
1087             return parameterDescription.hasModifiers();
1088         }
1089
1090         /**
1091          * {@inheritDoc}
1092          */

1093         public int getOffset() {
1094             return parameterDescription.getOffset();
1095         }
1096
1097         /**
1098          * {@inheritDoc}
1099          */

1100         public String getName() {
1101             return parameterDescription.getName();
1102         }
1103
1104         /**
1105          * {@inheritDoc}
1106          */

1107         public int getModifiers() {
1108             return parameterDescription.getModifiers();
1109         }
1110
1111         /**
1112          * {@inheritDoc}
1113          */

1114         public AnnotationList getDeclaredAnnotations() {
1115             return parameterDescription.getDeclaredAnnotations();
1116         }
1117
1118         /**
1119          * {@inheritDoc}
1120          */

1121         public InDefinedShape asDefined() {
1122             return parameterDescription.asDefined();
1123         }
1124     }
1125
1126     /**
1127      * A token representing a parameter's properties detached from a type.
1128      */

1129     class Token implements ByteCodeElement.Token<Token> {
1130
1131         /**
1132          * Indicator for a method parameter without an explicit name.
1133          */

1134         public static final String NO_NAME = null;
1135
1136         /**
1137          * Indicator for a method parameter without explicit modifiers.
1138          */

1139         public static final Integer NO_MODIFIERS = null;
1140
1141         /**
1142          * The type of the represented parameter.
1143          */

1144         private final TypeDescription.Generic type;
1145
1146         /**
1147          * A list of parameter annotations.
1148          */

1149         private final List<? extends AnnotationDescription> annotations;
1150
1151         /**
1152          * The name of the parameter or {@code nullif no explicit name is defined.
1153          */

1154         private final String name;
1155
1156         /**
1157          * The modifiers of the parameter or {@code nullif no explicit modifiers is defined.
1158          */

1159         private final Integer modifiers;
1160
1161         /**
1162          * Creates a new parameter token without an explicit name, an explicit modifier or annotations.
1163          * The parameter type must be represented in its detached format.
1164          *
1165          * @param type The type of the represented parameter.
1166          */

1167         public Token(TypeDescription.Generic type) {
1168             this(type, Collections.<AnnotationDescription>emptyList());
1169         }
1170
1171         /**
1172          * Creates a new parameter token without an explicit name or an explicit modifier. The parameter type must be represented in its detached format.
1173          *
1174          * @param type        The type of the represented parameter.
1175          * @param annotations The annotations of the parameter.
1176          */

1177         public Token(TypeDescription.Generic type, List<? extends AnnotationDescription> annotations) {
1178             this(type, annotations, NO_NAME, NO_MODIFIERS);
1179         }
1180
1181         /**
1182          * Creates a parameter token without annotations. The parameter type must be represented in its detached format.
1183          *
1184          * @param type      The type of the represented parameter.
1185          * @param name      The name of the parameter or {@code nullif no explicit name is defined.
1186          * @param modifiers The modifiers of the parameter or {@code nullif no explicit modifiers is defined.
1187          */

1188         public Token(TypeDescription.Generic type, String name, Integer modifiers) {
1189             this(type, Collections.<AnnotationDescription>emptyList(), name, modifiers);
1190         }
1191
1192         /**
1193          * Creates a new parameter token. The parameter type must be represented in its detached format.
1194          *
1195          * @param type        The type of the represented parameter.
1196          * @param annotations The annotations of the parameter.
1197          * @param name        The name of the parameter or {@code nullif no explicit name is defined.
1198          * @param modifiers   The modifiers of the parameter or {@code nullif no explicit modifiers is defined.
1199          */

1200         public Token(TypeDescription.Generic type,
1201                      List<? extends AnnotationDescription> annotations,
1202                      String name,
1203                      Integer modifiers) {
1204             this.type = type;
1205             this.annotations = annotations;
1206             this.name = name;
1207             this.modifiers = modifiers;
1208         }
1209
1210         /**
1211          * Returns the type of the represented method parameter.
1212          *
1213          * @return The type of the represented method parameter.
1214          */

1215         public TypeDescription.Generic getType() {
1216             return type;
1217         }
1218
1219         /**
1220          * Returns the annotations of the represented method parameter.
1221          *
1222          * @return The annotations of the represented method parameter.
1223          */

1224         public AnnotationList getAnnotations() {
1225             return new AnnotationList.Explicit(annotations);
1226         }
1227
1228         /**
1229          * Returns the name of the represented method parameter.
1230          *
1231          * @return The name of the parameter or {@code nullif no explicit name is defined.
1232          */

1233         public String getName() {
1234             return name;
1235         }
1236
1237         /**
1238          * Returns the modifiers of the represented method parameter.
1239          *
1240          * @return The modifiers of the parameter or {@code nullif no explicit modifiers is defined.
1241          */

1242         public Integer getModifiers() {
1243             return modifiers;
1244         }
1245
1246         /**
1247          * {@inheritDoc}
1248          */

1249         public Token accept(TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
1250             return new Token(type.accept(visitor),
1251                     annotations,
1252                     name,
1253                     modifiers);
1254         }
1255
1256         @Override
1257         @CachedReturnPlugin.Enhance
1258         public int hashCode() {
1259             int result = type.hashCode();
1260             result = 31 * result + annotations.hashCode();
1261             result = 31 * result + (name != null ? name.hashCode() : 0);
1262             result = 31 * result + (modifiers != null ? modifiers.hashCode() : 0);
1263             return result;
1264         }
1265
1266         @Override
1267         public boolean equals(Object other) {
1268             if (this == other) {
1269                 return true;
1270             } else if (!(other instanceof Token)) {
1271                 return false;
1272             }
1273             Token token = (Token) other;
1274             return type.equals(token.type)
1275                     && annotations.equals(token.annotations)
1276                     && (name != null ? name.equals(token.name) : token.name == null)
1277                     && (modifiers != null ? modifiers.equals(token.modifiers) : token.modifiers == null);
1278         }
1279
1280         @Override
1281         public String toString() {
1282             return "ParameterDescription.Token{" +
1283                     "type=" + type +
1284                     ", annotations=" + annotations +
1285                     ", name='" + name + '\'' +
1286                     ", modifiers=" + modifiers +
1287                     '}';
1288         }
1289
1290         /**
1291          * A list of types represented as a list of parameter tokens.
1292          */

1293         public static class TypeList extends AbstractList<Token> {
1294
1295             /**
1296              * The list of types to represent as parameter tokens.
1297              */

1298             private final List<? extends TypeDefinition> typeDescriptions;
1299
1300             /**
1301              * Creates a new list of types that represent parameters.
1302              *
1303              * @param typeDescriptions The types to represent.
1304              */

1305             public TypeList(List<? extends TypeDefinition> typeDescriptions) {
1306                 this.typeDescriptions = typeDescriptions;
1307             }
1308
1309             /**
1310              * {@inheritDoc}
1311              */

1312             public Token get(int index) {
1313                 return new Token(typeDescriptions.get(index).asGenericType());
1314             }
1315
1316             /**
1317              * {@inheritDoc}
1318              */

1319             public int size() {
1320                 return typeDescriptions.size();
1321             }
1322         }
1323     }
1324 }
1325