• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.dexlib2.analysis;
33 
34 import com.google.common.base.Strings;
35 import org.jf.dexlib2.iface.reference.FieldReference;
36 import org.jf.dexlib2.iface.reference.MethodReference;
37 import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
38 import org.jf.dexlib2.util.TypeUtils;
39 import org.jf.util.ExceptionWithContext;
40 
41 import javax.annotation.Nonnull;
42 import javax.annotation.Nullable;
43 
44 public class ArrayProto implements TypeProto {
45     protected final ClassPath classPath;
46     protected final int dimensions;
47     protected final String elementType;
48 
ArrayProto(@onnull ClassPath classPath, @Nonnull String type)49     public ArrayProto(@Nonnull ClassPath classPath, @Nonnull String type) {
50         this.classPath = classPath;
51         int i=0;
52         while (type.charAt(i) == '[') {
53             i++;
54             if (i == type.length()) {
55                 throw new ExceptionWithContext("Invalid array type: %s", type);
56             }
57         }
58 
59         if (i == 0) {
60             throw new ExceptionWithContext("Invalid array type: %s", type);
61         }
62 
63         dimensions = i;
64         elementType = type.substring(i);
65     }
66 
toString()67     @Override public String toString() { return getType(); }
getClassPath()68     @Nonnull @Override public ClassPath getClassPath() { return classPath; }
getType()69     @Nonnull @Override public String getType() { return makeArrayType(elementType, dimensions); }
getDimensions()70     public int getDimensions() { return dimensions; }
isInterface()71     @Override public boolean isInterface() { return false; }
72 
73     /**
74      * @return The base element type of this array. E.g. This would return Ljava/lang/String; for [[Ljava/lang/String;
75      */
getElementType()76     @Nonnull public String getElementType() { return elementType; }
77 
78     /**
79      * @return The immediate element type of this array. E.g. This would return [Ljava/lang/String; for
80      * [[Ljava/lang/String;
81      */
getImmediateElementType()82     @Nonnull public String getImmediateElementType() {
83         if (dimensions > 1) {
84             return makeArrayType(elementType, dimensions-1);
85         }
86         return elementType;
87     }
88 
implementsInterface(@onnull String iface)89     @Override public boolean implementsInterface(@Nonnull String iface) {
90         return iface.equals("Ljava/lang/Cloneable;") || iface.equals("Ljava/io/Serializable;");
91     }
92 
93     @Nullable @Override
getSuperclass()94     public String getSuperclass() {
95         return "Ljava/lang/Object;";
96     }
97 
98     @Nonnull @Override
getCommonSuperclass(@onnull TypeProto other)99     public TypeProto getCommonSuperclass(@Nonnull TypeProto other) {
100         if (other instanceof ArrayProto) {
101             if (TypeUtils.isPrimitiveType(getElementType()) ||
102                     TypeUtils.isPrimitiveType(((ArrayProto)other).getElementType())) {
103                 if (dimensions == ((ArrayProto)other).dimensions &&
104                         getElementType().equals(((ArrayProto)other).getElementType())) {
105                     return this;
106                 }
107                 return classPath.getClass("Ljava/lang/Object;");
108             }
109 
110             if (dimensions == ((ArrayProto)other).dimensions) {
111                 TypeProto thisClass = classPath.getClass(elementType);
112                 TypeProto otherClass = classPath.getClass(((ArrayProto)other).elementType);
113                 TypeProto mergedClass = thisClass.getCommonSuperclass(otherClass);
114                 if (thisClass == mergedClass) {
115                     return this;
116                 }
117                 if (otherClass == mergedClass) {
118                     return other;
119                 }
120                 return classPath.getClass(makeArrayType(mergedClass.getType(), dimensions));
121             }
122 
123             int dimensions = Math.min(this.dimensions, ((ArrayProto)other).dimensions);
124             return classPath.getClass(makeArrayType("Ljava/lang/Object;", dimensions));
125         }
126 
127         if (other instanceof ClassProto) {
128             try {
129                 if (other.isInterface()) {
130                     if (implementsInterface(other.getType())) {
131                         return other;
132                     }
133                 }
134             } catch (UnresolvedClassException ex) {
135                 // ignore
136             }
137             return classPath.getClass("Ljava/lang/Object;");
138         }
139 
140         // otherwise, defer to the other class' getCommonSuperclass
141         return other.getCommonSuperclass(this);
142     }
143 
144     private static final String BRACKETS = Strings.repeat("[", 256);
145 
146     @Nonnull
makeArrayType(@onnull String elementType, int dimensions)147     private static String makeArrayType(@Nonnull String elementType, int dimensions) {
148         return BRACKETS.substring(0, dimensions) + elementType;
149     }
150 
151 
152     @Override
153     @Nullable
getFieldByOffset(int fieldOffset)154     public FieldReference getFieldByOffset(int fieldOffset) {
155         if (fieldOffset==8) {
156             return new ImmutableFieldReference(getType(), "length", "int");
157         }
158         return null;
159     }
160 
161     @Override
162     @Nullable
getMethodByVtableIndex(int vtableIndex)163     public MethodReference getMethodByVtableIndex(int vtableIndex) {
164         return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex);
165     }
166 }
167