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(true, true, true),
238
239 /**
240 * Represents a resolved node that was not made visible by a visibility bridge.
241 */
242 RESOLVED(true, true, false),
243
244 /**
245 * Represents an ambiguous node, i.e. a node that might refer to several methods.
246 */
247 AMBIGUOUS(true, false, false),
248
249 /**
250 * Represents an unresolved node.
251 */
252 UNRESOLVED(false, false, false);
253
254 /**
255 * {@code true} if this sort represents a resolved node.
256 */
257 private final boolean resolved;
258
259 /**
260 * {@code true} if this sort represents a non-ambiguous node.
261 */
262 private final boolean unique;
263
264 /**
265 * {@code true} if 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 true} if this sort represents a resolved node.
273 * @param unique {@code true} if this sort represents a non-ambiguous node.
274 * @param madeVisible {@code true} if 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 true} if 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 true} if 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 true} if 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 true} if 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 true} if 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 true} if 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 true} if 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 true} if 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 true} if 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