-
Notifications
You must be signed in to change notification settings - Fork 228
Expand file tree
/
Copy pathNAttribute.java
More file actions
173 lines (147 loc) · 5.13 KB
/
NAttribute.java
File metadata and controls
173 lines (147 loc) · 5.13 KB
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
/**
* Copyright 2009, Google Inc. All rights reserved.
* Licensed to PSF under a Contributor Agreement.
*/
package org.python.indexer.ast;
import org.python.indexer.Indexer;
import org.python.indexer.NBinding;
import org.python.indexer.Scope;
import org.python.indexer.types.NType;
import org.python.indexer.types.NUnionType;
import org.python.indexer.types.NUnknownType;
import static org.python.indexer.NBinding.Kind.ATTRIBUTE;
public class NAttribute extends NNode {
static final long serialVersionUID = -1120979305017812255L;
public NNode target;
public NName attr;
public NAttribute(NNode target, NName attr) {
this(target, attr, 0, 1);
}
public NAttribute(NNode target, NName attr, int start, int end) {
super(start, end);
setTarget(target);
setAttr(attr);
addChildren(target, attr);
}
public String getAttributeName() {
return attr.id;
}
/**
* Sets the attribute node. Used when constructing the AST.
* @throws IllegalArgumentException if the param is null
*/
public void setAttr(NName attr) {
if (attr == null) {
throw new IllegalArgumentException("param cannot be null");
}
this.attr = attr;
}
public NName getAttr() {
return attr;
}
/**
* Sets the target node. Used when constructing the AST.
* @throws IllegalArgumentException if the param is null
*/
public void setTarget(NNode target) {
if (target == null) {
throw new IllegalArgumentException("param cannot be null");
}
this.target = target;
}
public NNode getTarget() {
return target;
}
/**
* Assign some definite value to the attribute. Used during the name
* resolution pass. This method is called when this node is in the lvalue of
* an assignment, in which case it is called in lieu of {@link #resolve}.<p>
*/
public void setAttr(Scope s, NType v) throws Exception {
setType(new NUnknownType());
NType targetType = resolveExpr(target, s);
if (targetType.isUnionType()) {
targetType = targetType.asUnionType().firstKnownNonNullAlternate();
if (targetType == null) {
return;
}
}
targetType = targetType.follow();
if (targetType == Indexer.idx.builtins.None) {
return;
}
NBinding b = targetType.getTable().putAttr(attr.id, attr, v, ATTRIBUTE);
if (b != null) {
setType(attr.setType(b.followType()));
}
}
@Override
public NType resolve(Scope s) throws Exception {
setType(new NUnknownType());
NType targetType = resolveExpr(target, s);
if (targetType.isUnionType()) {
NType ret = new NUnknownType();
for (NType tp : targetType.asUnionType().getTypes()) {
resolveAttributeOnType(tp);
ret = NUnionType.union(ret, getType());
}
setType(attr.setType(ret.follow()));
} else {
resolveAttributeOnType(targetType);
}
return getType();
}
private void resolveAttributeOnType(NType targetType) {
NType ttype = targetType.follow();
NBinding b = ttype.getTable().lookupAttr(attr.id);
if (b == null) {
b = makeProvisionalBinding(ttype);
}
if (b != null) {
Indexer.idx.putLocation(attr, b);
setType(attr.setType(b.getType()));
}
}
/**
* If we can't find the attribute in the target type, create a temp binding
* for the attribute. If later on the target type defines the attribute,
* that definition replaces the temp binding, and any references to the temp
* binding are updated to refer to the new definition.
*
* <p>We never create temp bindings for attributes of native types, as
* the attributes of native types are expected to be fully resolved.
*
* <p>This strategy is a temporary solution for inferring the types of
* attributes on targets that are not yet resolved. This whole approach
* needs to be replaced by dataflow analysis.
*/
private NBinding makeProvisionalBinding(NType targetType) {
if (targetType.isNative()) {
return null;
}
Scope targetScope = targetType.getTable();
// XXX: Eventually we need to fix out all the cases where the path is
// is empty here. For now, avoid an IndexingException.
if ("".equals(targetScope.getPath())) {
return null;
}
NType utype = new NUnknownType();
NBinding b = targetScope.putAttr(attr.id, null, utype, ATTRIBUTE);
if (b != null) {
b.setProvisional(true);
utype.getTable().setPath(b.getQname());
}
return b;
}
@Override
public String toString() {
return "<Attribute:" + start() + ":" + target + "." + getAttributeName() + ">";
}
@Override
public void visit(NNodeVisitor v) {
if (v.visit(this)) {
visitNode(target, v);
visitNode(attr, v);
}
}
}