| 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 // This code was auto-generated, is not intended to be edited, and is subject to | 5 // This code was auto-generated, is not intended to be edited, and is subject to |
| 6 // significant change. Please see the README file for more information. | 6 // significant change. Please see the README file for more information. |
| 7 | 7 |
| 8 library engine.constant; | 8 library engine.constant; |
| 9 | 9 |
| 10 import 'java_core.dart'; | 10 import 'java_core.dart'; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 * | 105 * |
| 106 * @return `true` if this object represents a boolean value | 106 * @return `true` if this object represents a boolean value |
| 107 */ | 107 */ |
| 108 @override | 108 @override |
| 109 bool get isBool => true; | 109 bool get isBool => true; |
| 110 | 110 |
| 111 @override | 111 @override |
| 112 bool get isBoolNumStringOrNull => true; | 112 bool get isBoolNumStringOrNull => true; |
| 113 | 113 |
| 114 @override | 114 @override |
| 115 bool get isUnknown => value == null; |
| 116 |
| 117 @override |
| 115 BoolState logicalAnd(InstanceState rightOperand) { | 118 BoolState logicalAnd(InstanceState rightOperand) { |
| 116 assertBool(rightOperand); | 119 assertBool(rightOperand); |
| 117 if (value == null) { | 120 if (value == null) { |
| 118 return UNKNOWN_VALUE; | 121 return UNKNOWN_VALUE; |
| 119 } | 122 } |
| 120 return value ? rightOperand.convertToBool() : FALSE_STATE; | 123 return value ? rightOperand.convertToBool() : FALSE_STATE; |
| 121 } | 124 } |
| 122 | 125 |
| 123 @override | 126 @override |
| 124 BoolState logicalNot() { | 127 BoolState logicalNot() { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 | 200 |
| 198 /** | 201 /** |
| 199 * Initialize a newly created evaluator to evaluate expressions in the given s
ource. | 202 * Initialize a newly created evaluator to evaluate expressions in the given s
ource. |
| 200 * | 203 * |
| 201 * @param source the source containing the expression(s) that will be evaluate
d | 204 * @param source the source containing the expression(s) that will be evaluate
d |
| 202 * @param typeProvider the type provider used to access known types | 205 * @param typeProvider the type provider used to access known types |
| 203 */ | 206 */ |
| 204 ConstantEvaluator(this._source, this._typeProvider); | 207 ConstantEvaluator(this._source, this._typeProvider); |
| 205 | 208 |
| 206 EvaluationResult evaluate(Expression expression) { | 209 EvaluationResult evaluate(Expression expression) { |
| 207 EvaluationResultImpl result = expression.accept(new ConstantVisitor(_typePro
vider)); | 210 EvaluationResultImpl result = expression.accept(new ConstantVisitor.con1(_ty
peProvider)); |
| 208 if (result is ValidResult) { | 211 if (result is ValidResult) { |
| 209 return EvaluationResult.forValue(result.value); | 212 return EvaluationResult.forValue(result.value); |
| 210 } | 213 } |
| 211 List<AnalysisError> errors = new List<AnalysisError>(); | 214 List<AnalysisError> errors = new List<AnalysisError>(); |
| 212 for (ErrorResult_ErrorData data in (result as ErrorResult).errorData) { | 215 for (ErrorResult_ErrorData data in (result as ErrorResult).errorData) { |
| 213 AstNode node = data.node; | 216 AstNode node = data.node; |
| 214 errors.add(new AnalysisError.con2(_source, node.offset, node.length, data.
errorCode, [])); | 217 errors.add(new AnalysisError.con2(_source, node.offset, node.length, data.
errorCode, [])); |
| 215 } | 218 } |
| 216 return EvaluationResult.forErrors(new List.from(errors)); | 219 return EvaluationResult.forErrors(new List.from(errors)); |
| 217 } | 220 } |
| 218 } | 221 } |
| 219 | 222 |
| 220 /** | 223 /** |
| 221 * Instances of the class `ConstantFinder` are used to traverse the AST structur
es of all of | 224 * Instances of the class `ConstantFinder` are used to traverse the AST structur
es of all of |
| 222 * the compilation units being resolved and build a table mapping constant varia
ble elements to the | 225 * the compilation units being resolved and build a table mapping constant varia
ble elements to the |
| 223 * declarations of those variables. | 226 * declarations of those variables. |
| 224 */ | 227 */ |
| 225 class ConstantFinder extends RecursiveAstVisitor<Object> { | 228 class ConstantFinder extends RecursiveAstVisitor<Object> { |
| 226 /** | 229 /** |
| 227 * A table mapping constant variable elements to the declarations of those var
iables. | 230 * A table mapping constant variable elements to the declarations of those var
iables. |
| 228 */ | 231 */ |
| 229 final Map<VariableElement, VariableDeclaration> variableMap = new Map<Variable
Element, VariableDeclaration>(); | 232 final Map<VariableElement, VariableDeclaration> variableMap = new Map<Variable
Element, VariableDeclaration>(); |
| 230 | 233 |
| 234 /** |
| 235 * A table mapping constant constructors to the declarations of those construc
tors. |
| 236 */ |
| 237 final Map<ConstructorElement, ConstructorDeclaration> constructorMap = new Map
<ConstructorElement, ConstructorDeclaration>(); |
| 238 |
| 239 /** |
| 240 * A collection of constant constructor invocations. |
| 241 */ |
| 242 final List<InstanceCreationExpression> constructorInvocations = new List<Insta
nceCreationExpression>(); |
| 243 |
| 244 @override |
| 245 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 246 super.visitConstructorDeclaration(node); |
| 247 if (node.constKeyword != null) { |
| 248 ConstructorElement element = node.element; |
| 249 if (element != null) { |
| 250 constructorMap[element] = node; |
| 251 } |
| 252 } |
| 253 return null; |
| 254 } |
| 255 |
| 256 @override |
| 257 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 258 super.visitInstanceCreationExpression(node); |
| 259 if (node.isConst) { |
| 260 constructorInvocations.add(node); |
| 261 } |
| 262 return null; |
| 263 } |
| 264 |
| 231 @override | 265 @override |
| 232 Object visitVariableDeclaration(VariableDeclaration node) { | 266 Object visitVariableDeclaration(VariableDeclaration node) { |
| 233 super.visitVariableDeclaration(node); | 267 super.visitVariableDeclaration(node); |
| 234 Expression initializer = node.initializer; | 268 Expression initializer = node.initializer; |
| 235 if (initializer != null && node.isConst) { | 269 if (initializer != null && node.isConst) { |
| 236 VariableElement element = node.element; | 270 VariableElement element = node.element; |
| 237 if (element != null) { | 271 if (element != null) { |
| 238 variableMap[element] = node; | 272 variableMap[element] = node; |
| 239 } | 273 } |
| 240 } | 274 } |
| 241 return null; | 275 return null; |
| 242 } | 276 } |
| 243 } | 277 } |
| 244 | 278 |
| 245 /** | 279 /** |
| 246 * Instances of the class `ConstantValueComputer` compute the values of constant
variables in | 280 * Instances of the class `ConstantValueComputer` compute the values of constant
variables and |
| 247 * one or more compilation units. The expected usage pattern is for the compilat
ion units to be | 281 * constant constructor invocations in one or more compilation units. The expect
ed usage pattern is |
| 248 * added to this computer using the method [add] and then for the method | 282 * for the compilation units to be added to this computer using the method |
| 249 * [computeValues] to be invoked exactly once. Any use of an instance after invo
king the | 283 * [add] and then for the method [computeValues] to be invoked |
| 250 * method [computeValues] will result in unpredictable behavior. | 284 * exactly once. Any use of an instance after invoking the method [computeValues
] will |
| 285 * result in unpredictable behavior. |
| 251 */ | 286 */ |
| 252 class ConstantValueComputer { | 287 class ConstantValueComputer { |
| 253 /** | 288 /** |
| 254 * The type provider used to access the known types. | 289 * The type provider used to access the known types. |
| 255 */ | 290 */ |
| 256 final TypeProvider _typeProvider; | 291 TypeProvider typeProvider; |
| 257 | 292 |
| 258 /** | 293 /** |
| 259 * The object used to find constant variables in the compilation units that we
re added. | 294 * The object used to find constant variables and constant constructor invocat
ions in the |
| 295 * compilation units that were added. |
| 260 */ | 296 */ |
| 261 ConstantFinder _constantFinder = new ConstantFinder(); | 297 ConstantFinder _constantFinder = new ConstantFinder(); |
| 262 | 298 |
| 263 /** | 299 /** |
| 264 * A graph in which the nodes are the constant variables and the edges are fro
m each variable to | 300 * A graph in which the nodes are the constants, and the edges are from each c
onstant to the other |
| 265 * the other constant variables that are referenced in the head's initializer. | 301 * constants that are referenced by it. |
| 266 */ | 302 */ |
| 267 DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableEle
ment>(); | 303 DirectedGraph<AstNode> referenceGraph = new DirectedGraph<AstNode>(); |
| 268 | 304 |
| 269 /** | 305 /** |
| 270 * A table mapping constant variables to the declarations of those variables. | 306 * A table mapping constant variables to the declarations of those variables. |
| 271 */ | 307 */ |
| 272 Map<VariableElement, VariableDeclaration> _declarationMap; | 308 Map<VariableElement, VariableDeclaration> _variableDeclarationMap; |
| 309 |
| 310 /** |
| 311 * A table mapping constant constructors to the declarations of those construc
tors. |
| 312 */ |
| 313 Map<ConstructorElement, ConstructorDeclaration> constructorDeclarationMap; |
| 314 |
| 315 /** |
| 316 * A collection of constant constructor invocations. |
| 317 */ |
| 318 List<InstanceCreationExpression> _constructorInvocations; |
| 273 | 319 |
| 274 /** | 320 /** |
| 275 * Initialize a newly created constant value computer. | 321 * Initialize a newly created constant value computer. |
| 276 * | 322 * |
| 277 * @param typeProvider the type provider used to access known types | 323 * @param typeProvider the type provider used to access known types |
| 278 */ | 324 */ |
| 279 ConstantValueComputer(this._typeProvider); | 325 ConstantValueComputer(TypeProvider typeProvider) { |
| 280 | 326 this.typeProvider = typeProvider; |
| 281 /** | 327 } |
| 282 * Add the constant variables in the given compilation unit to the list of con
stant variables | 328 |
| 283 * whose value needs to be computed. | 329 /** |
| 330 * Add the constants in the given compilation unit to the list of constants wh
ose value needs to |
| 331 * be computed. |
| 284 * | 332 * |
| 285 * @param unit the compilation unit defining the constant variables to be adde
d | 333 * @param unit the compilation unit defining the constants to be added |
| 286 */ | 334 */ |
| 287 void add(CompilationUnit unit) { | 335 void add(CompilationUnit unit) { |
| 288 unit.accept(_constantFinder); | 336 unit.accept(_constantFinder); |
| 289 } | 337 } |
| 290 | 338 |
| 291 /** | 339 /** |
| 292 * Compute values for all of the constant variables in the compilation units t
hat were added. | 340 * Compute values for all of the constants in the compilation units that were
added. |
| 293 */ | 341 */ |
| 294 void computeValues() { | 342 void computeValues() { |
| 295 _declarationMap = _constantFinder.variableMap; | 343 _variableDeclarationMap = _constantFinder.variableMap; |
| 296 for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(
_declarationMap)) { | 344 constructorDeclarationMap = _constantFinder.constructorMap; |
| 297 VariableElement element = entry.getKey(); | 345 _constructorInvocations = _constantFinder.constructorInvocations; |
| 298 ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceG
raph); | 346 for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(
_variableDeclarationMap)) { |
| 299 _referenceGraph.addNode(element); | 347 VariableDeclaration declaration = entry.getValue(); |
| 300 entry.getValue().initializer.accept(referenceFinder); | 348 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, referen
ceGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 301 } | 349 referenceGraph.addNode(declaration); |
| 302 while (!_referenceGraph.isEmpty) { | 350 declaration.initializer.accept(referenceFinder); |
| 303 VariableElement element = _referenceGraph.removeSink(); | 351 } |
| 304 while (element != null) { | 352 for (MapEntry<ConstructorElement, ConstructorDeclaration> entry in getMapEnt
rySet(constructorDeclarationMap)) { |
| 305 _computeValueFor(element); | 353 ConstructorDeclaration declaration = entry.getValue(); |
| 306 element = _referenceGraph.removeSink(); | 354 ReferenceFinder referenceFinder = new ReferenceFinder(declaration, referen
ceGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 307 } | 355 referenceGraph.addNode(declaration); |
| 308 if (!_referenceGraph.isEmpty) { | 356 bool superInvocationFound = false; |
| 309 List<VariableElement> variablesInCycle = _referenceGraph.findCycle(); | 357 NodeList<ConstructorInitializer> initializers = declaration.initializers; |
| 310 if (variablesInCycle == null) { | 358 for (ConstructorInitializer initializer in initializers) { |
| 311 // | 359 if (initializer is SuperConstructorInvocation) { |
| 312 // This should not happen. Either the graph should be empty, or there
should be at least | 360 superInvocationFound = true; |
| 313 // one sink, or there should be a cycle. If this does happen we exit t
o prevent an | 361 } |
| 314 // infinite loop. | 362 initializer.accept(referenceFinder); |
| 315 // | 363 } |
| 316 AnalysisEngine.instance.logger.logError("Exiting constant value comput
er with ${_referenceGraph.nodeCount} variables that are neither sinks nor in a c
ycle"); | 364 if (!superInvocationFound) { |
| 317 return; | 365 // No explicit superconstructor invocation found, so we need to manually
insert |
| 318 } | 366 // a reference to the implicit superconstructor. |
| 319 for (VariableElement variable in variablesInCycle) { | 367 InterfaceType superclass = (entry.getKey().returnType as InterfaceType).
superclass; |
| 320 _generateCycleError(variablesInCycle, variable); | 368 if (superclass != null && !superclass.isObject) { |
| 321 } | 369 ConstructorElement unnamedConstructor = superclass.element.unnamedCons
tructor; |
| 322 _referenceGraph.removeAllNodes(variablesInCycle); | 370 ConstructorDeclaration superConstructorDeclaration = findConstructorDe
claration(unnamedConstructor); |
| 323 } | 371 if (superConstructorDeclaration != null) { |
| 324 } | 372 referenceGraph.addEdge(declaration, superConstructorDeclaration); |
| 325 } | 373 } |
| 326 | 374 } |
| 327 /** | 375 } |
| 328 * Compute a value for the given variable. | 376 for (FormalParameter parameter in declaration.parameters.parameters) { |
| 377 referenceGraph.addNode(parameter); |
| 378 referenceGraph.addEdge(declaration, parameter); |
| 379 if (parameter is DefaultFormalParameter) { |
| 380 Expression defaultValue = parameter.defaultValue; |
| 381 if (defaultValue != null) { |
| 382 ReferenceFinder parameterReferenceFinder = new ReferenceFinder(param
eter, referenceGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 383 defaultValue.accept(parameterReferenceFinder); |
| 384 } |
| 385 } |
| 386 } |
| 387 } |
| 388 for (InstanceCreationExpression expression in _constructorInvocations) { |
| 389 referenceGraph.addNode(expression); |
| 390 ConstructorElement constructor = expression.staticElement; |
| 391 if (constructor == null) { |
| 392 break; |
| 393 } |
| 394 constructor = _followConstantRedirectionChain(constructor); |
| 395 ConstructorDeclaration declaration = findConstructorDeclaration(constructo
r); |
| 396 // An instance creation expression depends both on the constructor and the
arguments passed |
| 397 // to it. |
| 398 ReferenceFinder referenceFinder = new ReferenceFinder(expression, referenc
eGraph, _variableDeclarationMap, constructorDeclarationMap); |
| 399 if (declaration != null) { |
| 400 referenceGraph.addEdge(expression, declaration); |
| 401 } |
| 402 expression.argumentList.accept(referenceFinder); |
| 403 } |
| 404 List<List<AstNode>> topologicalSort = referenceGraph.computeTopologicalSort(
); |
| 405 for (List<AstNode> constantsInCycle in topologicalSort) { |
| 406 if (constantsInCycle.length == 1) { |
| 407 _computeValueFor(constantsInCycle[0]); |
| 408 } else { |
| 409 for (AstNode constant in constantsInCycle) { |
| 410 _generateCycleError(constantsInCycle, constant); |
| 411 } |
| 412 } |
| 413 } |
| 414 } |
| 415 |
| 416 /** |
| 417 * This method is called just before computing the constant value associated w
ith an AST node. |
| 418 * Unit tests will override this method to introduce additional error checking
. |
| 419 */ |
| 420 void beforeComputeValue(AstNode constNode) { |
| 421 } |
| 422 |
| 423 /** |
| 424 * This method is called just before getting the constant initializers associa
ted with a |
| 425 * constructor AST node. Unit tests will override this method to introduce add
itional error |
| 426 * checking. |
| 427 */ |
| 428 void beforeGetConstantInitializers(ConstructorElement constructor) { |
| 429 } |
| 430 |
| 431 /** |
| 432 * This method is called just before getting a parameter's default value. Unit
tests will override |
| 433 * this method to introduce additional error checking. |
| 434 */ |
| 435 void beforeGetParameterDefault(ParameterElement parameter) { |
| 436 } |
| 437 |
| 438 /** |
| 439 * Create the ConstantVisitor used to evaluate constants. Unit tests will over
ride this method to |
| 440 * introduce additional error checking. |
| 441 */ |
| 442 ConstantVisitor createConstantVisitor() => new ConstantVisitor.con1(typeProvid
er); |
| 443 |
| 444 ConstructorDeclaration findConstructorDeclaration(ConstructorElement construct
or) => constructorDeclarationMap[_getConstructorBase(constructor)]; |
| 445 |
| 446 /** |
| 447 * Compute a value for the given constant. |
| 329 * | 448 * |
| 330 * @param variable the variable for which a value is to be computed | 449 * @param constNode the constant for which a value is to be computed |
| 331 */ | 450 */ |
| 332 void _computeValueFor(VariableElement variable) { | 451 void _computeValueFor(AstNode constNode) { |
| 333 VariableDeclaration declaration = _declarationMap[variable]; | 452 beforeComputeValue(constNode); |
| 334 if (declaration == null) { | 453 if (constNode is VariableDeclaration) { |
| 335 // | 454 VariableDeclaration declaration = constNode; |
| 336 // The declaration will be null when the variable was added to the graph a
s a result of being | 455 Element element = declaration.element; |
| 337 // referenced by another variable but is not defined in the compilation un
its that were added | 456 EvaluationResultImpl result = declaration.initializer.accept(createConstan
tVisitor()); |
| 338 // to this computer. In such cases, the variable should already have a val
ue associated with | 457 (element as VariableElementImpl).evaluationResult = result; |
| 339 // it, but we don't bother to check because there's nothing we can do abou
t it at this point. | 458 } else if (constNode is InstanceCreationExpression) { |
| 340 // | 459 InstanceCreationExpression expression = constNode; |
| 460 ConstructorElement constructor = expression.staticElement; |
| 461 if (constructor == null) { |
| 462 // Couldn't resolve the constructor so we can't compute a value. No pro
blem--the error |
| 463 // has already been reported. |
| 464 return; |
| 465 } |
| 466 ConstantVisitor constantVisitor = createConstantVisitor(); |
| 467 ValidResult result = _evaluateConstructorCall(expression.argumentList.argu
ments, constructor, constantVisitor); |
| 468 expression.evaluationResult = result; |
| 469 } else if (constNode is ConstructorDeclaration) { |
| 470 ConstructorDeclaration declaration = constNode; |
| 471 NodeList<ConstructorInitializer> initializers = declaration.initializers; |
| 472 ConstructorElementImpl constructor = declaration.element as ConstructorEle
mentImpl; |
| 473 constructor.constantInitializers = new ConstantValueComputer_InitializerCl
oner().cloneNodeList(initializers); |
| 474 } else if (constNode is FormalParameter) { |
| 475 if (constNode is DefaultFormalParameter) { |
| 476 DefaultFormalParameter parameter = constNode; |
| 477 ParameterElement element = parameter.element; |
| 478 Expression defaultValue = parameter.defaultValue; |
| 479 if (defaultValue != null) { |
| 480 EvaluationResultImpl result = defaultValue.accept(createConstantVisito
r()); |
| 481 (element as ParameterElementImpl).evaluationResult = result; |
| 482 } |
| 483 } |
| 484 } else { |
| 485 // Should not happen. |
| 486 AnalysisEngine.instance.logger.logError("Constant value computer trying to
compute the value of a node which is not a VariableDeclaration, InstanceCreatio
nExpression, FormalParameter, or ConstructorDeclaration"); |
| 341 return; | 487 return; |
| 342 } | 488 } |
| 343 EvaluationResultImpl result = declaration.initializer.accept(new ConstantVis
itor(_typeProvider)); | 489 } |
| 344 (variable as VariableElementImpl).evaluationResult = result; | 490 |
| 345 if (result is ErrorResult) { | 491 ValidResult _evaluateConstructorCall(NodeList<Expression> arguments, Construct
orElement constructor, ConstantVisitor constantVisitor) { |
| 346 List<AnalysisError> errors = new List<AnalysisError>(); | 492 int argumentCount = arguments.length; |
| 347 for (ErrorResult_ErrorData data in result.errorData) { | 493 List<DartObjectImpl> argumentValues = new List<DartObjectImpl>(argumentCount
); |
| 348 AstNode node = data.node; | 494 Map<String, DartObjectImpl> namedArgumentValues = new Map<String, DartObject
Impl>(); |
| 349 Source source = variable.getAncestor((element) => element is Compilation
UnitElement).source; | 495 for (int i = 0; i < argumentCount; i++) { |
| 350 errors.add(new AnalysisError.con2(source, node.offset, node.length, data
.errorCode, [])); | 496 Expression argument = arguments[i]; |
| 351 } | 497 if (argument is NamedExpression) { |
| 352 } | 498 NamedExpression namedExpression = argument; |
| 353 } | 499 String name = namedExpression.name.label.name; |
| 354 | 500 namedArgumentValues[name] = constantVisitor._valueOf(namedExpression.exp
ression); |
| 355 /** | 501 argumentValues[i] = constantVisitor.null2; |
| 356 * Generate an error indicating that the given variable is not a valid compile
-time constant | 502 } else { |
| 357 * because it references at least one of the variables in the given cycle, eac
h of which directly | 503 argumentValues[i] = constantVisitor._valueOf(argument); |
| 358 * or indirectly references the variable. | 504 } |
| 505 } |
| 506 constructor = _followConstantRedirectionChain(constructor); |
| 507 InterfaceType definingClass = constructor.returnType as InterfaceType; |
| 508 if (constructor.isFactory) { |
| 509 // We couldn't find a non-factory constructor. See if it's because we rea
ched an external |
| 510 // const factory constructor that we can emulate. |
| 511 // TODO(paulberry): if the constructor is one of {bool,int,String}.fromEnv
ironment(), |
| 512 // we may be able to infer the value based on -D flags provided to the ana
lyzer (see |
| 513 // dartbug.com/17234). |
| 514 if (identical(definingClass, typeProvider.symbolType) && argumentCount ==
1) { |
| 515 String argumentValue = argumentValues[0].stringValue; |
| 516 if (argumentValue != null) { |
| 517 return constantVisitor._valid(definingClass, new SymbolState(argumentV
alue)); |
| 518 } |
| 519 } |
| 520 // Either it's an external const factory constructor that we can't emulate
, or an error |
| 521 // occurred (a cycle, or a const constructor trying to delegate to a non-c
onst constructor). |
| 522 // In the former case, the best we can do is consider it an unknown value.
In the latter |
| 523 // case, the error has already been reported, so considering it an unknown
value will |
| 524 // suppress further errors. |
| 525 return constantVisitor._validWithUnknownValue(definingClass); |
| 526 } |
| 527 beforeGetConstantInitializers(constructor); |
| 528 ConstructorElementImpl constructorBase = _getConstructorBase(constructor) as
ConstructorElementImpl; |
| 529 List<ConstructorInitializer> initializers = constructorBase.constantInitiali
zers; |
| 530 if (initializers == null) { |
| 531 // This can happen in some cases where there are compile errors in the cod
e being analyzed |
| 532 // (for example if the code is trying to create a const instance using a n
on-const |
| 533 // constructor, or the node we're visiting is involved in a cycle). The e
rror has already |
| 534 // been reported, so consider it an unknown value to suppress further erro
rs. |
| 535 return constantVisitor._validWithUnknownValue(definingClass); |
| 536 } |
| 537 Map<String, DartObjectImpl> fieldMap = new Map<String, DartObjectImpl>(); |
| 538 Map<String, DartObjectImpl> parameterMap = new Map<String, DartObjectImpl>()
; |
| 539 List<ParameterElement> parameters = constructorBase.parameters; |
| 540 int parameterCount = parameters.length; |
| 541 for (int i = 0; i < parameterCount; i++) { |
| 542 ParameterElement parameter = parameters[i]; |
| 543 while (parameter is ParameterMember) { |
| 544 parameter = (parameter as ParameterMember).baseElement; |
| 545 } |
| 546 DartObjectImpl argumentValue = null; |
| 547 if (parameter.parameterKind == ParameterKind.NAMED) { |
| 548 argumentValue = namedArgumentValues[parameter.name]; |
| 549 } else if (i < argumentCount) { |
| 550 argumentValue = argumentValues[i]; |
| 551 } |
| 552 if (argumentValue == null && parameter is ParameterElementImpl) { |
| 553 // The parameter is an optional positional parameter for which no value
was provided, so |
| 554 // use the default value. |
| 555 beforeGetParameterDefault(parameter); |
| 556 EvaluationResultImpl evaluationResult = (parameter as ParameterElementIm
pl).evaluationResult; |
| 557 if (evaluationResult is ValidResult) { |
| 558 argumentValue = evaluationResult.value; |
| 559 } else if (evaluationResult == null) { |
| 560 // No default was provided, so the default value is null. |
| 561 argumentValue = constantVisitor.null2; |
| 562 } |
| 563 } |
| 564 if (argumentValue != null) { |
| 565 if (parameter.isInitializingFormal) { |
| 566 FieldElement field = (parameter as FieldFormalParameterElement).field; |
| 567 if (field != null) { |
| 568 String fieldName = field.name; |
| 569 fieldMap[fieldName] = argumentValue; |
| 570 } |
| 571 } else { |
| 572 String name = parameter.name; |
| 573 parameterMap[name] = argumentValue; |
| 574 } |
| 575 } |
| 576 } |
| 577 ConstantVisitor initializerVisitor = new ConstantVisitor.con2(typeProvider,
parameterMap); |
| 578 String superName = null; |
| 579 NodeList<Expression> superArguments = null; |
| 580 for (ConstructorInitializer initializer in initializers) { |
| 581 if (initializer is ConstructorFieldInitializer) { |
| 582 ConstructorFieldInitializer constructorFieldInitializer = initializer; |
| 583 Expression initializerExpression = constructorFieldInitializer.expressio
n; |
| 584 EvaluationResultImpl evaluationResult = initializerExpression.accept(ini
tializerVisitor); |
| 585 if (evaluationResult is ValidResult) { |
| 586 DartObjectImpl value = evaluationResult.value; |
| 587 String fieldName = constructorFieldInitializer.fieldName.name; |
| 588 fieldMap[fieldName] = value; |
| 589 } |
| 590 } else if (initializer is SuperConstructorInvocation) { |
| 591 SuperConstructorInvocation superConstructorInvocation = initializer; |
| 592 SimpleIdentifier name = superConstructorInvocation.constructorName; |
| 593 if (name != null) { |
| 594 superName = name.name; |
| 595 } |
| 596 superArguments = superConstructorInvocation.argumentList.arguments; |
| 597 } |
| 598 } |
| 599 // Evaluate explicit or implicit call to super(). |
| 600 InterfaceType superclass = definingClass.superclass; |
| 601 if (superclass != null && !superclass.isObject) { |
| 602 ConstructorElement superConstructor = superclass.lookUpConstructor(superNa
me, constructor.library); |
| 603 if (superConstructor != null) { |
| 604 if (superArguments == null) { |
| 605 superArguments = new NodeList<Expression>(null); |
| 606 } |
| 607 _evaluateSuperConstructorCall(fieldMap, superConstructor, superArguments
, initializerVisitor); |
| 608 } |
| 609 } |
| 610 return constantVisitor._valid(definingClass, new GenericState(fieldMap)); |
| 611 } |
| 612 |
| 613 void _evaluateSuperConstructorCall(Map<String, DartObjectImpl> fieldMap, Const
ructorElement superConstructor, NodeList<Expression> superArguments, ConstantVis
itor initializerVisitor) { |
| 614 if (superConstructor != null && superConstructor.isConst) { |
| 615 ValidResult evaluationResult = _evaluateConstructorCall(superArguments, su
perConstructor, initializerVisitor); |
| 616 fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult.value; |
| 617 } |
| 618 } |
| 619 |
| 620 /** |
| 621 * Attempt to follow the chain of factory redirections until a constructor is
reached which is not |
| 622 * a const factory constructor. |
| 359 * | 623 * |
| 360 * @param variablesInCycle the variables in the cycle that includes the given
variable | 624 * @return the constant constructor which terminates the chain of factory redi
rections, if the |
| 361 * @param variable the variable that is not a valid compile-time constant | 625 * chain terminates. If there is a problem (e.g. a redirection can't b
e found, or a cycle |
| 362 */ | 626 * is encountered), the chain will be followed as far as possible and
then a const factory |
| 363 void _generateCycleError(List<VariableElement> variablesInCycle, VariableEleme
nt variable) { | 627 * constructor will be returned. |
| 628 */ |
| 629 ConstructorElement _followConstantRedirectionChain(ConstructorElement construc
tor) { |
| 630 Set<ConstructorElement> constructorsVisited = new Set<ConstructorElement>(); |
| 631 while (constructor.isFactory) { |
| 632 if (identical(constructor.enclosingElement.type, typeProvider.symbolType))
{ |
| 633 // The dart:core.Symbol has a const factory constructor that redirects t
o |
| 634 // dart:_internal.Symbol. That in turn redirects to an external const c
onstructor, which |
| 635 // we won't be able to evaluate. So stop following the chain of redirec
tions at |
| 636 // dart:core.Symbol, and let [evaluateInstanceCreationExpression] handle
it specially. |
| 637 break; |
| 638 } |
| 639 constructorsVisited.add(constructor); |
| 640 ConstructorElement redirectedConstructor = constructor.redirectedConstruct
or; |
| 641 if (redirectedConstructor == null) { |
| 642 // This can happen if constructor is an external factory constructor. |
| 643 break; |
| 644 } |
| 645 if (!redirectedConstructor.isConst) { |
| 646 // Delegating to a non-const constructor--this is not allowed (and |
| 647 // is checked elsewhere--see [ErrorVerifier.checkForRedirectToNonConstCo
nstructor()]). |
| 648 break; |
| 649 } |
| 650 if (constructorsVisited.contains(redirectedConstructor)) { |
| 651 // Cycle in redirecting factory constructors--this is not allowed |
| 652 // and is checked elsewhere--see [ErrorVerifier.checkForRecursiveFactory
Redirect()]). |
| 653 break; |
| 654 } |
| 655 constructor = redirectedConstructor; |
| 656 } |
| 657 return constructor; |
| 658 } |
| 659 |
| 660 /** |
| 661 * Generate an error indicating that the given constant is not a valid compile
-time constant |
| 662 * because it references at least one of the constants in the given cycle, eac
h of which directly |
| 663 * or indirectly references the constant. |
| 664 * |
| 665 * @param constantsInCycle the constants in the cycle that includes the given
constant |
| 666 * @param constant the constant that is not a valid compile-time constant |
| 667 */ |
| 668 void _generateCycleError(List<AstNode> constantsInCycle, AstNode constant) { |
| 669 } |
| 670 |
| 671 ConstructorElement _getConstructorBase(ConstructorElement constructor) { |
| 672 while (constructor is ConstructorMember) { |
| 673 constructor = (constructor as ConstructorMember).baseElement; |
| 674 } |
| 675 return constructor; |
| 364 } | 676 } |
| 365 } | 677 } |
| 366 | 678 |
| 679 /** |
| 680 * [AstCloner] that copies the necessary information from the AST to allow const
constructor |
| 681 * initializers to be evaluated. |
| 682 */ |
| 683 class ConstantValueComputer_InitializerCloner extends AstCloner { |
| 684 @override |
| 685 InstanceCreationExpression visitInstanceCreationExpression(InstanceCreationExp
ression node) { |
| 686 // All we need is the evaluation result, and the keyword so that we know whe
ther it's const. |
| 687 InstanceCreationExpression expression = new InstanceCreationExpression(node.
keyword, null, null); |
| 688 expression.evaluationResult = node.evaluationResult; |
| 689 return expression; |
| 690 } |
| 691 |
| 692 @override |
| 693 SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) { |
| 694 SimpleIdentifier identifier = super.visitSimpleIdentifier(node); |
| 695 identifier.staticElement = node.staticElement; |
| 696 return identifier; |
| 697 } |
| 698 |
| 699 @override |
| 700 SuperConstructorInvocation visitSuperConstructorInvocation(SuperConstructorInv
ocation node) { |
| 701 SuperConstructorInvocation invocation = super.visitSuperConstructorInvocatio
n(node); |
| 702 invocation.staticElement = node.staticElement; |
| 703 return invocation; |
| 704 } |
| 705 } |
| 706 |
| 367 /** | 707 /** |
| 368 * Instances of the class `ConstantVisitor` evaluate constant expressions to pro
duce their | 708 * Instances of the class `ConstantVisitor` evaluate constant expressions to pro
duce their |
| 369 * compile-time value. According to the Dart Language Specification: <blockquote
> A constant | 709 * compile-time value. According to the Dart Language Specification: <blockquote
> A constant |
| 370 * expression is one of the following: | 710 * expression is one of the following: |
| 371 * * A literal number. | 711 * * A literal number. |
| 372 * * A literal boolean. | 712 * * A literal boolean. |
| 373 * * A literal string where any interpolated expression is a compile-time consta
nt that evaluates | 713 * * A literal string where any interpolated expression is a compile-time consta
nt that evaluates |
| 374 * to a numeric, string or boolean value or to <b>null</b>. | 714 * to a numeric, string or boolean value or to <b>null</b>. |
| 375 * * A literal symbol. | 715 * * A literal symbol. |
| 376 * * <b>null</b>. | 716 * * <b>null</b>. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 /** | 751 /** |
| 412 * The type provider used to access the known types. | 752 * The type provider used to access the known types. |
| 413 */ | 753 */ |
| 414 final TypeProvider _typeProvider; | 754 final TypeProvider _typeProvider; |
| 415 | 755 |
| 416 /** | 756 /** |
| 417 * An shared object representing the value 'null'. | 757 * An shared object representing the value 'null'. |
| 418 */ | 758 */ |
| 419 DartObjectImpl _nullObject; | 759 DartObjectImpl _nullObject; |
| 420 | 760 |
| 761 Map<String, DartObjectImpl> _lexicalEnvironment; |
| 762 |
| 421 /** | 763 /** |
| 422 * Initialize a newly created constant visitor. | 764 * Initialize a newly created constant visitor. |
| 423 * | 765 * |
| 424 * @param typeProvider the type provider used to access known types | 766 * @param typeProvider the type provider used to access known types |
| 767 * @param lexicalEnvironment values which should override simpleIdentifiers, o
r null if no |
| 768 * overriding is necessary. |
| 425 */ | 769 */ |
| 426 ConstantVisitor(this._typeProvider); | 770 ConstantVisitor.con1(this._typeProvider) { |
| 771 this._lexicalEnvironment = null; |
| 772 } |
| 773 |
| 774 /** |
| 775 * Initialize a newly created constant visitor. |
| 776 * |
| 777 * @param typeProvider the type provider used to access known types |
| 778 * @param lexicalEnvironment values which should override simpleIdentifiers, o
r null if no |
| 779 * overriding is necessary. |
| 780 */ |
| 781 ConstantVisitor.con2(this._typeProvider, Map<String, DartObjectImpl> lexicalEn
vironment) { |
| 782 this._lexicalEnvironment = lexicalEnvironment; |
| 783 } |
| 427 | 784 |
| 428 @override | 785 @override |
| 429 EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { | 786 EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { |
| 430 EvaluationResultImpl result = null; | 787 EvaluationResultImpl result = null; |
| 431 for (StringLiteral string in node.strings) { | 788 for (StringLiteral string in node.strings) { |
| 432 if (result == null) { | 789 if (result == null) { |
| 433 result = string.accept(this); | 790 result = string.accept(this); |
| 434 } else { | 791 } else { |
| 435 result = result.concatenate(_typeProvider, node, string.accept(this)); | 792 result = result.concatenate(_typeProvider, node, string.accept(this)); |
| 436 } | 793 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 | 889 |
| 533 @override | 890 @override |
| 534 EvaluationResultImpl visitDoubleLiteral(DoubleLiteral node) => _valid(_typePro
vider.doubleType, new DoubleState(node.value)); | 891 EvaluationResultImpl visitDoubleLiteral(DoubleLiteral node) => _valid(_typePro
vider.doubleType, new DoubleState(node.value)); |
| 535 | 892 |
| 536 @override | 893 @override |
| 537 EvaluationResultImpl visitInstanceCreationExpression(InstanceCreationExpressio
n node) { | 894 EvaluationResultImpl visitInstanceCreationExpression(InstanceCreationExpressio
n node) { |
| 538 if (!node.isConst) { | 895 if (!node.isConst) { |
| 539 // TODO(brianwilkerson) Figure out which error to report. | 896 // TODO(brianwilkerson) Figure out which error to report. |
| 540 return _error(node, null); | 897 return _error(node, null); |
| 541 } | 898 } |
| 542 ConstructorElement constructor = node.staticElement; | 899 beforeGetEvaluationResult(node); |
| 543 if (constructor != null && constructor.isConst) { | 900 EvaluationResultImpl result = node.evaluationResult; |
| 544 NodeList<Expression> arguments = node.argumentList.arguments; | 901 if (result != null) { |
| 545 int argumentCount = arguments.length; | 902 return result; |
| 546 List<DartObjectImpl> argumentValues = new List<DartObjectImpl>(argumentCou
nt); | |
| 547 Map<String, DartObjectImpl> namedArgumentValues = new Map<String, DartObje
ctImpl>(); | |
| 548 for (int i = 0; i < argumentCount; i++) { | |
| 549 Expression argument = arguments[i]; | |
| 550 if (argument is NamedExpression) { | |
| 551 NamedExpression namedExpression = argument; | |
| 552 String name = namedExpression.name.label.name; | |
| 553 namedArgumentValues[name] = _valueOf(namedExpression.expression); | |
| 554 argumentValues[i] = null2; | |
| 555 } else { | |
| 556 argumentValues[i] = _valueOf(argument); | |
| 557 } | |
| 558 } | |
| 559 Set<ConstructorElement> constructorsVisited = new Set<ConstructorElement>(
); | |
| 560 InterfaceType definingClass = constructor.returnType as InterfaceType; | |
| 561 while (constructor.isFactory) { | |
| 562 if (definingClass.element.library.isDartCore) { | |
| 563 String className = definingClass.name; | |
| 564 if (className == "Symbol" && argumentCount == 1) { | |
| 565 String argumentValue = argumentValues[0].stringValue; | |
| 566 if (argumentValue != null) { | |
| 567 return _valid(definingClass, new SymbolState(argumentValue)); | |
| 568 } | |
| 569 } | |
| 570 } | |
| 571 constructorsVisited.add(constructor); | |
| 572 ConstructorElement redirectedConstructor = constructor.redirectedConstru
ctor; | |
| 573 if (redirectedConstructor == null) { | |
| 574 // This can happen if constructor is an external factory constructor.
Since there is no | |
| 575 // constructor to delegate to, we currently can't evaluate the constan
t. | |
| 576 // TODO(paulberry): if the constructor is one of {bool,int,String}.fro
mEnvironment(), | |
| 577 // we may be able to infer the value based on -D flags provided to the
analyzer (see | |
| 578 // dartbug.com/17234). | |
| 579 return _error(node, null); | |
| 580 } | |
| 581 if (!redirectedConstructor.isConst) { | |
| 582 // Delegating to a non-const constructor--this is not allowed (and | |
| 583 // is checked elsewhere--see [ErrorVerifier.checkForRedirectToNonConst
Constructor()]). | |
| 584 // So if we encounter it just error out. | |
| 585 return _error(node, null); | |
| 586 } | |
| 587 if (constructorsVisited.contains(redirectedConstructor)) { | |
| 588 // Cycle in redirecting factory constructors--this is not allowed | |
| 589 // and is checked elsewhere--see [ErrorVerifier.checkForRecursiveFacto
ryRedirect()]). | |
| 590 // So if we encounter it just error out. | |
| 591 return _error(node, null); | |
| 592 } | |
| 593 constructor = redirectedConstructor; | |
| 594 definingClass = constructor.returnType as InterfaceType; | |
| 595 } | |
| 596 Map<String, DartObjectImpl> fieldMap = new Map<String, DartObjectImpl>(); | |
| 597 List<ParameterElement> parameters = constructor.parameters; | |
| 598 int parameterCount = parameters.length; | |
| 599 for (int i = 0; i < parameterCount; i++) { | |
| 600 ParameterElement parameter = parameters[i]; | |
| 601 if (parameter.isInitializingFormal) { | |
| 602 FieldElement field = (parameter as FieldFormalParameterElement).field; | |
| 603 if (field != null) { | |
| 604 String fieldName = field.name; | |
| 605 if (parameter.parameterKind == ParameterKind.NAMED) { | |
| 606 DartObjectImpl argumentValue = namedArgumentValues[parameter.name]
; | |
| 607 if (argumentValue != null) { | |
| 608 fieldMap[fieldName] = argumentValue; | |
| 609 } | |
| 610 } else if (i < argumentCount) { | |
| 611 fieldMap[fieldName] = argumentValues[i]; | |
| 612 } | |
| 613 } | |
| 614 } | |
| 615 } | |
| 616 // TODO(brianwilkerson) This doesn't handle fields initialized in an initi
alizer. We should be | |
| 617 // able to handle fields initialized by the superclass' constructor fairly
easily, but other | |
| 618 // initializers will be harder. | |
| 619 return _valid(definingClass, new GenericState(fieldMap)); | |
| 620 } | 903 } |
| 621 // TODO(brianwilkerson) Figure out which error to report. | 904 // TODO(brianwilkerson) Figure out which error to report. |
| 622 return _error(node, null); | 905 return _error(node, null); |
| 623 } | 906 } |
| 624 | 907 |
| 625 @override | 908 @override |
| 626 EvaluationResultImpl visitIntegerLiteral(IntegerLiteral node) => _valid(_typeP
rovider.intType, new IntState(node.value)); | 909 EvaluationResultImpl visitIntegerLiteral(IntegerLiteral node) => _valid(_typeP
rovider.intType, new IntState(node.value)); |
| 627 | 910 |
| 628 @override | 911 @override |
| 629 EvaluationResultImpl visitInterpolationExpression(InterpolationExpression node
) { | 912 EvaluationResultImpl visitInterpolationExpression(InterpolationExpression node
) { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 return _error(node, null); | 1031 return _error(node, null); |
| 749 } | 1032 } |
| 750 break; | 1033 break; |
| 751 } | 1034 } |
| 752 } | 1035 } |
| 753 | 1036 |
| 754 @override | 1037 @override |
| 755 EvaluationResultImpl visitPropertyAccess(PropertyAccess node) => _getConstantV
alue(node, node.propertyName.staticElement); | 1038 EvaluationResultImpl visitPropertyAccess(PropertyAccess node) => _getConstantV
alue(node, node.propertyName.staticElement); |
| 756 | 1039 |
| 757 @override | 1040 @override |
| 758 EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) => _getConst
antValue(node, node.staticElement); | 1041 EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) { |
| 1042 if (_lexicalEnvironment != null && _lexicalEnvironment.containsKey(node.name
)) { |
| 1043 return new ValidResult(_lexicalEnvironment[node.name]); |
| 1044 } |
| 1045 return _getConstantValue(node, node.staticElement); |
| 1046 } |
| 759 | 1047 |
| 760 @override | 1048 @override |
| 761 EvaluationResultImpl visitSimpleStringLiteral(SimpleStringLiteral node) => _va
lid(_typeProvider.stringType, new StringState(node.value)); | 1049 EvaluationResultImpl visitSimpleStringLiteral(SimpleStringLiteral node) => _va
lid(_typeProvider.stringType, new StringState(node.value)); |
| 762 | 1050 |
| 763 @override | 1051 @override |
| 764 EvaluationResultImpl visitStringInterpolation(StringInterpolation node) { | 1052 EvaluationResultImpl visitStringInterpolation(StringInterpolation node) { |
| 765 EvaluationResultImpl result = null; | 1053 EvaluationResultImpl result = null; |
| 766 for (InterpolationElement element in node.elements) { | 1054 for (InterpolationElement element in node.elements) { |
| 767 if (result == null) { | 1055 if (result == null) { |
| 768 result = element.accept(this); | 1056 result = element.accept(this); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 780 for (int i = 0; i < components.length; i++) { | 1068 for (int i = 0; i < components.length; i++) { |
| 781 if (i > 0) { | 1069 if (i > 0) { |
| 782 builder.appendChar(0x2E); | 1070 builder.appendChar(0x2E); |
| 783 } | 1071 } |
| 784 builder.append(components[i].lexeme); | 1072 builder.append(components[i].lexeme); |
| 785 } | 1073 } |
| 786 return _valid(_typeProvider.symbolType, new SymbolState(builder.toString()))
; | 1074 return _valid(_typeProvider.symbolType, new SymbolState(builder.toString()))
; |
| 787 } | 1075 } |
| 788 | 1076 |
| 789 /** | 1077 /** |
| 1078 * This method is called just before retrieving an evaluation result from an A
ST node. Unit tests |
| 1079 * will override it to introduce additional error checking. |
| 1080 */ |
| 1081 void beforeGetEvaluationResult(AstNode node) { |
| 1082 } |
| 1083 |
| 1084 /** |
| 1085 * Return an object representing the value 'null'. |
| 1086 * |
| 1087 * @return an object representing the value 'null' |
| 1088 */ |
| 1089 DartObjectImpl get null2 { |
| 1090 if (_nullObject == null) { |
| 1091 _nullObject = new DartObjectImpl(_typeProvider.nullType, NullState.NULL_ST
ATE); |
| 1092 } |
| 1093 return _nullObject; |
| 1094 } |
| 1095 |
| 1096 ValidResult _valid(InterfaceType type, InstanceState state) => new ValidResult
(new DartObjectImpl(type, state)); |
| 1097 |
| 1098 ValidResult _validWithUnknownValue(InterfaceType type) { |
| 1099 if (type.element.library.isDartCore) { |
| 1100 String typeName = type.name; |
| 1101 if (typeName == "bool") { |
| 1102 return _valid(type, BoolState.UNKNOWN_VALUE); |
| 1103 } else if (typeName == "double") { |
| 1104 return _valid(type, DoubleState.UNKNOWN_VALUE); |
| 1105 } else if (typeName == "int") { |
| 1106 return _valid(type, IntState.UNKNOWN_VALUE); |
| 1107 } else if (typeName == "String") { |
| 1108 return _valid(type, StringState.UNKNOWN_VALUE); |
| 1109 } |
| 1110 } |
| 1111 return _valid(type, GenericState.UNKNOWN_VALUE); |
| 1112 } |
| 1113 |
| 1114 /** |
| 1115 * Return the value of the given expression, or a representation of 'null' if
the expression |
| 1116 * cannot be evaluated. |
| 1117 * |
| 1118 * @param expression the expression whose value is to be returned |
| 1119 * @return the value of the given expression |
| 1120 */ |
| 1121 DartObjectImpl _valueOf(Expression expression) { |
| 1122 EvaluationResultImpl expressionValue = expression.accept(this); |
| 1123 if (expressionValue is ValidResult) { |
| 1124 return expressionValue.value; |
| 1125 } |
| 1126 return null2; |
| 1127 } |
| 1128 |
| 1129 /** |
| 790 * Return a result object representing an error associated with the given node
. | 1130 * Return a result object representing an error associated with the given node
. |
| 791 * | 1131 * |
| 792 * @param node the AST node associated with the error | 1132 * @param node the AST node associated with the error |
| 793 * @param code the error code indicating the nature of the error | 1133 * @param code the error code indicating the nature of the error |
| 794 * @return a result object representing an error associated with the given nod
e | 1134 * @return a result object representing an error associated with the given nod
e |
| 795 */ | 1135 */ |
| 796 ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node,
code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); | 1136 ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node,
code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); |
| 797 | 1137 |
| 798 /** | 1138 /** |
| 799 * Return the constant value of the static constant represented by the given e
lement. | 1139 * Return the constant value of the static constant represented by the given e
lement. |
| 800 * | 1140 * |
| 801 * @param node the node to be used if an error needs to be reported | 1141 * @param node the node to be used if an error needs to be reported |
| 802 * @param element the element whose value is to be returned | 1142 * @param element the element whose value is to be returned |
| 803 * @return the constant value of the static constant | 1143 * @return the constant value of the static constant |
| 804 */ | 1144 */ |
| 805 EvaluationResultImpl _getConstantValue(AstNode node, Element element) { | 1145 EvaluationResultImpl _getConstantValue(AstNode node, Element element) { |
| 806 if (element is PropertyAccessorElement) { | 1146 if (element is PropertyAccessorElement) { |
| 807 element = (element as PropertyAccessorElement).variable; | 1147 element = (element as PropertyAccessorElement).variable; |
| 808 } | 1148 } |
| 809 if (element is VariableElementImpl) { | 1149 if (element is VariableElementImpl) { |
| 810 VariableElementImpl variableElementImpl = element; | 1150 VariableElementImpl variableElementImpl = element; |
| 1151 beforeGetEvaluationResult(node); |
| 811 EvaluationResultImpl value = variableElementImpl.evaluationResult; | 1152 EvaluationResultImpl value = variableElementImpl.evaluationResult; |
| 812 if (variableElementImpl.isConst && value != null) { | 1153 if (variableElementImpl.isConst && value != null) { |
| 813 return value; | 1154 return value; |
| 814 } | 1155 } |
| 815 } else if (element is ExecutableElement) { | 1156 } else if (element is ExecutableElement) { |
| 816 ExecutableElement function = element; | 1157 ExecutableElement function = element; |
| 817 if (function.isStatic) { | 1158 if (function.isStatic) { |
| 818 return _valid(_typeProvider.functionType, new FunctionState(function)); | 1159 return _valid(_typeProvider.functionType, new FunctionState(function)); |
| 819 } | 1160 } |
| 820 } else if (element is ClassElement || element is FunctionTypeAliasElement) { | 1161 } else if (element is ClassElement || element is FunctionTypeAliasElement) { |
| 821 return _valid(_typeProvider.typeType, new TypeState(element)); | 1162 return _valid(_typeProvider.typeType, new TypeState(element)); |
| 822 } | 1163 } |
| 823 // TODO(brianwilkerson) Figure out which error to report. | 1164 // TODO(brianwilkerson) Figure out which error to report. |
| 824 return _error(node, null); | 1165 return _error(node, null); |
| 825 } | 1166 } |
| 826 | 1167 |
| 827 /** | 1168 /** |
| 828 * Return an object representing the value 'null'. | |
| 829 * | |
| 830 * @return an object representing the value 'null' | |
| 831 */ | |
| 832 DartObjectImpl get null2 { | |
| 833 if (_nullObject == null) { | |
| 834 _nullObject = new DartObjectImpl(_typeProvider.nullType, NullState.NULL_ST
ATE); | |
| 835 } | |
| 836 return _nullObject; | |
| 837 } | |
| 838 | |
| 839 /** | |
| 840 * Return the union of the errors encoded in the given results. | 1169 * Return the union of the errors encoded in the given results. |
| 841 * | 1170 * |
| 842 * @param leftResult the first set of errors, or `null` if there was no previo
us collection | 1171 * @param leftResult the first set of errors, or `null` if there was no previo
us collection |
| 843 * of errors | 1172 * of errors |
| 844 * @param rightResult the errors to be added to the collection, or a valid res
ult if there are no | 1173 * @param rightResult the errors to be added to the collection, or a valid res
ult if there are no |
| 845 * errors to be added | 1174 * errors to be added |
| 846 * @return the union of the errors encoded in the given results | 1175 * @return the union of the errors encoded in the given results |
| 847 */ | 1176 */ |
| 848 ErrorResult _union(ErrorResult leftResult, EvaluationResultImpl rightResult) { | 1177 ErrorResult _union(ErrorResult leftResult, EvaluationResultImpl rightResult) { |
| 849 if (rightResult is ErrorResult) { | 1178 if (rightResult is ErrorResult) { |
| 850 if (leftResult != null) { | 1179 if (leftResult != null) { |
| 851 return new ErrorResult.con2(leftResult, rightResult); | 1180 return new ErrorResult.con2(leftResult, rightResult); |
| 852 } else { | 1181 } else { |
| 853 return rightResult; | 1182 return rightResult; |
| 854 } | 1183 } |
| 855 } | 1184 } |
| 856 return leftResult; | 1185 return leftResult; |
| 857 } | 1186 } |
| 858 | |
| 859 ValidResult _valid(InterfaceType type, InstanceState state) => new ValidResult
(new DartObjectImpl(type, state)); | |
| 860 | |
| 861 ValidResult _validWithUnknownValue(InterfaceType type) { | |
| 862 if (type.element.library.isDartCore) { | |
| 863 String typeName = type.name; | |
| 864 if (typeName == "bool") { | |
| 865 return _valid(type, BoolState.UNKNOWN_VALUE); | |
| 866 } else if (typeName == "double") { | |
| 867 return _valid(type, DoubleState.UNKNOWN_VALUE); | |
| 868 } else if (typeName == "int") { | |
| 869 return _valid(type, IntState.UNKNOWN_VALUE); | |
| 870 } else if (typeName == "String") { | |
| 871 return _valid(type, StringState.UNKNOWN_VALUE); | |
| 872 } | |
| 873 } | |
| 874 return _valid(type, GenericState.UNKNOWN_VALUE); | |
| 875 } | |
| 876 | |
| 877 /** | |
| 878 * Return the value of the given expression, or a representation of 'null' if
the expression | |
| 879 * cannot be evaluated. | |
| 880 * | |
| 881 * @param expression the expression whose value is to be returned | |
| 882 * @return the value of the given expression | |
| 883 */ | |
| 884 DartObjectImpl _valueOf(Expression expression) { | |
| 885 EvaluationResultImpl expressionValue = expression.accept(this); | |
| 886 if (expressionValue is ValidResult) { | |
| 887 return expressionValue.value; | |
| 888 } | |
| 889 return null2; | |
| 890 } | |
| 891 } | 1187 } |
| 892 | 1188 |
| 893 /** | 1189 /** |
| 894 * The interface `DartObject` defines the behavior of objects that represent the
state of a | 1190 * The interface `DartObject` defines the behavior of objects that represent the
state of a |
| 895 * Dart object. | 1191 * Dart object. |
| 896 */ | 1192 */ |
| 897 abstract class DartObject { | 1193 abstract class DartObject { |
| 898 /** | 1194 /** |
| 899 * Return the boolean value of this object, or `null` if either the value of t
his object is | 1195 * Return the boolean value of this object, or `null` if either the value of t
his object is |
| 900 * not known or this object is not of type 'bool'. | 1196 * not known or this object is not of type 'bool'. |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1136 } | 1432 } |
| 1137 | 1433 |
| 1138 @override | 1434 @override |
| 1139 double get doubleValue { | 1435 double get doubleValue { |
| 1140 if (_state is DoubleState) { | 1436 if (_state is DoubleState) { |
| 1141 return (_state as DoubleState).value; | 1437 return (_state as DoubleState).value; |
| 1142 } | 1438 } |
| 1143 return null; | 1439 return null; |
| 1144 } | 1440 } |
| 1145 | 1441 |
| 1442 Map<String, DartObjectImpl> get fields => _state.fields; |
| 1443 |
| 1146 @override | 1444 @override |
| 1147 int get intValue { | 1445 int get intValue { |
| 1148 if (_state is IntState) { | 1446 if (_state is IntState) { |
| 1149 return (_state as IntState).value; | 1447 return (_state as IntState).value; |
| 1150 } | 1448 } |
| 1151 return null; | 1449 return null; |
| 1152 } | 1450 } |
| 1153 | 1451 |
| 1154 @override | 1452 @override |
| 1155 String get stringValue { | 1453 String get stringValue { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1216 @override | 1514 @override |
| 1217 bool get isFalse => _state is BoolState && identical((_state as BoolState).val
ue, false); | 1515 bool get isFalse => _state is BoolState && identical((_state as BoolState).val
ue, false); |
| 1218 | 1516 |
| 1219 @override | 1517 @override |
| 1220 bool get isNull => _state is NullState; | 1518 bool get isNull => _state is NullState; |
| 1221 | 1519 |
| 1222 @override | 1520 @override |
| 1223 bool get isTrue => _state is BoolState && identical((_state as BoolState).valu
e, true); | 1521 bool get isTrue => _state is BoolState && identical((_state as BoolState).valu
e, true); |
| 1224 | 1522 |
| 1225 /** | 1523 /** |
| 1524 * Return true if this object represents an unknown value. |
| 1525 */ |
| 1526 bool get isUnknown => _state.isUnknown; |
| 1527 |
| 1528 /** |
| 1226 * Return `true` if this object represents an instance of a user-defined class
. | 1529 * Return `true` if this object represents an instance of a user-defined class
. |
| 1227 * | 1530 * |
| 1228 * @return `true` if this object represents an instance of a user-defined clas
s | 1531 * @return `true` if this object represents an instance of a user-defined clas
s |
| 1229 */ | 1532 */ |
| 1230 bool get isUserDefinedObject => _state is GenericState; | 1533 bool get isUserDefinedObject => _state is GenericState; |
| 1231 | 1534 |
| 1232 /** | 1535 /** |
| 1233 * Return the result of invoking the '<' operator on this object with the g
iven argument. | 1536 * Return the result of invoking the '<' operator on this object with the g
iven argument. |
| 1234 * | 1537 * |
| 1235 * @param typeProvider the type provider used to find known types | 1538 * @param typeProvider the type provider used to find known types |
| (...skipping 1206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2442 * Instances of the class `GenericState` represent the state of an object repres
enting a Dart | 2745 * Instances of the class `GenericState` represent the state of an object repres
enting a Dart |
| 2443 * object for which there is no more specific state. | 2746 * object for which there is no more specific state. |
| 2444 */ | 2747 */ |
| 2445 class GenericState extends InstanceState { | 2748 class GenericState extends InstanceState { |
| 2446 /** | 2749 /** |
| 2447 * The values of the fields of this instance. | 2750 * The values of the fields of this instance. |
| 2448 */ | 2751 */ |
| 2449 final Map<String, DartObjectImpl> _fieldMap; | 2752 final Map<String, DartObjectImpl> _fieldMap; |
| 2450 | 2753 |
| 2451 /** | 2754 /** |
| 2755 * Pseudo-field that we use to represent fields in the superclass. |
| 2756 */ |
| 2757 static String SUPERCLASS_FIELD = "(super)"; |
| 2758 |
| 2759 /** |
| 2452 * A state that can be used to represent an object whose state is not known. | 2760 * A state that can be used to represent an object whose state is not known. |
| 2453 */ | 2761 */ |
| 2454 static GenericState UNKNOWN_VALUE = new GenericState(new Map<String, DartObjec
tImpl>()); | 2762 static GenericState UNKNOWN_VALUE = new GenericState(new Map<String, DartObjec
tImpl>()); |
| 2455 | 2763 |
| 2456 /** | 2764 /** |
| 2457 * Initialize a newly created state to represent a newly created object. | 2765 * Initialize a newly created state to represent a newly created object. |
| 2458 * | 2766 * |
| 2459 * @param fieldMap the values of the fields of this instance | 2767 * @param fieldMap the values of the fields of this instance |
| 2460 */ | 2768 */ |
| 2461 GenericState(this._fieldMap); | 2769 GenericState(this._fieldMap); |
| 2462 | 2770 |
| 2463 @override | 2771 @override |
| 2464 StringState convertToString() => StringState.UNKNOWN_VALUE; | 2772 StringState convertToString() => StringState.UNKNOWN_VALUE; |
| 2465 | 2773 |
| 2466 @override | 2774 @override |
| 2775 BoolState equalEqual(InstanceState rightOperand) { |
| 2776 assertBoolNumStringOrNull(rightOperand); |
| 2777 if (rightOperand is DynamicState) { |
| 2778 return BoolState.UNKNOWN_VALUE; |
| 2779 } |
| 2780 return BoolState.from(this == rightOperand); |
| 2781 } |
| 2782 |
| 2783 @override |
| 2467 bool operator ==(Object object) { | 2784 bool operator ==(Object object) { |
| 2468 if (object is! GenericState) { | 2785 if (object is! GenericState) { |
| 2469 return false; | 2786 return false; |
| 2470 } | 2787 } |
| 2471 GenericState state = object as GenericState; | 2788 GenericState state = object as GenericState; |
| 2472 Set<String> otherFields = new Set<String>.from(state._fieldMap.keys.toSet())
; | 2789 Set<String> otherFields = new Set<String>.from(state._fieldMap.keys.toSet())
; |
| 2473 for (String fieldName in _fieldMap.keys.toSet()) { | 2790 for (String fieldName in _fieldMap.keys.toSet()) { |
| 2474 if (_fieldMap[fieldName] != state._fieldMap[fieldName]) { | 2791 if (_fieldMap[fieldName] != state._fieldMap[fieldName]) { |
| 2475 return false; | 2792 return false; |
| 2476 } | 2793 } |
| 2477 otherFields.remove(fieldName); | 2794 otherFields.remove(fieldName); |
| 2478 } | 2795 } |
| 2479 for (String fieldName in otherFields) { | 2796 for (String fieldName in otherFields) { |
| 2480 if (state._fieldMap[fieldName] != _fieldMap[fieldName]) { | 2797 if (state._fieldMap[fieldName] != _fieldMap[fieldName]) { |
| 2481 return false; | 2798 return false; |
| 2482 } | 2799 } |
| 2483 } | 2800 } |
| 2484 return true; | 2801 return true; |
| 2485 } | 2802 } |
| 2486 | 2803 |
| 2487 @override | 2804 @override |
| 2488 BoolState equalEqual(InstanceState rightOperand) { | 2805 Map<String, DartObjectImpl> get fields => _fieldMap; |
| 2489 assertBoolNumStringOrNull(rightOperand); | |
| 2490 if (rightOperand is DynamicState) { | |
| 2491 return BoolState.UNKNOWN_VALUE; | |
| 2492 } | |
| 2493 return BoolState.from(this == rightOperand); | |
| 2494 } | |
| 2495 | 2806 |
| 2496 @override | 2807 @override |
| 2497 String get typeName => "user defined type"; | 2808 String get typeName => "user defined type"; |
| 2498 | 2809 |
| 2499 @override | 2810 @override |
| 2500 int get hashCode { | 2811 int get hashCode { |
| 2501 int hashCode = 0; | 2812 int hashCode = 0; |
| 2502 for (DartObjectImpl value in _fieldMap.values) { | 2813 for (DartObjectImpl value in _fieldMap.values) { |
| 2503 hashCode += value.hashCode; | 2814 hashCode += value.hashCode; |
| 2504 } | 2815 } |
| 2505 return hashCode; | 2816 return hashCode; |
| 2506 } | 2817 } |
| 2818 |
| 2819 @override |
| 2820 bool get isUnknown => identical(this, UNKNOWN_VALUE); |
| 2507 } | 2821 } |
| 2508 | 2822 |
| 2509 /** | 2823 /** |
| 2510 * The class `InstanceState` defines the behavior of objects representing the st
ate of a Dart | 2824 * The class `InstanceState` defines the behavior of objects representing the st
ate of a Dart |
| 2511 * object. | 2825 * object. |
| 2512 */ | 2826 */ |
| 2513 abstract class InstanceState { | 2827 abstract class InstanceState { |
| 2514 /** | 2828 /** |
| 2515 * Return the result of invoking the '+' operator on this object with the give
n argument. | 2829 * Return the result of invoking the '+' operator on this object with the give
n argument. |
| 2516 * | 2830 * |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2618 /** | 2932 /** |
| 2619 * Return the result of invoking the '==' operator on this object with the giv
en argument. | 2933 * Return the result of invoking the '==' operator on this object with the giv
en argument. |
| 2620 * | 2934 * |
| 2621 * @param rightOperand the right-hand operand of the operation | 2935 * @param rightOperand the right-hand operand of the operation |
| 2622 * @return the result of invoking the '==' operator on this object with the gi
ven argument | 2936 * @return the result of invoking the '==' operator on this object with the gi
ven argument |
| 2623 * @throws EvaluationException if the operator is not appropriate for an objec
t of this kind | 2937 * @throws EvaluationException if the operator is not appropriate for an objec
t of this kind |
| 2624 */ | 2938 */ |
| 2625 BoolState equalEqual(InstanceState rightOperand); | 2939 BoolState equalEqual(InstanceState rightOperand); |
| 2626 | 2940 |
| 2627 /** | 2941 /** |
| 2942 * If this represents a generic dart object, return a map from its fieldnames
to their values. |
| 2943 * Otherwise return null. |
| 2944 */ |
| 2945 Map<String, DartObjectImpl> get fields => null; |
| 2946 |
| 2947 /** |
| 2628 * Return the name of the type of this value. | 2948 * Return the name of the type of this value. |
| 2629 * | 2949 * |
| 2630 * @return the name of the type of this value | 2950 * @return the name of the type of this value |
| 2631 */ | 2951 */ |
| 2632 String get typeName; | 2952 String get typeName; |
| 2633 | 2953 |
| 2634 /** | 2954 /** |
| 2635 * Return this object's value if it can be represented exactly, or `null` if e
ither the | 2955 * Return this object's value if it can be represented exactly, or `null` if e
ither the |
| 2636 * value cannot be represented exactly or if the value is `null`. Clients shou
ld use | 2956 * value cannot be represented exactly or if the value is `null`. Clients shou
ld use |
| 2637 * [hasExactValue] to distinguish between these two cases. | 2957 * [hasExactValue] to distinguish between these two cases. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2695 | 3015 |
| 2696 /** | 3016 /** |
| 2697 * Return `true` if this object represents an object whose type is either 'boo
l', 'num', | 3017 * Return `true` if this object represents an object whose type is either 'boo
l', 'num', |
| 2698 * 'String', or 'Null'. | 3018 * 'String', or 'Null'. |
| 2699 * | 3019 * |
| 2700 * @return `true` if this object represents either a boolean, numeric, string
or null value | 3020 * @return `true` if this object represents either a boolean, numeric, string
or null value |
| 2701 */ | 3021 */ |
| 2702 bool get isBoolNumStringOrNull => false; | 3022 bool get isBoolNumStringOrNull => false; |
| 2703 | 3023 |
| 2704 /** | 3024 /** |
| 3025 * Return true if this object represents an unknown value. |
| 3026 */ |
| 3027 bool get isUnknown => false; |
| 3028 |
| 3029 /** |
| 2705 * Return the result of invoking the '<' operator on this object with the g
iven argument. | 3030 * Return the result of invoking the '<' operator on this object with the g
iven argument. |
| 2706 * | 3031 * |
| 2707 * @param rightOperand the right-hand operand of the operation | 3032 * @param rightOperand the right-hand operand of the operation |
| 2708 * @return the result of invoking the '<' operator on this object with the
given argument | 3033 * @return the result of invoking the '<' operator on this object with the
given argument |
| 2709 * @throws EvaluationException if the operator is not appropriate for an objec
t of this kind | 3034 * @throws EvaluationException if the operator is not appropriate for an objec
t of this kind |
| 2710 */ | 3035 */ |
| 2711 BoolState lessThan(InstanceState rightOperand) { | 3036 BoolState lessThan(InstanceState rightOperand) { |
| 2712 assertNumOrNull(this); | 3037 assertNumOrNull(this); |
| 2713 assertNumOrNull(rightOperand); | 3038 assertNumOrNull(rightOperand); |
| 2714 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); | 3039 throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
| (...skipping 880 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3595 @override | 3920 @override |
| 3596 StringState convertToString() => StringState.UNKNOWN_VALUE; | 3921 StringState convertToString() => StringState.UNKNOWN_VALUE; |
| 3597 | 3922 |
| 3598 @override | 3923 @override |
| 3599 NumState divide(InstanceState rightOperand) { | 3924 NumState divide(InstanceState rightOperand) { |
| 3600 assertNumOrNull(rightOperand); | 3925 assertNumOrNull(rightOperand); |
| 3601 return UNKNOWN_VALUE; | 3926 return UNKNOWN_VALUE; |
| 3602 } | 3927 } |
| 3603 | 3928 |
| 3604 @override | 3929 @override |
| 3605 bool operator ==(Object object) => object is NumState; | |
| 3606 | |
| 3607 @override | |
| 3608 BoolState equalEqual(InstanceState rightOperand) { | 3930 BoolState equalEqual(InstanceState rightOperand) { |
| 3609 assertBoolNumStringOrNull(rightOperand); | 3931 assertBoolNumStringOrNull(rightOperand); |
| 3610 return BoolState.UNKNOWN_VALUE; | 3932 return BoolState.UNKNOWN_VALUE; |
| 3611 } | 3933 } |
| 3612 | 3934 |
| 3613 @override | 3935 @override |
| 3936 bool operator ==(Object object) => object is NumState; |
| 3937 |
| 3938 @override |
| 3614 String get typeName => "num"; | 3939 String get typeName => "num"; |
| 3615 | 3940 |
| 3616 @override | 3941 @override |
| 3617 BoolState greaterThan(InstanceState rightOperand) { | 3942 BoolState greaterThan(InstanceState rightOperand) { |
| 3618 assertNumOrNull(rightOperand); | 3943 assertNumOrNull(rightOperand); |
| 3619 return BoolState.UNKNOWN_VALUE; | 3944 return BoolState.UNKNOWN_VALUE; |
| 3620 } | 3945 } |
| 3621 | 3946 |
| 3622 @override | 3947 @override |
| 3623 BoolState greaterThanOrEqual(InstanceState rightOperand) { | 3948 BoolState greaterThanOrEqual(InstanceState rightOperand) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3641 } else if (rightOperand is DynamicState) { | 3966 } else if (rightOperand is DynamicState) { |
| 3642 return IntState.UNKNOWN_VALUE; | 3967 return IntState.UNKNOWN_VALUE; |
| 3643 } | 3968 } |
| 3644 return IntState.UNKNOWN_VALUE; | 3969 return IntState.UNKNOWN_VALUE; |
| 3645 } | 3970 } |
| 3646 | 3971 |
| 3647 @override | 3972 @override |
| 3648 bool get isBoolNumStringOrNull => true; | 3973 bool get isBoolNumStringOrNull => true; |
| 3649 | 3974 |
| 3650 @override | 3975 @override |
| 3976 bool get isUnknown => identical(this, UNKNOWN_VALUE); |
| 3977 |
| 3978 @override |
| 3651 BoolState lessThan(InstanceState rightOperand) { | 3979 BoolState lessThan(InstanceState rightOperand) { |
| 3652 assertNumOrNull(rightOperand); | 3980 assertNumOrNull(rightOperand); |
| 3653 return BoolState.UNKNOWN_VALUE; | 3981 return BoolState.UNKNOWN_VALUE; |
| 3654 } | 3982 } |
| 3655 | 3983 |
| 3656 @override | 3984 @override |
| 3657 BoolState lessThanOrEqual(InstanceState rightOperand) { | 3985 BoolState lessThanOrEqual(InstanceState rightOperand) { |
| 3658 assertNumOrNull(rightOperand); | 3986 assertNumOrNull(rightOperand); |
| 3659 return BoolState.UNKNOWN_VALUE; | 3987 return BoolState.UNKNOWN_VALUE; |
| 3660 } | 3988 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 3683 @override | 4011 @override |
| 3684 String toString() => "-unknown-"; | 4012 String toString() => "-unknown-"; |
| 3685 } | 4013 } |
| 3686 | 4014 |
| 3687 /** | 4015 /** |
| 3688 * Instances of the class `ReferenceFinder` add reference information for a give
n variable to | 4016 * Instances of the class `ReferenceFinder` add reference information for a give
n variable to |
| 3689 * the bi-directional mapping used to order the evaluation of constants. | 4017 * the bi-directional mapping used to order the evaluation of constants. |
| 3690 */ | 4018 */ |
| 3691 class ReferenceFinder extends RecursiveAstVisitor<Object> { | 4019 class ReferenceFinder extends RecursiveAstVisitor<Object> { |
| 3692 /** | 4020 /** |
| 3693 * The element representing the variable whose initializer will be visited. | 4021 * The element representing the construct that will be visited. |
| 3694 */ | 4022 */ |
| 3695 final VariableElement _source; | 4023 final AstNode _source; |
| 3696 | 4024 |
| 3697 /** | 4025 /** |
| 3698 * A graph in which the nodes are the constant variables and the edges are fro
m each variable to | 4026 * A graph in which the nodes are the constant variables and the edges are fro
m each variable to |
| 3699 * the other constant variables that are referenced in the head's initializer. | 4027 * the other constant variables that are referenced in the head's initializer. |
| 3700 */ | 4028 */ |
| 3701 final DirectedGraph<VariableElement> _referenceGraph; | 4029 final DirectedGraph<AstNode> _referenceGraph; |
| 4030 |
| 4031 /** |
| 4032 * A table mapping constant variables to the declarations of those variables. |
| 4033 */ |
| 4034 final Map<VariableElement, VariableDeclaration> _variableDeclarationMap; |
| 4035 |
| 4036 /** |
| 4037 * A table mapping constant constructors to the declarations of those construc
tors. |
| 4038 */ |
| 4039 final Map<ConstructorElement, ConstructorDeclaration> _constructorDeclarationM
ap; |
| 3702 | 4040 |
| 3703 /** | 4041 /** |
| 3704 * Initialize a newly created reference finder to find references from the giv
en variable to other | 4042 * Initialize a newly created reference finder to find references from the giv
en variable to other |
| 3705 * variables and to add those references to the given graph. | 4043 * variables and to add those references to the given graph. |
| 3706 * | 4044 * |
| 3707 * @param source the element representing the variable whose initializer will
be visited | 4045 * @param source the element representing the variable whose initializer will
be visited |
| 3708 * @param referenceGraph a graph recording which variables (heads) reference w
hich other variables | 4046 * @param referenceGraph a graph recording which variables (heads) reference w
hich other variables |
| 3709 * (tails) in their initializers | 4047 * (tails) in their initializers |
| 4048 * @param variableDeclarationMap A table mapping constant variables to the dec
larations of those |
| 4049 * variables. |
| 4050 * @param constructorDeclarationMap A table mapping constant constructors to t
he declarations of |
| 4051 * those constructors. |
| 3710 */ | 4052 */ |
| 3711 ReferenceFinder(this._source, this._referenceGraph); | 4053 ReferenceFinder(this._source, this._referenceGraph, this._variableDeclarationM
ap, this._constructorDeclarationMap); |
| 4054 |
| 4055 @override |
| 4056 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 4057 if (node.isConst) { |
| 4058 _referenceGraph.addEdge(_source, node); |
| 4059 } |
| 4060 return null; |
| 4061 } |
| 3712 | 4062 |
| 3713 @override | 4063 @override |
| 3714 Object visitSimpleIdentifier(SimpleIdentifier node) { | 4064 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 3715 Element element = node.staticElement; | 4065 Element element = node.staticElement; |
| 3716 if (element is PropertyAccessorElement) { | 4066 if (element is PropertyAccessorElement) { |
| 3717 element = (element as PropertyAccessorElement).variable; | 4067 element = (element as PropertyAccessorElement).variable; |
| 3718 } | 4068 } |
| 3719 if (element is VariableElement) { | 4069 if (element is VariableElement) { |
| 3720 VariableElement variable = element as VariableElement; | 4070 VariableElement variable = element as VariableElement; |
| 3721 if (variable.isConst) { | 4071 if (variable.isConst) { |
| 3722 _referenceGraph.addEdge(_source, variable); | 4072 VariableDeclaration variableDeclaration = _variableDeclarationMap[variab
le]; |
| 4073 // The declaration will be null when the variable is not defined in the
compilation units |
| 4074 // that were used to produce the variableDeclarationMap. In such cases,
the variable should |
| 4075 // already have a value associated with it, but we don't bother to check
because there's |
| 4076 // nothing we can do about it at this point. |
| 4077 if (variableDeclaration != null) { |
| 4078 _referenceGraph.addEdge(_source, variableDeclaration); |
| 4079 } |
| 3723 } | 4080 } |
| 3724 } | 4081 } |
| 3725 return null; | 4082 return null; |
| 4083 } |
| 4084 |
| 4085 @override |
| 4086 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 4087 super.visitSuperConstructorInvocation(node); |
| 4088 ConstructorElement constructor = node.staticElement; |
| 4089 if (constructor != null && constructor.isConst) { |
| 4090 ConstructorDeclaration constructorDeclaration = _constructorDeclarationMap
[constructor]; |
| 4091 // The declaration will be null when the constructor is not defined in the
compilation |
| 4092 // units that were used to produce the constructorDeclarationMap. In such
cases, the |
| 4093 // constructor should already have its initializer AST's stored in it, but
we don't bother |
| 4094 // to check because there's nothing we can do about it at this point. |
| 4095 if (constructorDeclaration != null) { |
| 4096 _referenceGraph.addEdge(_source, constructorDeclaration); |
| 4097 } |
| 4098 } |
| 4099 return null; |
| 3726 } | 4100 } |
| 3727 } | 4101 } |
| 3728 | 4102 |
| 3729 /** | 4103 /** |
| 3730 * Instances of the class `StringState` represent the state of an object represe
nting a | 4104 * Instances of the class `StringState` represent the state of an object represe
nting a |
| 3731 * string. | 4105 * string. |
| 3732 */ | 4106 */ |
| 3733 class StringState extends InstanceState { | 4107 class StringState extends InstanceState { |
| 3734 /** | 4108 /** |
| 3735 * The value of this instance. | 4109 * The value of this instance. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3795 @override | 4169 @override |
| 3796 bool get hasExactValue => true; | 4170 bool get hasExactValue => true; |
| 3797 | 4171 |
| 3798 @override | 4172 @override |
| 3799 int get hashCode => value == null ? 0 : value.hashCode; | 4173 int get hashCode => value == null ? 0 : value.hashCode; |
| 3800 | 4174 |
| 3801 @override | 4175 @override |
| 3802 bool get isBoolNumStringOrNull => true; | 4176 bool get isBoolNumStringOrNull => true; |
| 3803 | 4177 |
| 3804 @override | 4178 @override |
| 4179 bool get isUnknown => value == null; |
| 4180 |
| 4181 @override |
| 3805 String toString() => value == null ? "-unknown-" : "'${value}'"; | 4182 String toString() => value == null ? "-unknown-" : "'${value}'"; |
| 3806 } | 4183 } |
| 3807 | 4184 |
| 3808 /** | 4185 /** |
| 3809 * Instances of the class `StringState` represent the state of an object represe
nting a | 4186 * Instances of the class `StringState` represent the state of an object represe
nting a |
| 3810 * symbol. | 4187 * symbol. |
| 3811 */ | 4188 */ |
| 3812 class SymbolState extends InstanceState { | 4189 class SymbolState extends InstanceState { |
| 3813 /** | 4190 /** |
| 3814 * The value of this instance. | 4191 * The value of this instance. |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4356 ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node,
code); | 4733 ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node,
code); |
| 4357 | 4734 |
| 4358 /** | 4735 /** |
| 4359 * Return a result object representing the given value. | 4736 * Return a result object representing the given value. |
| 4360 * | 4737 * |
| 4361 * @param value the value to be represented as a result object | 4738 * @param value the value to be represented as a result object |
| 4362 * @return a result object representing the given value | 4739 * @return a result object representing the given value |
| 4363 */ | 4740 */ |
| 4364 ValidResult _valueOf(DartObjectImpl value) => new ValidResult(value); | 4741 ValidResult _valueOf(DartObjectImpl value) => new ValidResult(value); |
| 4365 } | 4742 } |
| OLD | NEW |