16c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll/*
26c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * Copyright (C) 2009 The Android Open Source Project
36c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll *
46c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * Licensed under the Apache License, Version 2.0 (the "License");
56c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * you may not use this file except in compliance with the License.
66c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * You may obtain a copy of the License at
76c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll *
86c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll *      http://www.apache.org/licenses/LICENSE-2.0
96c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll *
106c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * Unless required by applicable law or agreed to in writing, software
116c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * distributed under the License is distributed on an "AS IS" BASIS,
126c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * See the License for the specific language governing permissions and
146c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll * limitations under the License.
156c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll */
166c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
176c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollpackage com.android.mkstubs;
186c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
198252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphaelimport com.android.mkstubs.Main.Logger;
208252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael
216c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.AnnotationVisitor;
226c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.Attribute;
236c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.ClassVisitor;
246c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.FieldVisitor;
256c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.MethodVisitor;
266c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Mollimport org.objectweb.asm.Opcodes;
276c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
286c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll/**
298f17caaa8be3e790f0ee26fa5b009b12c56a16d7Raphael Moll * A class visitor that filters out all members (fields, methods and inner classes) that are
30c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet * either private, default-access or rejected by the {@link Filter}.
316c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll */
327fb8be5c6ab69d547a49da88093c57acc3694309Tor Norbyeclass FilterClassAdapter extends ClassVisitor {
336c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
348252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael    private final Logger mLog;
350cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll    private final Filter mFilter;
360cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll    private String mClassName;
376c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
388252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael    public FilterClassAdapter(ClassVisitor writer, Filter filter, Logger log) {
397fb8be5c6ab69d547a49da88093c57acc3694309Tor Norbye        super(Opcodes.ASM4, writer);
400cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        mFilter = filter;
418252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael        mLog = log;
426c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
436c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
446c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
456c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visit(int version, int access, String name, String signature,
466c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            String superName, String[] interfaces) {
476c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
480cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        mClassName = name;
496c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        super.visit(version, access, name, signature, superName, interfaces);
506c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
516c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
526c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
536c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visitEnd() {
546c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        super.visitEnd();
556c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
56c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
576c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    /**
586c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * Visits a field.
59c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet     *
606c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * {@inheritDoc}
61c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet     *
626c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * Examples:
636c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * name = mArg
646c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * desc = Ljava/Lang/String;
656c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * signature = null (not a template) or template type
666c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     */
676c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
686c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public FieldVisitor visitField(int access, String name, String desc,
696c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            String signature, Object value) {
70c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        // only accept public/protected fields
71c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
726c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            return null;
736c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        }
74c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
750cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // filter on field name
760cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        String filterName = String.format("%s#%s", mClassName, name);
770cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll
780cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        if (!mFilter.accept(filterName)) {
798252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael            mLog.debug("- Remove field " + filterName);
800cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            return null;
810cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        }
82c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
830cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // TODO we should produce an error if a filtered desc/signature is being used.
846c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
856c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        return super.visitField(access, name, desc, signature, value);
866c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
876c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
886c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    /**
896c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * Visits a method.
90c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet     *
916c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * {@inheritDoc}
92c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet     *
936c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * Examples:
946c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * name = <init>
956c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * desc = ()V
966c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     * signature = null (not a template) or template type
976c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll     */
986c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
996c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public MethodVisitor visitMethod(int access, String name, String desc,
1006c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            String signature, String[] exceptions) {
1016c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
102c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        // only accept public/protected methods
103c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
1046c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            return null;
1056c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        }
106c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
1070cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // filter on method name using the non-generic descriptor
1080cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        String filterName = String.format("%s#%s%s", mClassName, name, desc);
1096c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1100cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        if (!mFilter.accept(filterName)) {
1118252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael            mLog.debug("- Remove method " + filterName);
1120cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            return null;
1130cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        }
1140cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll
1150cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // filter on method name using the generic signature
1160cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        if (signature != null) {
1170cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            filterName = String.format("%s#%s%s", mClassName, name, signature);
118c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
1190cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            if (!mFilter.accept(filterName)) {
1208252cdea30a5a22ae8b2235d7dee2fdd02ba5ccdRaphael                mLog.debug("- Remove method " + filterName);
1210cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll                return null;
1220cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            }
1230cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        }
1240cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll
1250cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // TODO we should produce an error if a filtered desc/signature/exception is being used.
1266c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1276c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        return super.visitMethod(access, name, desc, signature, exceptions);
1286c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1296c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1306c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
1316c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
132c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet
1330cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // TODO produce an error if a filtered annotation type is being used
1346c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        return super.visitAnnotation(desc, visible);
1356c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1366c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1376c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
1386c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visitAttribute(Attribute attr) {
1396c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        // pass
1406c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1416c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1426c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
1436c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visitInnerClass(String name, String outerName, String innerName, int access) {
1446c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
145c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        // only accept public/protected inner classes
146c3c97d1db391f4e400343fd69be11c8b1f951ff3Xavier Ducrohet        if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
1476c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll            return;
1486c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        }
1496c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1500cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // filter on name
1510cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        if (!mFilter.accept(name)) {
1520cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll            return;
1530cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        }
1546c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1556c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        super.visitInnerClass(name, outerName, innerName, access);
1566c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1576c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1586c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
1596c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visitOuterClass(String owner, String name, String desc) {
1600cb5e26dab4d6c62f7e1ac5a6ddd509ba3ee8c8cRaphael Moll        // pass
1616c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1626c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll
1636c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    @Override
1646c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    public void visitSource(String source, String debug) {
1656c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll        // pass
1666c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll    }
1676c0d467cc25692bf3a9eb36d2d88b895aa18a18dRaphael Moll}
168