1/*
2 * Copyright (C) 2007 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
17package com.android.dx.rop.code;
18
19import com.android.dx.rop.cst.CstString;
20import com.android.dx.util.Hex;
21
22/**
23 * Information about a source position for code, which includes both a
24 * line number and original bytecode address.
25 */
26public final class SourcePosition {
27    /** {@code non-null;} convenient "no information known" instance */
28    public static final SourcePosition NO_INFO =
29        new SourcePosition(null, -1, -1);
30
31    /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
32    private final CstString sourceFile;
33
34    /**
35     * {@code >= -1;} the bytecode address, or {@code -1} if that
36     * information is unknown
37     */
38    private final int address;
39
40    /**
41     * {@code >= -1;} the line number, or {@code -1} if that
42     * information is unknown
43     */
44    private final int line;
45
46    /**
47     * Constructs an instance.
48     *
49     * @param sourceFile {@code null-ok;} name of the file of origin or
50     * {@code null} if unknown
51     * @param address {@code >= -1;} original bytecode address or {@code -1}
52     * if unknown
53     * @param line {@code >= -1;} original line number or {@code -1} if
54     * unknown
55     */
56    public SourcePosition(CstString sourceFile, int address, int line) {
57        if (address < -1) {
58            throw new IllegalArgumentException("address < -1");
59        }
60
61        if (line < -1) {
62            throw new IllegalArgumentException("line < -1");
63        }
64
65        this.sourceFile = sourceFile;
66        this.address = address;
67        this.line = line;
68    }
69
70    /** {@inheritDoc} */
71    @Override
72    public String toString() {
73        StringBuffer sb = new StringBuffer(50);
74
75        if (sourceFile != null) {
76            sb.append(sourceFile.toHuman());
77            sb.append(":");
78        }
79
80        if (line >= 0) {
81            sb.append(line);
82        }
83
84        sb.append('@');
85
86        if (address < 0) {
87            sb.append("????");
88        } else {
89            sb.append(Hex.u2(address));
90        }
91
92        return sb.toString();
93    }
94
95    /** {@inheritDoc} */
96    @Override
97    public boolean equals(Object other) {
98        if (!(other instanceof SourcePosition)) {
99            return false;
100        }
101
102        if (this == other) {
103            return true;
104        }
105
106        SourcePosition pos = (SourcePosition) other;
107
108        return (address == pos.address) && sameLineAndFile(pos);
109    }
110
111    /** {@inheritDoc} */
112    @Override
113    public int hashCode() {
114        return sourceFile.hashCode() + address + line;
115    }
116
117    /**
118     * Returns whether the lines match between this instance and
119     * the one given.
120     *
121     * @param other {@code non-null;} the instance to compare to
122     * @return {@code true} iff the lines match
123     */
124    public boolean sameLine(SourcePosition other) {
125        return (line == other.line);
126    }
127
128    /**
129     * Returns whether the lines and files match between this instance and
130     * the one given.
131     *
132     * @param other {@code non-null;} the instance to compare to
133     * @return {@code true} iff the lines and files match
134     */
135    public boolean sameLineAndFile(SourcePosition other) {
136        return (line == other.line) &&
137            ((sourceFile == other.sourceFile) ||
138             ((sourceFile != null) && sourceFile.equals(other.sourceFile)));
139    }
140
141    /**
142     * Gets the source file, if known.
143     *
144     * @return {@code null-ok;} the source file or {@code null} if unknown
145     */
146    public CstString getSourceFile() {
147        return sourceFile;
148    }
149
150    /**
151     * Gets the original bytecode address.
152     *
153     * @return {@code >= -1;} the address or {@code -1} if unknown
154     */
155    public int getAddress() {
156        return address;
157    }
158
159    /**
160     * Gets the original line number.
161     *
162     * @return {@code >= -1;} the original line number or {@code -1} if
163     * unknown
164     */
165    public int getLine() {
166        return line;
167    }
168}
169