12eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden/*
22eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Copyright (C) 2010 The Android Open Source Project
32eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden *
42eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
52eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * you may not use this file except in compliance with the License.
62eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * You may obtain a copy of the License at
72eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden *
82eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
92eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden *
102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Unless required by applicable law or agreed to in writing, software
112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * See the License for the specific language governing permissions and
142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * limitations under the License.
152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */
162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenpackage com.android.apkcheck;
182eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
192eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.ArrayList;
202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.HashMap;
212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.HashSet;
222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.Iterator;
232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenimport java.util.Set;
242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden/**
262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden * Container representing a class or interface with fields and methods.
272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden */
282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFaddenpublic class ClassInfo {
292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private String mName;
302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    // methods are hashed on name:descriptor
312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private HashMap<String,MethodInfo> mMethodList;
322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    // fields are hashed on name:type
332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private HashMap<String,FieldInfo> mFieldList;
342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private String mSuperclassName;
362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    // is this a static inner class?
382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private String mIsStatic;
392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    // holds the name of the superclass and all declared interfaces
412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private ArrayList<String> mSuperNames;
422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
434fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    // is this an enumerated type?
444fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    private boolean mIsEnum;
454fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    // is this an annotation type?
464fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    private boolean mIsAnnotation;
474fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden
482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private boolean mFlattening = false;
492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private boolean mFlattened = false;
502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Constructs a new ClassInfo with the provided class name.
532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param className Binary class name without the package name,
552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *      e.g. "AlertDialog$Builder".
562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param superclassName Fully-qualified binary or non-binary superclass
572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *      name (e.g. "java.lang.Enum").
582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param isStatic Class static attribute, may be "true", "false", or null.
592eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
602eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public ClassInfo(String className, String superclassName, String isStatic) {
612eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mName = className;
622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mMethodList = new HashMap<String,MethodInfo>();
632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFieldList = new HashMap<String,FieldInfo>();
642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mSuperNames = new ArrayList<String>();
652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mIsStatic = isStatic;
662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*
682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * Record the superclass name, and add it to the interface list
692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * since we'll need to do the same "flattening" work on it.
702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         *
712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * Interfaces and java.lang.Object have a null value.
722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         */
732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        if (superclassName != null) {
742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            mSuperclassName = superclassName;
752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            mSuperNames.add(superclassName);
762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns the name of the class.
812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public String getName() {
832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mName;
842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns the name of the superclass.
882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public String getSuperclassName() {
902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mSuperclassName;
912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns the "static" attribute.
952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * This is actually tri-state:
972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *   "true" means it is static
982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *   "false" means it's not static
992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *   null means it's unknown
1002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * The "unknown" state is associated with the APK input, while the
1022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * known states are from the public API definition.
1032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * This relates to the handling of the "secret" first parameter to
1052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * constructors of non-static inner classes.
1062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public String getStatic() {
1082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mIsStatic;
1092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1124fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     * Returns whether or not this class is an enumerated type.
1134fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     */
1144fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    public boolean isEnum() {
1154fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        assert mFlattened;
1164fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        return mIsEnum;
1174fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    }
1184fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden
1194fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    /**
1204fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     * Returns whether or not this class is an annotation type.
1214fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     */
1224fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    public boolean isAnnotation() {
1234fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        assert mFlattened;
1244fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        return mIsAnnotation;
1254fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    }
1264fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden
1274fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden    /**
1282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Adds a field to the list.
1292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public void addField(FieldInfo fieldInfo) {
1312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFieldList.put(fieldInfo.getNameAndType(), fieldInfo);
1322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Retrives a field from the list.
1362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param nameAndType fieldName:type
1382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public FieldInfo getField(String nameAndType) {
1402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mFieldList.get(nameAndType);
1412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1432eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1442eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns an iterator over all known fields.
1452eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1462eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public Iterator<FieldInfo> getFieldIterator() {
1472eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mFieldList.values().iterator();
1482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Adds a method to the list.
1522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public void addMethod(MethodInfo methInfo) {
1542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mMethodList.put(methInfo.getNameAndDescriptor(), methInfo);
1552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns an iterator over all known methods.
1592eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1602eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public Iterator<MethodInfo> getMethodIterator() {
1612eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mMethodList.values().iterator();
1622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Retrieves a method from the list.
1662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param nameAndDescr methodName:descriptor
1682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public MethodInfo getMethod(String nameAndDescr) {
1702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mMethodList.get(nameAndDescr);
1712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Retrieves a method from the list, matching on the part of the key
1752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * before the return type.
1762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * The API file doesn't include an entry for a method that overrides
1782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * a method in the superclass.  Ordinarily this is a good thing, but
1792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * if the override uses a covariant return type then the reference
1802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * to it in the APK won't match.
1812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
1822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param nameAndDescr methodName:descriptor
1832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
1842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public MethodInfo getMethodIgnoringReturn(String nameAndDescr) {
1852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        String shortKey = nameAndDescr.substring(0, nameAndDescr.indexOf(')')+1);
1862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        Iterator<MethodInfo> iter = getMethodIterator();
1882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        while (iter.hasNext()) {
1892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            MethodInfo methInfo = iter.next();
1902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            String nad = methInfo.getNameAndDescriptor();
1912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            if (nad.startsWith(shortKey))
1922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                return methInfo;
1932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
1942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return null;
1962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
1972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
1982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
1992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Returns true if the method and field lists are empty.
2002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
2012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public boolean hasNoFieldMethod() {
2022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return mMethodList.size() == 0 && mFieldList.size() == 0;
2032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
2042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
2062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Adds an interface to the list of classes implemented by this class.
2072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
2082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public void addInterface(String interfaceName) {
2092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mSuperNames.add(interfaceName);
2102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
2112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
2132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Flattens a class.  This involves copying all methods and fields
2142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * declared by the superclass and interfaces (and, recursively, their
2152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * superclasses and interfaces) into the local structure.
2162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
2172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * The public API file must be fully parsed before calling here.
2184fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     *
2194fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden     * This also detects if we're an Enum or Annotation.
2202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
2212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    public void flattenClass(ApiList apiList) {
2222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        if (mFlattened)
2232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            return;
2242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*
2262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * Recursive class definitions aren't allowed in Java code, but
2272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * there could be one in the API definition file.
2282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         */
2292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        if (mFlattening) {
2302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            throw new RuntimeException("Recursive invoke; current class is "
2312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                + mName);
2322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
2332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFlattening = true;
2342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*
2362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * Normalize the ambiguous types.  This requires regenerating the
2372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * field and method lists, because the signature is used as the
2382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * hash table key.
2392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         */
2402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        normalizeTypes(apiList);
2412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*
2434fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * Figure out if this class is an enumerated type.
2444fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         */
2454fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        mIsEnum = "java.lang.Enum".equals(mSuperclassName);
2464fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden
2474fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        /*
2484fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * Figure out if this class is an annotation type.  We expect it
2494fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * to extend Object, implement java.lang.annotation.Annotation,
2504fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * and declare no fields or methods.  (If the API XML file is
2514fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * fixed, it will declare methods; but at that point having special
2524fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         * handling for annotations will be unnecessary.)
2534fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden         */
2544fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        if ("java.lang.Object".equals(mSuperclassName) &&
2554fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden            mSuperNames.contains("java.lang.annotation.Annotation") &&
2564fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden            hasNoFieldMethod())
2574fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        {
2584fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden            mIsAnnotation = true;
2594fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        }
2604fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden
2614fbfbb3914cfcc6d2da41be818e76208f1e59866Andy McFadden        /*
2622eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         * Flatten our superclass and interfaces.
2632eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden         */
2642eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        for (int i = 0; i < mSuperNames.size(); i++) {
2652eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            /*
2662eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden             * The contents of mSuperNames are in an ambiguous form.
2672eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden             * Normalize it to binary form before working with it.
2682eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden             */
2692eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            String interfaceName = TypeUtils.ambiguousToBinaryName(mSuperNames.get(i),
2702eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                    apiList);
2712eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            ClassInfo classInfo = lookupClass(interfaceName, apiList);
2722eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            if (classInfo == null) {
2732eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                ApkCheck.apkWarning("Class " + interfaceName +
2742eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                    " not found (super of " + mName + ")");
2752eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden                continue;
2762eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            }
2772eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2782eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            /* flatten it */
2792eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            classInfo.flattenClass(apiList);
2802eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2812eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            /* copy everything from it in here */
2822eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            mergeFrom(classInfo);
2832eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
2842eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2852eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFlattened = true;
2862eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
2872eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
2882eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
2892eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Normalizes the type names used in field and method descriptors.
2902eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
2912eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * We call the field/method normalization function, which updates how
2922eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * it thinks of itself (and may be called multiple times from different
2932eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * classes).  We then have to re-add it to the hash map because the
2942eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * key may have changed.  (We're using an iterator, so we create a
2952eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * new hashmap and replace the old.)
2962eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
2972eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private void normalizeTypes(ApiList apiList) {
2982eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        Iterator<String> keyIter;
2992eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3002eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        HashMap<String,FieldInfo> tmpFieldList = new HashMap<String,FieldInfo>();
3012eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        keyIter = mFieldList.keySet().iterator();
3022eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        while (keyIter.hasNext()) {
3032eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            String key = keyIter.next();
3042eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            FieldInfo fieldInfo = mFieldList.get(key);
3052eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            fieldInfo.normalizeType(apiList);
3062eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            tmpFieldList.put(fieldInfo.getNameAndType(), fieldInfo);
3072eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
3082eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFieldList = tmpFieldList;
3092eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3102eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        HashMap<String,MethodInfo> tmpMethodList = new HashMap<String,MethodInfo>();
3112eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        keyIter = mMethodList.keySet().iterator();
3122eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        while (keyIter.hasNext()) {
3132eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            String key = keyIter.next();
3142eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            MethodInfo methodInfo = mMethodList.get(key);
3152eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            methodInfo.normalizeTypes(apiList);
3162eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            tmpMethodList.put(methodInfo.getNameAndDescriptor(), methodInfo);
3172eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        }
3182eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mMethodList = tmpMethodList;
3192eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
3202eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3212eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
3222eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Merges the fields and methods from "otherClass" into this class.
3232eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
3242eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Redundant entries will be merged.  We don't specify who the winner
3252eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * will be.
3262eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
3272eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private void mergeFrom(ClassInfo otherClass) {
3282eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*System.out.println("merging into " + getName() + ": fields=" +
3292eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            mFieldList.size() + "/" + otherClass.mFieldList.size() +
3302eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            ", methods=" +
3312eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            mMethodList.size() + "/" + otherClass.mMethodList.size());*/
3322eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3332eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mFieldList.putAll(otherClass.mFieldList);
3342eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        mMethodList.putAll(otherClass.mMethodList);
3352eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3362eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        /*System.out.println("  now fields=" + mFieldList.size() +
3372eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            ", methods=" + mMethodList.size());*/
3382eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
3392eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3402eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3412eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    /**
3422eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * Finds the named class in the ApiList.
3432eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     *
3442eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param className Fully-qualified dot notation (e.g. "java.lang.String")
3452eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @param apiList The hierarchy to search in.
3462eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     * @return The class or null if not found.
3472eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden     */
3482eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    private static ClassInfo lookupClass(String fullname, ApiList apiList) {
3492eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        String packageName = TypeUtils.packageNameOnly(fullname);
3502eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        String className = TypeUtils.classNameOnly(fullname);
3512eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
3522eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        PackageInfo pkg = apiList.getPackage(packageName);
3532eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        if (pkg == null)
3542eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden            return null;
3552eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden        return pkg.getClass(className);
3562eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden    }
3572eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden}
3582eceaea745773bb654bb4e52c00cafdedc68c0acAndy McFadden
359