| 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 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 sb.write('target=this.$identifier'); | 192 sb.write('target=this.$identifier'); |
| 193 } else { | 193 } else { |
| 194 sb.write('target=$target.$identifier'); | 194 sb.write('target=$target.$identifier'); |
| 195 } | 195 } |
| 196 } | 196 } |
| 197 sb.write(']'); | 197 sb.write(']'); |
| 198 return sb.toString(); | 198 return sb.toString(); |
| 199 } | 199 } |
| 200 } | 200 } |
| 201 | 201 |
| 202 /** | 202 // TODO(johnniwinther,paulberry): This should be a constant. |
| 203 * Return the semantics for [node]. | 203 final AccessSemanticsVisitor ACCESS_SEMANTICS_VISITOR = |
| 204 */ | 204 new AccessSemanticsVisitor(); |
| 205 AccessSemantics classifyMethodInvocation(MethodInvocation node) { | 205 |
| 206 Expression target = node.realTarget; | 206 // TODO(johnniwinther,paulberry): This should extend a non-recursive visitor. |
| 207 Element staticElement = node.methodName.staticElement; | 207 class AccessSemanticsVisitor extends RecursiveAstVisitor<AccessSemantics> { |
| 208 if (target == null) { | 208 /** |
| 209 if (staticElement is FunctionElement) { | 209 * Return the semantics for [node]. |
| 210 if (staticElement.enclosingElement is CompilationUnitElement) { | 210 */ |
| 211 @override |
| 212 AccessSemantics visitMethodInvocation(MethodInvocation node) { |
| 213 Expression target = node.realTarget; |
| 214 Element staticElement = node.methodName.staticElement; |
| 215 if (target == null) { |
| 216 if (staticElement is FunctionElement) { |
| 217 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 218 return new AccessSemantics.staticMethod( |
| 219 node.methodName, |
| 220 staticElement, |
| 221 null, |
| 222 isInvoke: true); |
| 223 } else { |
| 224 return new AccessSemantics.localFunction( |
| 225 node.methodName, |
| 226 staticElement, |
| 227 isInvoke: true); |
| 228 } |
| 229 } else if (staticElement is MethodElement && staticElement.isStatic) { |
| 211 return new AccessSemantics.staticMethod( | 230 return new AccessSemantics.staticMethod( |
| 212 node.methodName, | 231 node.methodName, |
| 213 staticElement, | 232 staticElement, |
| 214 null, | 233 staticElement.enclosingElement, |
| 215 isInvoke: true); | 234 isInvoke: true); |
| 216 } else { | 235 } else if (staticElement is PropertyAccessorElement) { |
| 217 return new AccessSemantics.localFunction( | 236 if (staticElement.isSynthetic) { |
| 237 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 238 return new AccessSemantics.staticField( |
| 239 node.methodName, |
| 240 staticElement.variable, |
| 241 null, |
| 242 isInvoke: true); |
| 243 } else if (staticElement.isStatic) { |
| 244 return new AccessSemantics.staticField( |
| 245 node.methodName, |
| 246 staticElement.variable, |
| 247 staticElement.enclosingElement, |
| 248 isInvoke: true); |
| 249 } |
| 250 } else { |
| 251 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 252 return new AccessSemantics.staticProperty( |
| 253 node.methodName, |
| 254 staticElement, |
| 255 null, |
| 256 isInvoke: true); |
| 257 } else if (staticElement.isStatic) { |
| 258 return new AccessSemantics.staticProperty( |
| 259 node.methodName, |
| 260 staticElement, |
| 261 staticElement.enclosingElement, |
| 262 isInvoke: true); |
| 263 } |
| 264 } |
| 265 } else if (staticElement is LocalVariableElement) { |
| 266 return new AccessSemantics.localVariable( |
| 218 node.methodName, | 267 node.methodName, |
| 219 staticElement, | 268 staticElement, |
| 220 isInvoke: true); | 269 isInvoke: true); |
| 221 } | 270 } else if (staticElement is ParameterElement) { |
| 222 } else if (staticElement is MethodElement && staticElement.isStatic) { | 271 return new AccessSemantics.parameter( |
| 223 return new AccessSemantics.staticMethod( | 272 node.methodName, |
| 224 node.methodName, | 273 staticElement, |
| 225 staticElement, | 274 isInvoke: true); |
| 226 staticElement.enclosingElement, | 275 } |
| 227 isInvoke: true); | 276 } else if (target is Identifier) { |
| 228 } else if (staticElement is PropertyAccessorElement) { | 277 Element targetStaticElement = target.staticElement; |
| 278 if (targetStaticElement is PrefixElement) { |
| 279 if (staticElement == null) { |
| 280 return new AccessSemantics.dynamic( |
| 281 node.methodName, |
| 282 null, |
| 283 isInvoke: true); |
| 284 } else if (staticElement is PropertyAccessorElement) { |
| 285 if (staticElement.isSynthetic) { |
| 286 return new AccessSemantics.staticField( |
| 287 node.methodName, |
| 288 staticElement.variable, |
| 289 null, |
| 290 isInvoke: true); |
| 291 } else { |
| 292 return new AccessSemantics.staticProperty( |
| 293 node.methodName, |
| 294 staticElement, |
| 295 null, |
| 296 isInvoke: true); |
| 297 } |
| 298 } else { |
| 299 return new AccessSemantics.staticMethod( |
| 300 node.methodName, |
| 301 staticElement, |
| 302 null, |
| 303 isInvoke: true); |
| 304 } |
| 305 } else if (targetStaticElement is ClassElement) { |
| 306 if (staticElement is PropertyAccessorElement) { |
| 307 if (staticElement.isSynthetic) { |
| 308 return new AccessSemantics.staticField( |
| 309 node.methodName, |
| 310 staticElement.variable, |
| 311 targetStaticElement, |
| 312 isInvoke: true); |
| 313 } else { |
| 314 return new AccessSemantics.staticProperty( |
| 315 node.methodName, |
| 316 staticElement, |
| 317 targetStaticElement, |
| 318 isInvoke: true); |
| 319 } |
| 320 } else { |
| 321 return new AccessSemantics.staticMethod( |
| 322 node.methodName, |
| 323 staticElement, |
| 324 targetStaticElement, |
| 325 isInvoke: true); |
| 326 } |
| 327 } |
| 328 } |
| 329 return new AccessSemantics.dynamic(node.methodName, target, isInvoke: true); |
| 330 } |
| 331 |
| 332 /** |
| 333 * Return the access semantics for [node]. |
| 334 */ |
| 335 @override |
| 336 AccessSemantics visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 337 return _classifyPrefixed(node.prefix, node.identifier); |
| 338 } |
| 339 |
| 340 /** |
| 341 * Helper function for classifying an expression of type |
| 342 * Identifier.SimpleIdentifier. |
| 343 */ |
| 344 AccessSemantics _classifyPrefixed(Identifier lhs, SimpleIdentifier rhs) { |
| 345 Element lhsElement = lhs.staticElement; |
| 346 Element rhsElement = rhs.staticElement; |
| 347 if (lhsElement is PrefixElement) { |
| 348 if (rhsElement is PropertyAccessorElement) { |
| 349 if (rhsElement.isSynthetic) { |
| 350 return new AccessSemantics.staticField(rhs, rhsElement.variable, null)
; |
| 351 } else { |
| 352 return new AccessSemantics.staticProperty(rhs, rhsElement, null); |
| 353 } |
| 354 } else if (rhsElement is FunctionElement) { |
| 355 return new AccessSemantics.staticMethod(rhs, rhsElement, null); |
| 356 } else { |
| 357 return new AccessSemantics.dynamic(rhs, null); |
| 358 } |
| 359 } else if (lhsElement is ClassElement) { |
| 360 if (rhsElement is PropertyAccessorElement && rhsElement.isSynthetic) { |
| 361 return new AccessSemantics.staticField( |
| 362 rhs, |
| 363 rhsElement.variable, |
| 364 lhsElement); |
| 365 } else if (rhsElement is MethodElement) { |
| 366 return new AccessSemantics.staticMethod(rhs, rhsElement, lhsElement); |
| 367 } else { |
| 368 return new AccessSemantics.staticProperty(rhs, rhsElement, lhsElement); |
| 369 } |
| 370 } else { |
| 371 return new AccessSemantics.dynamic(rhs, lhs); |
| 372 } |
| 373 } |
| 374 |
| 375 /** |
| 376 * Return the access semantics for [node]. |
| 377 */ |
| 378 @override |
| 379 AccessSemantics visitPropertyAccess(PropertyAccess node) { |
| 380 if (node.target is Identifier) { |
| 381 return _classifyPrefixed(node.target, node.propertyName); |
| 382 } else { |
| 383 return new AccessSemantics.dynamic(node.propertyName, node.realTarget); |
| 384 } |
| 385 } |
| 386 |
| 387 /** |
| 388 * Return the access semantics for [node]. |
| 389 * |
| 390 * Note: if [node] is the right hand side of a [PropertyAccess] or |
| 391 * [PrefixedIdentifier], or the method name of a [MethodInvocation], the retur
n |
| 392 * value is null, since the semantics are determined by the parent. In |
| 393 * practice these cases should never arise because the parent will visit the |
| 394 * parent node before visiting this one. |
| 395 */ |
| 396 @override |
| 397 AccessSemantics visitSimpleIdentifier(SimpleIdentifier node) { |
| 398 AstNode parent = node.parent; |
| 399 if (node.inDeclarationContext()) { |
| 400 // This identifier is a declaration, not a use. |
| 401 return null; |
| 402 } |
| 403 if (parent is TypeName) { |
| 404 // TODO(paulberry): handle this case. Or, perhaps it would be better to |
| 405 // require clients not to visit the children of a TypeName when visiting |
| 406 // the AST structure. |
| 407 // |
| 408 // TODO(paulberry): be sure to consider type literals, e.g.: |
| 409 // class A {} |
| 410 // var a = A; |
| 411 return null; |
| 412 } |
| 413 if ((parent is PropertyAccess && parent.propertyName == node) || |
| 414 (parent is PrefixedIdentifier && parent.identifier == node) || |
| 415 (parent is MethodInvocation && parent.methodName == node)) { |
| 416 // The access semantics are determined by the parent. |
| 417 return null; |
| 418 } |
| 419 // TODO(paulberry): handle PrefixElement. |
| 420 Element staticElement = node.staticElement; |
| 421 if (staticElement is PropertyAccessorElement) { |
| 229 if (staticElement.isSynthetic) { | 422 if (staticElement.isSynthetic) { |
| 230 if (staticElement.enclosingElement is CompilationUnitElement) { | 423 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 231 return new AccessSemantics.staticField( | 424 return new AccessSemantics.staticField( |
| 232 node.methodName, | 425 node, |
| 233 staticElement.variable, | 426 staticElement.variable, |
| 234 null, | 427 null); |
| 235 isInvoke: true); | |
| 236 } else if (staticElement.isStatic) { | 428 } else if (staticElement.isStatic) { |
| 237 return new AccessSemantics.staticField( | 429 return new AccessSemantics.staticField( |
| 238 node.methodName, | 430 node, |
| 239 staticElement.variable, | 431 staticElement.variable, |
| 240 staticElement.enclosingElement, | 432 staticElement.enclosingElement); |
| 241 isInvoke: true); | |
| 242 } | 433 } |
| 243 } else { | 434 } else { |
| 244 if (staticElement.enclosingElement is CompilationUnitElement) { | 435 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 245 return new AccessSemantics.staticProperty( | 436 return new AccessSemantics.staticProperty(node, staticElement, null); |
| 246 node.methodName, | |
| 247 staticElement, | |
| 248 null, | |
| 249 isInvoke: true); | |
| 250 } else if (staticElement.isStatic) { | 437 } else if (staticElement.isStatic) { |
| 251 return new AccessSemantics.staticProperty( | 438 return new AccessSemantics.staticProperty( |
| 252 node.methodName, | 439 node, |
| 253 staticElement, | 440 staticElement, |
| 254 staticElement.enclosingElement, | 441 staticElement.enclosingElement); |
| 255 isInvoke: true); | |
| 256 } | 442 } |
| 257 } | 443 } |
| 258 } else if (staticElement is LocalVariableElement) { | 444 } else if (staticElement is LocalVariableElement) { |
| 259 return new AccessSemantics.localVariable( | 445 return new AccessSemantics.localVariable(node, staticElement); |
| 260 node.methodName, | 446 } else if (staticElement is ParameterElement) { |
| 447 return new AccessSemantics.parameter(node, staticElement); |
| 448 } else if (staticElement is FunctionElement) { |
| 449 if (staticElement.enclosingElement is CompilationUnitElement) { |
| 450 return new AccessSemantics.staticMethod(node, staticElement, null); |
| 451 } else { |
| 452 return new AccessSemantics.localFunction(node, staticElement); |
| 453 } |
| 454 } else if (staticElement is MethodElement && staticElement.isStatic) { |
| 455 return new AccessSemantics.staticMethod( |
| 456 node, |
| 261 staticElement, | 457 staticElement, |
| 262 isInvoke: true); | 458 staticElement.enclosingElement); |
| 263 } else if (staticElement is ParameterElement) { | 459 } |
| 264 return new AccessSemantics.parameter( | 460 return new AccessSemantics.dynamic(node, null); |
| 265 node.methodName, | 461 } |
| 266 staticElement, | 462 } |
| 267 isInvoke: true); | |
| 268 } | |
| 269 } else if (target is Identifier) { | |
| 270 Element targetStaticElement = target.staticElement; | |
| 271 if (targetStaticElement is PrefixElement) { | |
| 272 if (staticElement == null) { | |
| 273 return new AccessSemantics.dynamic( | |
| 274 node.methodName, | |
| 275 null, | |
| 276 isInvoke: true); | |
| 277 } else if (staticElement is PropertyAccessorElement) { | |
| 278 if (staticElement.isSynthetic) { | |
| 279 return new AccessSemantics.staticField( | |
| 280 node.methodName, | |
| 281 staticElement.variable, | |
| 282 null, | |
| 283 isInvoke: true); | |
| 284 } else { | |
| 285 return new AccessSemantics.staticProperty( | |
| 286 node.methodName, | |
| 287 staticElement, | |
| 288 null, | |
| 289 isInvoke: true); | |
| 290 } | |
| 291 } else { | |
| 292 return new AccessSemantics.staticMethod( | |
| 293 node.methodName, | |
| 294 staticElement, | |
| 295 null, | |
| 296 isInvoke: true); | |
| 297 } | |
| 298 } else if (targetStaticElement is ClassElement) { | |
| 299 if (staticElement is PropertyAccessorElement) { | |
| 300 if (staticElement.isSynthetic) { | |
| 301 return new AccessSemantics.staticField( | |
| 302 node.methodName, | |
| 303 staticElement.variable, | |
| 304 targetStaticElement, | |
| 305 isInvoke: true); | |
| 306 } else { | |
| 307 return new AccessSemantics.staticProperty( | |
| 308 node.methodName, | |
| 309 staticElement, | |
| 310 targetStaticElement, | |
| 311 isInvoke: true); | |
| 312 } | |
| 313 } else { | |
| 314 return new AccessSemantics.staticMethod( | |
| 315 node.methodName, | |
| 316 staticElement, | |
| 317 targetStaticElement, | |
| 318 isInvoke: true); | |
| 319 } | |
| 320 } | |
| 321 } | |
| 322 return new AccessSemantics.dynamic(node.methodName, target, isInvoke: true); | |
| 323 } | |
| 324 | |
| 325 /** | |
| 326 * Return the access semantics for [node]. | |
| 327 */ | |
| 328 AccessSemantics classifyPrefixedIdentifier(PrefixedIdentifier node) { | |
| 329 return _classifyPrefixed(node.prefix, node.identifier); | |
| 330 } | |
| 331 | |
| 332 /** | |
| 333 * Helper function for classifying an expression of type | |
| 334 * Identifier.SimpleIdentifier. | |
| 335 */ | |
| 336 AccessSemantics _classifyPrefixed(Identifier lhs, SimpleIdentifier rhs) { | |
| 337 Element lhsElement = lhs.staticElement; | |
| 338 Element rhsElement = rhs.staticElement; | |
| 339 if (lhsElement is PrefixElement) { | |
| 340 if (rhsElement is PropertyAccessorElement) { | |
| 341 if (rhsElement.isSynthetic) { | |
| 342 return new AccessSemantics.staticField(rhs, rhsElement.variable, null); | |
| 343 } else { | |
| 344 return new AccessSemantics.staticProperty(rhs, rhsElement, null); | |
| 345 } | |
| 346 } else if (rhsElement is FunctionElement) { | |
| 347 return new AccessSemantics.staticMethod(rhs, rhsElement, null); | |
| 348 } else { | |
| 349 return new AccessSemantics.dynamic(rhs, null); | |
| 350 } | |
| 351 } else if (lhsElement is ClassElement) { | |
| 352 if (rhsElement is PropertyAccessorElement && rhsElement.isSynthetic) { | |
| 353 return new AccessSemantics.staticField( | |
| 354 rhs, | |
| 355 rhsElement.variable, | |
| 356 lhsElement); | |
| 357 } else if (rhsElement is MethodElement) { | |
| 358 return new AccessSemantics.staticMethod(rhs, rhsElement, lhsElement); | |
| 359 } else { | |
| 360 return new AccessSemantics.staticProperty(rhs, rhsElement, lhsElement); | |
| 361 } | |
| 362 } else { | |
| 363 return new AccessSemantics.dynamic(rhs, lhs); | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 /** | |
| 368 * Return the access semantics for [node]. | |
| 369 */ | |
| 370 AccessSemantics classifyPropertyAccess(PropertyAccess node) { | |
| 371 if (node.target is Identifier) { | |
| 372 return _classifyPrefixed(node.target, node.propertyName); | |
| 373 } else { | |
| 374 return new AccessSemantics.dynamic(node.propertyName, node.realTarget); | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 /** | |
| 379 * Return the access semantics for [node]. | |
| 380 * | |
| 381 * Note: if [node] is the right hand side of a [PropertyAccess] or | |
| 382 * [PrefixedIdentifier], or the method name of a [MethodInvocation], the return | |
| 383 * value is null, since the semantics are determined by the parent. In | |
| 384 * practice these cases should never arise because the parent will visit the | |
| 385 * parent node before visiting this one. | |
| 386 */ | |
| 387 AccessSemantics classifySimpleIdentifier(SimpleIdentifier node) { | |
| 388 AstNode parent = node.parent; | |
| 389 if (node.inDeclarationContext()) { | |
| 390 // This identifier is a declaration, not a use. | |
| 391 return null; | |
| 392 } | |
| 393 if (parent is TypeName) { | |
| 394 // TODO(paulberry): handle this case. Or, perhaps it would be better to | |
| 395 // require clients not to visit the children of a TypeName when visiting | |
| 396 // the AST structure. | |
| 397 // | |
| 398 // TODO(paulberry): be sure to consider type literals, e.g.: | |
| 399 // class A {} | |
| 400 // var a = A; | |
| 401 return null; | |
| 402 } | |
| 403 if ((parent is PropertyAccess && parent.propertyName == node) || | |
| 404 (parent is PrefixedIdentifier && parent.identifier == node) || | |
| 405 (parent is MethodInvocation && parent.methodName == node)) { | |
| 406 // The access semantics are determined by the parent. | |
| 407 return null; | |
| 408 } | |
| 409 // TODO(paulberry): handle PrefixElement. | |
| 410 Element staticElement = node.staticElement; | |
| 411 if (staticElement is PropertyAccessorElement) { | |
| 412 if (staticElement.isSynthetic) { | |
| 413 if (staticElement.enclosingElement is CompilationUnitElement) { | |
| 414 return new AccessSemantics.staticField( | |
| 415 node, | |
| 416 staticElement.variable, | |
| 417 null); | |
| 418 } else if (staticElement.isStatic) { | |
| 419 return new AccessSemantics.staticField( | |
| 420 node, | |
| 421 staticElement.variable, | |
| 422 staticElement.enclosingElement); | |
| 423 } | |
| 424 } else { | |
| 425 if (staticElement.enclosingElement is CompilationUnitElement) { | |
| 426 return new AccessSemantics.staticProperty(node, staticElement, null); | |
| 427 } else if (staticElement.isStatic) { | |
| 428 return new AccessSemantics.staticProperty( | |
| 429 node, | |
| 430 staticElement, | |
| 431 staticElement.enclosingElement); | |
| 432 } | |
| 433 } | |
| 434 } else if (staticElement is LocalVariableElement) { | |
| 435 return new AccessSemantics.localVariable(node, staticElement); | |
| 436 } else if (staticElement is ParameterElement) { | |
| 437 return new AccessSemantics.parameter(node, staticElement); | |
| 438 } else if (staticElement is FunctionElement) { | |
| 439 if (staticElement.enclosingElement is CompilationUnitElement) { | |
| 440 return new AccessSemantics.staticMethod(node, staticElement, null); | |
| 441 } else { | |
| 442 return new AccessSemantics.localFunction(node, staticElement); | |
| 443 } | |
| 444 } else if (staticElement is MethodElement && staticElement.isStatic) { | |
| 445 return new AccessSemantics.staticMethod( | |
| 446 node, | |
| 447 staticElement, | |
| 448 staticElement.enclosingElement); | |
| 449 } | |
| 450 return new AccessSemantics.dynamic(node, null); | |
| 451 } | |
| OLD | NEW |