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.implementation.bytecode.assign;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.description.type.TypeDescription;
20 import net.bytebuddy.implementation.bytecode.StackManipulation;
21 import net.bytebuddy.implementation.bytecode.assign.primitive.PrimitiveTypeAwareAssigner;
22 import net.bytebuddy.implementation.bytecode.assign.primitive.VoidAwareAssigner;
23 import net.bytebuddy.implementation.bytecode.assign.reference.GenericTypeAwareAssigner;
24 import net.bytebuddy.implementation.bytecode.assign.reference.ReferenceTypeAwareAssigner;
25
26 /**
27  * An assigner is responsible for converting some type {@code A} to another type {@code B} if possible.
28  * <p>&nbsp;</p>
29  * An assigner is for example responsible for type casting, auto boxing or unboxing or for the widening of primitive
30  * types.
31  */

32 @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
33 public interface Assigner {
34
35     /**
36      * A default assigner that can handle {@code void}, primitive types and reference types which considers generic types as raw types.
37      */

38     Assigner DEFAULT = new VoidAwareAssigner(new PrimitiveTypeAwareAssigner(ReferenceTypeAwareAssigner.INSTANCE));
39
40     /**
41      * A generics-aware assigner that can handle {@code void}, primitive types which reference types.
42      */

43     Assigner GENERICS_AWARE = new VoidAwareAssigner(new PrimitiveTypeAwareAssigner(GenericTypeAwareAssigner.INSTANCE));
44
45     /**
46      * @param source The original type that is to be transformed into the {@code targetType}.
47      * @param target The target type into which the {@code sourceType} is to be converted.
48      * @param typing A hint whether the assignment should consider the runtime type of the source type,
49      *               i.e. if type down or cross castings are allowed. If this hint is set, this is
50      *               also an indication that {@code void} to non-{@code void} assignments are permitted.
51      * @return A stack manipulation that transforms the {@code sourceType} into the {@code targetType} if this
52      * is possible. An illegal stack manipulation otherwise.
53      */

54     StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing);
55
56     /**
57      * Indicates for a type assignment, if a type casting should be applied in case that two types are not statically assignable.
58      * Also, a dynamic typing indicates that void values are assignable to other types by assigning the target type's default value.
59      */

60     enum Typing {
61
62         /**
63          * Requires static typing.
64          */

65         STATIC(false),
66
67         /**
68          * Allows dynamic typing.
69          */

70         DYNAMIC(true);
71
72         /**
73          * {@code trueif dynamic typing is a legitimate choice.
74          */

75         private final boolean dynamic;
76
77         /**
78          * Creates a new typing hint.
79          *
80          * @param dynamic {@code trueif dynamic typing is a legitimate choice.
81          */

82         Typing(boolean dynamic) {
83             this.dynamic = dynamic;
84         }
85
86         /**
87          * Resolves a typing constant for the presented boolean where {@code true} indicates that dynamic typing is a legitimate choice.
88          *
89          * @param dynamic An indicator for if dynamic typing is a legitimate choice.
90          * @return A corresponding typing constant.
91          */

92         public static Typing of(boolean dynamic) {
93             return dynamic
94                     ? DYNAMIC
95                     : STATIC;
96         }
97
98         /**
99          * Checks if this instance's typing behavior permits dynamic typing.
100          *
101          * @return {@code trueif dynamic typing is a legitimate choice.
102          */

103         public boolean isDynamic() {
104             return dynamic;
105         }
106     }
107
108     /**
109      * An assigner that only allows to assign types if they are equal to another.
110      */

111     enum EqualTypesOnly implements Assigner {
112
113         /**
114          * An type assigner that only considers equal generic types to be assignable.
115          */

116         GENERIC {
117             /** {@inheritDoc} */
118             public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing) {
119                 return source.equals(target)
120                         ? StackManipulation.Trivial.INSTANCE
121                         : StackManipulation.Illegal.INSTANCE;
122             }
123         },
124
125         /**
126          * A type assigner that considers two generic types to be equal if their erasure is equal.
127          */

128         ERASURE {
129             /** {@inheritDoc} */
130             public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing) {
131                 return source.asErasure().equals(target.asErasure())
132                         ? StackManipulation.Trivial.INSTANCE
133                         : StackManipulation.Illegal.INSTANCE;
134             }
135         };
136     }
137
138     /**
139      * An assigner that does not allow any assignments.
140      */

141     enum Refusing implements Assigner {
142
143         /**
144          * The singleton instance.
145          */

146         INSTANCE;
147
148         /**
149          * {@inheritDoc}
150          */

151         public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing) {
152             return StackManipulation.Illegal.INSTANCE;
153         }
154     }
155 }
156