14b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/*
24b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
34b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
44b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
54b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * you may not use this file except in compliance with the License.
64b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * You may obtain a copy of the License at
74b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
84b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
94b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet *
104b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
114b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
124b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * See the License for the specific language governing permissions and
144b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * limitations under the License.
154b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */
164b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
174b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetpackage com.android.tools.layoutlib.create;
184b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
194b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.ClassVisitor;
204b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.MethodVisitor;
214b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport org.objectweb.asm.Opcodes;
224b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
234b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohetimport java.util.Set;
244b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
254b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet/**
264b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * A {@link DelegateClassAdapter} can transform some methods from a class into
274b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * delegates that defer the call to an associated delegate class.
284b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * <p/>
294b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet * This is used to override specific methods and or all native methods in classes.
304b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet */
31f7270ba9083e5b0069f73fc88aec439ab439275bTor Norbyepublic class DelegateClassAdapter extends ClassVisitor {
324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
33865c3bef54228a353fd449a093b0c8d155618296Raphael Moll    /** Suffix added to original methods. */
34865c3bef54228a353fd449a093b0c8d155618296Raphael Moll    private static final String ORIGINAL_SUFFIX = "_Original";
35865c3bef54228a353fd449a093b0c8d155618296Raphael Moll    private static String CONSTRUCTOR = "<init>";
36865c3bef54228a353fd449a093b0c8d155618296Raphael Moll    private static String CLASS_INIT = "<clinit>";
37865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
384b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    public final static String ALL_NATIVES = "<<all_natives>>";
394b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
404b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final String mClassName;
414b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final Set<String> mDelegateMethods;
424b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    private final Log mLog;
434b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
444b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    /**
454b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * Creates a new {@link DelegateClassAdapter} that can transform some methods
464b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * from a class into delegates that defer the call to an associated delegate class.
474b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * <p/>
484b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * This is used to override specific methods and or all native methods in classes.
494b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     *
504b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * @param log The logger object. Must not be null.
514b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * @param cv the class visitor to which this adapter must delegate calls.
524b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * @param className The internal class name of the class to visit,
534b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     *          e.g. <code>com/android/SomeClass$InnerClass</code>.
544b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     * @param delegateMethods The set of method names to modify and/or the
554b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     *          special constant {@link #ALL_NATIVES} to convert all native methods.
564b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet     */
574b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    public DelegateClassAdapter(Log log,
584b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            ClassVisitor cv,
594b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            String className,
604b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            Set<String> delegateMethods) {
61f7270ba9083e5b0069f73fc88aec439ab439275bTor Norbye        super(Opcodes.ASM4, cv);
624b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        mLog = log;
634b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        mClassName = className;
644b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        mDelegateMethods = delegateMethods;
654b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
664b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
674b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    //----------------------------------
684b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    // Methods from the ClassAdapter
694b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
704b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    @Override
714b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    public MethodVisitor visitMethod(int access, String name, String desc,
724b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            String signature, String[] exceptions) {
734b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
744b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
754b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
764b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
774b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) ||
784b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet                              mDelegateMethods.contains(name);
794b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
80865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        if (!useDelegate) {
81865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            // Not creating a delegate for this method, pass it as-is from the reader
82865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            // to the writer.
83865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            return super.visitMethod(access, name, desc, signature, exceptions);
844b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
854b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet
864b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        if (useDelegate) {
87865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            if (CONSTRUCTOR.equals(name) || CLASS_INIT.equals(name)) {
88865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                // We don't currently support generating delegates for constructors.
89865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                throw new UnsupportedOperationException(
90865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                    String.format(
91865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                        "Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)",  //$NON-NLS-1$
92865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                        mClassName, name, desc));
934b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet            }
944b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet        }
95865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
96865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        if (isNative) {
97865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            // Remove native flag
98865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            access = access & ~Opcodes.ACC_NATIVE;
99865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions);
100865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
101865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            DelegateMethodAdapter2 a = new DelegateMethodAdapter2(
102865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                    mLog, null /*mwOriginal*/, mwDelegate, mClassName, name, desc, isStatic);
103865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
104865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            // A native has no code to visit, so we need to generate it directly.
105865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            a.generateDelegateCode();
106865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
107865c3bef54228a353fd449a093b0c8d155618296Raphael Moll            return mwDelegate;
108865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        }
109865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
110865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        // Given a non-native SomeClass.MethodName(), we want to generate 2 methods:
111865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        // - A copy of the original method named SomeClass.MethodName_Original().
112865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        //   The content is the original method as-is from the reader.
113865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        // - A brand new implementation of SomeClass.MethodName() which calls to a
114865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        //   non-existing method named SomeClass_Delegate.MethodName().
115865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        //   The implementation of this 'delegate' method is done in layoutlib_brigde.
116865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
117865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        int accessDelegate = access;
118865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        // change access to public for the original one
119caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll        if (Main.sOptions.generatePublicAccess) {
120caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll            access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
121caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll            access |= Opcodes.ACC_PUBLIC;
122caed59d90db8626462baaec351e66b2a3280dc34Raphael Moll        }
123865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
124865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX,
125865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                                                     desc, signature, exceptions);
126865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        MethodVisitor mwDelegate = super.visitMethod(accessDelegate, name,
127865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                                                     desc, signature, exceptions);
128865c3bef54228a353fd449a093b0c8d155618296Raphael Moll
129865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        DelegateMethodAdapter2 a = new DelegateMethodAdapter2(
130865c3bef54228a353fd449a093b0c8d155618296Raphael Moll                mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic);
131865c3bef54228a353fd449a093b0c8d155618296Raphael Moll        return a;
1324b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet    }
1334b52ec49fee79b0488d6a9eaaa4ea5d74ce90905Xavier Ducrohet}
134