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.dynamic.scaffold;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20 import net.bytebuddy.description.method.MethodDescription;
21 import net.bytebuddy.description.method.MethodList;
22 import net.bytebuddy.description.modifier.Visibility;
23 import net.bytebuddy.description.type.TypeDefinition;
24 import net.bytebuddy.description.type.TypeDescription;
25 import net.bytebuddy.matcher.ElementMatcher;
26 import net.bytebuddy.matcher.FilterableList;
27 import net.bytebuddy.jar.asm.Opcodes;
28
29 import java.util.*;
30
31 import static net.bytebuddy.matcher.ElementMatchers.*;
32
33 /**
34  * A method graph represents a view on a set of methods as they are seen from a given type. Any method is represented as a node that represents
35  * a method, its bridge methods, its resolution state and information on if it was made visible by a visibility bridge.
36  */

37 public interface MethodGraph {
38
39     /**
40      * Locates a node in this graph which represents the provided method token.
41      *
42      * @param token A method token that represents the method to be located.
43      * @return The node representing the given token.
44      */

45     Node locate(MethodDescription.SignatureToken token);
46
47     /**
48      * Lists all nodes of this method graph.
49      *
50      * @return A list of all nodes of this method graph.
51      */

52     NodeList listNodes();
53
54     /**
55      * A canonical implementation of an empty method graph.
56      */

57     enum Empty implements MethodGraph.Linked, MethodGraph.Compiler {
58
59         /**
60          * The singleton instance.
61          */

62         INSTANCE;
63
64         /**
65          * {@inheritDoc}
66          */

67         public Node locate(MethodDescription.SignatureToken token) {
68             return Node.Unresolved.INSTANCE;
69         }
70
71         /**
72          * {@inheritDoc}
73          */

74         public NodeList listNodes() {
75             return new NodeList(Collections.<Node>emptyList());
76         }
77
78         /**
79          * {@inheritDoc}
80          */

81         public MethodGraph getSuperClassGraph() {
82             return this;
83         }
84
85         /**
86          * {@inheritDoc}
87          */

88         public MethodGraph getInterfaceGraph(TypeDescription typeDescription) {
89             return this;
90         }
91
92         /**
93          * {@inheritDoc}
94          */

95         public Linked compile(TypeDescription typeDescription) {
96             return this;
97         }
98
99         /**
100          * {@inheritDoc}
101          */

102         public Linked compile(TypeDefinition typeDefinition, TypeDescription viewPoint) {
103             return this;
104         }
105     }
106
107     /**
108      * A linked method graph represents a view that additionally exposes information of a given type's super type view and a
109      * view on this graph's directly implemented interfaces.
110      */

111     interface Linked extends MethodGraph {
112
113         /**
114          * Returns a graph representing the view on this represented type's super type.
115          *
116          * @return A graph representing the view on this represented type's super type.
117          */

118         MethodGraph getSuperClassGraph();
119
120         /**
121          * Returns a graph representing the view on this represented type's directly implemented interface type.
122          *
123          * @param typeDescription The interface type for which a view is to be returned.
124          * @return A graph representing the view on this represented type's directly implemented interface type.
125          */

126         MethodGraph getInterfaceGraph(TypeDescription typeDescription);
127
128         /**
129          * A simple implementation of a linked method graph that exposes views by delegation to given method graphs.
130          */

131         @HashCodeAndEqualsPlugin.Enhance
132         class Delegation implements Linked {
133
134             /**
135              * The represented type's method graph.
136              */

137             private final MethodGraph methodGraph;
138
139             /**
140              * The super class's method graph.
141              */

142             private final MethodGraph superClassGraph;
143
144             /**
145              * A mapping of method graphs of the represented type's directly implemented interfaces to their graph representatives.
146              */

147             private final Map<TypeDescription, MethodGraph> interfaceGraphs;
148
149             /**
150              * Creates a new delegation method graph.
151              *
152              * @param methodGraph     The represented type's method graph.
153              * @param superClassGraph The super class's method graph.
154              * @param interfaceGraphs A mapping of method graphs of the represented type's directly implemented interfaces to their graph representatives.
155              */

156             public Delegation(MethodGraph methodGraph, MethodGraph superClassGraph, Map<TypeDescription, MethodGraph> interfaceGraphs) {
157                 this.methodGraph = methodGraph;
158                 this.superClassGraph = superClassGraph;
159                 this.interfaceGraphs = interfaceGraphs;
160             }
161
162             /**
163              * {@inheritDoc}
164              */

165             public MethodGraph getSuperClassGraph() {
166                 return superClassGraph;
167             }
168
169             /**
170              * {@inheritDoc}
171              */

172             public MethodGraph getInterfaceGraph(TypeDescription typeDescription) {
173                 MethodGraph interfaceGraph = interfaceGraphs.get(typeDescription);
174                 return interfaceGraph == null
175                         ? Empty.INSTANCE
176                         : interfaceGraph;
177             }
178
179             /**
180              * {@inheritDoc}
181              */

182             public Node locate(MethodDescription.SignatureToken token) {
183                 return methodGraph.locate(token);
184             }
185
186             /**
187              * {@inheritDoc}
188              */

189             public NodeList listNodes() {
190                 return methodGraph.listNodes();
191             }
192         }
193     }
194
195     /**
196      * Represents a node within a method graph.
197      */

198     interface Node {
199
200         /**
201          * Returns the sort of this node.
202          *
203          * @return The sort of this node.
204          */

205         Sort getSort();
206
207         /**
208          * Returns the method that is represented by this node.
209          *
210          * @return The method that is represented by this node.
211          */

212         MethodDescription getRepresentative();
213
214         /**
215          * Returns a set of type tokens that this method represents. This set contains the actual method's type including the
216          * types of all bridge methods.
217          *
218          * @return A set of type tokens that this method represents.
219          */

220         Set<MethodDescription.TypeToken> getMethodTypes();
221
222         /**
223          * Returns the minimal method visibility of all methods that are represented by this node.
224          *
225          * @return The minimal method visibility of all methods that are represented by this node.
226          */

227         Visibility getVisibility();
228
229         /**
230          * Represents a {@link net.bytebuddy.dynamic.scaffold.MethodGraph.Node}'s state.
231          */

232         enum Sort {
233
234             /**
235              * Represents a resolved node that was made visible by a visibility bridge.
236              */

237             VISIBLE(truetruetrue),
238
239             /**
240              * Represents a resolved node that was not made visible by a visibility bridge.
241              */

242             RESOLVED(truetruefalse),
243
244             /**
245              * Represents an ambiguous node, i.e. a node that might refer to several methods.
246              */

247             AMBIGUOUS(truefalsefalse),
248
249             /**
250              * Represents an unresolved node.
251              */

252             UNRESOLVED(falsefalsefalse);
253
254             /**
255              * {@code trueif this sort represents a resolved node.
256              */

257             private final boolean resolved;
258
259             /**
260              * {@code trueif this sort represents a non-ambiguous node.
261              */

262             private final boolean unique;
263
264             /**
265              * {@code trueif this sort represents a node that was made by a visibility bridge.
266              */

267             private final boolean madeVisible;
268
269             /**
270              * Creates a new sort.
271              *
272              * @param resolved    {@code trueif this sort represents a resolved node.
273              * @param unique      {@code trueif this sort represents a non-ambiguous node.
274              * @param madeVisible {@code trueif this sort represents a node that was made by a visibility bridge.
275              */

276             Sort(boolean resolved, boolean unique, boolean madeVisible) {
277                 this.resolved = resolved;
278                 this.unique = unique;
279                 this.madeVisible = madeVisible;
280             }
281
282             /**
283              * Verifies if this sort represents a resolved node.
284              *
285              * @return {@code trueif this sort represents a resolved node.
286              */

287             public boolean isResolved() {
288                 return resolved;
289             }
290
291             /**
292              * Verifies if this sort represents a non-ambiguous node.
293              *
294              * @return {@code trueif this sort represents a non-ambiguous node.
295              */

296             public boolean isUnique() {
297                 return unique;
298             }
299
300             /**
301              * Verifies if this sort represents a node that was made visible by a visibility bridge.
302              *
303              * @return {@code trueif this sort represents a node that was made visible by a visibility bridge.
304              */

305             public boolean isMadeVisible() {
306                 return madeVisible;
307             }
308         }
309
310         /**
311          * A canonical implementation of an unresolved node.
312          */

313         enum Unresolved implements Node {
314
315             /**
316              * The singleton instance.
317              */

318             INSTANCE;
319
320             /**
321              * {@inheritDoc}
322              */

323             public Sort getSort() {
324                 return Sort.UNRESOLVED;
325             }
326
327             /**
328              * {@inheritDoc}
329              */

330             public MethodDescription getRepresentative() {
331                 throw new IllegalStateException("Cannot resolve the method of an illegal node");
332             }
333
334             /**
335              * {@inheritDoc}
336              */

337             public Set<MethodDescription.TypeToken> getMethodTypes() {
338                 throw new IllegalStateException("Cannot resolve bridge method of an illegal node");
339             }
340
341             /**
342              * {@inheritDoc}
343              */

344             public Visibility getVisibility() {
345                 throw new IllegalStateException("Cannot resolve visibility of an illegal node");
346             }
347         }
348
349         /**
350          * A simple implementation of a resolved node of a method without bridges.
351          */

352         @HashCodeAndEqualsPlugin.Enhance
353         class Simple implements Node {
354
355             /**
356              * The represented method.
357              */

358             private final MethodDescription methodDescription;
359
360             /**
361              * Creates a simple node.
362              *
363              * @param methodDescription The represented method.
364              */

365             public Simple(MethodDescription methodDescription) {
366                 this.methodDescription = methodDescription;
367             }
368
369             /**
370              * {@inheritDoc}
371              */

372             public Sort getSort() {
373                 return Sort.RESOLVED;
374             }
375
376             /**
377              * {@inheritDoc}
378              */

379             public MethodDescription getRepresentative() {
380                 return methodDescription;
381             }
382
383             /**
384              * {@inheritDoc}
385              */

386             public Set<MethodDescription.TypeToken> getMethodTypes() {
387                 return Collections.emptySet();
388             }
389
390             /**
391              * {@inheritDoc}
392              */

393             public Visibility getVisibility() {
394                 return methodDescription.getVisibility();
395             }
396         }
397     }
398
399     /**
400      * A compiler to produce a {@link MethodGraph} from a given type.
401      */

402     @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
403     interface Compiler {
404
405         /**
406          * The default compiler for compiling Java methods.
407          */

408         Compiler DEFAULT = MethodGraph.Compiler.Default.forJavaHierarchy();
409
410         /**
411          * Compiles the given type into a method graph considering the type to be the viewpoint.
412          *
413          * @param typeDescription The type to be compiled.
414          * @return A linked method graph representing the given type.
415          */

416         MethodGraph.Linked compile(TypeDescription typeDescription);
417
418         /**
419          * Compiles the given type into a method graph.
420          *
421          * @param typeDefinition The type to be compiled.
422          * @param viewPoint      The view point that determines the method's visibility.
423          * @return A linked method graph representing the given type.
424          */

425         MethodGraph.Linked compile(TypeDefinition typeDefinition, TypeDescription viewPoint);
426
427         /**
428          * A flat compiler that simply returns the methods that are declared by the instrumented type.
429          */

430         enum ForDeclaredMethods implements Compiler {
431
432             /**
433              * The singleton instance.
434              */

435             INSTANCE;
436
437             /**
438              * {@inheritDoc}
439              */

440             public Linked compile(TypeDescription typeDescription) {
441                 return compile(typeDescription, typeDescription);
442             }
443
444             /**
445              * {@inheritDoc}
446              */

447             public Linked compile(TypeDefinition typeDefinition, TypeDescription viewPoint) {
448                 LinkedHashMap<MethodDescription.SignatureToken, Node> nodes = new LinkedHashMap<MethodDescription.SignatureToken, Node>();
449                 for (MethodDescription methodDescription : typeDefinition.getDeclaredMethods().filter(isVirtual().and(not(isBridge())).and(isVisibleTo(viewPoint)))) {
450                     nodes.put(methodDescription.asSignatureToken(), new Node.Simple(methodDescription));
451                 }
452                 return new Linked.Delegation(new MethodGraph.Simple(nodes), Empty.INSTANCE, Collections.<TypeDescription, MethodGraph>emptyMap());
453             }
454         }
455
456         /**
457          * An abstract base implementation of a method graph compiler.
458          */

459         abstract class AbstractBase implements Compiler {
460
461             /**
462              * {@inheritDoc}
463              */

464             public Linked compile(TypeDescription typeDescription) {
465                 return compile(typeDescription, typeDescription);
466             }
467         }
468
469         /**
470          * A default implementation of a method graph.
471          *
472          * @param <T> The type of the harmonizer token to be used for linking methods of different types.
473          */

474         @HashCodeAndEqualsPlugin.Enhance
475         class Default<T> extends AbstractBase {
476
477             /**
478              * The harmonizer to be used.
479              */

480             private final Harmonizer<T> harmonizer;
481
482             /**
483              * The merger to be used.
484              */

485             private final Merger merger;
486
487             /**
488              * A visitor to apply to all type descriptions before analyzing their methods or resolving super types.
489              */

490             private final TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor;
491
492             /**
493              * Creates a new default method graph compiler.
494              *
495              * @param harmonizer The harmonizer to be used.
496              * @param merger     The merger to be used.
497              * @param visitor    A visitor to apply to all type descriptions before analyzing their methods or resolving super types.
498              */

499             protected Default(Harmonizer<T> harmonizer, Merger merger, TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
500                 this.harmonizer = harmonizer;
501                 this.merger = merger;
502                 this.visitor = visitor;
503             }
504
505             /**
506              * Creates a default compiler using the given harmonizer and merger. All raw types are reified before analyzing their properties.
507              *
508              * @param harmonizer The harmonizer to be used for creating tokens that uniquely identify a method hierarchy.
509              * @param merger     The merger to be used for identifying a method to represent an ambiguous method resolution.
510              * @param <S>        The type of the harmonizer token.
511              * @return A default compiler for the given harmonizer and merger.
512              */

513             public static <S> Compiler of(Harmonizer<S> harmonizer, Merger merger) {
514                 return new Default<S>(harmonizer, merger, TypeDescription.Generic.Visitor.Reifying.INITIATING);
515             }
516
517             /**
518              * Creates a default compiler using the given harmonizer and merger.
519              *
520              * @param harmonizer The harmonizer to be used for creating tokens that uniquely identify a method hierarchy.
521              * @param merger     The merger to be used for identifying a method to represent an ambiguous method resolution.
522              * @param visitor    A visitor to apply to all type descriptions before analyzing their methods or resolving super types.
523              * @param <S>        The type of the harmonizer token.
524              * @return A default compiler for the given harmonizer and merger.
525              */

526             public static <S> Compiler of(Harmonizer<S> harmonizer, Merger merger, TypeDescription.Generic.Visitor<? extends TypeDescription.Generic> visitor) {
527                 return new Default<S>(harmonizer, merger, visitor);
528             }
529
530             /**
531              * <p>
532              * Creates a default compiler for a method hierarchy following the rules of the Java programming language. According
533              * to these rules, two methods of the same name are only different if their parameter types represent different raw
534              * types. The return type is not considered as a part of the signature.
535              * </p>
536              * <p>
537              * Ambiguous methods are merged by considering the method that was discovered first.
538              * </p>
539              *
540              * @return A compiler for resolving a method hierarchy following the rules of the Java programming language.
541              */

542             public static Compiler forJavaHierarchy() {
543                 return of(Harmonizer.ForJavaMethod.INSTANCE, Merger.Directional.LEFT);
544             }
545
546             /**
547              * <p>
548              * Creates a default compiler for a method hierarchy following the rules of the Java virtual machine. According
549              * to these rules, two methods of the same name are different if their parameter types and return types represent
550              * different type erasures.
551              * </p>
552              * <p>
553              * Ambiguous methods are merged by considering the method that was discovered first.
554              * </p>
555              *
556              * @return A compiler for resolving a method hierarchy following the rules of the Java programming language.
557              */

558             public static Compiler forJVMHierarchy() {
559                 return of(Harmonizer.ForJVMMethod.INSTANCE, Merger.Directional.LEFT);
560             }
561
562             /**
563              * {@inheritDoc}
564              */

565             public MethodGraph.Linked compile(TypeDefinition typeDefinition, TypeDescription viewPoint) {
566                 Map<TypeDefinition, Key.Store<T>> snapshots = new HashMap<TypeDefinition, Key.Store<T>>();
567                 Key.Store<?> rootStore = doAnalyze(typeDefinition, snapshots, isVirtual().and(isVisibleTo(viewPoint)));
568                 TypeDescription.Generic superClass = typeDefinition.getSuperClass();
569                 List<TypeDescription.Generic> interfaceTypes = typeDefinition.getInterfaces();
570                 Map<TypeDescription, MethodGraph> interfaceGraphs = new HashMap<TypeDescription, MethodGraph>();
571                 for (TypeDescription.Generic interfaceType : interfaceTypes) {
572                     interfaceGraphs.put(interfaceType.asErasure(), snapshots.get(interfaceType).asGraph(merger));
573                 }
574                 return new Linked.Delegation(rootStore.asGraph(merger),
575                         superClass == null
576                                 ? Empty.INSTANCE
577                                 : snapshots.get(superClass).asGraph(merger),
578                         interfaceGraphs);
579             }
580
581             /**
582              * Analyzes the given type description without checking if the end of the type hierarchy was reached.
583              *
584              * @param typeDefinition   The type to analyze.
585              * @param key              The type in its original form before applying the visitor.
586              * @param snapshots        A map containing snapshots of key stores for previously analyzed types.
587              * @param relevanceMatcher A matcher for filtering methods that should be included in the graph.
588              * @return A key store describing the provided type.
589              */

590             protected Key.Store<T> analyze(TypeDefinition typeDefinition,
591                                            TypeDefinition key,
592                                            Map<TypeDefinition, Key.Store<T>> snapshots,
593                                            ElementMatcher<? super MethodDescription> relevanceMatcher) {
594                 Key.Store<T> store = snapshots.get(key);
595                 if (store == null) {
596                     store = doAnalyze(typeDefinition, snapshots, relevanceMatcher);
597                     snapshots.put(key, store);
598                 }
599                 return store;
600             }
601
602             /**
603              * Analyzes the given type description.
604              *
605              * @param typeDescription  The type to analyze.
606              * @param snapshots        A map containing snapshots of key stores for previously analyzed types.
607              * @param relevanceMatcher A matcher for filtering methods that should be included in the graph.
608              * @return A key store describing the provided type.
609              */

610             protected Key.Store<T> analyzeNullable(TypeDescription.Generic typeDescription,
611                                                    Map<TypeDefinition, Key.Store<T>> snapshots,
612                                                    ElementMatcher<? super MethodDescription> relevanceMatcher) {
613                 return typeDescription == null
614                         ? new Key.Store<T>()
615                         : analyze(typeDescription.accept(visitor), typeDescription, snapshots, relevanceMatcher);
616             }
617
618             /**
619              * Analyzes the given type description without checking if it is already presented in the key store.
620              *
621              * @param typeDefinition   The type to analyze.
622              * @param snapshots        A map containing snapshots of key stores for previously analyzed types.
623              * @param relevanceMatcher A matcher for filtering methods that should be included in the graph.
624              * @return A key store describing the provided type.
625              */

626             protected Key.Store<T> doAnalyze(TypeDefinition typeDefinition,
627                                              Map<TypeDefinition, Key.Store<T>> snapshots,
628                                              ElementMatcher<? super MethodDescription> relevanceMatcher) {
629                 Key.Store<T> store = analyzeNullable(typeDefinition.getSuperClass(), snapshots, relevanceMatcher);
630                 Key.Store<T> interfaceStore = new Key.Store<T>();
631                 for (TypeDescription.Generic interfaceType : typeDefinition.getInterfaces()) {
632                     interfaceStore = interfaceStore.combineWith(analyze(interfaceType.accept(visitor), interfaceType, snapshots, relevanceMatcher));
633                 }
634                 return store.inject(interfaceStore).registerTopLevel(typeDefinition.getDeclaredMethods().filter(relevanceMatcher), harmonizer);
635             }
636
637             /**
638              * A harmonizer is responsible for creating a token that identifies a method's relevant attributes for considering
639              * two methods of being equal or not.
640              *
641              * @param <S> The type of the token that is created by the implementing harmonizer.
642              */

643             public interface Harmonizer<S> {
644
645                 /**
646                  * Harmonizes the given type token.
647                  *
648                  * @param typeToken The type token to harmonize.
649                  * @return A token representing the given type token.
650                  */

651                 S harmonize(MethodDescription.TypeToken typeToken);
652
653                 /**
654                  * A harmonizer for the Java programming language that identifies a method by its parameter types only.
655                  */

656                 enum ForJavaMethod implements Harmonizer<ForJavaMethod.Token> {
657
658                     /**
659                      * The singleton instance.
660                      */

661                     INSTANCE;
662
663                     /**
664                      * {@inheritDoc}
665                      */

666                     public Token harmonize(MethodDescription.TypeToken typeToken) {
667                         return new Token(typeToken);
668                     }
669
670                     /**
671                      * A token that identifies a Java method's type by its parameter types only.
672                      */

673                     protected static class Token {
674
675                         /**
676                          * The represented type token.
677                          */

678                         private final MethodDescription.TypeToken typeToken;
679
680                         /**
681                          * The hash code of this token which is precomputed for to improve performance.
682                          */

683                         private final int hashCode;
684
685                         /**
686                          * Creates a new type token for a Java method.
687                          *
688                          * @param typeToken The represented type token.
689                          */

690                         protected Token(MethodDescription.TypeToken typeToken) {
691                             this.typeToken = typeToken;
692                             hashCode = typeToken.getParameterTypes().hashCode();
693                         }
694
695                         @Override
696                         public int hashCode() {
697                             return hashCode;
698                         }
699
700                         @Override
701                         public boolean equals(Object other) {
702                             return this == other || other instanceof Token && typeToken.getParameterTypes().equals(((Token) other).typeToken.getParameterTypes());
703                         }
704
705                         @Override
706                         public String toString() {
707                             return typeToken.getParameterTypes().toString();
708                         }
709                     }
710                 }
711
712                 /**
713                  * A harmonizer for the Java virtual machine's method dispatching rules that identifies a method by its parameter types and return type.
714                  */

715                 enum ForJVMMethod implements Harmonizer<ForJVMMethod.Token> {
716
717                     /**
718                      * The singleton instance.
719                      */

720                     INSTANCE;
721
722                     /**
723                      * {@inheritDoc}
724                      */

725                     public Token harmonize(MethodDescription.TypeToken typeToken) {
726                         return new Token(typeToken);
727                     }
728
729                     /**
730                      * A token that identifies a Java method's type by its parameter types and return type.
731                      */

732                     protected static class Token {
733
734                         /**
735                          * The represented type token.
736                          */

737                         private final MethodDescription.TypeToken typeToken;
738
739                         /**
740                          * The hash code of this token which is precomputed for to improve performance.
741                          */

742                         private final int hashCode;
743
744                         /**
745                          * Creates a new type token for a JVM method.
746                          *
747                          * @param typeToken The represented type token.
748                          */

749                         public Token(MethodDescription.TypeToken typeToken) {
750                             this.typeToken = typeToken;
751                             hashCode = typeToken.getReturnType().hashCode() + 31 * typeToken.getParameterTypes().hashCode();
752                         }
753
754                         @Override
755                         public int hashCode() {
756                             return hashCode;
757                         }
758
759                         @Override
760                         public boolean equals(Object other) {
761                             if (this == other) {
762                                 return true;
763                             } else if (!(other instanceof Token)) {
764                                 return false;
765                             }
766                             Token token = (Token) other;
767                             return typeToken.getReturnType().equals(token.typeToken.getReturnType())
768                                     && typeToken.getParameterTypes().equals(token.typeToken.getParameterTypes());
769                         }
770
771                         @Override
772                         public String toString() {
773                             return typeToken.toString();
774                         }
775                     }
776                 }
777             }
778
779             /**
780              * Implementations are responsible for identifying a representative method for a {@link net.bytebuddy.dynamic.scaffold.MethodGraph.Node}
781              * between several ambiguously resolved methods.
782              */

783             public interface Merger {
784
785                 /**
786                  * Merges two ambiguously resolved methods to yield a single representative.
787                  *
788                  * @param left  The left method description, i.e. the method that was discovered first or was previously merged.
789                  * @param right The right method description, i.e. the method that was discovered last.
790                  * @return A method description compatible to both method's types that is used as a representative.
791                  */

792                 MethodDescription merge(MethodDescription left, MethodDescription right);
793
794                 /**
795                  * A directional merger that always returns either the left or right method description.
796                  */

797                 enum Directional implements Merger {
798
799                     /**
800                      * A merger that always returns the left method, i.e. the method that was discovered first or was previously merged.
801                      */

802                     LEFT(true),
803
804                     /**
805                      * A merger that always returns the right method, i.e. the method that was discovered last.
806                      */

807                     RIGHT(false);
808
809                     /**
810                      * {@code trueif the left method should be returned when merging methods.
811                      */

812                     private final boolean left;
813
814                     /**
815                      * Creates a directional merger.
816                      *
817                      * @param left {@code trueif the left method should be returned when merging methods.
818                      */

819                     Directional(boolean left) {
820                         this.left = left;
821                     }
822
823                     /**
824                      * {@inheritDoc}
825                      */

826                     public MethodDescription merge(MethodDescription left, MethodDescription right) {
827                         return this.left
828                                 ? left
829                                 : right;
830                     }
831                 }
832             }
833
834             /**
835              * A key represents a collection of methods within a method graph to later yield a node representing a collection of methods,
836              * i.e. a method representative including information on the required method bridges.
837              *
838              * @param <S> The type of the token used for deciding on method equality.
839              */

840             protected abstract static class Key<S> {
841
842                 /**
843                  * The internal name of the method this key identifies.
844                  */

845                 protected final String internalName;
846
847                 /**
848                  * The number of method parameters of the method this key identifies.
849                  */

850                 protected final int parameterCount;
851
852                 /**
853                  * Creates a new key.
854                  *
855                  * @param internalName   The internal name of the method this key identifies.
856                  * @param parameterCount The number of method parameters of the method this key identifies.
857                  */

858                 protected Key(String internalName, int parameterCount) {
859                     this.internalName = internalName;
860                     this.parameterCount = parameterCount;
861                 }
862
863                 /**
864                  * Returns a set of all identifiers of this key.
865                  *
866                  * @return A set of all identifiers of this key.
867                  */

868                 protected abstract Set<S> getIdentifiers();
869
870                 @Override
871                 public int hashCode() {
872                     return internalName.hashCode() + 31 * parameterCount;
873                 }
874
875                 @Override
876                 public boolean equals(Object other) {
877                     if (this == other) {
878                         return true;
879                     } else if (!(other instanceof Key)) {
880                         return false;
881                     }
882                     Key key = (Key) other;
883                     return internalName.equals(key.internalName)
884                             && parameterCount == key.parameterCount
885                             && !Collections.disjoint(getIdentifiers(), key.getIdentifiers());
886                 }
887
888                 /**
889                  * A harmonized key represents a key where equality is decided based on tokens that are returned by a
890                  * {@link net.bytebuddy.dynamic.scaffold.MethodGraph.Compiler.Default.Harmonizer}.
891                  *
892                  * @param <V> The type of the tokens yielded by a harmonizer.
893                  */

894                 protected static class Harmonized<V> extends Key<V> {
895
896                     /**
897                      * A mapping of identifiers to the type tokens they represent.
898                      */

899                     private final Map<V, Set<MethodDescription.TypeToken>> identifiers;
900
901                     /**
902                      * Creates a new harmonized key.
903                      *
904                      * @param internalName   The internal name of the method this key identifies.
905                      * @param parameterCount The number of method parameters of the method this key identifies.
906                      * @param identifiers    A mapping of identifiers to the type tokens they represent.
907                      */

908                     protected Harmonized(String internalName, int parameterCount, Map<V, Set<MethodDescription.TypeToken>> identifiers) {
909                         super(internalName, parameterCount);
910                         this.identifiers = identifiers;
911                     }
912
913                     /**
914                      * Creates a new harmonized key for the given method description.
915                      *
916                      * @param methodDescription The method description to represent as a harmonized key.
917                      * @param harmonizer        The harmonizer to use.
918                      * @param <Q>               The type of the token yielded by a harmonizer.
919                      * @return A harmonized key representing the provided method.
920                      */

921                     protected static <Q> Harmonized<Q> of(MethodDescription methodDescription, Harmonizer<Q> harmonizer) {
922                         MethodDescription.TypeToken typeToken = methodDescription.asTypeToken();
923                         return new Harmonized<Q>(methodDescription.getInternalName(),
924                                 methodDescription.getParameters().size(),
925                                 Collections.singletonMap(harmonizer.harmonize(typeToken), Collections.<MethodDescription.TypeToken>emptySet()));
926                     }
927
928                     /**
929                      * Creates a detached version of this key.
930                      *
931                      * @param typeToken The type token of the representative method.
932                      * @return The detached version of this key.
933                      */

934                     protected Detached detach(MethodDescription.TypeToken typeToken) {
935                         Set<MethodDescription.TypeToken> identifiers = new HashSet<MethodDescription.TypeToken>();
936                         for (Set<MethodDescription.TypeToken> typeTokens : this.identifiers.values()) {
937                             identifiers.addAll(typeTokens);
938                         }
939                         identifiers.add(typeToken);
940                         return new Detached(internalName, parameterCount, identifiers);
941                     }
942
943                     /**
944                      * Combines this key with the given key.
945                      *
946                      * @param key The key to be merged with this key.
947                      * @return A harmonized key representing the merger of this key and the given key.
948                      */

949                     protected Harmonized<V> combineWith(Harmonized<V> key) {
950                         Map<V, Set<MethodDescription.TypeToken>> identifiers = new HashMap<V, Set<MethodDescription.TypeToken>>(this.identifiers);
951                         for (Map.Entry<V, Set<MethodDescription.TypeToken>> entry : key.identifiers.entrySet()) {
952                             Set<MethodDescription.TypeToken> typeTokens = identifiers.get(entry.getKey());
953                             if (typeTokens == null) {
954                                 identifiers.put(entry.getKey(), entry.getValue());
955                             } else {
956                                 typeTokens = new HashSet<MethodDescription.TypeToken>(typeTokens);
957                                 typeTokens.addAll(entry.getValue());
958                                 identifiers.put(entry.getKey(), typeTokens);
959                             }
960                         }
961                         return new Harmonized<V>(internalName, parameterCount, identifiers);
962                     }
963
964                     /**
965                      * Extends this key by the given method description.
966                      *
967                      * @param methodDescription The method to extend this key with.
968                      * @param harmonizer        The harmonizer to use for determining method equality.
969                      * @return The harmonized key representing the extension of this key with the provided method.
970                      */

971                     protected Harmonized<V> extend(MethodDescription.InDefinedShape methodDescription, Harmonizer<V> harmonizer) {
972                         Map<V, Set<MethodDescription.TypeToken>> identifiers = new HashMap<V, Set<MethodDescription.TypeToken>>(this.identifiers);
973                         MethodDescription.TypeToken typeToken = methodDescription.asTypeToken();
974                         V identifier = harmonizer.harmonize(typeToken);
975                         Set<MethodDescription.TypeToken> typeTokens = identifiers.get(identifier);
976                         if (typeTokens == null) {
977                             identifiers.put(identifier, Collections.singleton(typeToken));
978                         } else {
979                             typeTokens = new HashSet<MethodDescription.TypeToken>(typeTokens);
980                             typeTokens.add(typeToken);
981                             identifiers.put(identifier, typeTokens);
982                         }
983                         return new Harmonized<V>(internalName, parameterCount, identifiers);
984                     }
985
986                     @Override
987                     protected Set<V> getIdentifiers() {
988                         return identifiers.keySet();
989                     }
990                 }
991
992                 /**
993                  * A detached version of a key that identifies methods by their JVM signature, i.e. parameter types and return type.
994                  */

995                 protected static class Detached extends Key<MethodDescription.TypeToken> {
996
997                     /**
998                      * The type tokens represented by this key.
999                      */

1000                     private final Set<MethodDescription.TypeToken> identifiers;
1001
1002                     /**
1003                      * Creates a new detached key.
1004                      *
1005                      * @param internalName   The internal name of the method this key identifies.
1006                      * @param parameterCount The number of method parameters of the method this key identifies.
1007                      * @param identifiers    The type tokens represented by this key.
1008                      */

1009                     protected Detached(String internalName, int parameterCount, Set<MethodDescription.TypeToken> identifiers) {
1010                         super(internalName, parameterCount);
1011                         this.identifiers = identifiers;
1012                     }
1013
1014                     /**
1015                      * Creates a new detached key of the given method token.
1016                      *
1017                      * @param token The method token to represent as a key.
1018                      * @return A detached key representing the given method token..
1019                      */

1020                     protected static Detached of(MethodDescription.SignatureToken token) {
1021                         return new Detached(token.getName(), token.getParameterTypes().size(), Collections.singleton(token.asTypeToken()));
1022                     }
1023
1024                     @Override
1025                     protected Set<MethodDescription.TypeToken> getIdentifiers() {
1026                         return identifiers;
1027                     }
1028                 }
1029
1030                 /**
1031                  * A store for collected methods that are identified by keys.
1032                  *
1033                  * @param <V> The type of the token used for deciding on method equality.
1034                  */

1035                 @HashCodeAndEqualsPlugin.Enhance
1036                 protected static class Store<V> {
1037
1038                     /**
1039                      * A mapping of harmonized keys to their represented entry.
1040                      */

1041                     private final LinkedHashMap<Harmonized<V>, Entry<V>> entries;
1042
1043                     /**
1044                      * Creates an empty store.
1045                      */

1046                     protected Store() {
1047                         this(new LinkedHashMap<Harmonized<V>, Entry<V>>());
1048                     }
1049
1050                     /**
1051                      * Creates a new store representing the given entries.
1052                      *
1053                      * @param entries A mapping of harmonized keys to their represented entry.
1054                      */

1055                     private Store(LinkedHashMap<Harmonized<V>, Entry<V>> entries) {
1056                         this.entries = entries;
1057                     }
1058
1059                     /**
1060                      * Combines the two given stores.
1061                      *
1062                      * @param left  The left store to be combined.
1063                      * @param right The right store to be combined.
1064                      * @param <W>   The type of the harmonized key of both stores.
1065                      * @return An entry representing the combination of both stores.
1066                      */

1067                     private static <W> Entry<W> combine(Entry<W> left, Entry<W> right) {
1068                         Set<MethodDescription> leftMethods = left.getCandidates(), rightMethods = right.getCandidates();
1069                         LinkedHashSet<MethodDescription> combined = new LinkedHashSet<MethodDescription>();
1070                         combined.addAll(leftMethods);
1071                         combined.addAll(rightMethods);
1072                         for (MethodDescription leftMethod : leftMethods) {
1073                             TypeDescription leftType = leftMethod.getDeclaringType().asErasure();
1074                             for (MethodDescription rightMethod : rightMethods) {
1075                                 TypeDescription rightType = rightMethod.getDeclaringType().asErasure();
1076                                 if (leftType.equals(rightType)) {
1077                                     break;
1078                                 } else if (leftType.isAssignableTo(rightType)) {
1079                                     combined.remove(rightMethod);
1080                                     break;
1081                                 } else if (leftType.isAssignableFrom(rightType)) {
1082                                     combined.remove(leftMethod);
1083                                     break;
1084                                 }
1085                             }
1086                         }
1087                         Key.Harmonized<W> key = left.getKey().combineWith(right.getKey());
1088                         Visibility visibility = left.getVisibility().expandTo(right.getVisibility());
1089                         return combined.size() == 1
1090                                 ? new Entry.Resolved<W>(key, combined.iterator().next(), visibility, Entry.Resolved.NOT_MADE_VISIBLE)
1091                                 : new Entry.Ambiguous<W>(key, combined, visibility);
1092                     }
1093
1094                     /**
1095                      * Registers a new top level method within this store.
1096                      *
1097                      * @param methodDescriptions The methods to register.
1098                      * @param harmonizer         The harmonizer to use for determining method equality.
1099                      * @return A store with the given method registered as a top-level method.
1100                      */

1101                     protected Store<V> registerTopLevel(List<? extends MethodDescription> methodDescriptions, Harmonizer<V> harmonizer) {
1102                         if (methodDescriptions.isEmpty()) {
1103                             return this;
1104                         }
1105                         LinkedHashMap<Harmonized<V>, Entry<V>> entries = new LinkedHashMap<Harmonized<V>, Entry<V>>(this.entries);
1106                         for (MethodDescription methodDescription : methodDescriptions) {
1107                             Harmonized<V> key = Harmonized.of(methodDescription, harmonizer);
1108                             Entry<V> currentEntry = entries.remove(key), extendedEntry = (currentEntry == null
1109                                     ? new Entry.Initial<V>(key)
1110                                     : currentEntry).extendBy(methodDescription, harmonizer);
1111                             entries.put(extendedEntry.getKey(), extendedEntry);
1112                         }
1113                         return new Store<V>(entries);
1114                     }
1115
1116                     /**
1117                      * Combines this store with the given store.
1118                      *
1119                      * @param store The store to combine with this store.
1120                      * @return A store representing a combination of this store and the given store.
1121                      */

1122                     protected Store<V> combineWith(Store<V> store) {
1123                         if (entries.isEmpty()) {
1124                             return store;
1125                         } else if (store.entries.isEmpty()) {
1126                             return this;
1127                         }
1128                         LinkedHashMap<Harmonized<V>, Entry<V>> entries = new LinkedHashMap<Harmonized<V>, Entry<V>>(this.entries);
1129                         for (Entry<V> entry : store.entries.values()) {
1130                             Entry<V> previousEntry = entries.remove(entry.getKey()), injectedEntry = previousEntry == null
1131                                     ? entry
1132                                     : combine(previousEntry, entry);
1133                             entries.put(injectedEntry.getKey(), injectedEntry);
1134                         }
1135                         return new Store<V>(entries);
1136                     }
1137
1138                     /**
1139                      * Injects the given store into this store.
1140                      *
1141                      * @param store The key store to inject into this store.
1142                      * @return A store that represents this store with the given store injected.
1143                      */

1144                     protected Store<V> inject(Store<V> store) {
1145                         if (entries.isEmpty()) {
1146                             return store;
1147                         } else if (store.entries.isEmpty()) {
1148                             return this;
1149                         }
1150                         LinkedHashMap<Harmonized<V>, Entry<V>> entries = new LinkedHashMap<Harmonized<V>, Entry<V>>(this.entries);
1151                         for (Entry<V> entry : store.entries.values()) {
1152                             Entry<V> dominantEntry = entries.remove(entry.getKey()), injectedEntry = dominantEntry == null
1153                                     ? entry
1154                                     : dominantEntry.inject(entry.getKey(), entry.getVisibility());
1155                             entries.put(injectedEntry.getKey(), injectedEntry);
1156                         }
1157                         return new Store<V>(entries);
1158                     }
1159
1160                     /**
1161                      * Transforms this store into a method graph by applying the given merger.
1162                      *
1163                      * @param merger The merger to apply for resolving the representative for ambiguous resolutions.
1164                      * @return The method graph that represents this key store.
1165                      */

1166                     protected MethodGraph asGraph(Merger merger) {
1167                         LinkedHashMap<Key<MethodDescription.TypeToken>, Node> entries = new LinkedHashMap<Key<MethodDescription.TypeToken>, Node>();
1168                         for (Entry<V> entry : this.entries.values()) {
1169                             Node node = entry.asNode(merger);
1170                             entries.put(entry.getKey().detach(node.getRepresentative().asTypeToken()), node);
1171                         }
1172                         return new Graph(entries);
1173                     }
1174
1175                     /**
1176                      * An entry of a key store.
1177                      *
1178                      * @param <W> The type of the harmonized token used for determining method equality.
1179                      */

1180                     protected interface Entry<W> {
1181
1182                         /**
1183                          * Returns the harmonized key of this entry.
1184                          *
1185                          * @return The harmonized key of this entry.
1186                          */

1187                         Harmonized<W> getKey();
1188
1189                         /**
1190                          * Returns all candidate methods represented by this entry.
1191                          *
1192                          * @return All candidate methods represented by this entry.
1193                          */

1194                         Set<MethodDescription> getCandidates();
1195
1196                         /**
1197                          * Returns the minimal visibility of this entry.
1198                          *
1199                          * @return The minimal visibility of this entry.
1200                          */

1201                         Visibility getVisibility();
1202
1203                         /**
1204                          * Extends this entry by the given method.
1205                          *
1206                          * @param methodDescription The method description to extend this entry with.
1207                          * @param harmonizer        The harmonizer to use for determining method equality.
1208                          * @return This key extended by the given method.
1209                          */

1210                         Entry<W> extendBy(MethodDescription methodDescription, Harmonizer<W> harmonizer);
1211
1212                         /**
1213                          * Injects the given key into this entry.
1214                          *
1215                          * @param key        The key to inject into this entry.
1216                          * @param visibility The entry's minimal visibility.
1217                          * @return This entry extended with the given key.
1218                          */

1219                         Entry<W> inject(Harmonized<W> key, Visibility visibility);
1220
1221                         /**
1222                          * Transforms this entry into a node.
1223                          *
1224                          * @param merger The merger to use for determining the representative method of an ambiguous node.
1225                          * @return The resolved node.
1226                          */

1227                         Node asNode(Merger merger);
1228
1229                         /**
1230                          * An entry in its initial state before registering any method as a representative.
1231                          *
1232                          * @param <U> The type of the harmonized key to determine method equality.
1233                          */

1234                         class Initial<U> implements Entry<U> {
1235
1236                             /**
1237                              * The harmonized key this entry represents.
1238                              */

1239                             private final Harmonized<U> key;
1240
1241                             /**
1242                              * Creates a new initial key.
1243                              *
1244                              * @param key The harmonized key this entry represents.
1245                              */

1246                             protected Initial(Harmonized<U> key) {
1247                                 this.key = key;
1248                             }
1249
1250                             /**
1251                              * {@inheritDoc}
1252                              */

1253                             public Harmonized<U> getKey() {
1254                                 throw new IllegalStateException("Cannot extract key from initial entry:" + this);
1255                             }
1256
1257                             /**
1258                              * {@inheritDoc}
1259                              */

1260                             public Set<MethodDescription> getCandidates() {
1261                                 throw new IllegalStateException("Cannot extract method from initial entry:" + this);
1262                             }
1263
1264                             /**
1265                              * {@inheritDoc}
1266                              */

1267                             public Visibility getVisibility() {
1268                                 throw new IllegalStateException("Cannot extract visibility from initial entry:" + this);
1269                             }
1270
1271                             /**
1272                              * {@inheritDoc}
1273                              */

1274                             public Entry<U> extendBy(MethodDescription methodDescription, Harmonizer<U> harmonizer) {
1275                                 return new Resolved<U>(key.extend(methodDescription.asDefined(), harmonizer),
1276                                         methodDescription,
1277                                         methodDescription.getVisibility(),
1278                                         Resolved.NOT_MADE_VISIBLE);
1279                             }
1280
1281                             /**
1282                              * {@inheritDoc}
1283                              */

1284                             public Entry<U> inject(Harmonized<U> key, Visibility visibility) {
1285                                 throw new IllegalStateException("Cannot inject into initial entry without a registered method: " + this);
1286                             }
1287
1288                             /**
1289                              * {@inheritDoc}
1290                              */

1291                             public Node asNode(Merger merger) {
1292                                 throw new IllegalStateException("Cannot transform initial entry without a registered method: " + this);
1293                             }
1294
1295                             @Override
1296                             public int hashCode() {
1297                                 return key.hashCode();
1298                             }
1299
1300                             @Override
1301                             public boolean equals(Object other) {
1302                                 if (this == other) {
1303                                     return true;
1304                                 } else if (other == null || getClass() != other.getClass()) {
1305                                     return false;
1306                                 }
1307                                 Initial<?> initial = (Initial<?>) other;
1308                                 return key.equals(initial.key);
1309                             }
1310                         }
1311
1312                         /**
1313                          * An entry representing a non-ambiguous node resolution.
1314                          *
1315                          * @param <U> The type of the harmonized key to determine method equality.
1316                          */

1317                         @HashCodeAndEqualsPlugin.Enhance
1318                         class Resolved<U> implements Entry<U> {
1319
1320                             /**
1321                              * Indicates that a type's methods are already globally visible, meaning that a bridge method is not added
1322                              * with the intend of creating a visibility bridge.
1323                              */

1324                             private static final int MADE_VISIBLE = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED;
1325
1326                             /**
1327                              * Indicates that the entry was not made visible.
1328                              */

1329                             private static final boolean NOT_MADE_VISIBLE = false;
1330
1331                             /**
1332                              * The harmonized key this entry represents.
1333                              */

1334                             private final Harmonized<U> key;
1335
1336                             /**
1337                              * The non-ambiguous, representative method of this entry.
1338                              */

1339                             private final MethodDescription methodDescription;
1340
1341                             /**
1342                              * The minimal required visibility for this method.
1343                              */

1344                             private final Visibility visibility;
1345
1346                             /**
1347                              * {@code trueif this entry's representative was made visible by a visibility bridge.
1348                              */

1349                             private final boolean madeVisible;
1350
1351                             /**
1352                              * Creates a new resolved entry.
1353                              *
1354                              * @param key               The harmonized key this entry represents.
1355                              * @param methodDescription The non-ambiguous, representative method of this entry.
1356                              * @param visibility        The minimal required visibility for this method.
1357                              * @param madeVisible       {@code trueif this entry's representative was made visible by a visibility bridge.
1358                              */

1359                             protected Resolved(Harmonized<U> key, MethodDescription methodDescription, Visibility visibility, boolean madeVisible) {
1360                                 this.key = key;
1361                                 this.methodDescription = methodDescription;
1362                                 this.visibility = visibility;
1363                                 this.madeVisible = madeVisible;
1364                             }
1365
1366                             /**
1367                              * Creates an entry for an override where a method overrides another method within a super class.
1368                              *
1369                              * @param key        The merged key for both methods.
1370                              * @param override   The method declared by the extending type, potentially a bridge method.
1371                              * @param original   The method that is overridden by the extending type.
1372                              * @param visibility The minimal required visibility for this entry.
1373                              * @param <V>        The type of the harmonized key to determine method equality.
1374                              * @return An entry representing the merger of both methods.
1375                              */

1376                             private static <V> Entry<V> of(Harmonized<V> key, MethodDescription override, MethodDescription original, Visibility visibility) {
1377                                 visibility = visibility.expandTo(original.getVisibility()).expandTo(override.getVisibility());
1378                                 return override.isBridge()
1379                                         ? new Resolved<V>(key, original, visibility, (original.getDeclaringType().getModifiers() & MADE_VISIBLE) == 0)
1380                                         : new Resolved<V>(key, override, visibility, NOT_MADE_VISIBLE);
1381                             }
1382
1383                             /**
1384                              * {@inheritDoc}
1385                              */

1386                             public Harmonized<U> getKey() {
1387                                 return key;
1388                             }
1389
1390                             /**
1391                              * {@inheritDoc}
1392                              */

1393                             public Set<MethodDescription> getCandidates() {
1394                                 return Collections.singleton(methodDescription);
1395                             }
1396
1397                             /**
1398                              * {@inheritDoc}
1399                              */

1400                             public Visibility getVisibility() {
1401                                 return visibility;
1402                             }
1403
1404                             /**
1405                              * {@inheritDoc}
1406                              */

1407                             public Entry<U> extendBy(MethodDescription methodDescription, Harmonizer<U> harmonizer) {
1408                                 Harmonized<U> key = this.key.extend(methodDescription.asDefined(), harmonizer);
1409                                 Visibility visibility = this.visibility.expandTo(methodDescription.getVisibility());
1410                                 return methodDescription.getDeclaringType().equals(this.methodDescription.getDeclaringType())
1411                                         ? Ambiguous.of(key, methodDescription, this.methodDescription, visibility)
1412                                         : Resolved.of(key, methodDescription, this.methodDescription, visibility);
1413                             }
1414
1415                             /**
1416                              * {@inheritDoc}
1417                              */

1418                             public Entry<U> inject(Harmonized<U> key, Visibility visibility) {
1419                                 return new Resolved<U>(this.key.combineWith(key), methodDescription, this.visibility.expandTo(visibility), madeVisible);
1420                             }
1421
1422                             /**
1423                              * {@inheritDoc}
1424                              */

1425                             public MethodGraph.Node asNode(Merger merger) {
1426                                 return new Node(key.detach(methodDescription.asTypeToken()), methodDescription, visibility, madeVisible);
1427                             }
1428
1429                             /**
1430                              * A node implementation representing a non-ambiguous method.
1431                              */

1432                             @HashCodeAndEqualsPlugin.Enhance
1433                             protected static class Node implements MethodGraph.Node {
1434
1435                                 /**
1436                                  * The detached key representing this node.
1437                                  */

1438                                 private final Detached key;
1439
1440                                 /**
1441                                  * The representative method of this node.
1442                                  */

1443                                 private final MethodDescription methodDescription;
1444
1445                                 /**
1446                                  * The node's minimal visibility.
1447                                  */

1448                                 private final Visibility visibility;
1449
1450                                 /**
1451                                  * {@code trueif the represented method was made explicitly visible by a visibility bridge.
1452                                  */

1453                                 private final boolean visible;
1454
1455                                 /**
1456                                  * Creates a new node.
1457                                  *
1458                                  * @param key               The detached key representing this node.
1459                                  * @param methodDescription The representative method of this node.
1460                                  * @param visibility        The node's minimal visibility.
1461                                  * @param visible           {@code trueif the represented method was made explicitly visible by a visibility bridge.
1462                                  */

1463                                 protected Node(Detached key, MethodDescription methodDescription, Visibility visibility, boolean visible) {
1464                                     this.key = key;
1465                                     this.methodDescription = methodDescription;
1466                                     this.visibility = visibility;
1467                                     this.visible = visible;
1468                                 }
1469
1470                                 /**
1471                                  * {@inheritDoc}
1472                                  */

1473                                 public Sort getSort() {
1474                                     return visible
1475                                             ? Sort.VISIBLE
1476                                             : Sort.RESOLVED;
1477                                 }
1478
1479                                 /**
1480                                  * {@inheritDoc}
1481                                  */

1482                                 public MethodDescription getRepresentative() {
1483                                     return methodDescription;
1484                                 }
1485
1486                                 /**
1487                                  * {@inheritDoc}
1488                                  */

1489                                 public Set<MethodDescription.TypeToken> getMethodTypes() {
1490                                     return key.getIdentifiers();
1491                                 }
1492
1493                                 /**
1494                                  * {@inheritDoc}
1495                                  */

1496                                 public Visibility getVisibility() {
1497                                     return visibility;
1498                                 }
1499                             }
1500                         }
1501
1502                         /**
1503                          * An entry representing an ambiguous node resolution.
1504                          *
1505                          * @param <U> The type of the harmonized key to determine method equality.
1506                          */

1507                         @HashCodeAndEqualsPlugin.Enhance
1508                         class Ambiguous<U> implements Entry<U> {
1509
1510                             /**
1511                              * The harmonized key this entry represents.
1512                              */

1513                             private final Harmonized<U> key;
1514
1515                             /**
1516                              * A set of ambiguous methods that this entry represents.
1517                              */

1518                             private final LinkedHashSet<MethodDescription> methodDescriptions;
1519
1520                             /**
1521                              * The minimal required visibility for this method.
1522                              */

1523                             private final Visibility visibility;
1524
1525                             /**
1526                              * Creates a new ambiguous entry.
1527                              *
1528                              * @param key                The harmonized key this entry represents.
1529                              * @param methodDescriptions A set of ambiguous methods that this entry represents.
1530                              * @param visibility         The minimal required visibility for this method.
1531                              */

1532                             protected Ambiguous(Harmonized<U> key, LinkedHashSet<MethodDescription> methodDescriptions, Visibility visibility) {
1533                                 this.key = key;
1534                                 this.methodDescriptions = methodDescriptions;
1535                                 this.visibility = visibility;
1536                             }
1537
1538                             /**
1539                              * Creates a new ambiguous entry if both provided entries are not considered to be a bridge of one another.
1540                              *
1541                              * @param key        The key of the entry to be created.
1542                              * @param left       The left method to be considered.
1543                              * @param right      The right method to be considered.
1544                              * @param visibility The entry's minimal visibility.
1545                              * @param <Q>        The type of the token of the harmonized key to determine method equality.
1546                              * @return The entry representing both methods.
1547                              */

1548                             protected static <Q> Entry<Q> of(Harmonized<Q> key, MethodDescription left, MethodDescription right, Visibility visibility) {
1549                                 visibility = visibility.expandTo(left.getVisibility()).expandTo(right.getVisibility());
1550                                 return left.isBridge() ^ right.isBridge()
1551                                         ? new Resolved<Q>(key, left.isBridge() ? right : left, visibility, Resolved.NOT_MADE_VISIBLE)
1552                                         : new Ambiguous<Q>(key, new LinkedHashSet<MethodDescription>(Arrays.asList(left, right)), visibility);
1553                             }
1554
1555                             /**
1556                              * {@inheritDoc}
1557                              */

1558                             public Harmonized<U> getKey() {
1559                                 return key;
1560                             }
1561
1562                             /**
1563                              * {@inheritDoc}
1564                              */

1565                             public Set<MethodDescription> getCandidates() {
1566                                 return methodDescriptions;
1567                             }
1568
1569                             /**
1570                              * {@inheritDoc}
1571                              */

1572                             public Visibility getVisibility() {
1573                                 return visibility;
1574                             }
1575
1576                             /**
1577                              * {@inheritDoc}
1578                              */

1579                             public Entry<U> extendBy(MethodDescription methodDescription, Harmonizer<U> harmonizer) {
1580                                 Harmonized<U> key = this.key.extend(methodDescription.asDefined(), harmonizer);
1581                                 LinkedHashSet<MethodDescription> methodDescriptions = new LinkedHashSet<MethodDescription>();
1582                                 TypeDescription declaringType = methodDescription.getDeclaringType().asErasure();
1583                                 boolean bridge = methodDescription.isBridge();
1584                                 Visibility visibility = this.visibility;
1585                                 for (MethodDescription extendedMethod : this.methodDescriptions) {
1586                                     if (extendedMethod.getDeclaringType().asErasure().equals(declaringType)) {
1587                                         if (extendedMethod.isBridge() ^ bridge) {
1588                                             methodDescriptions.add(bridge ? extendedMethod : methodDescription);
1589                                         } else {
1590                                             methodDescriptions.add(methodDescription);
1591                                             methodDescriptions.add(extendedMethod);
1592                                         }
1593                                     }
1594                                     visibility = visibility.expandTo(extendedMethod.getVisibility());
1595                                 }
1596                                 if (methodDescriptions.isEmpty()) {
1597                                     return new Resolved<U>(key, methodDescription, visibility, bridge);
1598                                 } else if (methodDescriptions.size() == 1) {
1599                                     return new Resolved<U>(key, methodDescriptions.iterator().next(), visibility, Resolved.NOT_MADE_VISIBLE);
1600                                 } else {
1601                                     return new Ambiguous<U>(key, methodDescriptions, visibility);
1602                                 }
1603                             }
1604
1605                             /**
1606                              * {@inheritDoc}
1607                              */

1608                             public Entry<U> inject(Harmonized<U> key, Visibility visibility) {
1609                                 return new Ambiguous<U>(this.key.combineWith(key), methodDescriptions, this.visibility.expandTo(visibility));
1610                             }
1611
1612                             /**
1613                              * {@inheritDoc}
1614                              */

1615                             public MethodGraph.Node asNode(Merger merger) {
1616                                 Iterator<MethodDescription> iterator = methodDescriptions.iterator();
1617                                 MethodDescription methodDescription = iterator.next();
1618                                 while (iterator.hasNext()) {
1619                                     methodDescription = merger.merge(methodDescription, iterator.next());
1620                                 }
1621                                 return new Node(key.detach(methodDescription.asTypeToken()), methodDescription, visibility);
1622                             }
1623
1624                             /**
1625                              * A node implementation representing an ambiguous method resolution.
1626                              */

1627                             @HashCodeAndEqualsPlugin.Enhance
1628                             protected static class Node implements MethodGraph.Node {
1629
1630                                 /**
1631                                  * The detached key representing this node.
1632                                  */

1633                                 private final Detached key;
1634
1635                                 /**
1636                                  * The representative method of this node.
1637                                  */

1638                                 private final MethodDescription methodDescription;
1639
1640                                 /**
1641                                  * The node's minimal visibility.
1642                                  */

1643                                 private final Visibility visibility;
1644
1645                                 /**
1646                                  * @param key               The detached key representing this node.
1647                                  * @param methodDescription The representative method of this node.
1648                                  * @param visibility        The node's minimal visibility.
1649                                  */

1650                                 protected Node(Detached key, MethodDescription methodDescription, Visibility visibility) {
1651                                     this.key = key;
1652                                     this.methodDescription = methodDescription;
1653                                     this.visibility = visibility;
1654                                 }
1655
1656                                 /**
1657                                  * {@inheritDoc}
1658                                  */

1659                                 public Sort getSort() {
1660                                     return Sort.AMBIGUOUS;
1661                                 }
1662
1663                                 /**
1664                                  * {@inheritDoc}
1665                                  */

1666                                 public MethodDescription getRepresentative() {
1667                                     return methodDescription;
1668                                 }
1669
1670                                 /**
1671                                  * {@inheritDoc}
1672                                  */

1673                                 public Set<MethodDescription.TypeToken> getMethodTypes() {
1674                                     return key.getIdentifiers();
1675                                 }
1676
1677                                 /**
1678                                  * {@inheritDoc}
1679                                  */

1680                                 public Visibility getVisibility() {
1681                                     return visibility;
1682                                 }
1683                             }
1684                         }
1685                     }
1686
1687                     /**
1688                      * A graph implementation based on a key store.
1689                      */

1690                     @HashCodeAndEqualsPlugin.Enhance
1691                     protected static class Graph implements MethodGraph {
1692
1693                         /**
1694                          * A mapping of a node's type tokens to the represented node.
1695                          */

1696                         private final LinkedHashMap<Key<MethodDescription.TypeToken>, Node> entries;
1697
1698                         /**
1699                          * Creates a new graph.
1700                          *
1701                          * @param entries A mapping of a node's type tokens to the represented node.
1702                          */

1703                         protected Graph(LinkedHashMap<Key<MethodDescription.TypeToken>, Node> entries) {
1704                             this.entries = entries;
1705                         }
1706
1707                         /**
1708                          * {@inheritDoc}
1709                          */

1710                         public Node locate(MethodDescription.SignatureToken token) {
1711                             Node node = entries.get(Detached.of(token));
1712                             return node == null
1713                                     ? Node.Unresolved.INSTANCE
1714                                     : node;
1715                         }
1716
1717                         /**
1718                          * {@inheritDoc}
1719                          */

1720                         public NodeList listNodes() {
1721                             return new NodeList(new ArrayList<Node>(entries.values()));
1722                         }
1723                     }
1724                 }
1725             }
1726         }
1727     }
1728
1729     /**
1730      * A list of nodes.
1731      */

1732     class NodeList extends FilterableList.AbstractBase<Node, NodeList> {
1733
1734         /**
1735          * The represented nodes.
1736          */

1737         private final List<? extends Node> nodes;
1738
1739         /**
1740          * Creates a list of nodes.
1741          *
1742          * @param nodes The represented nodes.
1743          */

1744         public NodeList(List<? extends Node> nodes) {
1745             this.nodes = nodes;
1746         }
1747
1748         /**
1749          * {@inheritDoc}
1750          */

1751         public Node get(int index) {
1752             return nodes.get(index);
1753         }
1754
1755         /**
1756          * {@inheritDoc}
1757          */

1758         public int size() {
1759             return nodes.size();
1760         }
1761
1762         @Override
1763         protected NodeList wrap(List<Node> values) {
1764             return new NodeList(values);
1765         }
1766
1767         /**
1768          * Transforms this list of nodes into a list of the node's representatives.
1769          *
1770          * @return A list of these node's representatives.
1771          */

1772         public MethodList<?> asMethodList() {
1773             List<MethodDescription> methodDescriptions = new ArrayList<MethodDescription>(size());
1774             for (Node node : nodes) {
1775                 methodDescriptions.add(node.getRepresentative());
1776             }
1777             return new MethodList.Explicit<MethodDescription>(methodDescriptions);
1778         }
1779     }
1780
1781     /**
1782      * A simple implementation of a method graph.
1783      */

1784     @HashCodeAndEqualsPlugin.Enhance
1785     class Simple implements MethodGraph {
1786
1787         /**
1788          * The nodes represented by this method graph.
1789          */

1790         private final LinkedHashMap<MethodDescription.SignatureToken, Node> nodes;
1791
1792         /**
1793          * Creates a new simple method graph.
1794          *
1795          * @param nodes The nodes represented by this method graph.
1796          */

1797         public Simple(LinkedHashMap<MethodDescription.SignatureToken, Node> nodes) {
1798             this.nodes = nodes;
1799         }
1800
1801         /**
1802          * Returns a method graph that contains all of the provided methods as simple nodes.
1803          *
1804          * @param methodDescriptions A list of method descriptions to be represented as simple nodes.
1805          * @return A method graph that represents all of the provided methods as simple nodes.
1806          */

1807         public static MethodGraph of(List<? extends MethodDescription> methodDescriptions) {
1808             LinkedHashMap<MethodDescription.SignatureToken, Node> nodes = new LinkedHashMap<MethodDescription.SignatureToken, Node>();
1809             for (MethodDescription methodDescription : methodDescriptions) {
1810                 nodes.put(methodDescription.asSignatureToken(), new Node.Simple(methodDescription));
1811             }
1812             return new Simple(nodes);
1813         }
1814
1815         /**
1816          * {@inheritDoc}
1817          */

1818         public Node locate(MethodDescription.SignatureToken token) {
1819             Node node = nodes.get(token);
1820             return node == null
1821                     ? Node.Unresolved.INSTANCE
1822                     : node;
1823         }
1824
1825         /**
1826          * {@inheritDoc}
1827          */

1828         public NodeList listNodes() {
1829             return new NodeList(new ArrayList<Node>(nodes.values()));
1830         }
1831     }
1832 }
1833