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 |