1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.merge;
18 
19 import com.android.dex.ClassDef;
20 import com.android.dex.Dex;
21 import com.android.dex.DexException;
22 import java.util.Comparator;
23 
24 /**
25  * Name and structure of a type. Used to order types such that each type is
26  * preceded by its supertype and implemented interfaces.
27  */
28 final class SortableType {
29     public static final Comparator<SortableType> NULLS_LAST_ORDER = new Comparator<SortableType>() {
30         @Override
31         public int compare(SortableType a, SortableType b) {
32             if (a == b) {
33                 return 0;
34             }
35             if (b == null) {
36                 return -1;
37             }
38             if (a == null) {
39                 return 1;
40             }
41             if (a.depth != b.depth) {
42                 return a.depth - b.depth;
43             }
44             return a.getTypeIndex() - b.getTypeIndex();
45         }
46     };
47 
48     private final Dex dex;
49     private final IndexMap indexMap;
50     private final ClassDef classDef;
51     private int depth = -1;
52 
SortableType(Dex dex, IndexMap indexMap, ClassDef classDef)53     public SortableType(Dex dex, IndexMap indexMap, ClassDef classDef) {
54         this.dex = dex;
55         this.indexMap = indexMap;
56         this.classDef = classDef;
57     }
58 
getDex()59     public Dex getDex() {
60         return dex;
61     }
62 
getIndexMap()63     public IndexMap getIndexMap() {
64         return indexMap;
65     }
66 
getClassDef()67     public ClassDef getClassDef() {
68         return classDef;
69     }
70 
getTypeIndex()71     public int getTypeIndex() {
72         return classDef.getTypeIndex();
73     }
74 
75     /**
76      * Assigns this type's depth if the depths of its supertype and implemented
77      * interfaces are known. Returns false if the depth couldn't be computed
78      * yet.
79      */
tryAssignDepth(SortableType[] types)80     public boolean tryAssignDepth(SortableType[] types) {
81         int max;
82         if (classDef.getSupertypeIndex() == ClassDef.NO_INDEX) {
83             max = 0; // this is Object.class or an interface
84         } else if (classDef.getSupertypeIndex() == classDef.getTypeIndex()) {
85             // This is an invalid class extending itself.
86             throw new DexException("Class with type index " + classDef.getTypeIndex()
87                     + " extends itself");
88         } else {
89             SortableType sortableSupertype = types[classDef.getSupertypeIndex()];
90             if (sortableSupertype == null) {
91                 max = 1; // unknown, so assume it's a root.
92             } else if (sortableSupertype.depth == -1) {
93                 return false;
94             } else {
95                 max = sortableSupertype.depth;
96             }
97         }
98 
99         for (short interfaceIndex : classDef.getInterfaces()) {
100             SortableType implemented = types[interfaceIndex];
101             if (implemented == null) {
102                 max = Math.max(max, 1); // unknown, so assume it's a root.
103             } else if (implemented.depth == -1) {
104                 return false;
105             } else {
106                 max = Math.max(max, implemented.depth);
107             }
108         }
109 
110         depth = max + 1;
111         return true;
112     }
113 
isDepthAssigned()114     public boolean isDepthAssigned() {
115         return depth != -1;
116     }
117 }
118