OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Code for classifying the semantics of identifiers appearing in a Dart file. | 6 * Code for classifying the semantics of identifiers appearing in a Dart file. |
7 */ | 7 */ |
8 library analyzer2dart.identifierSemantics; | 8 library analyzer2dart.identifierSemantics; |
9 | 9 |
10 import 'package:analyzer/analyzer.dart'; | 10 import 'package:analyzer/analyzer.dart'; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 */ | 51 */ |
52 static const AccessKind STATIC_METHOD = const AccessKind._('STATIC_METHOD'); | 52 static const AccessKind STATIC_METHOD = const AccessKind._('STATIC_METHOD'); |
53 | 53 |
54 /** | 54 /** |
55 * The destination of the access is a property getter/setter that is defined | 55 * The destination of the access is a property getter/setter that is defined |
56 * statically within a class, or at top level within a library. | 56 * statically within a class, or at top level within a library. |
57 */ | 57 */ |
58 static const AccessKind STATIC_PROPERTY = | 58 static const AccessKind STATIC_PROPERTY = |
59 const AccessKind._('STATIC_PROPERTY'); | 59 const AccessKind._('STATIC_PROPERTY'); |
60 | 60 |
61 /** | |
62 * The destination of the access is a toplevel class. | |
63 */ | |
64 static const AccessKind TOPLEVEL_CLASS = | |
65 const AccessKind._('TOPLEVEL_CLASS'); | |
66 | |
67 /** | |
68 * The destination of the access is a type parameter of the enclosing class. | |
69 */ | |
70 static const AccessKind TYPE_PARAMETER = | |
71 const AccessKind._('TYPE_PARAMETER'); | |
72 | |
61 final String name; | 73 final String name; |
62 | 74 |
63 String toString() => name; | 75 String toString() => name; |
64 | 76 |
65 const AccessKind._(this.name); | 77 const AccessKind._(this.name); |
66 } | 78 } |
67 | 79 |
68 /** | 80 /** |
69 * Data structure used to classify the semantics of a property access or method | 81 * Data structure used to classify the semantics of a property access or method |
70 * or function invocation. | 82 * or function invocation. |
(...skipping 13 matching lines...) Expand all Loading... | |
84 /** | 96 /** |
85 * The element being accessed, if statically known. This will be null if | 97 * The element being accessed, if statically known. This will be null if |
86 * [kind] is DYNAMIC or if the element is undefined (e.g. an attempt to | 98 * [kind] is DYNAMIC or if the element is undefined (e.g. an attempt to |
87 * access a non-existent static method in a class). | 99 * access a non-existent static method in a class). |
88 */ | 100 */ |
89 final Element element; | 101 final Element element; |
90 | 102 |
91 /** | 103 /** |
92 * The class containing the element being accessed, if this is a static | 104 * The class containing the element being accessed, if this is a static |
93 * reference to an element in a class. This will be null if [kind] is | 105 * reference to an element in a class. This will be null if [kind] is |
94 * DYNAMIC, LOCAL_FUNCTION, LOCAL_VARIABLE, or PARAMETER, or if the element | 106 * DYNAMIC, LOCAL_FUNCTION, LOCAL_VARIABLE, PARAMETER, TOPLEVEL_CLASS, or |
95 * being accessed is defined at toplevel within a library. | 107 * TYPE_PARAMETER, or if the element being accessed is defined at toplevel |
108 * within a library. | |
96 * | 109 * |
97 * Note: it is possible for [classElement] to be non-null and for [element] | 110 * Note: it is possible for [classElement] to be non-null and for [element] |
98 * to be null; for example this occurs if the element being accessed is a | 111 * to be null; for example this occurs if the element being accessed is a |
99 * non-existent static method or field inside an existing class. | 112 * non-existent static method or field inside an existing class. |
100 */ | 113 */ |
101 final ClassElement classElement; | 114 final ClassElement classElement; |
102 | 115 |
103 // TODO(paulberry): would it also be useful to store the libraryElement? | 116 // TODO(paulberry): would it also be useful to store the libraryElement? |
104 | 117 |
105 /** | 118 /** |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 AccessSemantics.staticMethod(this.identifier, this.element, this.classElement, | 160 AccessSemantics.staticMethod(this.identifier, this.element, this.classElement, |
148 {this.isInvoke: false}) | 161 {this.isInvoke: false}) |
149 : kind = AccessKind.STATIC_METHOD, | 162 : kind = AccessKind.STATIC_METHOD, |
150 target = null; | 163 target = null; |
151 | 164 |
152 AccessSemantics.staticProperty(this.identifier, this.element, | 165 AccessSemantics.staticProperty(this.identifier, this.element, |
153 this.classElement, {this.isInvoke: false}) | 166 this.classElement, {this.isInvoke: false}) |
154 : kind = AccessKind.STATIC_PROPERTY, | 167 : kind = AccessKind.STATIC_PROPERTY, |
155 target = null; | 168 target = null; |
156 | 169 |
170 AccessSemantics.toplevelClass(this.identifier, this.element) | |
171 : kind = AccessKind.TOPLEVEL_CLASS, | |
172 classElement = null, | |
173 isInvoke = false, | |
174 target = null; | |
175 | |
176 AccessSemantics.typeParameter(this.identifier, this.element) | |
177 : kind = AccessKind.TYPE_PARAMETER, | |
178 classElement = null, | |
179 isInvoke = false, | |
180 target = null; | |
181 | |
157 /** | 182 /** |
158 * True if this is a read access to a property, or a method tear-off. Note | 183 * True if this is a read access to a property, or a method tear-off. Note |
159 * that both [isRead] and [isWrite] will be true in the case of a | 184 * that both [isRead] and [isWrite] will be true in the case of a |
160 * read-modify-write operation (e.g. "+="). | 185 * read-modify-write operation (e.g. "+="). |
161 */ | 186 */ |
162 bool get isRead => !isInvoke && identifier.inGetterContext(); | 187 bool get isRead => !isInvoke && identifier.inGetterContext(); |
163 | 188 |
164 /** | 189 /** |
165 * True if this is a write access to a property, or an (erroneous) attempt to | 190 * True if this is a write access to a property, or an (erroneous) attempt to |
166 * write to a method. Note that both [isRead] and [isWrite] will be true in | 191 * write to a method. Note that both [isRead] and [isWrite] will be true in |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 Element rhsElement = rhs.staticElement; | 372 Element rhsElement = rhs.staticElement; |
348 if (lhsElement is PrefixElement) { | 373 if (lhsElement is PrefixElement) { |
349 if (rhsElement is PropertyAccessorElement) { | 374 if (rhsElement is PropertyAccessorElement) { |
350 if (rhsElement.isSynthetic) { | 375 if (rhsElement.isSynthetic) { |
351 return new AccessSemantics.staticField(rhs, rhsElement.variable, null) ; | 376 return new AccessSemantics.staticField(rhs, rhsElement.variable, null) ; |
352 } else { | 377 } else { |
353 return new AccessSemantics.staticProperty(rhs, rhsElement, null); | 378 return new AccessSemantics.staticProperty(rhs, rhsElement, null); |
354 } | 379 } |
355 } else if (rhsElement is FunctionElement) { | 380 } else if (rhsElement is FunctionElement) { |
356 return new AccessSemantics.staticMethod(rhs, rhsElement, null); | 381 return new AccessSemantics.staticMethod(rhs, rhsElement, null); |
382 } else if (rhsElement is ClassElement) { | |
383 return new AccessSemantics.toplevelClass(rhs, rhsElement); | |
357 } else { | 384 } else { |
358 return new AccessSemantics.dynamic(rhs, null); | 385 return new AccessSemantics.dynamic(rhs, null); |
359 } | 386 } |
360 } else if (lhsElement is ClassElement) { | 387 } else if (lhsElement is ClassElement) { |
361 if (rhsElement is PropertyAccessorElement && rhsElement.isSynthetic) { | 388 if (rhsElement is PropertyAccessorElement && rhsElement.isSynthetic) { |
362 return new AccessSemantics.staticField( | 389 return new AccessSemantics.staticField( |
363 rhs, | 390 rhs, |
364 rhsElement.variable, | 391 rhsElement.variable, |
365 lhsElement); | 392 lhsElement); |
366 } else if (rhsElement is MethodElement) { | 393 } else if (rhsElement is MethodElement) { |
(...skipping 28 matching lines...) Expand all Loading... | |
395 * parent node before visiting this one. | 422 * parent node before visiting this one. |
396 */ | 423 */ |
397 @override | 424 @override |
398 AccessSemantics visitSimpleIdentifier(SimpleIdentifier node) { | 425 AccessSemantics visitSimpleIdentifier(SimpleIdentifier node) { |
399 AstNode parent = node.parent; | 426 AstNode parent = node.parent; |
400 if (node.inDeclarationContext()) { | 427 if (node.inDeclarationContext()) { |
401 // This identifier is a declaration, not a use. | 428 // This identifier is a declaration, not a use. |
402 return null; | 429 return null; |
403 } | 430 } |
404 if (parent is TypeName) { | 431 if (parent is TypeName) { |
405 // TODO(paulberry): handle this case. Or, perhaps it would be better to | 432 // TODO(paulberry): do we need to handle this case? |
406 // require clients not to visit the children of a TypeName when visiting | |
407 // the AST structure. | |
408 // | |
409 // TODO(paulberry): be sure to consider type literals, e.g.: | |
410 // class A {} | |
411 // var a = A; | |
412 return null; | 433 return null; |
413 } | 434 } |
414 if ((parent is PropertyAccess && parent.propertyName == node) || | 435 if ((parent is PropertyAccess && parent.propertyName == node) || |
415 (parent is PrefixedIdentifier && parent.identifier == node) || | 436 (parent is PrefixedIdentifier && parent.identifier == node) || |
416 (parent is MethodInvocation && parent.methodName == node)) { | 437 (parent is MethodInvocation && parent.methodName == node)) { |
417 // The access semantics are determined by the parent. | 438 // The access semantics are determined by the parent. |
418 return null; | 439 return null; |
419 } | 440 } |
420 // TODO(paulberry): handle PrefixElement. | 441 // TODO(paulberry): handle PrefixElement. |
421 Element staticElement = node.staticElement; | 442 Element staticElement = node.staticElement; |
(...skipping 28 matching lines...) Expand all Loading... | |
450 if (staticElement.enclosingElement is CompilationUnitElement) { | 471 if (staticElement.enclosingElement is CompilationUnitElement) { |
451 return new AccessSemantics.staticMethod(node, staticElement, null); | 472 return new AccessSemantics.staticMethod(node, staticElement, null); |
452 } else { | 473 } else { |
453 return new AccessSemantics.localFunction(node, staticElement); | 474 return new AccessSemantics.localFunction(node, staticElement); |
454 } | 475 } |
455 } else if (staticElement is MethodElement && staticElement.isStatic) { | 476 } else if (staticElement is MethodElement && staticElement.isStatic) { |
456 return new AccessSemantics.staticMethod( | 477 return new AccessSemantics.staticMethod( |
457 node, | 478 node, |
458 staticElement, | 479 staticElement, |
459 staticElement.enclosingElement); | 480 staticElement.enclosingElement); |
481 } else if (staticElement is TypeParameterElement) { | |
482 return new AccessSemantics.typeParameter(node, staticElement); | |
483 } else if (staticElement is ClassElement) { | |
484 return new AccessSemantics.toplevelClass(node, staticElement); | |
Johnni Winther
2014/11/11 12:49:45
How do you handle 'dynamic' as a type literal?
Paul Berry
2014/11/11 13:22:34
Whoops, I forgot to handle this case. I also forg
| |
460 } | 485 } |
461 return new AccessSemantics.dynamic(node, null); | 486 return new AccessSemantics.dynamic(node, null); |
462 } | 487 } |
463 } | 488 } |
OLD | NEW |