• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.naming;
5 
6 import com.android.tools.r8.graph.DexField;
7 import com.android.tools.r8.graph.DexMethod;
8 import com.android.tools.r8.graph.DexType;
9 import com.android.tools.r8.naming.MemberNaming.Signature.SignatureKind;
10 import java.io.IOException;
11 import java.io.StringWriter;
12 import java.io.Writer;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.LinkedList;
16 import java.util.List;
17 
18 /**
19  * Stores renaming information for a member.
20  * <p>
21  * This includes the signature, the original name and inlining range information.
22  */
23 public class MemberNaming {
24 
25   private static final int UNDEFINED_START_NUMBER = -1;
26 
27   @Override
equals(Object o)28   public boolean equals(Object o) {
29     if (this == o) {
30       return true;
31     }
32     if (!(o instanceof MemberNaming)) {
33       return false;
34     }
35 
36     MemberNaming that = (MemberNaming) o;
37     return signature.equals(that.signature)
38         && renamedSignature.equals(that.renamedSignature)
39         && topLevelRange.equals(that.topLevelRange)
40         && inlineInformation.equals(that.inlineInformation);
41   }
42 
43   @Override
hashCode()44   public int hashCode() {
45     int result = signature.hashCode();
46     result = 31 * result + renamedSignature.hashCode();
47     result = 31 * result + inlineInformation.hashCode();
48     result = 31 * result + topLevelRange.hashCode();
49     return result;
50   }
51 
52   /**
53    * Original signature of the member
54    */
55   final Signature signature;
56   /**
57    * Renamed signature where the name (but not the types) have been renamed.
58    */
59   final Signature renamedSignature;
60   public final List<InlineInformation> inlineInformation = new LinkedList<>();
61   public final Range topLevelRange;
62 
63   private int collapsedStartLineNumber = UNDEFINED_START_NUMBER;
64   private int originalStartLineNumber = UNDEFINED_START_NUMBER;
65 
MemberNaming(Signature signature, String renamedName, Range inlinedLineRange)66   MemberNaming(Signature signature, String renamedName, Range inlinedLineRange) {
67     this.signature = signature;
68     this.renamedSignature = signature.asRenamed(renamedName);
69     topLevelRange = inlinedLineRange == null ? fakeZeroRange : inlinedLineRange;
70   }
71 
addInliningRange(Range inlinedRange, Signature signature, Range originalRange)72   public void addInliningRange(Range inlinedRange, Signature signature, Range originalRange) {
73     inlineInformation.add(new InlineInformation(inlinedRange, originalRange, signature));
74   }
75 
getInlineRanges()76   public List<Range> getInlineRanges() {
77     List<Range> inlineRanges = new ArrayList<>();
78     for (InlineInformation information : inlineInformation) {
79       if (information.isActualInlining()) {
80         inlineRanges.add(information.inlinedRange);
81       }
82     }
83     return inlineRanges;
84   }
85 
getOriginalSignature()86   public Signature getOriginalSignature() {
87     return signature;
88   }
89 
getRenamedName()90   public String getRenamedName() {
91     return renamedSignature.name;
92   }
93 
setCollapsedStartLineNumber(int value)94   public void setCollapsedStartLineNumber(int value) {
95     assert collapsedStartLineNumber == UNDEFINED_START_NUMBER;
96     collapsedStartLineNumber = value;
97   }
98 
isMethodNaming()99   public boolean isMethodNaming() {
100     return signature.kind() == SignatureKind.METHOD;
101   }
102 
getCollapsedStartLineNumber()103   private int getCollapsedStartLineNumber() {
104     return collapsedStartLineNumber;
105   }
106 
write(Writer writer, boolean collapseRanges, boolean indent)107   protected void write(Writer writer, boolean collapseRanges, boolean indent) throws IOException {
108     if (indent) {
109       writer.append("    ");
110     }
111     int rangeCounter =
112         collapseRanges ? getCollapsedStartLineNumber() : InlineInformation.DO_NOT_COLLAPSE;
113     // Avoid printing the range information if there was none in the original file.
114     if (topLevelRange != fakeZeroRange || rangeCounter != UNDEFINED_START_NUMBER) {
115       if (collapseRanges) {
116         // Skip ranges for methods that are used only once, as they do not have debug information.
117         if (rangeCounter != UNDEFINED_START_NUMBER) {
118           String rangeString = Integer.toString(rangeCounter);
119           writer.append(rangeString).append(":").append(rangeString).append(":");
120         } else {
121           rangeCounter = 0;
122         }
123       } else {
124         writer.append(topLevelRange.toString());
125         writer.append(':');
126       }
127     } else {
128       // We might end up in a case where we have no line information for the top entry but still
129       // have inline ranges. Just to be sure, set rangeCounter to a useful value.
130       if (collapseRanges) {
131         rangeCounter = 0;
132       }
133     }
134     signature.write(writer);
135     if (originalStartLineNumber != UNDEFINED_START_NUMBER) {
136       // If we have original line number information, print it here.
137       String originalSourceLineString = Integer.toString(originalStartLineNumber);
138       writer.append(':')
139           .append(originalSourceLineString)
140           .append(':')
141           .append(originalSourceLineString);
142     }
143     writer.append(" -> ");
144     writer.append(renamedSignature.name);
145     writer.append("\n");
146     for (InlineInformation information : inlineInformation) {
147       assert !collapseRanges || rangeCounter >= 0;
148       if (collapseRanges && information.isActualInlining()) {
149         rangeCounter++;
150       }
151       information.write(writer, rangeCounter, indent);
152     }
153   }
154 
155   @Override
toString()156   public String toString() {
157     try {
158       StringWriter writer = new StringWriter();
159       write(writer, false, false);
160       return writer.toString();
161     } catch (IOException e) {
162       return e.toString();
163     }
164   }
165 
setOriginalStartLineNumber(int originalStartLineNumber)166   public void setOriginalStartLineNumber(int originalStartLineNumber) {
167     assert this.originalStartLineNumber == UNDEFINED_START_NUMBER;
168     this.originalStartLineNumber = originalStartLineNumber;
169   }
170 
171   public abstract static class Signature {
172 
173     public final String name;
174 
Signature(String name)175     protected Signature(String name) {
176       this.name = name;
177     }
178 
asRenamed(String renamedName)179     abstract Signature asRenamed(String renamedName);
180 
kind()181     abstract public SignatureKind kind();
182 
183     @Override
equals(Object o)184     abstract public boolean equals(Object o);
185 
186     @Override
hashCode()187     abstract public int hashCode();
188 
write(Writer builder)189     abstract void write(Writer builder) throws IOException;
190 
191     @Override
toString()192     public String toString() {
193       try {
194         StringWriter writer = new StringWriter();
195         write(writer);
196         return writer.toString();
197       } catch (IOException e) {
198         return e.toString();
199       }
200     }
201 
202     enum SignatureKind {
203       METHOD,
204       FIELD
205     }
206   }
207 
208   public static class FieldSignature extends Signature {
209 
210     public final String type;
211 
FieldSignature(String name, String type)212     public FieldSignature(String name, String type) {
213       super(name);
214       this.type = type;
215     }
216 
fromDexField(DexField field)217     public static FieldSignature fromDexField(DexField field) {
218       return new FieldSignature(field.name.toSourceString(),
219           field.type.toSourceString());
220     }
221 
222     @Override
asRenamed(String renamedName)223     Signature asRenamed(String renamedName) {
224       return new FieldSignature(renamedName, type);
225     }
226 
227     @Override
kind()228     public SignatureKind kind() {
229       return SignatureKind.FIELD;
230     }
231 
232     @Override
equals(Object o)233     public boolean equals(Object o) {
234       if (this == o) {
235         return true;
236       }
237       if (!(o instanceof FieldSignature)) {
238         return false;
239       }
240       FieldSignature that = (FieldSignature) o;
241       return name.equals(that.name) && type.equals(that.type);
242     }
243 
244     @Override
hashCode()245     public int hashCode() {
246       return name.hashCode() * 31 + type.hashCode();
247     }
248 
249     @Override
toString()250     public String toString() {
251       return type + " " + name;
252     }
253 
254     @Override
write(Writer writer)255     void write(Writer writer) throws IOException {
256       writer.append(type);
257       writer.append(' ');
258       writer.append(name);
259     }
260   }
261 
262   public static class MethodSignature extends Signature {
263 
264     public final String type;
265     public final String[] parameters;
266 
MethodSignature(String name, String type, String[] parameters)267     public MethodSignature(String name, String type, String[] parameters) {
268       super(name);
269       this.type = type;
270       this.parameters = parameters;
271     }
272 
fromDexMethod(DexMethod method)273     public static MethodSignature fromDexMethod(DexMethod method) {
274       String[] paramNames = new String[method.proto.parameters.values.length];
275       DexType[] values = method.proto.parameters.values;
276       for (int i = 0; i < values.length; i++) {
277         paramNames[i] = values[i].toSourceString();
278       }
279       return new MethodSignature(method.name.toSourceString(),
280           method.proto.returnType.toSourceString(), paramNames);
281     }
282 
283     @Override
asRenamed(String renamedName)284     Signature asRenamed(String renamedName) {
285       return new MethodSignature(renamedName, type, parameters);
286     }
287 
288     @Override
kind()289     public SignatureKind kind() {
290       return SignatureKind.METHOD;
291     }
292 
293     @Override
equals(Object o)294     public boolean equals(Object o) {
295       if (this == o) {
296         return true;
297       }
298       if (!(o instanceof MethodSignature)) {
299         return false;
300       }
301 
302       MethodSignature that = (MethodSignature) o;
303       return type.equals(that.type)
304           && name.equals(that.name)
305           && Arrays.equals(parameters, that.parameters);
306     }
307 
308     @Override
hashCode()309     public int hashCode() {
310       return (type.hashCode() * 17
311           + name.hashCode()) * 31
312           + Arrays.hashCode(parameters);
313     }
314 
315     @Override
write(Writer writer)316     void write(Writer writer) throws IOException {
317       writer.append(type)
318           .append(' ')
319           .append(name)
320           .append('(');
321       for (int i = 0; i < parameters.length; i++) {
322         writer.append(parameters[i]);
323         if (i < parameters.length - 1) {
324           writer.append(',');
325         }
326       }
327       writer.append(')');
328     }
329   }
330 
331   public class InlineInformation {
332     static final int DO_NOT_COLLAPSE = -1;
333 
334     public final Range inlinedRange;
335     public final Range originalRange;
336     public final Signature signature;
337 
InlineInformation(Range inlinedRange, Range originalRange, Signature signature)338     public InlineInformation(Range inlinedRange, Range originalRange, Signature signature) {
339       this.inlinedRange = inlinedRange;
340       this.originalRange = originalRange;
341       this.signature = signature;
342     }
343 
isActualInlining()344     public boolean isActualInlining() {
345       return !(originalRange instanceof SingleLineRange);
346     }
347 
write(Writer writer, int collapsedRange, boolean indent)348     public void write(Writer writer, int collapsedRange, boolean indent) throws IOException {
349       if (indent) {
350         writer.append("    ");
351       }
352       if (collapsedRange == DO_NOT_COLLAPSE) {
353         writer.append(inlinedRange.toString());
354       } else {
355         writer.append(Range.toCollapsedString(collapsedRange));
356       }
357       writer.append(":");
358       signature.write(writer);
359       if (originalRange != null) {
360         writer.append(':')
361             .append(originalRange.toString());
362       }
363       writer.append(" -> ")
364           .append(renamedSignature.name);
365       writer.append("\n");
366     }
367 
368     @Override
equals(Object o)369     public boolean equals(Object o) {
370       if (this == o) {
371         return true;
372       }
373       if (!(o instanceof InlineInformation)) {
374         return false;
375       }
376 
377       InlineInformation that = (InlineInformation) o;
378 
379       return inlinedRange.equals(that.inlinedRange)
380           && ((originalRange == null && that.originalRange == null)
381               || originalRange.equals(that.originalRange))
382           && signature.equals(that.signature);
383 
384     }
385 
386     @Override
hashCode()387     public int hashCode() {
388       int result = inlinedRange.hashCode();
389       result = 31 * result + originalRange.hashCode();
390       result = 31 * result + signature.hashCode();
391       return result;
392     }
393   }
394 
395   /**
396    * Represents a linenumber range.
397    */
398   public static class Range {
399 
400     public final int from;
401     public final int to;
402 
Range(int from, int to)403     Range(int from, int to) {
404       this.from = from;
405       this.to = to;
406     }
407 
contains(int value)408     public boolean contains(int value) {
409       return value >= from && value <= to;
410     }
411 
isSingle()412     public boolean isSingle() {
413       return false;
414     }
415 
416     @Override
toString()417     public String toString() {
418       return from + ":" + to;
419     }
420 
toCollapsedString(int value)421     public static String toCollapsedString(int value) {
422       return value + ":" + value;
423     }
424 
425     @Override
equals(Object o)426     public boolean equals(Object o) {
427       if (this == o) {
428         return true;
429       }
430       if (!(o instanceof Range)) {
431         return false;
432       }
433 
434       Range range = (Range) o;
435       return from == range.from && to == range.to;
436     }
437 
438     @Override
hashCode()439     public int hashCode() {
440       int result = from;
441       result = 31 * result + to;
442       return result;
443     }
444 
445   }
446 
447   /**
448    * Represents a single linenumber range (':' followed by a signle number), which
449    * is different semantically from a normal range that has the same from and to.
450    */
451   public static class SingleLineRange extends Range {
SingleLineRange(int fromAndTo)452     public SingleLineRange(int fromAndTo) {
453       super(fromAndTo, fromAndTo);
454     }
455 
456     @Override
isSingle()457     public boolean isSingle() {
458       return true;
459     }
460 
461     @Override
toString()462     public String toString() {
463       return Integer.toString(from);
464     }
465   }
466 
467   public final static Range fakeZeroRange = new Range(0, 0);
468 }
469