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.primitive;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.type.TypeDescription;
20 import net.bytebuddy.implementation.bytecode.Removal;
21 import net.bytebuddy.implementation.bytecode.StackManipulation;
22 import net.bytebuddy.implementation.bytecode.assign.Assigner;
23 import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
24
25 /**
26  * This assigner is able to handle the {@code void} type. This means:
27  * <ol>
28  * <li>If a {@code void} type is assigned to the {@code void} it will consider this a trivial operation.</li>
29  * <li>If a {@code void} type is assigned to a non-{@code void} type, it will pop the top value from the stack.</li>
30  * <li>If a non-{@code void} type is assigned to a {@code void} type, it will load the target type's default value
31  * only if this was configured at the assigner's construction.</li>
32  * <li>If two non-{@code void} types are subject of the assignment, it will delegate the assignment to its chained
33  * assigner.</li>
34  * </ol>
35  */

36 @HashCodeAndEqualsPlugin.Enhance
37 public class VoidAwareAssigner implements Assigner {
38
39     /**
40      * An assigner that is capable of handling assignments that do not involve {@code void} types.
41      */

42     private final Assigner chained;
43
44     /**
45      * Creates a new assigner that is capable of handling void types.
46      *
47      * @param chained A chained assigner which will be queried by this assigner to handle assignments that
48      *                do not involve a {@code void} type.
49      */

50     public VoidAwareAssigner(Assigner chained) {
51         this.chained = chained;
52     }
53
54     /**
55      * {@inheritDoc}
56      */

57     public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing) {
58         if (source.represents(void.class) && target.represents(void.class)) {
59             return StackManipulation.Trivial.INSTANCE;
60         } else if (source.represents(void.class/* && target != void.class */) {
61             return typing.isDynamic()
62                     ? DefaultValue.of(target)
63                     : StackManipulation.Illegal.INSTANCE;
64         } else if (/* source != void.class && */ target.represents(void.class)) {
65             return Removal.of(source);
66         } else /* source != void.class && target != void.class */ {
67             return chained.assign(source, target, typing);
68         }
69     }
70 }
71