Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: pkg/analyzer2dart/lib/src/identifier_semantics.dart

Issue 587323004: Classify method and property accesses semantically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/analyzer2dart/lib/src/tree_shaker.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart 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
5 /**
6 * Code for classifying the semantics of identifiers appearing in a Dart file.
7 */
8 library analyzer2dart.identifierSemantics;
9
10 import 'package:analyzer/analyzer.dart';
11 import 'package:analyzer/src/generated/element.dart';
12
13 /**
14 * Base class used to classify the semantics of a method or function
15 * invocation.
16 */
17 abstract class MethodInvocationSemantics {}
18
19 /**
20 * MethodInvocationSemantics object representing the invocation of a method
21 * that is defined statically within a class, or of a function that is defined
22 * at toplevel within a library.
23 */
24 class StaticMethodInvocation extends MethodInvocationSemantics {
25 /**
26 * The method or function being invoked.
27 */
28 final ExecutableElement methodElement;
29
30 /**
31 * The class containing the member being invoked, or null if a toplevel
32 * function is being invoked.
33 */
34 final ClassElement classElement;
35
36 /**
37 * The identifier being used to invoke the method or function.
38 */
39 final SimpleIdentifier methodName;
40
41 // TODO(paulberry): would it also be useful to store the libraryElement?
42
43 StaticMethodInvocation(this.methodElement, this.classElement,
44 this.methodName);
45 }
46
47 /**
48 * MethodInvocationSemantics object representing the invocation of a function
49 * that is defined inside of another function or method.
50 */
51 class LocalFunctionInvocation extends MethodInvocationSemantics {
52 /**
53 * The function being invoked.
54 */
55 final FunctionElement functionElement;
56
57 LocalFunctionInvocation(this.functionElement);
58 }
59
60 /**
61 * MethodInvocationSemantics object representing the invocation of an instance
62 * method within a class.
63 *
64 * This also handles calls to an undefined method using a bare
65 * identifier (since it cannot be determined until runtime whether the method
66 * is truly undefined).
67 */
68 class DynamicMethodInvocation extends MethodInvocationSemantics {
69 /**
70 * The expression on which the method is being invoked (or null if the target
71 * is an implicit "this").
72 */
73 final Expression target;
74
75 /**
76 * The identifier being used to invoke the method.
77 */
78 final SimpleIdentifier methodName;
79
80 DynamicMethodInvocation(this.target, this.methodName);
81 }
82
83 /**
84 * Base class used to classify the semantics of a property access.
85 */
86 abstract class AccessSemantics {
87 /**
88 * The identifier being used to access the property.
89 */
90 final SimpleIdentifier _identifier;
91
92 AccessSemantics(this._identifier);
93
94 /**
95 * True if this is a read access to the property. Note that both
96 * [isRead] and [isWrite] will be true in the case of a read-modify-write
97 * operation (e.g. "+=").
98 */
99 bool get isRead => _identifier.inGetterContext();
100
101 /**
102 * True if this is a write access to the property. Note that both
103 * [isRead] and [isWrite] will be true in the case of a read-modify-write
104 * operation (e.g. "+=").
105 */
106 bool get isWrite => _identifier.inSetterContext();
107 }
108
109 /**
110 * AccessSemantics object representing an access to a field that is defined
111 * statically within a class, or to a variable that is defined at toplevel
112 * within a library.
113 */
114 class StaticFieldAccess extends AccessSemantics {
115 /**
116 * The field or variable being referenced.
117 */
118 final PropertyInducingElement field;
119
120 /**
121 * The class containing the field being referenced, or null if a toplevel
122 * variable is being referenced.
123 */
124 final ClassElement classElement;
125
126 // TODO(paulberry): would it also be useful to store the libraryElement?
127
128 StaticFieldAccess(this.field, this.classElement, SimpleIdentifier identifier)
129 : super(identifier);
130 }
131
132 /**
133 * AccessSemantics object representing an access to a property that is defined
134 * statically within a class, or defined at toplevel within a library.
135 */
136 class StaticPropertyAccess extends AccessSemantics {
137 /**
138 * The property being referenced, or null if the property is undefined.
139 */
140 final PropertyAccessorElement property;
141
142 /**
143 * The class containing the property being referenced, or null if a toplevel
144 * property is being referenced.
145 */
146 final ClassElement classElement;
147
148 /**
149 * The identifier being used to access the property.
150 */
151 SimpleIdentifier get propertyName => _identifier;
152
153 // TODO(paulberry): would it also be useful to store the libraryElement?
154
155 StaticPropertyAccess(this.property, this.classElement,
156 SimpleIdentifier propertyName)
157 : super(propertyName);
158 }
159
160 /**
161 * AccessSemantics object representing an access to an instance property or
162 * field within a class.
163 *
164 * This also handles access to an undefined property using a bare
165 * identifier (since it cannot be determined until runtime whether the property
166 * is truly undefined).
167 */
168 class DynamicPropertyAccess extends AccessSemantics {
169 /**
170 * The expression on which the method is being invoked (or null if the target
171 * is an implicit "this").
172 */
173 final Expression target;
174
175 /**
176 * The identifier being used to access the property.
177 */
178 final SimpleIdentifier propertyName;
179
180 DynamicPropertyAccess(this.target, SimpleIdentifier propertyName)
181 : super(propertyName),
182 propertyName = propertyName;
183 }
184
185 /**
186 * AccessSemantics object representing an access to a local variable within a
187 * function or method.
188 */
189 class LocalVariableAccess extends AccessSemantics {
190 final LocalVariableElement variable;
191 LocalVariableAccess(this.variable, SimpleIdentifier identifier)
192 : super(identifier);
193 }
194
195 /**
196 * Return the method invocation semantics for [node].
197 */
198 MethodInvocationSemantics classifyMethodInvocation(MethodInvocation node) {
199 Expression target = node.realTarget;
200 if (target == null) {
201 Element staticElement = node.methodName.staticElement;
202 if (staticElement is FunctionElement) {
203 if (staticElement.enclosingElement is CompilationUnitElement) {
204 return new StaticMethodInvocation(staticElement, null, node.methodName);
205 } else {
206 return new LocalFunctionInvocation(staticElement);
207 }
208 } else if (staticElement is MethodElement && staticElement.isStatic) {
209 return new StaticMethodInvocation(
210 staticElement,
211 staticElement.enclosingElement,
212 node.methodName);
213 }
Brian Wilkerson 2014/09/22 19:44:48 It's also possible for the static element to be a
Paul Berry 2014/09/23 16:32:49 Done.
214 } else if (target is SimpleIdentifier) {
215 Element targetStaticElement = target.staticElement;
216 if (targetStaticElement is PrefixElement) {
217 if (node.methodName.staticElement != null) {
218 return new StaticMethodInvocation(
219 node.methodName.staticElement,
220 null,
221 node.methodName);
222 } else {
223 return new DynamicMethodInvocation(null, node.methodName);
224 }
225 } else if (targetStaticElement is ClassElement) {
226 return new StaticMethodInvocation(
227 node.methodName.staticElement,
228 targetStaticElement,
229 node.methodName);
230 }
231 }
Brian Wilkerson 2014/09/22 19:44:47 This is missing the case where the target is a Pre
Paul Berry 2014/09/23 16:32:49 Done. It turned out that I was able to handle thi
232 return new DynamicMethodInvocation(target, node.methodName);
233 }
234
235 /**
236 * Return the access semantics for [node].
237 */
238 AccessSemantics classifyPrefixedIdentifier(PrefixedIdentifier node) {
239 Element prefixElement = node.prefix.staticElement;
240 Element suffixElement = node.identifier.staticElement;
241 if (prefixElement is PrefixElement) {
242 Element staticElement = node.identifier.staticElement;
Brian Wilkerson 2014/09/22 19:44:48 staticElement == suffixElement
Paul Berry 2014/09/23 16:32:49 Done.
243 if (staticElement is PropertyAccessorElement) {
244 if (staticElement.isSynthetic) {
245 return new StaticFieldAccess(
246 staticElement.variable,
247 null,
248 node.identifier);
249 } else {
250 return new StaticPropertyAccess(staticElement, null, node.identifier);
251 }
252 }
253 return new DynamicPropertyAccess(null, node.identifier);
254 } else if (prefixElement is ClassElement) {
255 if (suffixElement is PropertyAccessorElement && suffixElement.isSynthetic) {
256 return new StaticFieldAccess(
257 suffixElement.variable,
258 prefixElement,
259 node.identifier);
260 }
261 return new StaticPropertyAccess(
262 suffixElement,
263 prefixElement,
264 node.identifier);
265 } else {
266 return new DynamicPropertyAccess(node.prefix, node.identifier);
Brian Wilkerson 2014/09/22 19:44:47 Do we represent method tear-offs as property acces
Paul Berry 2014/09/23 16:32:49 Method tear-offs weren't being handled properly.
267 }
268 }
269
270 /**
271 * Return the access semantics for [node].
272 */
273 DynamicPropertyAccess classifyPropertyAccess(PropertyAccess node) {
274 return new DynamicPropertyAccess(node.realTarget, node.propertyName);
275 }
276
277 /**
278 * Return the access semantics for [node]. Caller must ensure that [node] is
279 * not the right hand side of a [PropertyAccess] or [PrefixedIdentifier], or
280 * the method name of a [MethodInvocation].
281 */
282 AccessSemantics classifyBareIdentifier(SimpleIdentifier node) {
283 AstNode parent = node.parent;
284 if ((parent is FunctionDeclaration && parent.name == node) ||
Brian Wilkerson 2014/09/22 19:44:47 Replace this 'if' with if (node.inDeclarationCont
Paul Berry 2014/09/23 16:32:49 Aha, that's much better. Thanks!
285 parent is ImportDirective ||
286 (parent is ClassDeclaration && parent.name == node) ||
287 (parent is MethodDeclaration && parent.name == node) ||
288 (parent is VariableDeclaration && parent.name == node) ||
289 (parent is FormalParameter && parent.identifier == node)) {
290 // This identifier is a declaration, not a use.
291 // TODO(paulberry): Can some of the above cases be coalesced?
292 // TODO(paulberry): Additional cases
293 return null;
294 }
295 if (parent is TypeName) {
296 // TODO(paulberry): handle this case.
Brian Wilkerson 2014/09/22 19:44:48 It might be cleanest to not visit the children of
Paul Berry 2014/09/23 16:32:49 Hmm, that may be true. I'm not sure whether I wan
Brian Wilkerson 2014/09/23 17:03:58 It looks like you're currently exiting if you're v
Paul Berry 2014/09/23 17:45:56 Acknowledged.
297 return null;
298 }
299 // TODO(paulberry): handle PrefixElement.
300 Element staticElement = node.staticElement;
301 if (staticElement is PropertyAccessorElement) {
302 if (staticElement.isSynthetic) {
303 if (staticElement.enclosingElement is CompilationUnitElement) {
304 return new StaticFieldAccess(staticElement.variable, null, node);
305 } else if (staticElement.isStatic) {
306 return new StaticFieldAccess(
307 staticElement.variable,
308 staticElement.enclosingElement,
309 node);
310 }
311 } else {
312 if (staticElement.enclosingElement is CompilationUnitElement) {
313 return new StaticPropertyAccess(staticElement, null, node);
314 } else if (staticElement.isStatic) {
315 return new StaticPropertyAccess(
316 staticElement,
317 staticElement.enclosingElement,
318 node);
319 }
320 }
321 } else if (staticElement is LocalVariableElement) {
322 return new LocalVariableAccess(staticElement, node);
323 }
Brian Wilkerson 2014/09/22 19:44:48 Missing ParameterElement?
Paul Berry 2014/09/23 16:32:49 Done.
324 return new DynamicPropertyAccess(null, node);
325 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer2dart/lib/src/tree_shaker.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698