1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.tools.layoutlib.create;
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.ClassVisitor;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.MethodVisitor;
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.objectweb.asm.Opcodes;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.Set;
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * A {@link DelegateClassAdapter} can transform some methods from a class into
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * delegates that defer the call to an associated delegate class.
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * <p/>
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * This is used to override specific methods and or all native methods in classes.
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class DelegateClassAdapter extends ClassVisitor {
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /** Suffix added to original methods. */
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static final String ORIGINAL_SUFFIX = "_Original";
35c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta    private static final String CONSTRUCTOR = "<init>";
36c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta    private static final String CLASS_INIT = "<clinit>";
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
38c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta    public static final String ALL_NATIVES = "<<all_natives>>";
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final String mClassName;
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final Set<String> mDelegateMethods;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final Log mLog;
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Creates a new {@link DelegateClassAdapter} that can transform some methods
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * from a class into delegates that defer the call to an associated delegate class.
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p/>
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This is used to override specific methods and or all native methods in classes.
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param log The logger object. Must not be null.
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param cv the class visitor to which this adapter must delegate calls.
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param className The internal class name of the class to visit,
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *          e.g. <code>com/android/SomeClass$InnerClass</code>.
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param delegateMethods The set of method names to modify and/or the
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *          special constant {@link #ALL_NATIVES} to convert all native methods.
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public DelegateClassAdapter(Log log,
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ClassVisitor cv,
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String className,
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Set<String> delegateMethods) {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        super(Opcodes.ASM4, cv);
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mLog = log;
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mClassName = className;
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mDelegateMethods = delegateMethods;
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    //----------------------------------
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // Methods from the ClassAdapter
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public MethodVisitor visitMethod(int access, String name, String desc,
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String signature, String[] exceptions) {
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) ||
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                              mDelegateMethods.contains(name);
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (!useDelegate) {
81c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta            // Not creating a delegate for this method, pass it as-is from the reader to the writer.
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return super.visitMethod(access, name, desc, signature, exceptions);
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta        if (CONSTRUCTOR.equals(name) || CLASS_INIT.equals(name)) {
86c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta            // We don't currently support generating delegates for constructors.
87c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta            throw new UnsupportedOperationException(
88c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta                String.format(
89c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta                    "Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)",  //$NON-NLS-1$
90c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta                    mClassName, name, desc));
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (isNative) {
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Remove native flag
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            access = access & ~Opcodes.ACC_NATIVE;
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions);
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
98c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta            DelegateMethodAdapter a = new DelegateMethodAdapter(
99c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta                    mLog, null, mwDelegate, mClassName, name, desc, isStatic);
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // A native has no code to visit, so we need to generate it directly.
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            a.generateDelegateCode();
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mwDelegate;
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // Given a non-native SomeClass.MethodName(), we want to generate 2 methods:
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // - A copy of the original method named SomeClass.MethodName_Original().
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //   The content is the original method as-is from the reader.
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // - A brand new implementation of SomeClass.MethodName() which calls to a
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        //   non-existing method named SomeClass_Delegate.MethodName().
112c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta        //   The implementation of this 'delegate' method is done in layoutlib_bridge.
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int accessDelegate = access;
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX,
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                     desc, signature, exceptions);
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        MethodVisitor mwDelegate = super.visitMethod(accessDelegate, name,
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                                     desc, signature, exceptions);
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
121c5a58437e62698f34abde93ec785c4cbe36aec2dDeepanshu Gupta        return new DelegateMethodAdapter(
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic);
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
125