-
Notifications
You must be signed in to change notification settings - Fork 698
/
Ref.java
189 lines (163 loc) · 4.85 KB
/
Ref.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package org.python.indexer;
import org.python.indexer.ast.Attribute;
import org.python.indexer.ast.Name;
import org.python.indexer.ast.Node;
import org.python.indexer.ast.Str;
/**
* Encapsulates information about a binding reference.
*/
public class Ref {
private static final int ATTRIBUTE = 0x1;
private static final int CALL = 0x2; // function/method call
private static final int NEW = 0x4; // instantiation
private static final int STRING = 0x8; // source node is a String
private int start;
private String file;
private String name;
private int flags;
public Ref(Node node) {
if (node == null) {
throw new IllegalArgumentException("null node");
}
file = node.getFile();
start = node.start();
if (node instanceof Name) {
Name nn = ((Name)node);
name = nn.getId();
if (nn.isCall()) {
// We don't always have enough information at this point to know
// if it's a constructor call or a regular function/method call,
// so we just determine if it looks like a call or not, and the
// indexer will convert constructor-calls to NEW in a later pass.
markAsCall();
}
} else if (node instanceof Str) {
markAsString();
name = ((Str)node).getStr();
} else {
throw new IllegalArgumentException("I don't know what " + node + " is.");
}
Node parent = node.getParent();
if ((parent instanceof Attribute)
&& node == ((Attribute)parent).attr) {
markAsAttribute();
}
}
/**
* Constructor that provides a way for clients to add additional references
* not associated with an AST node (e.g. inside a comment or doc string).
* @param path absolute path to the file containing the reference
* @param offset the 0-indexed file offset of the reference
* @param text the text of the reference
*/
public Ref(String path, int offset, String text) {
if (path == null) {
throw new IllegalArgumentException("'path' cannot be null");
}
if (text == null) {
throw new IllegalArgumentException("'text' cannot be null");
}
file = path;
start = offset;
name = text;
}
/**
* Returns the file containing the reference.
*/
public String getFile() {
return file;
}
/**
* Returns the text of the reference.
*/
public String getName() {
return name;
}
/**
* Returns the starting file offset of the reference.
*/
public int start() {
return start;
}
/**
* Returns the ending file offset of the reference.
*/
public int end() {
return start + length();
}
/**
* Returns the length of the reference text.
*/
public int length() {
return isString() ? name.length() + 2 : name.length();
}
/**
* Returns {@code true} if this reference was unquoted name.
*/
public boolean isName() {
return !isString();
}
/**
* Returns {@code true} if this reference was an attribute
* of some other node.
*/
public boolean isAttribute() {
return (flags & ATTRIBUTE) != 0;
}
public void markAsAttribute() {
flags |= ATTRIBUTE;
}
/**
* Returns {@code true} if this reference was a quoted name.
* If so, the {@link #start} and {@link #length} include the positions
* of the opening and closing quotes, but {@link #isName} returns the
* text within the quotes.
*/
public boolean isString() {
return (flags & STRING) != 0;
}
public void markAsString() {
flags |= STRING;
}
/**
* Returns {@code true} if this reference is a function or method call.
*/
public boolean isCall() {
return (flags & CALL) != 0;
}
/**
* Returns {@code true} if this reference is a class instantiation.
*/
public void markAsCall() {
flags |= CALL;
flags &= ~NEW;
}
public boolean isNew() {
return (flags & NEW) != 0;
}
public void markAsNew() {
flags |= NEW;
flags &= ~CALL;
}
public boolean isRef() {
return !(isCall() || isNew());
}
@Override
public String toString() {
return "<Ref:" + file + ":" + name + ":" + start + ">";
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Ref)) {
return false;
} else {
Ref ref = (Ref)obj;
return (start == ref.start &&
(file == null && ref.file == null) || file.equals(ref.file));
}
}
@Override
public int hashCode() {
return ("" + file + start).hashCode();
}
}