/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.taobao.atlas.dexmerge.dx.merge; import com.taobao.atlas.dex.ClassDef; import com.taobao.atlas.dex.Dex; import com.taobao.atlas.dex.DexException2; import java.util.ArrayList; import java.util.Comparator; import java.util.List; /** * Name and structure of a type. Used to order types such that each type is * preceded by its supertype and implemented interfaces. */ final class SortableType { public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() { public int compare(SortableType a, SortableType b) { if (a == b) { return 0; } if (b == null) { return -1; } if (a == null) { return 1; } if (a.depth != b.depth) { return a.depth - b.depth; } return a.getTypeIndex() - b.getTypeIndex(); } }; private final Dex dex; private final IndexMap indexMap; private ClassDef classDef; private int depth = -1; private List<SortableType> dupTypes; public SortableType(Dex dex, IndexMap indexMap, ClassDef classDef) { this.dex = dex; this.indexMap = indexMap; this.classDef = classDef; } public Dex getDex() { return dex; } public IndexMap getIndexMap() { return indexMap; } public ClassDef getClassDef() { return classDef; } public int getTypeIndex() { return classDef.getTypeIndex(); } public List<SortableType> getDupTypes() { return dupTypes; } public void addDupSortableType(SortableType sortableType){ if(null == dupTypes){ dupTypes = new ArrayList<SortableType>(); } dupTypes.add(sortableType); } /** * Assigns this type's depth if the depths of its supertype and implemented * interfaces are known. Returns false if the depth couldn't be computed * yet. */ public boolean tryAssignDepth(SortableType[] types) { int max; if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) { max = 0; // this is Object.class or an interface } else if (classDef.getSupertypeIndex() == classDef.getTypeIndex()) { // This is an invalid class extending itself. throw new DexException2("Class with type index " + classDef.getTypeIndex() + " extends itself"); } else { SortableType sortableSupertype = types[classDef.getSupertypeIndex()]; if (sortableSupertype == null) { max = 1; // unknown, so assume it's a root. } else if (sortableSupertype.depth == -1) { return false; } else { max = sortableSupertype.depth; } } for (short interfaceIndex : classDef.getInterfaces()) { SortableType implemented = types[interfaceIndex]; if (implemented == null) { max = Math.max(max, 1); // unknown, so assume it's a root. } else if (implemented.depth == -1) { return false; } else { max = Math.max(max, implemented.depth); } } depth = max + 1; return true; } public boolean isDepthAssigned() { return depth != -1; } }