OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library analyzer.src.task.dart; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/src/context/cache.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart'; |
| 11 import 'package:analyzer/src/generated/constant.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/engine.dart' |
| 14 hide AnalysisCache, AnalysisTask; |
| 15 import 'package:analyzer/src/generated/error.dart'; |
| 16 import 'package:analyzer/src/generated/error_verifier.dart'; |
| 17 import 'package:analyzer/src/generated/incremental_resolver.dart'; |
| 18 import 'package:analyzer/src/generated/java_engine.dart'; |
| 19 import 'package:analyzer/src/generated/parser.dart'; |
| 20 import 'package:analyzer/src/generated/resolver.dart'; |
| 21 import 'package:analyzer/src/generated/scanner.dart'; |
| 22 import 'package:analyzer/src/generated/sdk.dart'; |
| 23 import 'package:analyzer/src/generated/source.dart'; |
| 24 import 'package:analyzer/src/task/driver.dart'; |
| 25 import 'package:analyzer/src/task/general.dart'; |
| 26 import 'package:analyzer/src/task/html.dart'; |
| 27 import 'package:analyzer/src/task/inputs.dart'; |
| 28 import 'package:analyzer/src/task/model.dart'; |
| 29 import 'package:analyzer/src/task/strong_mode.dart'; |
| 30 import 'package:analyzer/task/dart.dart'; |
| 31 import 'package:analyzer/task/general.dart'; |
| 32 import 'package:analyzer/task/model.dart'; |
| 33 |
| 34 /** |
| 35 * The [ResultCachingPolicy] for ASTs. |
| 36 */ |
| 37 const ResultCachingPolicy AST_CACHING_POLICY = |
| 38 const SimpleResultCachingPolicy(8192, 8192); |
| 39 |
| 40 /** |
| 41 * The [ResultCachingPolicy] for [Element]s. |
| 42 */ |
| 43 const ResultCachingPolicy ELEMENT_CACHING_POLICY = |
| 44 const SimpleResultCachingPolicy(-1, -1); |
| 45 |
| 46 /** |
| 47 * The [ResultCachingPolicy] for [TOKEN_STREAM]. |
| 48 */ |
| 49 const ResultCachingPolicy TOKEN_STREAM_CACHING_POLICY = |
| 50 const SimpleResultCachingPolicy(1, 1); |
| 51 |
| 52 /** |
| 53 * The errors produced while resolving a library directives. |
| 54 * |
| 55 * The list will be empty if there were no errors, but will not be `null`. |
| 56 * |
| 57 * The result is only available for [Source]s representing a library. |
| 58 */ |
| 59 final ListResultDescriptor<AnalysisError> BUILD_DIRECTIVES_ERRORS = |
| 60 new ListResultDescriptor<AnalysisError>( |
| 61 'BUILD_DIRECTIVES_ERRORS', AnalysisError.NO_ERRORS); |
| 62 |
| 63 /** |
| 64 * The errors produced while building a library element. |
| 65 * |
| 66 * The list will be empty if there were no errors, but will not be `null`. |
| 67 * |
| 68 * The result is only available for [Source]s representing a library. |
| 69 */ |
| 70 final ListResultDescriptor<AnalysisError> BUILD_LIBRARY_ERRORS = |
| 71 new ListResultDescriptor<AnalysisError>( |
| 72 'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS); |
| 73 |
| 74 /** |
| 75 * A list of the [ClassElement]s representing the classes defined in a |
| 76 * compilation unit. |
| 77 * |
| 78 * The result is only available for [LibrarySpecificUnit]s, and only when strong |
| 79 * mode is enabled. |
| 80 */ |
| 81 final ListResultDescriptor<ClassElement> CLASSES_IN_UNIT = |
| 82 new ListResultDescriptor<ClassElement>('CLASSES_IN_UNIT', null); |
| 83 |
| 84 /** |
| 85 * A list of the [ConstantEvaluationTarget]s defined in a unit. This includes |
| 86 * constants defined at top level, statically inside classes, and local to |
| 87 * functions, as well as constant constructors, annotations, and default values |
| 88 * of parameters to constant constructors. |
| 89 */ |
| 90 final ListResultDescriptor< |
| 91 ConstantEvaluationTarget> COMPILATION_UNIT_CONSTANTS = |
| 92 new ListResultDescriptor<ConstantEvaluationTarget>( |
| 93 'COMPILATION_UNIT_CONSTANTS', null, |
| 94 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 95 |
| 96 /** |
| 97 * The element model associated with a single compilation unit. |
| 98 * |
| 99 * The result is only available for [LibrarySpecificUnit]s. |
| 100 */ |
| 101 final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT = |
| 102 new ResultDescriptor<CompilationUnitElement>( |
| 103 'COMPILATION_UNIT_ELEMENT', null, |
| 104 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 105 |
| 106 /** |
| 107 * The list of [ConstantEvaluationTarget]s on which the target constant element |
| 108 * depends. |
| 109 * |
| 110 * The result is only available for targets representing a |
| 111 * [ConstantEvaluationTarget] (i.e. a constant variable declaration, a constant |
| 112 * constructor, or a parameter element with a default value). |
| 113 */ |
| 114 final ListResultDescriptor<ConstantEvaluationTarget> CONSTANT_DEPENDENCIES = |
| 115 new ListResultDescriptor<ConstantEvaluationTarget>( |
| 116 'CONSTANT_DEPENDENCIES', const <ConstantEvaluationTarget>[]); |
| 117 |
| 118 /** |
| 119 * A [ConstantEvaluationTarget] that has been successfully constant-evaluated. |
| 120 * |
| 121 * TODO(paulberry): is ELEMENT_CACHING_POLICY the correct caching policy? |
| 122 */ |
| 123 final ResultDescriptor<ConstantEvaluationTarget> CONSTANT_VALUE = |
| 124 new ResultDescriptor<ConstantEvaluationTarget>('CONSTANT_VALUE', null, |
| 125 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 126 |
| 127 /** |
| 128 * The sources representing the libraries that include a given source as a part. |
| 129 * |
| 130 * The result is only available for [Source]s representing a compilation unit. |
| 131 */ |
| 132 final ListResultDescriptor<Source> CONTAINING_LIBRARIES = |
| 133 new ListResultDescriptor<Source>('CONTAINING_LIBRARIES', Source.EMPTY_LIST); |
| 134 |
| 135 /** |
| 136 * The sources representing the export closure of a library. |
| 137 * The [Source]s include only library sources, not their units. |
| 138 * |
| 139 * The result is only available for [Source]s representing a library. |
| 140 */ |
| 141 final ListResultDescriptor<Source> EXPORT_SOURCE_CLOSURE = |
| 142 new ListResultDescriptor<Source>('EXPORT_SOURCE_CLOSURE', null); |
| 143 |
| 144 /** |
| 145 * The errors produced while generating hints a compilation unit. |
| 146 * |
| 147 * The list will be empty if there were no errors, but will not be `null`. |
| 148 * |
| 149 * The result is only available for [LibrarySpecificUnit]s. |
| 150 */ |
| 151 final ListResultDescriptor<AnalysisError> HINTS = |
| 152 new ListResultDescriptor<AnalysisError>( |
| 153 'HINT_ERRORS', AnalysisError.NO_ERRORS); |
| 154 |
| 155 /** |
| 156 * The sources representing the combined import/export closure of a library. |
| 157 * The [Source]s include only library sources, not their units. |
| 158 * |
| 159 * The result is only available for [Source]s representing a library. |
| 160 */ |
| 161 final ListResultDescriptor<Source> IMPORT_EXPORT_SOURCE_CLOSURE = |
| 162 new ListResultDescriptor<Source>('IMPORT_EXPORT_SOURCE_CLOSURE', null); |
| 163 |
| 164 /** |
| 165 * A list of the [VariableElement]s whose type should be inferred that another |
| 166 * inferable static variable (the target) depends on. |
| 167 * |
| 168 * The result is only available for [VariableElement]s, and only when strong |
| 169 * mode is enabled. |
| 170 */ |
| 171 final ListResultDescriptor< |
| 172 VariableElement> INFERABLE_STATIC_VARIABLE_DEPENDENCIES = |
| 173 new ListResultDescriptor<VariableElement>( |
| 174 'INFERABLE_STATIC_VARIABLE_DEPENDENCIES', null); |
| 175 |
| 176 /** |
| 177 * A list of the [VariableElement]s defined in a unit whose type should be |
| 178 * inferred. This includes variables defined at the library level as well as |
| 179 * static members inside classes. |
| 180 * |
| 181 * The result is only available for [LibrarySpecificUnit]s, and only when strong |
| 182 * mode is enabled. |
| 183 */ |
| 184 final ListResultDescriptor<VariableElement> INFERABLE_STATIC_VARIABLES_IN_UNIT = |
| 185 new ListResultDescriptor<VariableElement>( |
| 186 'INFERABLE_STATIC_VARIABLES_IN_UNIT', null); |
| 187 |
| 188 /** |
| 189 * An inferrable static variable ([VariableElement]) whose type has been |
| 190 * inferred. |
| 191 */ |
| 192 final ResultDescriptor<VariableElement> INFERRED_STATIC_VARIABLE = |
| 193 new ResultDescriptor<VariableElement>('INFERRED_STATIC_VARIABLE', null, |
| 194 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 195 |
| 196 /** |
| 197 * The partial [LibraryElement] associated with a library. |
| 198 * |
| 199 * The [LibraryElement] and its [CompilationUnitElement]s are attached to each |
| 200 * other. Directives 'library', 'part' and 'part of' are resolved. |
| 201 * |
| 202 * The result is only available for [Source]s representing a library. |
| 203 */ |
| 204 final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT1 = |
| 205 new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT1', null, |
| 206 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 207 |
| 208 /** |
| 209 * The partial [LibraryElement] associated with a library. |
| 210 * |
| 211 * In addition to [LIBRARY_ELEMENT1] [LibraryElement.imports] and |
| 212 * [LibraryElement.exports] are set. |
| 213 * |
| 214 * The result is only available for [Source]s representing a library. |
| 215 */ |
| 216 final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT2 = |
| 217 new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT2', null, |
| 218 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 219 |
| 220 /** |
| 221 * The partial [LibraryElement] associated with a library. |
| 222 * |
| 223 * In addition to [LIBRARY_ELEMENT2] the [LibraryElement.publicNamespace] is set
. |
| 224 * |
| 225 * The result is only available for [Source]s representing a library. |
| 226 */ |
| 227 final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT3 = |
| 228 new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT3', null, |
| 229 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 230 |
| 231 /** |
| 232 * The partial [LibraryElement] associated with a library. |
| 233 * |
| 234 * In addition to [LIBRARY_ELEMENT3] the [LibraryElement.entryPoint] is set, |
| 235 * if the library does not declare one already and one of the exported |
| 236 * libraries exports one. |
| 237 * |
| 238 * Also [LibraryElement.exportNamespace] is set. |
| 239 * |
| 240 * The result is only available for [Source]s representing a library. |
| 241 */ |
| 242 final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT4 = |
| 243 new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT4', null, |
| 244 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 245 |
| 246 /** |
| 247 * The partial [LibraryElement] associated with a library. |
| 248 * |
| 249 * [LIBRARY_ELEMENT4] plus resolved types for every element. |
| 250 * |
| 251 * The result is only available for [Source]s representing a library. |
| 252 */ |
| 253 final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT5 = |
| 254 new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null, |
| 255 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 256 |
| 257 /** |
| 258 * The flag specifying whether all analysis errors are computed in a specific |
| 259 * library. |
| 260 * |
| 261 * The result is only available for [Source]s representing a library. |
| 262 */ |
| 263 final ResultDescriptor<bool> LIBRARY_ERRORS_READY = |
| 264 new ResultDescriptor<bool>('LIBRARY_ERRORS_READY', false); |
| 265 |
| 266 /** |
| 267 * The analysis errors associated with a compilation unit in a specific library. |
| 268 * |
| 269 * The result is only available for [LibrarySpecificUnit]s. |
| 270 */ |
| 271 final ListResultDescriptor<AnalysisError> LIBRARY_UNIT_ERRORS = |
| 272 new ListResultDescriptor<AnalysisError>( |
| 273 'LIBRARY_UNIT_ERRORS', AnalysisError.NO_ERRORS); |
| 274 |
| 275 /** |
| 276 * The errors produced while parsing a compilation unit. |
| 277 * |
| 278 * The list will be empty if there were no errors, but will not be `null`. |
| 279 * |
| 280 * The result is only available for [Source]s representing a compilation unit. |
| 281 */ |
| 282 final ListResultDescriptor<AnalysisError> PARSE_ERRORS = |
| 283 new ListResultDescriptor<AnalysisError>( |
| 284 'PARSE_ERRORS', AnalysisError.NO_ERRORS); |
| 285 |
| 286 /** |
| 287 * The errors produced while resolving references outside of function bodies. |
| 288 * |
| 289 * The list will be empty if there were no errors, but will not be `null`. |
| 290 * |
| 291 * The result is only available for [LibrarySpecificUnit]s. |
| 292 */ |
| 293 final ListResultDescriptor<AnalysisError> PARTIALLY_RESOLVE_REFERENCES_ERRORS = |
| 294 new ListResultDescriptor<AnalysisError>( |
| 295 'PARTIALLY_RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_ERRORS); |
| 296 |
| 297 /** |
| 298 * The names (resolved and not) referenced by a unit. |
| 299 * |
| 300 * The result is only available for [Source]s representing a compilation unit. |
| 301 */ |
| 302 final ResultDescriptor<ReferencedNames> REFERENCED_NAMES = |
| 303 new ResultDescriptor<ReferencedNames>('REFERENCED_NAMES', null); |
| 304 |
| 305 /** |
| 306 * The errors produced while resolving references. |
| 307 * |
| 308 * The list will be empty if there were no errors, but will not be `null`. |
| 309 * |
| 310 * The result is only available for [LibrarySpecificUnit]s. |
| 311 */ |
| 312 final ListResultDescriptor<AnalysisError> RESOLVE_REFERENCES_ERRORS = |
| 313 new ListResultDescriptor<AnalysisError>( |
| 314 'RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_ERRORS); |
| 315 |
| 316 /** |
| 317 * The errors produced while resolving type names. |
| 318 * |
| 319 * The list will be empty if there were no errors, but will not be `null`. |
| 320 * |
| 321 * The result is only available for [LibrarySpecificUnit]s. |
| 322 */ |
| 323 final ListResultDescriptor<AnalysisError> RESOLVE_TYPE_NAMES_ERRORS = |
| 324 new ListResultDescriptor<AnalysisError>( |
| 325 'RESOLVE_TYPE_NAMES_ERRORS', AnalysisError.NO_ERRORS); |
| 326 |
| 327 /** |
| 328 * The partially resolved [CompilationUnit] associated with a unit. |
| 329 * |
| 330 * All declarations bound to the element defined by the declaration. |
| 331 * |
| 332 * The result is only available for [LibrarySpecificUnit]s. |
| 333 */ |
| 334 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT1 = |
| 335 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT1', null, |
| 336 cachingPolicy: AST_CACHING_POLICY); |
| 337 |
| 338 /** |
| 339 * The partially resolved [CompilationUnit] associated with a unit. |
| 340 * |
| 341 * All the enum member elements are built. |
| 342 * |
| 343 * The result is only available for [LibrarySpecificUnit]s. |
| 344 */ |
| 345 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT2 = |
| 346 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT2', null, |
| 347 cachingPolicy: AST_CACHING_POLICY); |
| 348 |
| 349 /** |
| 350 * The partially resolved [CompilationUnit] associated with a unit. |
| 351 * |
| 352 * [RESOLVED_UNIT2] with resolved type names. |
| 353 * |
| 354 * The result is only available for [LibrarySpecificUnit]s. |
| 355 */ |
| 356 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT3 = |
| 357 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT3', null, |
| 358 cachingPolicy: AST_CACHING_POLICY); |
| 359 |
| 360 /** |
| 361 * The partially resolved [CompilationUnit] associated with a unit. |
| 362 * |
| 363 * [RESOLVED_UNIT3] plus resolved local variables and formal parameters. |
| 364 * |
| 365 * The result is only available for [LibrarySpecificUnit]s. |
| 366 */ |
| 367 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT4 = |
| 368 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null, |
| 369 cachingPolicy: AST_CACHING_POLICY); |
| 370 |
| 371 /** |
| 372 * The resolved [CompilationUnit] associated with a compilation unit in which |
| 373 * elements and types have been initially resolved outside of method bodies in |
| 374 * addition to everything that is true of a [RESOLVED_UNIT4]. |
| 375 * |
| 376 * The result is only available for [LibrarySpecificUnit]s. |
| 377 */ |
| 378 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT5 = |
| 379 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null, |
| 380 cachingPolicy: AST_CACHING_POLICY); |
| 381 |
| 382 /** |
| 383 * The resolved [CompilationUnit] associated with a compilation unit in which |
| 384 * the types of static variables have been inferred in addition to everything |
| 385 * that is true of a [RESOLVED_UNIT5]. |
| 386 * |
| 387 * The result is only available for [LibrarySpecificUnit]s. |
| 388 */ |
| 389 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT6 = |
| 390 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT6', null, |
| 391 cachingPolicy: AST_CACHING_POLICY); |
| 392 |
| 393 /** |
| 394 * The resolved [CompilationUnit] associated with a compilation unit in which |
| 395 * the types of class members have been inferred in addition to everything that |
| 396 * is true of a [RESOLVED_UNIT7]. |
| 397 * |
| 398 * The result is only available for [LibrarySpecificUnit]s. |
| 399 */ |
| 400 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT7 = |
| 401 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT7', null, |
| 402 cachingPolicy: AST_CACHING_POLICY); |
| 403 |
| 404 /** |
| 405 * The resolved [CompilationUnit] associated with a compilation unit, with |
| 406 * constants not yet resolved. |
| 407 * |
| 408 * The result is only available for [LibrarySpecificUnit]s. |
| 409 */ |
| 410 final ResultDescriptor<CompilationUnit> RESOLVED_UNIT8 = |
| 411 new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT8', null, |
| 412 cachingPolicy: AST_CACHING_POLICY); |
| 413 |
| 414 /** |
| 415 * The errors produced while scanning a compilation unit. |
| 416 * |
| 417 * The list will be empty if there were no errors, but will not be `null`. |
| 418 * |
| 419 * The result is only available for [Source]s representing a compilation unit. |
| 420 */ |
| 421 final ListResultDescriptor<AnalysisError> SCAN_ERRORS = |
| 422 new ListResultDescriptor<AnalysisError>( |
| 423 'SCAN_ERRORS', AnalysisError.NO_ERRORS); |
| 424 |
| 425 /** |
| 426 * The [TypeProvider] of the [AnalysisContext]. |
| 427 */ |
| 428 final ResultDescriptor<TypeProvider> TYPE_PROVIDER = |
| 429 new ResultDescriptor<TypeProvider>('TYPE_PROVIDER', null); |
| 430 |
| 431 /** |
| 432 * The [UsedImportedElements] of a [LibrarySpecificUnit]. |
| 433 */ |
| 434 final ResultDescriptor<UsedImportedElements> USED_IMPORTED_ELEMENTS = |
| 435 new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null, |
| 436 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 437 |
| 438 /** |
| 439 * The [UsedLocalElements] of a [LibrarySpecificUnit]. |
| 440 */ |
| 441 final ResultDescriptor<UsedLocalElements> USED_LOCAL_ELEMENTS = |
| 442 new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null, |
| 443 cachingPolicy: ELEMENT_CACHING_POLICY); |
| 444 |
| 445 /** |
| 446 * The errors produced while resolving variable references in a compilation unit
. |
| 447 * |
| 448 * The list will be empty if there were no errors, but will not be `null`. |
| 449 * |
| 450 * The result is only available for [LibrarySpecificUnit]s. |
| 451 */ |
| 452 final ListResultDescriptor<AnalysisError> VARIABLE_REFERENCE_ERRORS = |
| 453 new ListResultDescriptor<AnalysisError>( |
| 454 'VARIABLE_REFERENCE_ERRORS', AnalysisError.NO_ERRORS); |
| 455 |
| 456 /** |
| 457 * The errors produced while verifying a compilation unit. |
| 458 * |
| 459 * The list will be empty if there were no errors, but will not be `null`. |
| 460 * |
| 461 * The result is only available for [LibrarySpecificUnit]s. |
| 462 */ |
| 463 final ListResultDescriptor<AnalysisError> VERIFY_ERRORS = |
| 464 new ListResultDescriptor<AnalysisError>( |
| 465 'VERIFY_ERRORS', AnalysisError.NO_ERRORS); |
| 466 |
| 467 /** |
| 468 * Return a list of errors containing the errors from the given [errors] list |
| 469 * but with duplications removed. |
| 470 */ |
| 471 List<AnalysisError> removeDuplicateErrors(List<AnalysisError> errors) { |
| 472 if (errors.isEmpty) { |
| 473 return errors; |
| 474 } |
| 475 return errors.toSet().toList(); |
| 476 } |
| 477 |
| 478 /** |
| 479 * A task that builds a compilation unit element for a single compilation unit. |
| 480 */ |
| 481 class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask { |
| 482 /** |
| 483 * The name of the input whose value is the AST for the compilation unit. |
| 484 */ |
| 485 static const String PARSED_UNIT_INPUT_NAME = 'PARSED_UNIT_INPUT_NAME'; |
| 486 |
| 487 /** |
| 488 * The task descriptor describing this kind of task. |
| 489 */ |
| 490 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 491 'BuildCompilationUnitElementTask', |
| 492 createTask, |
| 493 buildInputs, <ResultDescriptor>[ |
| 494 COMPILATION_UNIT_CONSTANTS, |
| 495 COMPILATION_UNIT_ELEMENT, |
| 496 RESOLVED_UNIT1 |
| 497 ]); |
| 498 |
| 499 /** |
| 500 * Initialize a newly created task to build a compilation unit element for |
| 501 * the given [target] in the given [context]. |
| 502 */ |
| 503 BuildCompilationUnitElementTask( |
| 504 InternalAnalysisContext context, AnalysisTarget target) |
| 505 : super(context, target); |
| 506 |
| 507 @override |
| 508 TaskDescriptor get descriptor => DESCRIPTOR; |
| 509 |
| 510 @override |
| 511 void internalPerform() { |
| 512 // |
| 513 // Prepare inputs. |
| 514 // |
| 515 LibrarySpecificUnit librarySpecificUnit = target; |
| 516 Source source = getRequiredSource(); |
| 517 CompilationUnit unit = getRequiredInput(PARSED_UNIT_INPUT_NAME); |
| 518 // |
| 519 // Build or reuse CompilationUnitElement. |
| 520 // |
| 521 unit = AstCloner.clone(unit); |
| 522 AnalysisCache analysisCache = |
| 523 (context as InternalAnalysisContext).analysisCache; |
| 524 CompilationUnitElement element = |
| 525 analysisCache.getValue(target, COMPILATION_UNIT_ELEMENT); |
| 526 if (element == null) { |
| 527 CompilationUnitBuilder builder = new CompilationUnitBuilder(); |
| 528 element = builder.buildCompilationUnit( |
| 529 source, unit, librarySpecificUnit.library); |
| 530 } else { |
| 531 new DeclarationResolver().resolve(unit, element); |
| 532 } |
| 533 // |
| 534 // Prepare constants. |
| 535 // |
| 536 ConstantFinder constantFinder = |
| 537 new ConstantFinder(context, source, librarySpecificUnit.library); |
| 538 unit.accept(constantFinder); |
| 539 List<ConstantEvaluationTarget> constants = new List< |
| 540 ConstantEvaluationTarget>.from(constantFinder.constantsToCompute); |
| 541 // |
| 542 // Record outputs. |
| 543 // |
| 544 outputs[COMPILATION_UNIT_CONSTANTS] = constants; |
| 545 outputs[COMPILATION_UNIT_ELEMENT] = element; |
| 546 outputs[RESOLVED_UNIT1] = unit; |
| 547 } |
| 548 |
| 549 /** |
| 550 * Return a map from the names of the inputs of this kind of task to the task |
| 551 * input descriptors describing those inputs for a task with the given |
| 552 * [target]. |
| 553 */ |
| 554 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 555 LibrarySpecificUnit unit = target; |
| 556 return <String, TaskInput>{ |
| 557 PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit) |
| 558 }; |
| 559 } |
| 560 |
| 561 /** |
| 562 * Create a [BuildCompilationUnitElementTask] based on the given [target] in |
| 563 * the given [context]. |
| 564 */ |
| 565 static BuildCompilationUnitElementTask createTask( |
| 566 AnalysisContext context, AnalysisTarget target) { |
| 567 return new BuildCompilationUnitElementTask(context, target); |
| 568 } |
| 569 } |
| 570 |
| 571 /** |
| 572 * A task that builds imports and export directive elements for a library. |
| 573 */ |
| 574 class BuildDirectiveElementsTask extends SourceBasedAnalysisTask { |
| 575 /** |
| 576 * The name of the input whose value is the defining [LIBRARY_ELEMENT1]. |
| 577 */ |
| 578 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 579 |
| 580 /** |
| 581 * The name of the input for [RESOLVED_UNIT1] of a library unit. |
| 582 */ |
| 583 static const String UNIT_INPUT_NAME = 'UNIT_INPUT_NAME'; |
| 584 |
| 585 /** |
| 586 * The input with a list of [LIBRARY_ELEMENT3]s of imported libraries. |
| 587 */ |
| 588 static const String IMPORTS_LIBRARY_ELEMENT_INPUT_NAME = |
| 589 'IMPORTS_LIBRARY_ELEMENT1_INPUT_NAME'; |
| 590 |
| 591 /** |
| 592 * The input with a list of [LIBRARY_ELEMENT3]s of exported libraries. |
| 593 */ |
| 594 static const String EXPORTS_LIBRARY_ELEMENT_INPUT_NAME = |
| 595 'EXPORTS_LIBRARY_ELEMENT_INPUT_NAME'; |
| 596 |
| 597 /** |
| 598 * The input with a list of [SOURCE_KIND]s of imported libraries. |
| 599 */ |
| 600 static const String IMPORTS_SOURCE_KIND_INPUT_NAME = |
| 601 'IMPORTS_SOURCE_KIND_INPUT_NAME'; |
| 602 |
| 603 /** |
| 604 * The input with a list of [SOURCE_KIND]s of exported libraries. |
| 605 */ |
| 606 static const String EXPORTS_SOURCE_KIND_INPUT_NAME = |
| 607 'EXPORTS_SOURCE_KIND_INPUT_NAME'; |
| 608 |
| 609 /** |
| 610 * The task descriptor describing this kind of task. |
| 611 */ |
| 612 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 613 'BuildDirectiveElementsTask', |
| 614 createTask, |
| 615 buildInputs, |
| 616 <ResultDescriptor>[LIBRARY_ELEMENT2, BUILD_DIRECTIVES_ERRORS]); |
| 617 |
| 618 BuildDirectiveElementsTask( |
| 619 InternalAnalysisContext context, AnalysisTarget target) |
| 620 : super(context, target); |
| 621 |
| 622 @override |
| 623 TaskDescriptor get descriptor => DESCRIPTOR; |
| 624 |
| 625 @override |
| 626 void internalPerform() { |
| 627 List<AnalysisError> errors = <AnalysisError>[]; |
| 628 // |
| 629 // Prepare inputs. |
| 630 // |
| 631 LibraryElementImpl libraryElement = getRequiredInput(LIBRARY_INPUT); |
| 632 CompilationUnit libraryUnit = getRequiredInput(UNIT_INPUT_NAME); |
| 633 Map<Source, LibraryElement> importLibraryMap = |
| 634 getRequiredInput(IMPORTS_LIBRARY_ELEMENT_INPUT_NAME); |
| 635 Map<Source, LibraryElement> exportLibraryMap = |
| 636 getRequiredInput(EXPORTS_LIBRARY_ELEMENT_INPUT_NAME); |
| 637 Map<Source, SourceKind> importSourceKindMap = |
| 638 getRequiredInput(IMPORTS_SOURCE_KIND_INPUT_NAME); |
| 639 Map<Source, SourceKind> exportSourceKindMap = |
| 640 getRequiredInput(EXPORTS_SOURCE_KIND_INPUT_NAME); |
| 641 Source librarySource = libraryElement.source; |
| 642 // |
| 643 // Resolve directives. |
| 644 // |
| 645 HashMap<String, PrefixElementImpl> nameToPrefixMap = |
| 646 new HashMap<String, PrefixElementImpl>(); |
| 647 List<ImportElement> imports = <ImportElement>[]; |
| 648 List<ExportElement> exports = <ExportElement>[]; |
| 649 bool explicitlyImportsCore = false; |
| 650 for (Directive directive in libraryUnit.directives) { |
| 651 if (directive is ImportDirective) { |
| 652 ImportDirective importDirective = directive; |
| 653 String uriContent = importDirective.uriContent; |
| 654 if (DartUriResolver.isDartExtUri(uriContent)) { |
| 655 libraryElement.hasExtUri = true; |
| 656 } |
| 657 Source importedSource = importDirective.source; |
| 658 if (importedSource != null && context.exists(importedSource)) { |
| 659 // The imported source will be null if the URI in the import |
| 660 // directive was invalid. |
| 661 LibraryElement importedLibrary = importLibraryMap[importedSource]; |
| 662 if (importedLibrary != null) { |
| 663 if (importedLibrary.isDartCore) { |
| 664 explicitlyImportsCore = true; |
| 665 } |
| 666 ImportElementImpl importElement = |
| 667 new ImportElementImpl(directive.offset); |
| 668 StringLiteral uriLiteral = importDirective.uri; |
| 669 if (uriLiteral != null) { |
| 670 importElement.uriOffset = uriLiteral.offset; |
| 671 importElement.uriEnd = uriLiteral.end; |
| 672 } |
| 673 importElement.uri = uriContent; |
| 674 importElement.deferred = importDirective.deferredKeyword != null; |
| 675 importElement.combinators = _buildCombinators(importDirective); |
| 676 importElement.importedLibrary = importedLibrary; |
| 677 SimpleIdentifier prefixNode = directive.prefix; |
| 678 if (prefixNode != null) { |
| 679 importElement.prefixOffset = prefixNode.offset; |
| 680 String prefixName = prefixNode.name; |
| 681 PrefixElementImpl prefix = nameToPrefixMap[prefixName]; |
| 682 if (prefix == null) { |
| 683 prefix = new PrefixElementImpl.forNode(prefixNode); |
| 684 nameToPrefixMap[prefixName] = prefix; |
| 685 } |
| 686 importElement.prefix = prefix; |
| 687 prefixNode.staticElement = prefix; |
| 688 } |
| 689 directive.element = importElement; |
| 690 imports.add(importElement); |
| 691 if (importSourceKindMap[importedSource] != SourceKind.LIBRARY) { |
| 692 ErrorCode errorCode = (importElement.isDeferred |
| 693 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY |
| 694 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); |
| 695 errors.add(new AnalysisError(importedSource, uriLiteral.offset, |
| 696 uriLiteral.length, errorCode, [uriLiteral.toSource()])); |
| 697 } |
| 698 } |
| 699 } |
| 700 } else if (directive is ExportDirective) { |
| 701 ExportDirective exportDirective = directive; |
| 702 Source exportedSource = exportDirective.source; |
| 703 if (exportedSource != null && context.exists(exportedSource)) { |
| 704 // The exported source will be null if the URI in the export |
| 705 // directive was invalid. |
| 706 LibraryElement exportedLibrary = exportLibraryMap[exportedSource]; |
| 707 if (exportedLibrary != null) { |
| 708 ExportElementImpl exportElement = |
| 709 new ExportElementImpl(directive.offset); |
| 710 StringLiteral uriLiteral = exportDirective.uri; |
| 711 if (uriLiteral != null) { |
| 712 exportElement.uriOffset = uriLiteral.offset; |
| 713 exportElement.uriEnd = uriLiteral.end; |
| 714 } |
| 715 exportElement.uri = exportDirective.uriContent; |
| 716 exportElement.combinators = _buildCombinators(exportDirective); |
| 717 exportElement.exportedLibrary = exportedLibrary; |
| 718 directive.element = exportElement; |
| 719 exports.add(exportElement); |
| 720 if (exportSourceKindMap[exportedSource] != SourceKind.LIBRARY) { |
| 721 errors.add(new AnalysisError( |
| 722 exportedSource, |
| 723 uriLiteral.offset, |
| 724 uriLiteral.length, |
| 725 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, |
| 726 [uriLiteral.toSource()])); |
| 727 } |
| 728 } |
| 729 } |
| 730 } |
| 731 } |
| 732 // |
| 733 // Ensure "dart:core" import. |
| 734 // |
| 735 Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE); |
| 736 if (!explicitlyImportsCore && coreLibrarySource != librarySource) { |
| 737 ImportElementImpl importElement = new ImportElementImpl(-1); |
| 738 importElement.importedLibrary = importLibraryMap[coreLibrarySource]; |
| 739 importElement.synthetic = true; |
| 740 imports.add(importElement); |
| 741 } |
| 742 // |
| 743 // Populate the library element. |
| 744 // |
| 745 libraryElement.imports = imports; |
| 746 libraryElement.exports = exports; |
| 747 // |
| 748 // Record outputs. |
| 749 // |
| 750 outputs[LIBRARY_ELEMENT2] = libraryElement; |
| 751 outputs[BUILD_DIRECTIVES_ERRORS] = errors; |
| 752 } |
| 753 |
| 754 /** |
| 755 * Return a map from the names of the inputs of this kind of task to the task |
| 756 * input descriptors describing those inputs for a task with the |
| 757 * given library [libSource]. |
| 758 */ |
| 759 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 760 Source source = target; |
| 761 return <String, TaskInput>{ |
| 762 LIBRARY_INPUT: LIBRARY_ELEMENT1.of(source), |
| 763 UNIT_INPUT_NAME: |
| 764 RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)), |
| 765 IMPORTS_LIBRARY_ELEMENT_INPUT_NAME: |
| 766 IMPORTED_LIBRARIES.of(source).toMapOf(LIBRARY_ELEMENT1), |
| 767 EXPORTS_LIBRARY_ELEMENT_INPUT_NAME: |
| 768 EXPORTED_LIBRARIES.of(source).toMapOf(LIBRARY_ELEMENT1), |
| 769 IMPORTS_SOURCE_KIND_INPUT_NAME: |
| 770 IMPORTED_LIBRARIES.of(source).toMapOf(SOURCE_KIND), |
| 771 EXPORTS_SOURCE_KIND_INPUT_NAME: |
| 772 EXPORTED_LIBRARIES.of(source).toMapOf(SOURCE_KIND) |
| 773 }; |
| 774 } |
| 775 |
| 776 /** |
| 777 * Create a [BuildDirectiveElementsTask] based on the given [target] in |
| 778 * the given [context]. |
| 779 */ |
| 780 static BuildDirectiveElementsTask createTask( |
| 781 AnalysisContext context, AnalysisTarget target) { |
| 782 return new BuildDirectiveElementsTask(context, target); |
| 783 } |
| 784 |
| 785 /** |
| 786 * Build the element model representing the combinators declared by |
| 787 * the given [directive]. |
| 788 */ |
| 789 static List<NamespaceCombinator> _buildCombinators( |
| 790 NamespaceDirective directive) { |
| 791 List<NamespaceCombinator> combinators = <NamespaceCombinator>[]; |
| 792 for (Combinator combinator in directive.combinators) { |
| 793 if (combinator is ShowCombinator) { |
| 794 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); |
| 795 show.offset = combinator.offset; |
| 796 show.end = combinator.end; |
| 797 show.shownNames = _getIdentifiers(combinator.shownNames); |
| 798 combinators.add(show); |
| 799 } else if (combinator is HideCombinator) { |
| 800 HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); |
| 801 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames); |
| 802 combinators.add(hide); |
| 803 } |
| 804 } |
| 805 return combinators; |
| 806 } |
| 807 |
| 808 /** |
| 809 * Return the lexical identifiers associated with the given [identifiers]. |
| 810 */ |
| 811 static List<String> _getIdentifiers(NodeList<SimpleIdentifier> identifiers) { |
| 812 return identifiers.map((identifier) => identifier.name).toList(); |
| 813 } |
| 814 } |
| 815 |
| 816 /** |
| 817 * A task that builds the elements representing the members of enum |
| 818 * declarations. |
| 819 */ |
| 820 class BuildEnumMemberElementsTask extends SourceBasedAnalysisTask { |
| 821 /** |
| 822 * The name of the [TYPE_PROVIDER] input. |
| 823 */ |
| 824 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 825 |
| 826 /** |
| 827 * The name of the [RESOLVED_UNIT1] input. |
| 828 */ |
| 829 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 830 |
| 831 /** |
| 832 * The task descriptor describing this kind of task. |
| 833 */ |
| 834 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 835 'BuildEnumMemberElementsTask', |
| 836 createTask, |
| 837 buildInputs, |
| 838 <ResultDescriptor>[RESOLVED_UNIT2]); |
| 839 |
| 840 BuildEnumMemberElementsTask( |
| 841 InternalAnalysisContext context, AnalysisTarget target) |
| 842 : super(context, target); |
| 843 |
| 844 @override |
| 845 TaskDescriptor get descriptor => DESCRIPTOR; |
| 846 |
| 847 @override |
| 848 void internalPerform() { |
| 849 // |
| 850 // Prepare inputs. |
| 851 // |
| 852 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 853 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 854 // |
| 855 // Record outputs. |
| 856 // |
| 857 EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider); |
| 858 unit.accept(builder); |
| 859 outputs[RESOLVED_UNIT2] = unit; |
| 860 } |
| 861 |
| 862 /** |
| 863 * Return a map from the names of the inputs of this kind of task to the task |
| 864 * input descriptors describing those inputs for a task with the |
| 865 * given [target]. |
| 866 */ |
| 867 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 868 LibrarySpecificUnit unit = target; |
| 869 return <String, TaskInput>{ |
| 870 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request), |
| 871 UNIT_INPUT: RESOLVED_UNIT1.of(unit) |
| 872 }; |
| 873 } |
| 874 |
| 875 /** |
| 876 * Create a [BuildEnumMemberElementsTask] based on the given [target] in |
| 877 * the given [context]. |
| 878 */ |
| 879 static BuildEnumMemberElementsTask createTask( |
| 880 AnalysisContext context, AnalysisTarget target) { |
| 881 return new BuildEnumMemberElementsTask(context, target); |
| 882 } |
| 883 } |
| 884 |
| 885 /** |
| 886 * A task that builds [EXPORT_NAMESPACE] and [LIBRARY_ELEMENT4] for a library. |
| 887 */ |
| 888 class BuildExportNamespaceTask extends SourceBasedAnalysisTask { |
| 889 /** |
| 890 * The name of the input for [LIBRARY_ELEMENT3] of a library. |
| 891 */ |
| 892 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 893 |
| 894 /** |
| 895 * The task descriptor describing this kind of task. |
| 896 */ |
| 897 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 898 'BuildExportNamespaceTask', |
| 899 createTask, |
| 900 buildInputs, |
| 901 <ResultDescriptor>[LIBRARY_ELEMENT4]); |
| 902 |
| 903 BuildExportNamespaceTask( |
| 904 InternalAnalysisContext context, AnalysisTarget target) |
| 905 : super(context, target); |
| 906 |
| 907 @override |
| 908 TaskDescriptor get descriptor => DESCRIPTOR; |
| 909 |
| 910 @override |
| 911 void internalPerform() { |
| 912 LibraryElementImpl library = getRequiredInput(LIBRARY_INPUT); |
| 913 // |
| 914 // Compute export namespace. |
| 915 // |
| 916 ExportNamespaceBuilder builder = new ExportNamespaceBuilder(); |
| 917 Namespace namespace = builder.build(library); |
| 918 library.exportNamespace = namespace; |
| 919 // |
| 920 // Update entry point. |
| 921 // |
| 922 if (library.entryPoint == null) { |
| 923 Iterable<Element> exportedElements = namespace.definedNames.values; |
| 924 library.entryPoint = exportedElements.firstWhere( |
| 925 (element) => element is FunctionElement && element.isEntryPoint, |
| 926 orElse: () => null); |
| 927 } |
| 928 // |
| 929 // Record outputs. |
| 930 // |
| 931 outputs[LIBRARY_ELEMENT4] = library; |
| 932 } |
| 933 |
| 934 /** |
| 935 * Return a map from the names of the inputs of this kind of task to the task |
| 936 * input descriptors describing those inputs for a task with the |
| 937 * given library [libSource]. |
| 938 */ |
| 939 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 940 Source source = target; |
| 941 return <String, TaskInput>{ |
| 942 LIBRARY_INPUT: LIBRARY_ELEMENT3.of(source), |
| 943 'exportsLibraryPublicNamespace': |
| 944 EXPORT_SOURCE_CLOSURE.of(source).toMapOf(LIBRARY_ELEMENT3) |
| 945 }; |
| 946 } |
| 947 |
| 948 /** |
| 949 * Create a [BuildExportNamespaceTask] based on the given [target] in |
| 950 * the given [context]. |
| 951 */ |
| 952 static BuildExportNamespaceTask createTask( |
| 953 AnalysisContext context, AnalysisTarget target) { |
| 954 return new BuildExportNamespaceTask(context, target); |
| 955 } |
| 956 } |
| 957 |
| 958 /** |
| 959 * A task that builds a library element for a Dart library. |
| 960 */ |
| 961 class BuildLibraryElementTask extends SourceBasedAnalysisTask { |
| 962 /** |
| 963 * The name of the input whose value is the defining [RESOLVED_UNIT1]. |
| 964 */ |
| 965 static const String DEFINING_UNIT_INPUT = 'DEFINING_UNIT_INPUT'; |
| 966 |
| 967 /** |
| 968 * The name of the input whose value is a list of built [RESOLVED_UNIT1]s |
| 969 * of the parts sourced by a library. |
| 970 */ |
| 971 static const String PARTS_UNIT_INPUT = 'PARTS_UNIT_INPUT'; |
| 972 |
| 973 /** |
| 974 * The task descriptor describing this kind of task. |
| 975 */ |
| 976 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 977 'BuildLibraryElementTask', createTask, buildInputs, <ResultDescriptor>[ |
| 978 BUILD_LIBRARY_ERRORS, |
| 979 LIBRARY_ELEMENT1, |
| 980 IS_LAUNCHABLE |
| 981 ]); |
| 982 |
| 983 /** |
| 984 * The constant used as an unknown common library name in parts. |
| 985 */ |
| 986 static const String _UNKNOWN_LIBRARY_NAME = 'unknown-library-name'; |
| 987 |
| 988 /** |
| 989 * Initialize a newly created task to build a library element for the given |
| 990 * [target] in the given [context]. |
| 991 */ |
| 992 BuildLibraryElementTask( |
| 993 InternalAnalysisContext context, AnalysisTarget target) |
| 994 : super(context, target); |
| 995 |
| 996 @override |
| 997 TaskDescriptor get descriptor => DESCRIPTOR; |
| 998 |
| 999 @override |
| 1000 void internalPerform() { |
| 1001 List<AnalysisError> errors = <AnalysisError>[]; |
| 1002 // |
| 1003 // Prepare inputs. |
| 1004 // |
| 1005 Source librarySource = getRequiredSource(); |
| 1006 CompilationUnit definingCompilationUnit = |
| 1007 getRequiredInput(DEFINING_UNIT_INPUT); |
| 1008 List<CompilationUnit> partUnits = getRequiredInput(PARTS_UNIT_INPUT); |
| 1009 // |
| 1010 // Process inputs. |
| 1011 // |
| 1012 CompilationUnitElementImpl definingCompilationUnitElement = |
| 1013 definingCompilationUnit.element; |
| 1014 Map<Source, CompilationUnit> partUnitMap = |
| 1015 new HashMap<Source, CompilationUnit>(); |
| 1016 for (CompilationUnit partUnit in partUnits) { |
| 1017 Source partSource = partUnit.element.source; |
| 1018 partUnitMap[partSource] = partUnit; |
| 1019 } |
| 1020 // |
| 1021 // Update "part" directives. |
| 1022 // |
| 1023 LibraryIdentifier libraryNameNode = null; |
| 1024 String partsLibraryName = _UNKNOWN_LIBRARY_NAME; |
| 1025 bool hasPartDirective = false; |
| 1026 FunctionElement entryPoint = |
| 1027 _findEntryPoint(definingCompilationUnitElement); |
| 1028 List<Directive> directivesToResolve = <Directive>[]; |
| 1029 List<CompilationUnitElementImpl> sourcedCompilationUnits = |
| 1030 <CompilationUnitElementImpl>[]; |
| 1031 for (Directive directive in definingCompilationUnit.directives) { |
| 1032 if (directive is LibraryDirective) { |
| 1033 if (libraryNameNode == null) { |
| 1034 libraryNameNode = directive.name; |
| 1035 directivesToResolve.add(directive); |
| 1036 } |
| 1037 } else if (directive is PartDirective) { |
| 1038 PartDirective partDirective = directive; |
| 1039 StringLiteral partUri = partDirective.uri; |
| 1040 Source partSource = partDirective.source; |
| 1041 hasPartDirective = true; |
| 1042 CompilationUnit partUnit = partUnitMap[partSource]; |
| 1043 if (partUnit != null) { |
| 1044 CompilationUnitElementImpl partElement = partUnit.element; |
| 1045 partElement.uriOffset = partUri.offset; |
| 1046 partElement.uriEnd = partUri.end; |
| 1047 partElement.uri = partDirective.uriContent; |
| 1048 // |
| 1049 // Validate that the part contains a part-of directive with the same |
| 1050 // name as the library. |
| 1051 // |
| 1052 if (context.exists(partSource)) { |
| 1053 String partLibraryName = |
| 1054 _getPartLibraryName(partSource, partUnit, directivesToResolve); |
| 1055 if (partLibraryName == null) { |
| 1056 errors.add(new AnalysisError( |
| 1057 librarySource, |
| 1058 partUri.offset, |
| 1059 partUri.length, |
| 1060 CompileTimeErrorCode.PART_OF_NON_PART, |
| 1061 [partUri.toSource()])); |
| 1062 } else if (libraryNameNode == null) { |
| 1063 if (partsLibraryName == _UNKNOWN_LIBRARY_NAME) { |
| 1064 partsLibraryName = partLibraryName; |
| 1065 } else if (partsLibraryName != partLibraryName) { |
| 1066 partsLibraryName = null; |
| 1067 } |
| 1068 } else if (libraryNameNode.name != partLibraryName) { |
| 1069 errors.add(new AnalysisError( |
| 1070 librarySource, |
| 1071 partUri.offset, |
| 1072 partUri.length, |
| 1073 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, |
| 1074 [libraryNameNode.name, partLibraryName])); |
| 1075 } |
| 1076 } |
| 1077 if (entryPoint == null) { |
| 1078 entryPoint = _findEntryPoint(partElement); |
| 1079 } |
| 1080 directive.element = partElement; |
| 1081 sourcedCompilationUnits.add(partElement); |
| 1082 } |
| 1083 } |
| 1084 } |
| 1085 if (hasPartDirective && libraryNameNode == null) { |
| 1086 AnalysisError error; |
| 1087 if (partsLibraryName != _UNKNOWN_LIBRARY_NAME && |
| 1088 partsLibraryName != null) { |
| 1089 error = new AnalysisErrorWithProperties(librarySource, 0, 0, |
| 1090 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART) |
| 1091 ..setProperty(ErrorProperty.PARTS_LIBRARY_NAME, partsLibraryName); |
| 1092 } else { |
| 1093 error = new AnalysisError(librarySource, 0, 0, |
| 1094 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART); |
| 1095 } |
| 1096 errors.add(error); |
| 1097 } |
| 1098 // |
| 1099 // Create and populate the library element. |
| 1100 // |
| 1101 AnalysisContext owningContext = context; |
| 1102 if (context is InternalAnalysisContext) { |
| 1103 InternalAnalysisContext internalContext = context; |
| 1104 owningContext = internalContext.getContextFor(librarySource); |
| 1105 } |
| 1106 LibraryElementImpl libraryElement = |
| 1107 new LibraryElementImpl.forNode(owningContext, libraryNameNode); |
| 1108 libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
| 1109 libraryElement.entryPoint = entryPoint; |
| 1110 libraryElement.parts = sourcedCompilationUnits; |
| 1111 for (Directive directive in directivesToResolve) { |
| 1112 directive.element = libraryElement; |
| 1113 } |
| 1114 if (sourcedCompilationUnits.isNotEmpty) { |
| 1115 _patchTopLevelAccessors(libraryElement); |
| 1116 } |
| 1117 // |
| 1118 // Record outputs. |
| 1119 // |
| 1120 outputs[BUILD_LIBRARY_ERRORS] = errors; |
| 1121 outputs[LIBRARY_ELEMENT1] = libraryElement; |
| 1122 outputs[IS_LAUNCHABLE] = entryPoint != null; |
| 1123 } |
| 1124 |
| 1125 /** |
| 1126 * Add all of the non-synthetic [getters] and [setters] defined in the given |
| 1127 * [unit] that have no corresponding accessor to one of the given collections. |
| 1128 */ |
| 1129 void _collectAccessors(Map<String, PropertyAccessorElement> getters, |
| 1130 List<PropertyAccessorElement> setters, CompilationUnitElement unit) { |
| 1131 for (PropertyAccessorElement accessor in unit.accessors) { |
| 1132 if (accessor.isGetter) { |
| 1133 if (!accessor.isSynthetic && accessor.correspondingSetter == null) { |
| 1134 getters[accessor.displayName] = accessor; |
| 1135 } |
| 1136 } else { |
| 1137 if (!accessor.isSynthetic && accessor.correspondingGetter == null) { |
| 1138 setters.add(accessor); |
| 1139 } |
| 1140 } |
| 1141 } |
| 1142 } |
| 1143 |
| 1144 /** |
| 1145 * Return the top-level [FunctionElement] entry point, or `null` if the given |
| 1146 * [element] does not define an entry point. |
| 1147 */ |
| 1148 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) { |
| 1149 for (FunctionElement function in element.functions) { |
| 1150 if (function.isEntryPoint) { |
| 1151 return function; |
| 1152 } |
| 1153 } |
| 1154 return null; |
| 1155 } |
| 1156 |
| 1157 /** |
| 1158 * Return the name of the library that the given part is declared to be a |
| 1159 * part of, or `null` if the part does not contain a part-of directive. |
| 1160 */ |
| 1161 String _getPartLibraryName(Source partSource, CompilationUnit partUnit, |
| 1162 List<Directive> directivesToResolve) { |
| 1163 for (Directive directive in partUnit.directives) { |
| 1164 if (directive is PartOfDirective) { |
| 1165 directivesToResolve.add(directive); |
| 1166 LibraryIdentifier libraryName = directive.libraryName; |
| 1167 if (libraryName != null) { |
| 1168 return libraryName.name; |
| 1169 } |
| 1170 } |
| 1171 } |
| 1172 return null; |
| 1173 } |
| 1174 |
| 1175 /** |
| 1176 * Look through all of the compilation units defined for the given [library], |
| 1177 * looking for getters and setters that are defined in different compilation |
| 1178 * units but that have the same names. If any are found, make sure that they |
| 1179 * have the same variable element. |
| 1180 */ |
| 1181 void _patchTopLevelAccessors(LibraryElementImpl library) { |
| 1182 HashMap<String, PropertyAccessorElement> getters = |
| 1183 new HashMap<String, PropertyAccessorElement>(); |
| 1184 List<PropertyAccessorElement> setters = <PropertyAccessorElement>[]; |
| 1185 _collectAccessors(getters, setters, library.definingCompilationUnit); |
| 1186 for (CompilationUnitElement unit in library.parts) { |
| 1187 _collectAccessors(getters, setters, unit); |
| 1188 } |
| 1189 for (PropertyAccessorElement setter in setters) { |
| 1190 PropertyAccessorElement getter = getters[setter.displayName]; |
| 1191 if (getter != null) { |
| 1192 TopLevelVariableElementImpl variable = getter.variable; |
| 1193 TopLevelVariableElementImpl setterVariable = setter.variable; |
| 1194 CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement; |
| 1195 setterUnit.replaceTopLevelVariable(setterVariable, variable); |
| 1196 variable.setter = setter; |
| 1197 (setter as PropertyAccessorElementImpl).variable = variable; |
| 1198 } |
| 1199 } |
| 1200 } |
| 1201 |
| 1202 /** |
| 1203 * Return a map from the names of the inputs of this kind of task to the task |
| 1204 * input descriptors describing those inputs for a task with the given |
| 1205 * [libSource]. |
| 1206 */ |
| 1207 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1208 Source source = target; |
| 1209 return <String, TaskInput>{ |
| 1210 DEFINING_UNIT_INPUT: |
| 1211 RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, source)), |
| 1212 PARTS_UNIT_INPUT: INCLUDED_PARTS.of(source).toList((Source unit) { |
| 1213 return RESOLVED_UNIT1.of(new LibrarySpecificUnit(source, unit)); |
| 1214 }) |
| 1215 }; |
| 1216 } |
| 1217 |
| 1218 /** |
| 1219 * Create a [BuildLibraryElementTask] based on the given [target] in the |
| 1220 * given [context]. |
| 1221 */ |
| 1222 static BuildLibraryElementTask createTask( |
| 1223 AnalysisContext context, AnalysisTarget target) { |
| 1224 return new BuildLibraryElementTask(context, target); |
| 1225 } |
| 1226 } |
| 1227 |
| 1228 /** |
| 1229 * A task that builds [PUBLIC_NAMESPACE] for a library. |
| 1230 */ |
| 1231 class BuildPublicNamespaceTask extends SourceBasedAnalysisTask { |
| 1232 /** |
| 1233 * The name of the input for [LIBRARY_ELEMENT2] of a library. |
| 1234 */ |
| 1235 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 1236 |
| 1237 /** |
| 1238 * The task descriptor describing this kind of task. |
| 1239 */ |
| 1240 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1241 'BuildPublicNamespaceTask', |
| 1242 createTask, |
| 1243 buildInputs, |
| 1244 <ResultDescriptor>[LIBRARY_ELEMENT3]); |
| 1245 |
| 1246 BuildPublicNamespaceTask( |
| 1247 InternalAnalysisContext context, AnalysisTarget target) |
| 1248 : super(context, target); |
| 1249 |
| 1250 @override |
| 1251 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1252 |
| 1253 @override |
| 1254 void internalPerform() { |
| 1255 LibraryElementImpl library = getRequiredInput(LIBRARY_INPUT); |
| 1256 library.publicNamespace = new PublicNamespaceBuilder().build(library); |
| 1257 outputs[LIBRARY_ELEMENT3] = library; |
| 1258 } |
| 1259 |
| 1260 /** |
| 1261 * Return a map from the names of the inputs of this kind of task to the task |
| 1262 * input descriptors describing those inputs for a task with the |
| 1263 * given library [libSource]. |
| 1264 */ |
| 1265 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1266 Source source = target; |
| 1267 return <String, TaskInput>{LIBRARY_INPUT: LIBRARY_ELEMENT2.of(source)}; |
| 1268 } |
| 1269 |
| 1270 /** |
| 1271 * Create a [BuildPublicNamespaceTask] based on the given [target] in |
| 1272 * the given [context]. |
| 1273 */ |
| 1274 static BuildPublicNamespaceTask createTask( |
| 1275 AnalysisContext context, AnalysisTarget target) { |
| 1276 return new BuildPublicNamespaceTask(context, target); |
| 1277 } |
| 1278 } |
| 1279 |
| 1280 /** |
| 1281 * A task that builds [EXPORT_SOURCE_CLOSURE] of a library. |
| 1282 */ |
| 1283 class BuildSourceExportClosureTask extends SourceBasedAnalysisTask { |
| 1284 /** |
| 1285 * The name of the export closure. |
| 1286 */ |
| 1287 static const String EXPORT_INPUT = 'EXPORT_INPUT'; |
| 1288 |
| 1289 /** |
| 1290 * The task descriptor describing this kind of task. |
| 1291 */ |
| 1292 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1293 'BuildSourceExportClosureTask', |
| 1294 createTask, |
| 1295 buildInputs, |
| 1296 <ResultDescriptor>[EXPORT_SOURCE_CLOSURE]); |
| 1297 |
| 1298 BuildSourceExportClosureTask( |
| 1299 InternalAnalysisContext context, AnalysisTarget target) |
| 1300 : super(context, target); |
| 1301 |
| 1302 @override |
| 1303 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1304 |
| 1305 @override |
| 1306 void internalPerform() { |
| 1307 List<Source> exportClosure = getRequiredInput(EXPORT_INPUT); |
| 1308 // |
| 1309 // Record output. |
| 1310 // |
| 1311 outputs[EXPORT_SOURCE_CLOSURE] = exportClosure; |
| 1312 } |
| 1313 |
| 1314 /** |
| 1315 * Return a map from the names of the inputs of this kind of task to the task |
| 1316 * input descriptors describing those inputs for a task with the |
| 1317 * given library [libSource]. |
| 1318 */ |
| 1319 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1320 Source source = target; |
| 1321 return <String, TaskInput>{ |
| 1322 EXPORT_INPUT: new _ExportSourceClosureTaskInput(source, LIBRARY_ELEMENT2) |
| 1323 }; |
| 1324 } |
| 1325 |
| 1326 /** |
| 1327 * Create a [BuildSourceExportClosureTask] based on the given [target] in |
| 1328 * the given [context]. |
| 1329 */ |
| 1330 static BuildSourceExportClosureTask createTask( |
| 1331 AnalysisContext context, AnalysisTarget target) { |
| 1332 return new BuildSourceExportClosureTask(context, target); |
| 1333 } |
| 1334 } |
| 1335 |
| 1336 /** |
| 1337 * A task that builds [IMPORT_EXPORT_SOURCE_CLOSURE] of a library, and also |
| 1338 * sets [IS_CLIENT]. |
| 1339 */ |
| 1340 class BuildSourceImportExportClosureTask extends SourceBasedAnalysisTask { |
| 1341 /** |
| 1342 * The name of the import/export closure. |
| 1343 */ |
| 1344 static const String IMPORT_EXPORT_INPUT = 'IMPORT_EXPORT_INPUT'; |
| 1345 |
| 1346 /** |
| 1347 * The task descriptor describing this kind of task. |
| 1348 */ |
| 1349 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1350 'BuildSourceImportExportClosureTask', |
| 1351 createTask, |
| 1352 buildInputs, |
| 1353 <ResultDescriptor>[IMPORT_EXPORT_SOURCE_CLOSURE, IS_CLIENT]); |
| 1354 |
| 1355 BuildSourceImportExportClosureTask( |
| 1356 InternalAnalysisContext context, AnalysisTarget target) |
| 1357 : super(context, target); |
| 1358 |
| 1359 @override |
| 1360 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1361 |
| 1362 @override |
| 1363 void internalPerform() { |
| 1364 List<Source> importExportClosure = getRequiredInput(IMPORT_EXPORT_INPUT); |
| 1365 Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML); |
| 1366 // |
| 1367 // Record outputs. |
| 1368 // |
| 1369 outputs[IMPORT_EXPORT_SOURCE_CLOSURE] = importExportClosure; |
| 1370 outputs[IS_CLIENT] = importExportClosure.contains(htmlSource); |
| 1371 } |
| 1372 |
| 1373 /** |
| 1374 * Return a map from the names of the inputs of this kind of task to the task |
| 1375 * input descriptors describing those inputs for a task with the |
| 1376 * given library [libSource]. |
| 1377 */ |
| 1378 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1379 Source source = target; |
| 1380 return <String, TaskInput>{ |
| 1381 IMPORT_EXPORT_INPUT: |
| 1382 new _ImportExportSourceClosureTaskInput(source, LIBRARY_ELEMENT2) |
| 1383 }; |
| 1384 } |
| 1385 |
| 1386 /** |
| 1387 * Create a [BuildSourceImportExportClosureTask] based on the given [target] |
| 1388 * in the given [context]. |
| 1389 */ |
| 1390 static BuildSourceImportExportClosureTask createTask( |
| 1391 AnalysisContext context, AnalysisTarget target) { |
| 1392 return new BuildSourceImportExportClosureTask(context, target); |
| 1393 } |
| 1394 } |
| 1395 |
| 1396 /** |
| 1397 * A task that builds [TYPE_PROVIDER] for a context. |
| 1398 */ |
| 1399 class BuildTypeProviderTask extends SourceBasedAnalysisTask { |
| 1400 /** |
| 1401 * The [PUBLIC_NAMESPACE] input of the `dart:core` library. |
| 1402 */ |
| 1403 static const String CORE_INPUT = 'CORE_INPUT'; |
| 1404 |
| 1405 /** |
| 1406 * The [PUBLIC_NAMESPACE] input of the `dart:async` library. |
| 1407 */ |
| 1408 static const String ASYNC_INPUT = 'ASYNC_INPUT'; |
| 1409 |
| 1410 /** |
| 1411 * The task descriptor describing this kind of task. |
| 1412 */ |
| 1413 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1414 'BuildTypeProviderTask', |
| 1415 createTask, |
| 1416 buildInputs, |
| 1417 <ResultDescriptor>[TYPE_PROVIDER]); |
| 1418 |
| 1419 BuildTypeProviderTask( |
| 1420 InternalAnalysisContext context, AnalysisContextTarget target) |
| 1421 : super(context, target); |
| 1422 |
| 1423 @override |
| 1424 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1425 |
| 1426 @override |
| 1427 void internalPerform() { |
| 1428 LibraryElement coreLibrary = getRequiredInput(CORE_INPUT); |
| 1429 LibraryElement asyncLibrary = getRequiredInput(ASYNC_INPUT); |
| 1430 Namespace coreNamespace = coreLibrary.publicNamespace; |
| 1431 Namespace asyncNamespace = asyncLibrary.publicNamespace; |
| 1432 // |
| 1433 // Record outputs. |
| 1434 // |
| 1435 TypeProvider typeProvider = |
| 1436 new TypeProviderImpl.forNamespaces(coreNamespace, asyncNamespace); |
| 1437 (context as InternalAnalysisContext).typeProvider = typeProvider; |
| 1438 outputs[TYPE_PROVIDER] = typeProvider; |
| 1439 } |
| 1440 |
| 1441 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1442 AnalysisContextTarget contextTarget = target; |
| 1443 SourceFactory sourceFactory = contextTarget.context.sourceFactory; |
| 1444 Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE); |
| 1445 Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC); |
| 1446 return <String, TaskInput>{ |
| 1447 CORE_INPUT: LIBRARY_ELEMENT3.of(coreSource), |
| 1448 ASYNC_INPUT: LIBRARY_ELEMENT3.of(asyncSource) |
| 1449 }; |
| 1450 } |
| 1451 |
| 1452 /** |
| 1453 * Create a [BuildTypeProviderTask] based on the given [context]. |
| 1454 */ |
| 1455 static BuildTypeProviderTask createTask( |
| 1456 AnalysisContext context, AnalysisTarget target) { |
| 1457 return new BuildTypeProviderTask(context, target); |
| 1458 } |
| 1459 } |
| 1460 |
| 1461 /** |
| 1462 * A task that computes [CONSTANT_DEPENDENCIES] for a constant. |
| 1463 */ |
| 1464 class ComputeConstantDependenciesTask extends ConstantEvaluationAnalysisTask { |
| 1465 /** |
| 1466 * The name of the [RESOLVED_UNIT8] input. |
| 1467 */ |
| 1468 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 1469 |
| 1470 /** |
| 1471 * The name of the [TYPE_PROVIDER] input. |
| 1472 */ |
| 1473 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 1474 |
| 1475 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1476 'ComputeConstantDependenciesTask', |
| 1477 createTask, |
| 1478 buildInputs, |
| 1479 <ResultDescriptor>[CONSTANT_DEPENDENCIES]); |
| 1480 |
| 1481 ComputeConstantDependenciesTask( |
| 1482 InternalAnalysisContext context, ConstantEvaluationTarget constant) |
| 1483 : super(context, constant); |
| 1484 |
| 1485 @override |
| 1486 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1487 |
| 1488 @override |
| 1489 void internalPerform() { |
| 1490 // |
| 1491 // Prepare inputs. |
| 1492 // |
| 1493 // Note: UNIT_INPUT is not needed. It is merely a bookkeeping dependency |
| 1494 // to ensure that resolution has occurred before we attempt to determine |
| 1495 // constant dependencies. |
| 1496 // |
| 1497 ConstantEvaluationTarget constant = target; |
| 1498 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 1499 // |
| 1500 // Compute dependencies. |
| 1501 // |
| 1502 List<ConstantEvaluationTarget> dependencies = <ConstantEvaluationTarget>[]; |
| 1503 new ConstantEvaluationEngine(typeProvider, context.declaredVariables) |
| 1504 .computeDependencies(constant, dependencies.add); |
| 1505 // |
| 1506 // Record outputs. |
| 1507 // |
| 1508 outputs[CONSTANT_DEPENDENCIES] = dependencies; |
| 1509 } |
| 1510 |
| 1511 /** |
| 1512 * Return a map from the names of the inputs of this kind of task to the task |
| 1513 * input descriptors describing those inputs for a task with the |
| 1514 * given [target]. |
| 1515 */ |
| 1516 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1517 if (target is Element) { |
| 1518 CompilationUnitElementImpl unit = target |
| 1519 .getAncestor((Element element) => element is CompilationUnitElement); |
| 1520 return <String, TaskInput>{ |
| 1521 UNIT_INPUT: RESOLVED_UNIT8 |
| 1522 .of(new LibrarySpecificUnit(unit.librarySource, target.source)), |
| 1523 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 1524 }; |
| 1525 } else if (target is ConstantEvaluationTarget_Annotation) { |
| 1526 return <String, TaskInput>{ |
| 1527 UNIT_INPUT: RESOLVED_UNIT8 |
| 1528 .of(new LibrarySpecificUnit(target.librarySource, target.source)), |
| 1529 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 1530 }; |
| 1531 } |
| 1532 throw new AnalysisException( |
| 1533 'Cannot build inputs for a ${target.runtimeType}'); |
| 1534 } |
| 1535 |
| 1536 /** |
| 1537 * Create a [ComputeConstantDependenciesTask] based on the given [target] in |
| 1538 * the given [context]. |
| 1539 */ |
| 1540 static ComputeConstantDependenciesTask createTask( |
| 1541 AnalysisContext context, AnalysisTarget target) { |
| 1542 return new ComputeConstantDependenciesTask(context, target); |
| 1543 } |
| 1544 } |
| 1545 |
| 1546 /** |
| 1547 * A task that computes the value of a constant ([CONSTANT_VALUE]) and |
| 1548 * stores it in the element model. |
| 1549 */ |
| 1550 class ComputeConstantValueTask extends ConstantEvaluationAnalysisTask { |
| 1551 /** |
| 1552 * The name of the input which ensures that dependent constants are evaluated |
| 1553 * before the target. |
| 1554 */ |
| 1555 static const String DEPENDENCIES_INPUT = 'DEPENDENCIES_INPUT'; |
| 1556 |
| 1557 /** |
| 1558 * The name of the [TYPE_PROVIDER] input. |
| 1559 */ |
| 1560 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 1561 |
| 1562 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1563 'ComputeConstantValueTask', |
| 1564 createTask, |
| 1565 buildInputs, |
| 1566 <ResultDescriptor>[CONSTANT_VALUE]); |
| 1567 |
| 1568 ComputeConstantValueTask( |
| 1569 InternalAnalysisContext context, ConstantEvaluationTarget constant) |
| 1570 : super(context, constant); |
| 1571 |
| 1572 @override |
| 1573 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1574 |
| 1575 @override |
| 1576 bool get handlesDependencyCycles => true; |
| 1577 |
| 1578 @override |
| 1579 void internalPerform() { |
| 1580 // |
| 1581 // Prepare inputs. |
| 1582 // |
| 1583 // Note: DEPENDENCIES_INPUT is not needed. It is merely a bookkeeping |
| 1584 // dependency to ensure that the constants that this constant depends on |
| 1585 // are computed first. |
| 1586 ConstantEvaluationTarget constant = target; |
| 1587 AnalysisContext context = constant.context; |
| 1588 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 1589 // |
| 1590 // Compute the value of the constant, or report an error if there was a |
| 1591 // cycle. |
| 1592 // |
| 1593 ConstantEvaluationEngine constantEvaluationEngine = |
| 1594 new ConstantEvaluationEngine(typeProvider, context.declaredVariables); |
| 1595 if (dependencyCycle == null) { |
| 1596 constantEvaluationEngine.computeConstantValue(constant); |
| 1597 } else { |
| 1598 List<ConstantEvaluationTarget> constantsInCycle = |
| 1599 <ConstantEvaluationTarget>[]; |
| 1600 for (WorkItem workItem in dependencyCycle) { |
| 1601 if (workItem.descriptor == DESCRIPTOR) { |
| 1602 constantsInCycle.add(workItem.target); |
| 1603 } |
| 1604 } |
| 1605 assert(constantsInCycle.isNotEmpty); |
| 1606 constantEvaluationEngine.generateCycleError(constantsInCycle, constant); |
| 1607 } |
| 1608 // |
| 1609 // Record outputs. |
| 1610 // |
| 1611 outputs[CONSTANT_VALUE] = constant; |
| 1612 } |
| 1613 |
| 1614 /** |
| 1615 * Return a map from the names of the inputs of this kind of task to the task |
| 1616 * input descriptors describing those inputs for a task with the given |
| 1617 * [target]. |
| 1618 */ |
| 1619 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1620 ConstantEvaluationTarget evaluationTarget = target; |
| 1621 return <String, TaskInput>{ |
| 1622 DEPENDENCIES_INPUT: |
| 1623 CONSTANT_DEPENDENCIES.of(evaluationTarget).toListOf(CONSTANT_VALUE), |
| 1624 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 1625 }; |
| 1626 } |
| 1627 |
| 1628 /** |
| 1629 * Create a [ComputeConstantValueTask] based on the given [target] in the |
| 1630 * given [context]. |
| 1631 */ |
| 1632 static ComputeConstantValueTask createTask( |
| 1633 AnalysisContext context, AnalysisTarget target) { |
| 1634 return new ComputeConstantValueTask(context, target); |
| 1635 } |
| 1636 } |
| 1637 |
| 1638 /** |
| 1639 * A task that computes the [INFERABLE_STATIC_VARIABLE_DEPENDENCIES] for a |
| 1640 * static variable whose type should be inferred. |
| 1641 */ |
| 1642 class ComputeInferableStaticVariableDependenciesTask |
| 1643 extends ConstantEvaluationAnalysisTask { |
| 1644 /** |
| 1645 * The name of the [RESOLVED_UNIT5] input. |
| 1646 */ |
| 1647 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 1648 |
| 1649 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1650 'ComputeInferableStaticVariableDependenciesTask', |
| 1651 createTask, |
| 1652 buildInputs, |
| 1653 <ResultDescriptor>[INFERABLE_STATIC_VARIABLE_DEPENDENCIES]); |
| 1654 |
| 1655 ComputeInferableStaticVariableDependenciesTask( |
| 1656 InternalAnalysisContext context, VariableElement variable) |
| 1657 : super(context, variable); |
| 1658 |
| 1659 @override |
| 1660 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1661 |
| 1662 @override |
| 1663 void internalPerform() { |
| 1664 // |
| 1665 // Prepare inputs. |
| 1666 // |
| 1667 VariableElement variable = target; |
| 1668 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 1669 // |
| 1670 // Compute dependencies. |
| 1671 // |
| 1672 NodeLocator locator = new NodeLocator(variable.nameOffset); |
| 1673 AstNode node = locator.searchWithin(unit); |
| 1674 VariableDeclaration declaration = |
| 1675 node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); |
| 1676 if (declaration == null || declaration.name != node) { |
| 1677 throw new AnalysisException( |
| 1678 "NodeLocator failed to find a variable's declaration"); |
| 1679 } |
| 1680 VariableGatherer gatherer = new VariableGatherer(_isInferableStatic); |
| 1681 declaration.initializer.accept(gatherer); |
| 1682 // |
| 1683 // Record outputs. |
| 1684 // |
| 1685 outputs[INFERABLE_STATIC_VARIABLE_DEPENDENCIES] = gatherer.results.toList(); |
| 1686 } |
| 1687 |
| 1688 /** |
| 1689 * Return `true` if the given [variable] is a static variable whose type |
| 1690 * should be inferred. |
| 1691 */ |
| 1692 bool _isInferableStatic(VariableElement variable) => variable.isStatic && |
| 1693 variable.hasImplicitType && |
| 1694 variable.initializer != null; |
| 1695 |
| 1696 /** |
| 1697 * Return a map from the names of the inputs of this kind of task to the task |
| 1698 * input descriptors describing those inputs for a task with the |
| 1699 * given [target]. |
| 1700 */ |
| 1701 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1702 if (target is VariableElement) { |
| 1703 CompilationUnitElementImpl unit = target |
| 1704 .getAncestor((Element element) => element is CompilationUnitElement); |
| 1705 return <String, TaskInput>{ |
| 1706 UNIT_INPUT: RESOLVED_UNIT5 |
| 1707 .of(new LibrarySpecificUnit(unit.librarySource, unit.source)) |
| 1708 }; |
| 1709 } |
| 1710 throw new AnalysisException( |
| 1711 'Cannot build inputs for a ${target.runtimeType}'); |
| 1712 } |
| 1713 |
| 1714 /** |
| 1715 * Create a [ComputeInferableStaticVariableDependenciesTask] based on the |
| 1716 * given [target] in the given [context]. |
| 1717 */ |
| 1718 static ComputeInferableStaticVariableDependenciesTask createTask( |
| 1719 AnalysisContext context, AnalysisTarget target) { |
| 1720 return new ComputeInferableStaticVariableDependenciesTask(context, target); |
| 1721 } |
| 1722 } |
| 1723 |
| 1724 /** |
| 1725 * A base class for analysis tasks whose target is expected to be a |
| 1726 * [ConstantEvaluationTarget]. |
| 1727 */ |
| 1728 abstract class ConstantEvaluationAnalysisTask extends AnalysisTask { |
| 1729 /** |
| 1730 * Initialize a newly created task to perform analysis within the given |
| 1731 * [context] in order to produce results for the given [constant]. |
| 1732 */ |
| 1733 ConstantEvaluationAnalysisTask( |
| 1734 AnalysisContext context, ConstantEvaluationTarget constant) |
| 1735 : super(context, constant); |
| 1736 |
| 1737 @override |
| 1738 String get description { |
| 1739 Source source = target.source; |
| 1740 String sourceName = source == null ? '<unknown source>' : source.fullName; |
| 1741 return '${descriptor.name} for element $target in source $sourceName'; |
| 1742 } |
| 1743 } |
| 1744 |
| 1745 /** |
| 1746 * Interface for [AnalysisTarget]s for which constant evaluation can be |
| 1747 * performed. |
| 1748 */ |
| 1749 abstract class ConstantEvaluationTarget extends AnalysisTarget { |
| 1750 /** |
| 1751 * Return the [AnalysisContext] which should be used to evaluate this |
| 1752 * constant. |
| 1753 */ |
| 1754 AnalysisContext get context; |
| 1755 } |
| 1756 |
| 1757 /** |
| 1758 * A task that computes a list of the libraries containing the target source. |
| 1759 */ |
| 1760 class ContainingLibrariesTask extends SourceBasedAnalysisTask { |
| 1761 /** |
| 1762 * The task descriptor describing this kind of task. |
| 1763 */ |
| 1764 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 1765 'ContainingLibrariesTask', |
| 1766 createTask, |
| 1767 buildInputs, |
| 1768 <ResultDescriptor>[CONTAINING_LIBRARIES]); |
| 1769 |
| 1770 ContainingLibrariesTask( |
| 1771 InternalAnalysisContext context, AnalysisTarget target) |
| 1772 : super(context, target); |
| 1773 |
| 1774 @override |
| 1775 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1776 |
| 1777 @override |
| 1778 void internalPerform() { |
| 1779 // TODO(brianwilkerson) This value can change as new libraries are analyzed |
| 1780 // so we need some way of making sure that this result is removed from the |
| 1781 // cache appropriately. |
| 1782 Source source = getRequiredSource(); |
| 1783 outputs[CONTAINING_LIBRARIES] = context.getLibrariesContaining(source); |
| 1784 } |
| 1785 |
| 1786 /** |
| 1787 * Return a map from the names of the inputs of this kind of task to the task |
| 1788 * input descriptors describing those inputs for a task with the |
| 1789 * given [target]. |
| 1790 */ |
| 1791 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1792 return <String, TaskInput>{}; |
| 1793 } |
| 1794 |
| 1795 /** |
| 1796 * Create a [ContainingLibrariesTask] based on the given [target] in the given |
| 1797 * [context]. |
| 1798 */ |
| 1799 static ContainingLibrariesTask createTask( |
| 1800 AnalysisContext context, AnalysisTarget target) { |
| 1801 return new ContainingLibrariesTask(context, target); |
| 1802 } |
| 1803 } |
| 1804 |
| 1805 /** |
| 1806 * The description for a change in a Dart source. |
| 1807 */ |
| 1808 class DartDelta extends Delta { |
| 1809 bool hasDirectiveChange = false; |
| 1810 |
| 1811 final Set<String> addedNames = new Set<String>(); |
| 1812 final Set<String> changedNames = new Set<String>(); |
| 1813 final Set<String> removedNames = new Set<String>(); |
| 1814 |
| 1815 final Set<Source> invalidatedSources = new Set<Source>(); |
| 1816 |
| 1817 DartDelta(Source source) : super(source) { |
| 1818 invalidatedSources.add(source); |
| 1819 } |
| 1820 |
| 1821 void elementAdded(Element element) { |
| 1822 addedNames.add(element.name); |
| 1823 } |
| 1824 |
| 1825 void elementChanged(Element element) { |
| 1826 changedNames.add(element.name); |
| 1827 } |
| 1828 |
| 1829 void elementRemoved(Element element) { |
| 1830 removedNames.add(element.name); |
| 1831 } |
| 1832 |
| 1833 bool isNameAffected(String name) { |
| 1834 return addedNames.contains(name) || |
| 1835 changedNames.contains(name) || |
| 1836 removedNames.contains(name); |
| 1837 } |
| 1838 |
| 1839 bool nameChanged(String name) { |
| 1840 return changedNames.add(name); |
| 1841 } |
| 1842 |
| 1843 @override |
| 1844 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target, |
| 1845 ResultDescriptor descriptor) { |
| 1846 if (hasDirectiveChange) { |
| 1847 return DeltaResult.INVALIDATE; |
| 1848 } |
| 1849 // Prepare target source. |
| 1850 Source targetSource = null; |
| 1851 if (target is Source) { |
| 1852 targetSource = target; |
| 1853 } |
| 1854 if (target is LibrarySpecificUnit) { |
| 1855 targetSource = target.library; |
| 1856 } |
| 1857 if (target is Element) { |
| 1858 targetSource = target.source; |
| 1859 } |
| 1860 // Keep results that are updated incrementally. |
| 1861 // If we want to analyze only some references to the source being changed, |
| 1862 // we need to keep the same instances of CompilationUnitElement and |
| 1863 // LibraryElement. |
| 1864 if (targetSource == source) { |
| 1865 if (ParseDartTask.DESCRIPTOR.results.contains(descriptor)) { |
| 1866 return DeltaResult.KEEP_CONTINUE; |
| 1867 } |
| 1868 if (BuildCompilationUnitElementTask.DESCRIPTOR.results |
| 1869 .contains(descriptor)) { |
| 1870 return DeltaResult.KEEP_CONTINUE; |
| 1871 } |
| 1872 if (BuildLibraryElementTask.DESCRIPTOR.results.contains(descriptor)) { |
| 1873 return DeltaResult.KEEP_CONTINUE; |
| 1874 } |
| 1875 return DeltaResult.INVALIDATE; |
| 1876 } |
| 1877 // Use the target library dependency information to decide whether |
| 1878 // the delta affects the library. |
| 1879 if (targetSource != null) { |
| 1880 List<Source> librarySources = |
| 1881 context.getLibrariesContaining(targetSource); |
| 1882 for (Source librarySource in librarySources) { |
| 1883 AnalysisCache cache = context.analysisCache; |
| 1884 ReferencedNames referencedNames = |
| 1885 cache.getValue(librarySource, REFERENCED_NAMES); |
| 1886 if (referencedNames == null) { |
| 1887 return DeltaResult.INVALIDATE; |
| 1888 } |
| 1889 referencedNames.addChangedElements(this); |
| 1890 if (referencedNames.isAffectedBy(this)) { |
| 1891 return DeltaResult.INVALIDATE; |
| 1892 } |
| 1893 } |
| 1894 return DeltaResult.STOP; |
| 1895 } |
| 1896 // We don't know what to do with the given target, invalidate it. |
| 1897 return DeltaResult.INVALIDATE; |
| 1898 } |
| 1899 } |
| 1900 |
| 1901 /** |
| 1902 * A task that merges all of the errors for a single source into a single list |
| 1903 * of errors. |
| 1904 */ |
| 1905 class DartErrorsTask extends SourceBasedAnalysisTask { |
| 1906 /** |
| 1907 * The name of the [BUILD_DIRECTIVES_ERRORS] input. |
| 1908 */ |
| 1909 static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS'; |
| 1910 |
| 1911 /** |
| 1912 * The name of the [BUILD_LIBRARY_ERRORS] input. |
| 1913 */ |
| 1914 static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS'; |
| 1915 |
| 1916 /** |
| 1917 * The name of the [LIBRARY_UNIT_ERRORS] input. |
| 1918 */ |
| 1919 static const String LIBRARY_UNIT_ERRORS_INPUT = 'LIBRARY_UNIT_ERRORS'; |
| 1920 |
| 1921 /** |
| 1922 * The name of the [PARSE_ERRORS] input. |
| 1923 */ |
| 1924 static const String PARSE_ERRORS_INPUT = 'PARSE_ERRORS'; |
| 1925 |
| 1926 /** |
| 1927 * The name of the [SCAN_ERRORS] input. |
| 1928 */ |
| 1929 static const String SCAN_ERRORS_INPUT = 'SCAN_ERRORS'; |
| 1930 |
| 1931 /** |
| 1932 * The task descriptor describing this kind of task. |
| 1933 */ |
| 1934 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask', |
| 1935 createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]); |
| 1936 |
| 1937 DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target) |
| 1938 : super(context, target); |
| 1939 |
| 1940 @override |
| 1941 TaskDescriptor get descriptor => DESCRIPTOR; |
| 1942 |
| 1943 @override |
| 1944 void internalPerform() { |
| 1945 // |
| 1946 // Prepare inputs. |
| 1947 // |
| 1948 List<List<AnalysisError>> errorLists = <List<AnalysisError>>[]; |
| 1949 errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT)); |
| 1950 errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT)); |
| 1951 errorLists.add(getRequiredInput(PARSE_ERRORS_INPUT)); |
| 1952 errorLists.add(getRequiredInput(SCAN_ERRORS_INPUT)); |
| 1953 Map<Source, List<AnalysisError>> unitErrors = |
| 1954 getRequiredInput(LIBRARY_UNIT_ERRORS_INPUT); |
| 1955 for (List<AnalysisError> errors in unitErrors.values) { |
| 1956 errorLists.add(errors); |
| 1957 } |
| 1958 // |
| 1959 // Record outputs. |
| 1960 // |
| 1961 outputs[DART_ERRORS] = AnalysisError.mergeLists(errorLists); |
| 1962 } |
| 1963 |
| 1964 /** |
| 1965 * Return a map from the names of the inputs of this kind of task to the task |
| 1966 * input descriptors describing those inputs for a task with the |
| 1967 * given [target]. |
| 1968 */ |
| 1969 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 1970 Source source = target; |
| 1971 return <String, TaskInput>{ |
| 1972 BUILD_DIRECTIVES_ERRORS_INPUT: BUILD_DIRECTIVES_ERRORS.of(source), |
| 1973 BUILD_LIBRARY_ERRORS_INPUT: BUILD_LIBRARY_ERRORS.of(source), |
| 1974 PARSE_ERRORS_INPUT: PARSE_ERRORS.of(source), |
| 1975 SCAN_ERRORS_INPUT: SCAN_ERRORS.of(source), |
| 1976 LIBRARY_UNIT_ERRORS_INPUT: |
| 1977 CONTAINING_LIBRARIES.of(source).toMap((Source library) { |
| 1978 LibrarySpecificUnit unit = new LibrarySpecificUnit(library, source); |
| 1979 return LIBRARY_UNIT_ERRORS.of(unit); |
| 1980 }) |
| 1981 }; |
| 1982 } |
| 1983 |
| 1984 /** |
| 1985 * Create a [DartErrorsTask] based on the given [target] in the given |
| 1986 * [context]. |
| 1987 */ |
| 1988 static DartErrorsTask createTask( |
| 1989 AnalysisContext context, AnalysisTarget target) { |
| 1990 return new DartErrorsTask(context, target); |
| 1991 } |
| 1992 } |
| 1993 |
| 1994 /** |
| 1995 * A task that builds [RESOLVED_UNIT] for a unit. |
| 1996 */ |
| 1997 class EvaluateUnitConstantsTask extends SourceBasedAnalysisTask { |
| 1998 /** |
| 1999 * The name of the [RESOLVED_UNIT8] input. |
| 2000 */ |
| 2001 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2002 |
| 2003 /** |
| 2004 * The name of the [CONSTANT_VALUE] input. |
| 2005 */ |
| 2006 static const String CONSTANT_VALUES = 'CONSTANT_VALUES'; |
| 2007 |
| 2008 /** |
| 2009 * The task descriptor describing this kind of task. |
| 2010 */ |
| 2011 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2012 'EvaluateUnitConstantsTask', |
| 2013 createTask, |
| 2014 buildInputs, |
| 2015 <ResultDescriptor>[RESOLVED_UNIT]); |
| 2016 |
| 2017 EvaluateUnitConstantsTask(AnalysisContext context, LibrarySpecificUnit target) |
| 2018 : super(context, target); |
| 2019 |
| 2020 @override |
| 2021 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2022 |
| 2023 @override |
| 2024 void internalPerform() { |
| 2025 // No actual work needs to be performed; the task manager will ensure that |
| 2026 // all constants are evaluated before this method is called. |
| 2027 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 2028 outputs[RESOLVED_UNIT] = unit; |
| 2029 } |
| 2030 |
| 2031 /** |
| 2032 * Return a map from the names of the inputs of this kind of task to the task |
| 2033 * input descriptors describing those inputs for a task with the |
| 2034 * given [target]. |
| 2035 */ |
| 2036 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2037 LibrarySpecificUnit unit = target; |
| 2038 return <String, TaskInput>{ |
| 2039 'libraryElement': LIBRARY_ELEMENT.of(unit.library), |
| 2040 UNIT_INPUT: RESOLVED_UNIT8.of(unit), |
| 2041 CONSTANT_VALUES: |
| 2042 COMPILATION_UNIT_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE) |
| 2043 }; |
| 2044 } |
| 2045 |
| 2046 /** |
| 2047 * Create an [EvaluateUnitConstantsTask] based on the given [target] in |
| 2048 * the given [context]. |
| 2049 */ |
| 2050 static EvaluateUnitConstantsTask createTask( |
| 2051 AnalysisContext context, AnalysisTarget target) { |
| 2052 return new EvaluateUnitConstantsTask(context, target); |
| 2053 } |
| 2054 } |
| 2055 |
| 2056 /** |
| 2057 * The helper for building the export [Namespace] of a [LibraryElement]. |
| 2058 */ |
| 2059 class ExportNamespaceBuilder { |
| 2060 /** |
| 2061 * Build the export [Namespace] of the given [LibraryElement]. |
| 2062 */ |
| 2063 Namespace build(LibraryElement library) { |
| 2064 return new Namespace( |
| 2065 _createExportMapping(library, new HashSet<LibraryElement>())); |
| 2066 } |
| 2067 |
| 2068 /** |
| 2069 * Create a mapping table representing the export namespace of the given |
| 2070 * [library]. |
| 2071 * |
| 2072 * The given [visitedElements] a set of libraries that do not need to be |
| 2073 * visited when processing the export directives of the given library because |
| 2074 * all of the names defined by them will be added by another library. |
| 2075 */ |
| 2076 HashMap<String, Element> _createExportMapping( |
| 2077 LibraryElement library, HashSet<LibraryElement> visitedElements) { |
| 2078 visitedElements.add(library); |
| 2079 try { |
| 2080 HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| 2081 // Add names of the export directives. |
| 2082 for (ExportElement element in library.exports) { |
| 2083 LibraryElement exportedLibrary = element.exportedLibrary; |
| 2084 if (exportedLibrary != null && |
| 2085 !visitedElements.contains(exportedLibrary)) { |
| 2086 // |
| 2087 // The exported library will be null if the URI does not reference a |
| 2088 // valid library. |
| 2089 // |
| 2090 HashMap<String, Element> exportedNames = |
| 2091 _createExportMapping(exportedLibrary, visitedElements); |
| 2092 exportedNames = _applyCombinators(exportedNames, element.combinators); |
| 2093 definedNames.addAll(exportedNames); |
| 2094 } |
| 2095 } |
| 2096 // Add names of the public namespace. |
| 2097 { |
| 2098 Namespace publicNamespace = library.publicNamespace; |
| 2099 if (publicNamespace != null) { |
| 2100 definedNames.addAll(publicNamespace.definedNames); |
| 2101 } |
| 2102 } |
| 2103 return definedNames; |
| 2104 } finally { |
| 2105 visitedElements.remove(library); |
| 2106 } |
| 2107 } |
| 2108 |
| 2109 /** |
| 2110 * Apply the given [combinators] to all of the names in [definedNames]. |
| 2111 */ |
| 2112 static HashMap<String, Element> _applyCombinators( |
| 2113 HashMap<String, Element> definedNames, |
| 2114 List<NamespaceCombinator> combinators) { |
| 2115 for (NamespaceCombinator combinator in combinators) { |
| 2116 if (combinator is HideElementCombinator) { |
| 2117 _hide(definedNames, combinator.hiddenNames); |
| 2118 } else if (combinator is ShowElementCombinator) { |
| 2119 definedNames = _show(definedNames, combinator.shownNames); |
| 2120 } |
| 2121 } |
| 2122 return definedNames; |
| 2123 } |
| 2124 |
| 2125 /** |
| 2126 * Hide all of the [hiddenNames] by removing them from the given |
| 2127 * [definedNames]. |
| 2128 */ |
| 2129 static void _hide( |
| 2130 HashMap<String, Element> definedNames, List<String> hiddenNames) { |
| 2131 for (String name in hiddenNames) { |
| 2132 definedNames.remove(name); |
| 2133 definedNames.remove('$name='); |
| 2134 } |
| 2135 } |
| 2136 |
| 2137 /** |
| 2138 * Show only the given [shownNames] by removing all other names from the given |
| 2139 * [definedNames]. |
| 2140 */ |
| 2141 static HashMap<String, Element> _show( |
| 2142 HashMap<String, Element> definedNames, List<String> shownNames) { |
| 2143 HashMap<String, Element> newNames = new HashMap<String, Element>(); |
| 2144 for (String name in shownNames) { |
| 2145 Element element = definedNames[name]; |
| 2146 if (element != null) { |
| 2147 newNames[name] = element; |
| 2148 } |
| 2149 String setterName = '$name='; |
| 2150 element = definedNames[setterName]; |
| 2151 if (element != null) { |
| 2152 newNames[setterName] = element; |
| 2153 } |
| 2154 } |
| 2155 return newNames; |
| 2156 } |
| 2157 } |
| 2158 |
| 2159 /** |
| 2160 * A task that builds [USED_IMPORTED_ELEMENTS] for a unit. |
| 2161 */ |
| 2162 class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask { |
| 2163 /** |
| 2164 * The name of the [RESOLVED_UNIT8] input. |
| 2165 */ |
| 2166 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2167 |
| 2168 /** |
| 2169 * The task descriptor describing this kind of task. |
| 2170 */ |
| 2171 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2172 'GatherUsedImportedElementsTask', |
| 2173 createTask, |
| 2174 buildInputs, |
| 2175 <ResultDescriptor>[USED_IMPORTED_ELEMENTS]); |
| 2176 |
| 2177 GatherUsedImportedElementsTask( |
| 2178 InternalAnalysisContext context, AnalysisTarget target) |
| 2179 : super(context, target); |
| 2180 |
| 2181 @override |
| 2182 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2183 |
| 2184 @override |
| 2185 void internalPerform() { |
| 2186 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 2187 CompilationUnitElement unitElement = unit.element; |
| 2188 LibraryElement libraryElement = unitElement.library; |
| 2189 // |
| 2190 // Prepare used imported elements. |
| 2191 // |
| 2192 GatherUsedImportedElementsVisitor visitor = |
| 2193 new GatherUsedImportedElementsVisitor(libraryElement); |
| 2194 unit.accept(visitor); |
| 2195 // |
| 2196 // Record outputs. |
| 2197 // |
| 2198 outputs[USED_IMPORTED_ELEMENTS] = visitor.usedElements; |
| 2199 } |
| 2200 |
| 2201 /** |
| 2202 * Return a map from the names of the inputs of this kind of task to the task |
| 2203 * input descriptors describing those inputs for a task with the |
| 2204 * given [target]. |
| 2205 */ |
| 2206 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2207 LibrarySpecificUnit unit = target; |
| 2208 return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT8.of(unit)}; |
| 2209 } |
| 2210 |
| 2211 /** |
| 2212 * Create a [GatherUsedImportedElementsTask] based on the given [target] in |
| 2213 * the given [context]. |
| 2214 */ |
| 2215 static GatherUsedImportedElementsTask createTask( |
| 2216 AnalysisContext context, AnalysisTarget target) { |
| 2217 return new GatherUsedImportedElementsTask(context, target); |
| 2218 } |
| 2219 } |
| 2220 |
| 2221 /** |
| 2222 * A task that builds [USED_LOCAL_ELEMENTS] for a unit. |
| 2223 */ |
| 2224 class GatherUsedLocalElementsTask extends SourceBasedAnalysisTask { |
| 2225 /** |
| 2226 * The name of the [RESOLVED_UNIT8] input. |
| 2227 */ |
| 2228 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2229 |
| 2230 /** |
| 2231 * The task descriptor describing this kind of task. |
| 2232 */ |
| 2233 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2234 'GatherUsedLocalElementsTask', |
| 2235 createTask, |
| 2236 buildInputs, |
| 2237 <ResultDescriptor>[USED_LOCAL_ELEMENTS]); |
| 2238 |
| 2239 GatherUsedLocalElementsTask( |
| 2240 InternalAnalysisContext context, AnalysisTarget target) |
| 2241 : super(context, target); |
| 2242 |
| 2243 @override |
| 2244 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2245 |
| 2246 @override |
| 2247 void internalPerform() { |
| 2248 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 2249 CompilationUnitElement unitElement = unit.element; |
| 2250 LibraryElement libraryElement = unitElement.library; |
| 2251 // |
| 2252 // Prepare used local elements. |
| 2253 // |
| 2254 GatherUsedLocalElementsVisitor visitor = |
| 2255 new GatherUsedLocalElementsVisitor(libraryElement); |
| 2256 unit.accept(visitor); |
| 2257 // |
| 2258 // Record outputs. |
| 2259 // |
| 2260 outputs[USED_LOCAL_ELEMENTS] = visitor.usedElements; |
| 2261 } |
| 2262 |
| 2263 /** |
| 2264 * Return a map from the names of the inputs of this kind of task to the task |
| 2265 * input descriptors describing those inputs for a task with the |
| 2266 * given [target]. |
| 2267 */ |
| 2268 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2269 LibrarySpecificUnit unit = target; |
| 2270 return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT8.of(unit)}; |
| 2271 } |
| 2272 |
| 2273 /** |
| 2274 * Create a [GatherUsedLocalElementsTask] based on the given [target] in |
| 2275 * the given [context]. |
| 2276 */ |
| 2277 static GatherUsedLocalElementsTask createTask( |
| 2278 AnalysisContext context, AnalysisTarget target) { |
| 2279 return new GatherUsedLocalElementsTask(context, target); |
| 2280 } |
| 2281 } |
| 2282 |
| 2283 /** |
| 2284 * A task that generates [HINTS] for a unit. |
| 2285 */ |
| 2286 class GenerateHintsTask extends SourceBasedAnalysisTask { |
| 2287 /** |
| 2288 * The name of the [RESOLVED_UNIT8] input. |
| 2289 */ |
| 2290 static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT'; |
| 2291 |
| 2292 /** |
| 2293 * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input. |
| 2294 */ |
| 2295 static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS'; |
| 2296 |
| 2297 /** |
| 2298 * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input. |
| 2299 */ |
| 2300 static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS'; |
| 2301 |
| 2302 /** |
| 2303 * The name of the [TYPE_PROVIDER] input. |
| 2304 */ |
| 2305 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 2306 |
| 2307 /** |
| 2308 * The task descriptor describing this kind of task. |
| 2309 */ |
| 2310 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2311 'GenerateHintsTask', createTask, buildInputs, <ResultDescriptor>[HINTS]); |
| 2312 |
| 2313 GenerateHintsTask(InternalAnalysisContext context, AnalysisTarget target) |
| 2314 : super(context, target); |
| 2315 |
| 2316 @override |
| 2317 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2318 |
| 2319 @override |
| 2320 void internalPerform() { |
| 2321 AnalysisOptions analysisOptions = context.analysisOptions; |
| 2322 if (!analysisOptions.hint) { |
| 2323 outputs[HINTS] = AnalysisError.NO_ERRORS; |
| 2324 return; |
| 2325 } |
| 2326 // |
| 2327 // Prepare collectors. |
| 2328 // |
| 2329 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 2330 Source source = getRequiredSource(); |
| 2331 ErrorReporter errorReporter = new ErrorReporter(errorListener, source); |
| 2332 // |
| 2333 // Prepare inputs. |
| 2334 // |
| 2335 CompilationUnit unit = getRequiredInput(RESOLVED_UNIT_INPUT); |
| 2336 List<UsedImportedElements> usedImportedElementsList = |
| 2337 getRequiredInput(USED_IMPORTED_ELEMENTS_INPUT); |
| 2338 List<UsedLocalElements> usedLocalElementsList = |
| 2339 getRequiredInput(USED_LOCAL_ELEMENTS_INPUT); |
| 2340 CompilationUnitElement unitElement = unit.element; |
| 2341 LibraryElement libraryElement = unitElement.library; |
| 2342 // |
| 2343 // Generate errors. |
| 2344 // |
| 2345 unit.accept(new DeadCodeVerifier(errorReporter)); |
| 2346 // Verify imports. |
| 2347 { |
| 2348 ImportsVerifier verifier = new ImportsVerifier(); |
| 2349 verifier.addImports(unit); |
| 2350 usedImportedElementsList.forEach(verifier.removeUsedElements); |
| 2351 verifier.generateDuplicateImportHints(errorReporter); |
| 2352 verifier.generateUnusedImportHints(errorReporter); |
| 2353 } |
| 2354 // Unused local elements. |
| 2355 { |
| 2356 UsedLocalElements usedElements = |
| 2357 new UsedLocalElements.merge(usedLocalElementsList); |
| 2358 UnusedLocalElementsVerifier visitor = |
| 2359 new UnusedLocalElementsVerifier(errorListener, usedElements); |
| 2360 unitElement.accept(visitor); |
| 2361 } |
| 2362 // Dart2js analysis. |
| 2363 if (analysisOptions.dart2jsHint) { |
| 2364 unit.accept(new Dart2JSVerifier(errorReporter)); |
| 2365 } |
| 2366 // Dart best practices. |
| 2367 InheritanceManager inheritanceManager = |
| 2368 new InheritanceManager(libraryElement); |
| 2369 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 2370 unit.accept(new BestPracticesVerifier(errorReporter, typeProvider)); |
| 2371 unit.accept(new OverrideVerifier(errorReporter, inheritanceManager)); |
| 2372 // Find to-do comments. |
| 2373 new ToDoFinder(errorReporter).findIn(unit); |
| 2374 // |
| 2375 // Record outputs. |
| 2376 // |
| 2377 outputs[HINTS] = errorListener.errors; |
| 2378 } |
| 2379 |
| 2380 /** |
| 2381 * Return a map from the names of the inputs of this kind of task to the task |
| 2382 * input descriptors describing those inputs for a task with the |
| 2383 * given [target]. |
| 2384 */ |
| 2385 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2386 LibrarySpecificUnit unit = target; |
| 2387 Source libSource = unit.library; |
| 2388 return <String, TaskInput>{ |
| 2389 RESOLVED_UNIT_INPUT: RESOLVED_UNIT.of(unit), |
| 2390 USED_LOCAL_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) { |
| 2391 LibrarySpecificUnit target = new LibrarySpecificUnit(libSource, unit); |
| 2392 return USED_LOCAL_ELEMENTS.of(target); |
| 2393 }), |
| 2394 USED_IMPORTED_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) { |
| 2395 LibrarySpecificUnit target = new LibrarySpecificUnit(libSource, unit); |
| 2396 return USED_IMPORTED_ELEMENTS.of(target); |
| 2397 }), |
| 2398 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 2399 }; |
| 2400 } |
| 2401 |
| 2402 /** |
| 2403 * Create a [GenerateHintsTask] based on the given [target] in |
| 2404 * the given [context]. |
| 2405 */ |
| 2406 static GenerateHintsTask createTask( |
| 2407 AnalysisContext context, AnalysisTarget target) { |
| 2408 return new GenerateHintsTask(context, target); |
| 2409 } |
| 2410 } |
| 2411 |
| 2412 /** |
| 2413 * An abstract class that defines utility methods that are useful for tasks |
| 2414 * operating on static variables. |
| 2415 */ |
| 2416 abstract class InferStaticVariableTask extends ConstantEvaluationAnalysisTask { |
| 2417 InferStaticVariableTask( |
| 2418 InternalAnalysisContext context, VariableElement variable) |
| 2419 : super(context, variable); |
| 2420 |
| 2421 /** |
| 2422 * Return the declaration of the target within the given compilation [unit]. |
| 2423 * Throw an exception if the declaration cannot be found. |
| 2424 */ |
| 2425 VariableDeclaration getDeclaration(CompilationUnit unit) { |
| 2426 VariableElement variable = target; |
| 2427 NodeLocator locator = new NodeLocator(variable.nameOffset); |
| 2428 AstNode node = locator.searchWithin(unit); |
| 2429 VariableDeclaration declaration = |
| 2430 node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); |
| 2431 if (declaration == null || declaration.name != node) { |
| 2432 throw new AnalysisException( |
| 2433 "Failed to find the declaration of the variable ${variable.displayName
} in ${variable.source}"); |
| 2434 } |
| 2435 return declaration; |
| 2436 } |
| 2437 } |
| 2438 |
| 2439 /** |
| 2440 * A task that ensures that all of the inferrable static variables in a |
| 2441 * compilation unit have had their type inferred. |
| 2442 */ |
| 2443 class InferStaticVariableTypesInUnitTask extends SourceBasedAnalysisTask { |
| 2444 /** |
| 2445 * The name of the input whose value is the [RESOLVED_UNIT5] for the |
| 2446 * compilation unit. |
| 2447 */ |
| 2448 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2449 |
| 2450 /** |
| 2451 * The name of the input whose value is a list of the inferrable static |
| 2452 * variables whose types have been computed. |
| 2453 */ |
| 2454 static const String INFERRED_VARIABLES_INPUT = 'INFERRED_VARIABLES_INPUT'; |
| 2455 |
| 2456 /** |
| 2457 * The task descriptor describing this kind of task. |
| 2458 */ |
| 2459 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2460 'InferStaticVariableTypesInUnitTask', |
| 2461 createTask, |
| 2462 buildInputs, |
| 2463 <ResultDescriptor>[RESOLVED_UNIT6]); |
| 2464 |
| 2465 /** |
| 2466 * Initialize a newly created task to build a library element for the given |
| 2467 * [unit] in the given [context]. |
| 2468 */ |
| 2469 InferStaticVariableTypesInUnitTask( |
| 2470 InternalAnalysisContext context, LibrarySpecificUnit unit) |
| 2471 : super(context, unit); |
| 2472 |
| 2473 @override |
| 2474 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2475 |
| 2476 @override |
| 2477 void internalPerform() { |
| 2478 // |
| 2479 // Prepare inputs. |
| 2480 // |
| 2481 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 2482 // |
| 2483 // Record outputs. There is no additional work to be done at this time |
| 2484 // because the work has implicitly been done by virtue of the task model |
| 2485 // preparing all of the inputs. |
| 2486 // |
| 2487 outputs[RESOLVED_UNIT6] = unit; |
| 2488 } |
| 2489 |
| 2490 /** |
| 2491 * Return a map from the names of the inputs of this kind of task to the task |
| 2492 * input descriptors describing those inputs for a task with the given |
| 2493 * [libSource]. |
| 2494 */ |
| 2495 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2496 LibrarySpecificUnit unit = target; |
| 2497 return <String, TaskInput>{ |
| 2498 INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT |
| 2499 .of(unit) |
| 2500 .toListOf(INFERRED_STATIC_VARIABLE), |
| 2501 UNIT_INPUT: RESOLVED_UNIT5.of(unit) |
| 2502 }; |
| 2503 } |
| 2504 |
| 2505 /** |
| 2506 * Create a [InferStaticVariableTypesInUnitTask] based on the given [target] i
n the |
| 2507 * given [context]. |
| 2508 */ |
| 2509 static InferStaticVariableTypesInUnitTask createTask( |
| 2510 AnalysisContext context, AnalysisTarget target) { |
| 2511 return new InferStaticVariableTypesInUnitTask(context, target); |
| 2512 } |
| 2513 } |
| 2514 |
| 2515 /** |
| 2516 * A task that computes the type of an inferrable static variable and |
| 2517 * stores it in the element model. |
| 2518 */ |
| 2519 class InferStaticVariableTypeTask extends InferStaticVariableTask { |
| 2520 /** |
| 2521 * The name of the input which ensures that dependent values have their type |
| 2522 * inferred before the target. |
| 2523 */ |
| 2524 static const String DEPENDENCIES_INPUT = 'DEPENDENCIES_INPUT'; |
| 2525 |
| 2526 /** |
| 2527 * The name of the [TYPE_PROVIDER] input. |
| 2528 */ |
| 2529 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 2530 |
| 2531 /** |
| 2532 * The name of the [RESOLVED_UNIT5] input. |
| 2533 */ |
| 2534 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2535 |
| 2536 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2537 'InferStaticVariableTypeTask', |
| 2538 createTask, |
| 2539 buildInputs, |
| 2540 <ResultDescriptor>[INFERRED_STATIC_VARIABLE]); |
| 2541 |
| 2542 InferStaticVariableTypeTask( |
| 2543 InternalAnalysisContext context, VariableElement variable) |
| 2544 : super(context, variable); |
| 2545 |
| 2546 @override |
| 2547 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2548 |
| 2549 @override |
| 2550 bool get handlesDependencyCycles => true; |
| 2551 |
| 2552 @override |
| 2553 void internalPerform() { |
| 2554 // |
| 2555 // Prepare inputs. |
| 2556 // |
| 2557 // Note: DEPENDENCIES_INPUT is not needed. It is merely a bookkeeping |
| 2558 // dependency to ensure that the variables that this variable references |
| 2559 // have types inferred before inferring the type of this variable. |
| 2560 // |
| 2561 VariableElementImpl variable = target; |
| 2562 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 2563 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 2564 // |
| 2565 // Re-resolve the variable's initializer so that the inferred types of other |
| 2566 // variables will be propagated. |
| 2567 // |
| 2568 NodeLocator locator = new NodeLocator(variable.nameOffset); |
| 2569 AstNode node = locator.searchWithin(unit); |
| 2570 VariableDeclaration declaration = |
| 2571 node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration); |
| 2572 if (declaration == null || declaration.name != node) { |
| 2573 throw new AnalysisException( |
| 2574 "NodeLocator failed to find a variable's declaration"); |
| 2575 } |
| 2576 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 2577 Expression initializer = declaration.initializer; |
| 2578 ResolutionContext resolutionContext = |
| 2579 ResolutionContextBuilder.contextFor(initializer, errorListener); |
| 2580 ResolverVisitor visitor = new ResolverVisitor( |
| 2581 variable.library, variable.source, typeProvider, errorListener, |
| 2582 nameScope: resolutionContext.scope); |
| 2583 if (resolutionContext.enclosingClassDeclaration != null) { |
| 2584 visitor.prepareToResolveMembersInClass( |
| 2585 resolutionContext.enclosingClassDeclaration); |
| 2586 } |
| 2587 visitor.initForIncrementalResolution(); |
| 2588 initializer.accept(visitor); |
| 2589 // |
| 2590 // Record the type of the variable. |
| 2591 // |
| 2592 DartType newType = initializer.staticType; |
| 2593 variable.type = newType; |
| 2594 (variable.initializer as ExecutableElementImpl).returnType = newType; |
| 2595 if (variable is PropertyInducingElementImpl) { |
| 2596 setReturnType(variable.getter, newType); |
| 2597 setParameterType(variable.setter, newType); |
| 2598 } |
| 2599 // |
| 2600 // Record outputs. |
| 2601 // |
| 2602 outputs[INFERRED_STATIC_VARIABLE] = variable; |
| 2603 } |
| 2604 |
| 2605 /** |
| 2606 * Return a map from the names of the inputs of this kind of task to the task |
| 2607 * input descriptors describing those inputs for a task with the given |
| 2608 * [target]. |
| 2609 */ |
| 2610 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2611 VariableElement variable = target; |
| 2612 LibrarySpecificUnit unit = |
| 2613 new LibrarySpecificUnit(variable.library.source, variable.source); |
| 2614 return <String, TaskInput>{ |
| 2615 DEPENDENCIES_INPUT: INFERABLE_STATIC_VARIABLE_DEPENDENCIES |
| 2616 .of(variable) |
| 2617 .toListOf(INFERRED_STATIC_VARIABLE), |
| 2618 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request), |
| 2619 UNIT_INPUT: RESOLVED_UNIT5.of(unit) |
| 2620 }; |
| 2621 } |
| 2622 |
| 2623 /** |
| 2624 * Create a [InferStaticVariableTypeTask] based on the given [target] in the |
| 2625 * given [context]. |
| 2626 */ |
| 2627 static InferStaticVariableTypeTask createTask( |
| 2628 AnalysisContext context, AnalysisTarget target) { |
| 2629 return new InferStaticVariableTypeTask(context, target); |
| 2630 } |
| 2631 } |
| 2632 |
| 2633 /** |
| 2634 * A task computes all of the errors of all of the units for a single |
| 2635 * library source and sets the [LIBRARY_ERRORS_READY] flag. |
| 2636 */ |
| 2637 class LibraryErrorsReadyTask extends SourceBasedAnalysisTask { |
| 2638 /** |
| 2639 * The task descriptor describing this kind of task. |
| 2640 */ |
| 2641 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2642 'LibraryErrorsReadyTask', |
| 2643 createTask, |
| 2644 buildInputs, |
| 2645 <ResultDescriptor>[LIBRARY_ERRORS_READY]); |
| 2646 |
| 2647 LibraryErrorsReadyTask(InternalAnalysisContext context, AnalysisTarget target) |
| 2648 : super(context, target); |
| 2649 |
| 2650 @override |
| 2651 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2652 |
| 2653 @override |
| 2654 void internalPerform() { |
| 2655 outputs[LIBRARY_ERRORS_READY] = true; |
| 2656 } |
| 2657 |
| 2658 /** |
| 2659 * Return a map from the names of the inputs of this kind of task to the task |
| 2660 * input descriptors describing those inputs for a task with the |
| 2661 * given [library]. |
| 2662 */ |
| 2663 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2664 Source source = target; |
| 2665 return <String, TaskInput>{ |
| 2666 'allErrors': UNITS.of(source).toListOf(DART_ERRORS) |
| 2667 }; |
| 2668 } |
| 2669 |
| 2670 /** |
| 2671 * Create a [LibraryErrorsReadyTask] based on the given [target] in the given |
| 2672 * [context]. |
| 2673 */ |
| 2674 static LibraryErrorsReadyTask createTask( |
| 2675 AnalysisContext context, AnalysisTarget target) { |
| 2676 return new LibraryErrorsReadyTask(context, target); |
| 2677 } |
| 2678 } |
| 2679 |
| 2680 /** |
| 2681 * A task that merges all of the errors for a single source into a single list |
| 2682 * of errors. |
| 2683 */ |
| 2684 class LibraryUnitErrorsTask extends SourceBasedAnalysisTask { |
| 2685 /** |
| 2686 * The name of the [HINTS] input. |
| 2687 */ |
| 2688 static const String HINTS_INPUT = 'HINTS'; |
| 2689 |
| 2690 /** |
| 2691 * The name of the [RESOLVE_REFERENCES_ERRORS] input. |
| 2692 */ |
| 2693 static const String RESOLVE_REFERENCES_ERRORS_INPUT = |
| 2694 'RESOLVE_REFERENCES_ERRORS'; |
| 2695 |
| 2696 /** |
| 2697 * The name of the [RESOLVE_TYPE_NAMES_ERRORS] input. |
| 2698 */ |
| 2699 static const String RESOLVE_TYPE_NAMES_ERRORS_INPUT = |
| 2700 'RESOLVE_TYPE_NAMES_ERRORS'; |
| 2701 |
| 2702 /** |
| 2703 * The name of the [VARIABLE_REFERENCE_ERRORS] input. |
| 2704 */ |
| 2705 static const String VARIABLE_REFERENCE_ERRORS_INPUT = |
| 2706 'VARIABLE_REFERENCE_ERRORS'; |
| 2707 |
| 2708 /** |
| 2709 * The name of the [VERIFY_ERRORS] input. |
| 2710 */ |
| 2711 static const String VERIFY_ERRORS_INPUT = 'VERIFY_ERRORS'; |
| 2712 |
| 2713 /** |
| 2714 * The task descriptor describing this kind of task. |
| 2715 */ |
| 2716 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2717 'LibraryUnitErrorsTask', |
| 2718 createTask, |
| 2719 buildInputs, |
| 2720 <ResultDescriptor>[LIBRARY_UNIT_ERRORS]); |
| 2721 |
| 2722 LibraryUnitErrorsTask(InternalAnalysisContext context, AnalysisTarget target) |
| 2723 : super(context, target); |
| 2724 |
| 2725 @override |
| 2726 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2727 |
| 2728 @override |
| 2729 void internalPerform() { |
| 2730 // |
| 2731 // Prepare inputs. |
| 2732 // |
| 2733 List<List<AnalysisError>> errorLists = <List<AnalysisError>>[]; |
| 2734 errorLists.add(getRequiredInput(HINTS_INPUT)); |
| 2735 errorLists.add(getRequiredInput(RESOLVE_REFERENCES_ERRORS_INPUT)); |
| 2736 errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT)); |
| 2737 errorLists.add(getRequiredInput(VARIABLE_REFERENCE_ERRORS_INPUT)); |
| 2738 errorLists.add(getRequiredInput(VERIFY_ERRORS_INPUT)); |
| 2739 // |
| 2740 // Record outputs. |
| 2741 // |
| 2742 outputs[LIBRARY_UNIT_ERRORS] = AnalysisError.mergeLists(errorLists); |
| 2743 } |
| 2744 |
| 2745 /** |
| 2746 * Return a map from the names of the inputs of this kind of task to the task |
| 2747 * input descriptors describing those inputs for a task with the |
| 2748 * given [unit]. |
| 2749 */ |
| 2750 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2751 LibrarySpecificUnit unit = target; |
| 2752 return <String, TaskInput>{ |
| 2753 HINTS_INPUT: HINTS.of(unit), |
| 2754 RESOLVE_REFERENCES_ERRORS_INPUT: RESOLVE_REFERENCES_ERRORS.of(unit), |
| 2755 RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit), |
| 2756 VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit), |
| 2757 VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit) |
| 2758 }; |
| 2759 } |
| 2760 |
| 2761 /** |
| 2762 * Create a [LibraryUnitErrorsTask] based on the given [target] in the given |
| 2763 * [context]. |
| 2764 */ |
| 2765 static LibraryUnitErrorsTask createTask( |
| 2766 AnalysisContext context, AnalysisTarget target) { |
| 2767 return new LibraryUnitErrorsTask(context, target); |
| 2768 } |
| 2769 } |
| 2770 |
| 2771 /** |
| 2772 * A task that parses the content of a Dart file, producing an AST structure. |
| 2773 */ |
| 2774 class ParseDartTask extends SourceBasedAnalysisTask { |
| 2775 /** |
| 2776 * The name of the input whose value is the line information produced for the |
| 2777 * file. |
| 2778 */ |
| 2779 static const String LINE_INFO_INPUT_NAME = 'LINE_INFO_INPUT_NAME'; |
| 2780 |
| 2781 /** |
| 2782 * The name of the input whose value is the modification time of the file. |
| 2783 */ |
| 2784 static const String MODIFICATION_TIME_INPUT_NAME = |
| 2785 'MODIFICATION_TIME_INPUT_NAME'; |
| 2786 |
| 2787 /** |
| 2788 * The name of the input whose value is the token stream produced for the file
. |
| 2789 */ |
| 2790 static const String TOKEN_STREAM_INPUT_NAME = 'TOKEN_STREAM_INPUT_NAME'; |
| 2791 |
| 2792 /** |
| 2793 * The task descriptor describing this kind of task. |
| 2794 */ |
| 2795 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2796 'ParseDartTask', createTask, buildInputs, <ResultDescriptor>[ |
| 2797 EXPLICITLY_IMPORTED_LIBRARIES, |
| 2798 EXPORTED_LIBRARIES, |
| 2799 IMPORTED_LIBRARIES, |
| 2800 INCLUDED_PARTS, |
| 2801 PARSE_ERRORS, |
| 2802 PARSED_UNIT, |
| 2803 SOURCE_KIND, |
| 2804 UNITS |
| 2805 ]); |
| 2806 |
| 2807 /** |
| 2808 * Initialize a newly created task to parse the content of the Dart file |
| 2809 * associated with the given [target] in the given [context]. |
| 2810 */ |
| 2811 ParseDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| 2812 : super(context, target); |
| 2813 |
| 2814 @override |
| 2815 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2816 |
| 2817 @override |
| 2818 void internalPerform() { |
| 2819 Source source = getRequiredSource(); |
| 2820 LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT_NAME); |
| 2821 int modificationTime = getRequiredInput(MODIFICATION_TIME_INPUT_NAME); |
| 2822 Token tokenStream = getRequiredInput(TOKEN_STREAM_INPUT_NAME); |
| 2823 |
| 2824 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 2825 Parser parser = new Parser(source, errorListener); |
| 2826 AnalysisOptions options = context.analysisOptions; |
| 2827 parser.parseFunctionBodies = options.analyzeFunctionBodiesPredicate(source); |
| 2828 parser.parseGenericMethods = options.enableGenericMethods; |
| 2829 CompilationUnit unit = parser.parseCompilationUnit(tokenStream); |
| 2830 unit.lineInfo = lineInfo; |
| 2831 |
| 2832 bool hasNonPartOfDirective = false; |
| 2833 bool hasPartOfDirective = false; |
| 2834 HashSet<Source> explicitlyImportedSourceSet = new HashSet<Source>(); |
| 2835 HashSet<Source> exportedSourceSet = new HashSet<Source>(); |
| 2836 HashSet<Source> includedSourceSet = new HashSet<Source>(); |
| 2837 for (Directive directive in unit.directives) { |
| 2838 if (directive is PartOfDirective) { |
| 2839 hasPartOfDirective = true; |
| 2840 } else { |
| 2841 hasNonPartOfDirective = true; |
| 2842 if (directive is UriBasedDirective) { |
| 2843 Source referencedSource = |
| 2844 resolveDirective(context, source, directive, errorListener); |
| 2845 if (referencedSource != null) { |
| 2846 if (directive is ExportDirective) { |
| 2847 exportedSourceSet.add(referencedSource); |
| 2848 } else if (directive is ImportDirective) { |
| 2849 explicitlyImportedSourceSet.add(referencedSource); |
| 2850 } else if (directive is PartDirective) { |
| 2851 includedSourceSet.add(referencedSource); |
| 2852 } else { |
| 2853 throw new AnalysisException( |
| 2854 '$runtimeType failed to handle a ${directive.runtimeType}'); |
| 2855 } |
| 2856 } |
| 2857 } |
| 2858 } |
| 2859 } |
| 2860 // |
| 2861 // Always include "dart:core" source. |
| 2862 // |
| 2863 HashSet<Source> importedSourceSet = |
| 2864 new HashSet.from(explicitlyImportedSourceSet); |
| 2865 Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE); |
| 2866 importedSourceSet.add(coreLibrarySource); |
| 2867 // |
| 2868 // Compute kind. |
| 2869 // |
| 2870 SourceKind sourceKind = SourceKind.LIBRARY; |
| 2871 if (modificationTime == -1) { |
| 2872 sourceKind = SourceKind.UNKNOWN; |
| 2873 } else if (hasPartOfDirective && !hasNonPartOfDirective) { |
| 2874 sourceKind = SourceKind.PART; |
| 2875 } |
| 2876 // |
| 2877 // Record outputs. |
| 2878 // |
| 2879 List<Source> explicitlyImportedSources = |
| 2880 explicitlyImportedSourceSet.toList(); |
| 2881 List<Source> exportedSources = exportedSourceSet.toList(); |
| 2882 List<Source> importedSources = importedSourceSet.toList(); |
| 2883 List<Source> includedSources = includedSourceSet.toList(); |
| 2884 List<AnalysisError> parseErrors = |
| 2885 removeDuplicateErrors(errorListener.errors); |
| 2886 List<Source> unitSources = <Source>[source]..addAll(includedSourceSet); |
| 2887 outputs[EXPLICITLY_IMPORTED_LIBRARIES] = explicitlyImportedSources; |
| 2888 outputs[EXPORTED_LIBRARIES] = exportedSources; |
| 2889 outputs[IMPORTED_LIBRARIES] = importedSources; |
| 2890 outputs[INCLUDED_PARTS] = includedSources; |
| 2891 outputs[PARSE_ERRORS] = parseErrors; |
| 2892 outputs[PARSED_UNIT] = unit; |
| 2893 outputs[SOURCE_KIND] = sourceKind; |
| 2894 outputs[UNITS] = unitSources; |
| 2895 } |
| 2896 |
| 2897 /** |
| 2898 * Return a map from the names of the inputs of this kind of task to the task |
| 2899 * input descriptors describing those inputs for a task with the given |
| 2900 * [source]. |
| 2901 */ |
| 2902 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 2903 return <String, TaskInput>{ |
| 2904 LINE_INFO_INPUT_NAME: LINE_INFO.of(target), |
| 2905 MODIFICATION_TIME_INPUT_NAME: MODIFICATION_TIME.of(target), |
| 2906 TOKEN_STREAM_INPUT_NAME: TOKEN_STREAM.of(target) |
| 2907 }; |
| 2908 } |
| 2909 |
| 2910 /** |
| 2911 * Create a [ParseDartTask] based on the given [target] in the given |
| 2912 * [context]. |
| 2913 */ |
| 2914 static ParseDartTask createTask( |
| 2915 AnalysisContext context, AnalysisTarget target) { |
| 2916 return new ParseDartTask(context, target); |
| 2917 } |
| 2918 |
| 2919 /** |
| 2920 * Return the result of resolving the URI of the given URI-based [directive] |
| 2921 * against the URI of the given library, or `null` if the URI is not valid. |
| 2922 * |
| 2923 * Resolution is to be performed in the given [context]. Errors should be |
| 2924 * reported to the [errorListener]. |
| 2925 */ |
| 2926 static Source resolveDirective(AnalysisContext context, Source librarySource, |
| 2927 UriBasedDirective directive, AnalysisErrorListener errorListener) { |
| 2928 StringLiteral uriLiteral = directive.uri; |
| 2929 String uriContent = uriLiteral.stringValue; |
| 2930 if (uriContent != null) { |
| 2931 uriContent = uriContent.trim(); |
| 2932 directive.uriContent = uriContent; |
| 2933 } |
| 2934 UriValidationCode code = directive.validate(); |
| 2935 if (code == null) { |
| 2936 String encodedUriContent = Uri.encodeFull(uriContent); |
| 2937 Source source = |
| 2938 context.sourceFactory.resolveUri(librarySource, encodedUriContent); |
| 2939 directive.source = source; |
| 2940 return source; |
| 2941 } |
| 2942 if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) { |
| 2943 return null; |
| 2944 } |
| 2945 if (code == UriValidationCode.URI_WITH_INTERPOLATION) { |
| 2946 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, |
| 2947 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION)); |
| 2948 return null; |
| 2949 } |
| 2950 if (code == UriValidationCode.INVALID_URI) { |
| 2951 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, |
| 2952 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent])); |
| 2953 return null; |
| 2954 } |
| 2955 throw new AnalysisException('Failed to handle validation code: $code'); |
| 2956 } |
| 2957 } |
| 2958 |
| 2959 /** |
| 2960 * A task that builds [RESOLVED_UNIT5] for a unit. |
| 2961 */ |
| 2962 class PartiallyResolveUnitReferencesTask extends SourceBasedAnalysisTask { |
| 2963 /** |
| 2964 * The name of the [LIBRARY_ELEMENT5] input. |
| 2965 */ |
| 2966 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 2967 |
| 2968 /** |
| 2969 * The name of the [RESOLVED_UNIT4] input. |
| 2970 */ |
| 2971 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 2972 |
| 2973 /** |
| 2974 * The name of the [TYPE_PROVIDER] input. |
| 2975 */ |
| 2976 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 2977 |
| 2978 /** |
| 2979 * The task descriptor describing this kind of task. |
| 2980 */ |
| 2981 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 2982 'PartiallyResolveUnitReferencesTask', |
| 2983 createTask, |
| 2984 buildInputs, <ResultDescriptor>[ |
| 2985 CLASSES_IN_UNIT, |
| 2986 INFERABLE_STATIC_VARIABLES_IN_UNIT, |
| 2987 PARTIALLY_RESOLVE_REFERENCES_ERRORS, |
| 2988 RESOLVED_UNIT5 |
| 2989 ]); |
| 2990 |
| 2991 PartiallyResolveUnitReferencesTask( |
| 2992 InternalAnalysisContext context, AnalysisTarget target) |
| 2993 : super(context, target); |
| 2994 |
| 2995 @override |
| 2996 TaskDescriptor get descriptor => DESCRIPTOR; |
| 2997 |
| 2998 @override |
| 2999 void internalPerform() { |
| 3000 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3001 // |
| 3002 // Prepare inputs. |
| 3003 // |
| 3004 LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| 3005 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 3006 CompilationUnitElement unitElement = unit.element; |
| 3007 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 3008 // |
| 3009 // Resolve references. |
| 3010 // |
| 3011 InheritanceManager inheritanceManager = |
| 3012 new InheritanceManager(libraryElement); |
| 3013 // TODO(brianwilkerson) Improve performance by not resolving anything inside |
| 3014 // function bodies. Function bodies will be resolved later so this is wasted |
| 3015 // effort. |
| 3016 AstVisitor visitor = new ResolverVisitor( |
| 3017 libraryElement, unitElement.source, typeProvider, errorListener, |
| 3018 inheritanceManager: inheritanceManager); |
| 3019 unit.accept(visitor); |
| 3020 // |
| 3021 // Prepare targets for inference. |
| 3022 // |
| 3023 List<VariableElement> staticVariables = <VariableElement>[]; |
| 3024 List<ClassElement> classes = <ClassElement>[]; |
| 3025 if (context.analysisOptions.strongMode) { |
| 3026 InferrenceFinder inferrenceFinder = new InferrenceFinder(); |
| 3027 unit.accept(inferrenceFinder); |
| 3028 staticVariables = inferrenceFinder.staticVariables; |
| 3029 classes = inferrenceFinder.classes; |
| 3030 } |
| 3031 // |
| 3032 // Record outputs. |
| 3033 // |
| 3034 outputs[CLASSES_IN_UNIT] = classes; |
| 3035 outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = staticVariables; |
| 3036 outputs[PARTIALLY_RESOLVE_REFERENCES_ERRORS] = |
| 3037 removeDuplicateErrors(errorListener.errors); |
| 3038 outputs[RESOLVED_UNIT5] = unit; |
| 3039 } |
| 3040 |
| 3041 /** |
| 3042 * Return a map from the names of the inputs of this kind of task to the task |
| 3043 * input descriptors describing those inputs for a task with the |
| 3044 * given [target]. |
| 3045 */ |
| 3046 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3047 LibrarySpecificUnit unit = target; |
| 3048 return <String, TaskInput>{ |
| 3049 'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE |
| 3050 .of(unit.library) |
| 3051 .toListOf(LIBRARY_ELEMENT5), |
| 3052 LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library), |
| 3053 UNIT_INPUT: RESOLVED_UNIT4.of(unit), |
| 3054 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 3055 }; |
| 3056 } |
| 3057 |
| 3058 /** |
| 3059 * Create a [PartiallyResolveUnitReferencesTask] based on the given [target] |
| 3060 * in the given [context]. |
| 3061 */ |
| 3062 static PartiallyResolveUnitReferencesTask createTask( |
| 3063 AnalysisContext context, AnalysisTarget target) { |
| 3064 return new PartiallyResolveUnitReferencesTask(context, target); |
| 3065 } |
| 3066 } |
| 3067 |
| 3068 /** |
| 3069 * The helper for building the public [Namespace] of a [LibraryElement]. |
| 3070 */ |
| 3071 class PublicNamespaceBuilder { |
| 3072 final HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| 3073 |
| 3074 /** |
| 3075 * Build a public [Namespace] of the given [library]. |
| 3076 */ |
| 3077 Namespace build(LibraryElement library) { |
| 3078 definedNames.clear(); |
| 3079 _addPublicNames(library.definingCompilationUnit); |
| 3080 library.parts.forEach(_addPublicNames); |
| 3081 return new Namespace(definedNames); |
| 3082 } |
| 3083 |
| 3084 /** |
| 3085 * Add the given [element] if it has a publicly visible name. |
| 3086 */ |
| 3087 void _addIfPublic(Element element) { |
| 3088 String name = element.name; |
| 3089 if (name != null && !Scope.isPrivateName(name)) { |
| 3090 definedNames[name] = element; |
| 3091 } |
| 3092 } |
| 3093 |
| 3094 /** |
| 3095 * Add all of the public top-level names that are defined in the given |
| 3096 * [compilationUnit]. |
| 3097 */ |
| 3098 void _addPublicNames(CompilationUnitElement compilationUnit) { |
| 3099 compilationUnit.accessors.forEach(_addIfPublic); |
| 3100 compilationUnit.enums.forEach(_addIfPublic); |
| 3101 compilationUnit.functions.forEach(_addIfPublic); |
| 3102 compilationUnit.functionTypeAliases.forEach(_addIfPublic); |
| 3103 compilationUnit.types.forEach(_addIfPublic); |
| 3104 } |
| 3105 } |
| 3106 |
| 3107 /** |
| 3108 * Information about a library - which names it uses, which names it defines |
| 3109 * with their externally visible dependencies. |
| 3110 */ |
| 3111 class ReferencedNames { |
| 3112 final Set<String> names = new Set<String>(); |
| 3113 final Map<String, Set<String>> userToDependsOn = <String, Set<String>>{}; |
| 3114 |
| 3115 /** |
| 3116 * Updates [delta] by adding names that are changed in this library. |
| 3117 */ |
| 3118 void addChangedElements(DartDelta delta) { |
| 3119 bool hasProgress = true; |
| 3120 while (hasProgress) { |
| 3121 hasProgress = false; |
| 3122 userToDependsOn.forEach((user, dependencies) { |
| 3123 for (String dependency in dependencies) { |
| 3124 if (delta.isNameAffected(dependency)) { |
| 3125 if (delta.nameChanged(user)) { |
| 3126 hasProgress = true; |
| 3127 } |
| 3128 } |
| 3129 } |
| 3130 }); |
| 3131 } |
| 3132 } |
| 3133 |
| 3134 /** |
| 3135 * Returns `true` if the library described by this object is affected by |
| 3136 * the given [delta]. |
| 3137 */ |
| 3138 bool isAffectedBy(DartDelta delta) { |
| 3139 for (String name in names) { |
| 3140 if (delta.isNameAffected(name)) { |
| 3141 return true; |
| 3142 } |
| 3143 } |
| 3144 return false; |
| 3145 } |
| 3146 } |
| 3147 |
| 3148 /** |
| 3149 * A builder for creating [ReferencedNames]. |
| 3150 * |
| 3151 * TODO(scheglov) Record dependencies for all other top-level declarations. |
| 3152 */ |
| 3153 class ReferencedNamesBuilder extends RecursiveAstVisitor { |
| 3154 final ReferencedNames names; |
| 3155 int bodyLevel = 0; |
| 3156 Set<String> dependsOn; |
| 3157 |
| 3158 ReferencedNamesBuilder(this.names); |
| 3159 |
| 3160 ReferencedNames build(CompilationUnit unit) { |
| 3161 unit.accept(this); |
| 3162 return names; |
| 3163 } |
| 3164 |
| 3165 @override |
| 3166 visitBlockFunctionBody(BlockFunctionBody node) { |
| 3167 try { |
| 3168 bodyLevel++; |
| 3169 super.visitBlockFunctionBody(node); |
| 3170 } finally { |
| 3171 bodyLevel--; |
| 3172 } |
| 3173 } |
| 3174 |
| 3175 @override |
| 3176 visitClassDeclaration(ClassDeclaration node) { |
| 3177 dependsOn = new Set<String>(); |
| 3178 super.visitClassDeclaration(node); |
| 3179 names.userToDependsOn[node.name.name] = dependsOn; |
| 3180 dependsOn = null; |
| 3181 } |
| 3182 |
| 3183 @override |
| 3184 visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 3185 try { |
| 3186 bodyLevel++; |
| 3187 super.visitExpressionFunctionBody(node); |
| 3188 } finally { |
| 3189 bodyLevel--; |
| 3190 } |
| 3191 } |
| 3192 |
| 3193 @override |
| 3194 visitSimpleIdentifier(SimpleIdentifier node) { |
| 3195 if (!node.inDeclarationContext()) { |
| 3196 String name = node.name; |
| 3197 names.names.add(name); |
| 3198 if (dependsOn != null && bodyLevel == 0) { |
| 3199 dependsOn.add(name); |
| 3200 } |
| 3201 } |
| 3202 } |
| 3203 } |
| 3204 |
| 3205 /** |
| 3206 * A task that finishes resolution by requesting [RESOLVED_UNIT_NO_CONSTANTS] fo
r every |
| 3207 * unit in the libraries closure and produces [LIBRARY_ELEMENT]. |
| 3208 */ |
| 3209 class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask { |
| 3210 /** |
| 3211 * The name of the [LIBRARY_ELEMENT5] input. |
| 3212 */ |
| 3213 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 3214 |
| 3215 /** |
| 3216 * The name of the list of [RESOLVED_UNIT8] input. |
| 3217 */ |
| 3218 static const String UNITS_INPUT = 'UNITS_INPUT'; |
| 3219 |
| 3220 /** |
| 3221 * The task descriptor describing this kind of task. |
| 3222 */ |
| 3223 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3224 'ResolveLibraryReferencesTask', |
| 3225 createTask, |
| 3226 buildInputs, |
| 3227 <ResultDescriptor>[LIBRARY_ELEMENT, REFERENCED_NAMES]); |
| 3228 |
| 3229 ResolveLibraryReferencesTask( |
| 3230 InternalAnalysisContext context, AnalysisTarget target) |
| 3231 : super(context, target); |
| 3232 |
| 3233 @override |
| 3234 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3235 |
| 3236 @override |
| 3237 void internalPerform() { |
| 3238 // |
| 3239 // Prepare inputs. |
| 3240 // |
| 3241 LibraryElement library = getRequiredInput(LIBRARY_INPUT); |
| 3242 List<CompilationUnit> units = getRequiredInput(UNITS_INPUT); |
| 3243 // Compute referenced names. |
| 3244 ReferencedNames referencedNames = new ReferencedNames(); |
| 3245 for (CompilationUnit unit in units) { |
| 3246 new ReferencedNamesBuilder(referencedNames).build(unit); |
| 3247 } |
| 3248 // |
| 3249 // Record outputs. |
| 3250 // |
| 3251 outputs[LIBRARY_ELEMENT] = library; |
| 3252 outputs[REFERENCED_NAMES] = referencedNames; |
| 3253 } |
| 3254 |
| 3255 /** |
| 3256 * Return a map from the names of the inputs of this kind of task to the task |
| 3257 * input descriptors describing those inputs for a task with the |
| 3258 * given [target]. |
| 3259 */ |
| 3260 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3261 Source source = target; |
| 3262 return <String, TaskInput>{ |
| 3263 LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source), |
| 3264 UNITS_INPUT: UNITS.of(source).toList((Source unit) => |
| 3265 RESOLVED_UNIT8.of(new LibrarySpecificUnit(source, unit))), |
| 3266 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE |
| 3267 .of(source) |
| 3268 .toMapOf(UNITS) |
| 3269 .toFlattenList((Source library, Source unit) => |
| 3270 RESOLVED_UNIT8.of(new LibrarySpecificUnit(library, unit))), |
| 3271 }; |
| 3272 } |
| 3273 |
| 3274 /** |
| 3275 * Create a [ResolveLibraryReferencesTask] based on the given [target] in |
| 3276 * the given [context]. |
| 3277 */ |
| 3278 static ResolveLibraryReferencesTask createTask( |
| 3279 AnalysisContext context, AnalysisTarget target) { |
| 3280 return new ResolveLibraryReferencesTask(context, target); |
| 3281 } |
| 3282 } |
| 3283 |
| 3284 /** |
| 3285 * An artifitial task that does nothing except to force type names resolution |
| 3286 * for the defining and part units of a library. |
| 3287 */ |
| 3288 class ResolveLibraryTypeNamesTask extends SourceBasedAnalysisTask { |
| 3289 /** |
| 3290 * The name of the [LIBRARY_ELEMENT4] input. |
| 3291 */ |
| 3292 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 3293 |
| 3294 /** |
| 3295 * The task descriptor describing this kind of task. |
| 3296 */ |
| 3297 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3298 'ResolveLibraryTypeNamesTask', |
| 3299 createTask, |
| 3300 buildInputs, |
| 3301 <ResultDescriptor>[LIBRARY_ELEMENT5]); |
| 3302 |
| 3303 ResolveLibraryTypeNamesTask( |
| 3304 InternalAnalysisContext context, AnalysisTarget target) |
| 3305 : super(context, target); |
| 3306 |
| 3307 @override |
| 3308 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3309 |
| 3310 @override |
| 3311 void internalPerform() { |
| 3312 LibraryElement library = getRequiredInput(LIBRARY_INPUT); |
| 3313 outputs[LIBRARY_ELEMENT5] = library; |
| 3314 } |
| 3315 |
| 3316 /** |
| 3317 * Return a map from the names of the inputs of this kind of task to the task |
| 3318 * input descriptors describing those inputs for a task with the |
| 3319 * given [target]. |
| 3320 */ |
| 3321 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3322 Source source = target; |
| 3323 return <String, TaskInput>{ |
| 3324 'resolvedUnit': UNITS.of(source).toList((Source unit) => |
| 3325 RESOLVED_UNIT3.of(new LibrarySpecificUnit(source, unit))), |
| 3326 LIBRARY_INPUT: LIBRARY_ELEMENT4.of(source) |
| 3327 }; |
| 3328 } |
| 3329 |
| 3330 /** |
| 3331 * Create a [ResolveLibraryTypeNamesTask] based on the given [target] in |
| 3332 * the given [context]. |
| 3333 */ |
| 3334 static ResolveLibraryTypeNamesTask createTask( |
| 3335 AnalysisContext context, AnalysisTarget target) { |
| 3336 return new ResolveLibraryTypeNamesTask(context, target); |
| 3337 } |
| 3338 } |
| 3339 |
| 3340 /** |
| 3341 * A task that builds [RESOLVED_UNIT8] for a unit. |
| 3342 */ |
| 3343 class ResolveUnitReferencesTask extends SourceBasedAnalysisTask { |
| 3344 /** |
| 3345 * The name of the [LIBRARY_ELEMENT5] input. |
| 3346 */ |
| 3347 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 3348 |
| 3349 /** |
| 3350 * The name of the [RESOLVED_UNIT4] input. |
| 3351 */ |
| 3352 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 3353 |
| 3354 /** |
| 3355 * The name of the [TYPE_PROVIDER] input. |
| 3356 */ |
| 3357 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 3358 |
| 3359 /** |
| 3360 * The task descriptor describing this kind of task. |
| 3361 */ |
| 3362 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3363 'ResolveUnitReferencesTask', |
| 3364 createTask, |
| 3365 buildInputs, |
| 3366 <ResultDescriptor>[RESOLVE_REFERENCES_ERRORS, RESOLVED_UNIT8]); |
| 3367 |
| 3368 ResolveUnitReferencesTask( |
| 3369 InternalAnalysisContext context, AnalysisTarget target) |
| 3370 : super(context, target); |
| 3371 |
| 3372 @override |
| 3373 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3374 |
| 3375 @override |
| 3376 void internalPerform() { |
| 3377 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3378 // |
| 3379 // Prepare inputs. |
| 3380 // |
| 3381 LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| 3382 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 3383 CompilationUnitElement unitElement = unit.element; |
| 3384 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 3385 // |
| 3386 // Resolve references. |
| 3387 // |
| 3388 InheritanceManager inheritanceManager = |
| 3389 new InheritanceManager(libraryElement); |
| 3390 AstVisitor visitor = new ResolverVisitor( |
| 3391 libraryElement, unitElement.source, typeProvider, errorListener, |
| 3392 inheritanceManager: inheritanceManager); |
| 3393 unit.accept(visitor); |
| 3394 // |
| 3395 // Record outputs. |
| 3396 // |
| 3397 outputs[RESOLVE_REFERENCES_ERRORS] = |
| 3398 removeDuplicateErrors(errorListener.errors); |
| 3399 outputs[RESOLVED_UNIT8] = unit; |
| 3400 } |
| 3401 |
| 3402 /** |
| 3403 * Return a map from the names of the inputs of this kind of task to the task |
| 3404 * input descriptors describing those inputs for a task with the |
| 3405 * given [target]. |
| 3406 */ |
| 3407 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3408 LibrarySpecificUnit unit = target; |
| 3409 return <String, TaskInput>{ |
| 3410 'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE |
| 3411 .of(unit.library) |
| 3412 .toListOf(LIBRARY_ELEMENT5), |
| 3413 LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library), |
| 3414 UNIT_INPUT: RESOLVED_UNIT4.of(unit), |
| 3415 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 3416 }; |
| 3417 } |
| 3418 |
| 3419 /** |
| 3420 * Create a [ResolveUnitReferencesTask] based on the given [target] in |
| 3421 * the given [context]. |
| 3422 */ |
| 3423 static ResolveUnitReferencesTask createTask( |
| 3424 AnalysisContext context, AnalysisTarget target) { |
| 3425 return new ResolveUnitReferencesTask(context, target); |
| 3426 } |
| 3427 } |
| 3428 |
| 3429 /** |
| 3430 * A task that builds [RESOLVED_UNIT3] for a unit. |
| 3431 */ |
| 3432 class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask { |
| 3433 /** |
| 3434 * The name of the input whose value is the defining [LIBRARY_ELEMENT4]. |
| 3435 */ |
| 3436 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 3437 |
| 3438 /** |
| 3439 * The name of the [RESOLVED_UNIT2] input. |
| 3440 */ |
| 3441 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 3442 |
| 3443 /** |
| 3444 * The name of the [TYPE_PROVIDER] input. |
| 3445 */ |
| 3446 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 3447 |
| 3448 /** |
| 3449 * The task descriptor describing this kind of task. |
| 3450 */ |
| 3451 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3452 'ResolveUnitTypeNamesTask', |
| 3453 createTask, |
| 3454 buildInputs, |
| 3455 <ResultDescriptor>[RESOLVE_TYPE_NAMES_ERRORS, RESOLVED_UNIT3]); |
| 3456 |
| 3457 ResolveUnitTypeNamesTask( |
| 3458 InternalAnalysisContext context, AnalysisTarget target) |
| 3459 : super(context, target); |
| 3460 |
| 3461 @override |
| 3462 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3463 |
| 3464 @override |
| 3465 void internalPerform() { |
| 3466 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3467 // |
| 3468 // Prepare inputs. |
| 3469 // |
| 3470 LibraryElement library = getRequiredInput(LIBRARY_INPUT); |
| 3471 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 3472 CompilationUnitElement unitElement = unit.element; |
| 3473 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 3474 // |
| 3475 // Resolve TypeName nodes. |
| 3476 // |
| 3477 TypeResolverVisitor visitor = new TypeResolverVisitor( |
| 3478 library, unitElement.source, typeProvider, errorListener); |
| 3479 unit.accept(visitor); |
| 3480 // |
| 3481 // Record outputs. |
| 3482 // |
| 3483 outputs[RESOLVE_TYPE_NAMES_ERRORS] = |
| 3484 removeDuplicateErrors(errorListener.errors); |
| 3485 outputs[RESOLVED_UNIT3] = unit; |
| 3486 } |
| 3487 |
| 3488 /** |
| 3489 * Return a map from the names of the inputs of this kind of task to the task |
| 3490 * input descriptors describing those inputs for a task with the |
| 3491 * given [target]. |
| 3492 */ |
| 3493 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3494 LibrarySpecificUnit unit = target; |
| 3495 return <String, TaskInput>{ |
| 3496 'importsExportNamespace': |
| 3497 IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4), |
| 3498 LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library), |
| 3499 UNIT_INPUT: RESOLVED_UNIT2.of(unit), |
| 3500 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 3501 }; |
| 3502 } |
| 3503 |
| 3504 /** |
| 3505 * Create a [ResolveUnitTypeNamesTask] based on the given [target] in |
| 3506 * the given [context]. |
| 3507 */ |
| 3508 static ResolveUnitTypeNamesTask createTask( |
| 3509 AnalysisContext context, AnalysisTarget target) { |
| 3510 return new ResolveUnitTypeNamesTask(context, target); |
| 3511 } |
| 3512 } |
| 3513 |
| 3514 /** |
| 3515 * A task that builds [RESOLVED_UNIT4] for a unit. |
| 3516 */ |
| 3517 class ResolveVariableReferencesTask extends SourceBasedAnalysisTask { |
| 3518 /** |
| 3519 * The name of the [LIBRARY_ELEMENT1] input. |
| 3520 */ |
| 3521 static const String LIBRARY_INPUT = 'LIBRARY_INPUT'; |
| 3522 |
| 3523 /** |
| 3524 * The name of the [RESOLVED_UNIT3] input. |
| 3525 */ |
| 3526 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 3527 |
| 3528 /** |
| 3529 * The name of the [TYPE_PROVIDER] input. |
| 3530 */ |
| 3531 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 3532 |
| 3533 /** |
| 3534 * The task descriptor describing this kind of task. |
| 3535 */ |
| 3536 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3537 'ResolveVariableReferencesTask', |
| 3538 createTask, |
| 3539 buildInputs, |
| 3540 <ResultDescriptor>[RESOLVED_UNIT4, VARIABLE_REFERENCE_ERRORS]); |
| 3541 |
| 3542 ResolveVariableReferencesTask( |
| 3543 InternalAnalysisContext context, AnalysisTarget target) |
| 3544 : super(context, target); |
| 3545 |
| 3546 @override |
| 3547 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3548 |
| 3549 @override |
| 3550 void internalPerform() { |
| 3551 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3552 // |
| 3553 // Prepare inputs. |
| 3554 // |
| 3555 LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT); |
| 3556 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 3557 CompilationUnitElement unitElement = unit.element; |
| 3558 // |
| 3559 // Resolve local variables. |
| 3560 // |
| 3561 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 3562 Scope nameScope = new LibraryScope(libraryElement, errorListener); |
| 3563 AstVisitor visitor = new VariableResolverVisitor( |
| 3564 libraryElement, unitElement.source, typeProvider, errorListener, |
| 3565 nameScope: nameScope); |
| 3566 unit.accept(visitor); |
| 3567 // |
| 3568 // Record outputs. |
| 3569 // |
| 3570 outputs[RESOLVED_UNIT4] = unit; |
| 3571 outputs[VARIABLE_REFERENCE_ERRORS] = |
| 3572 removeDuplicateErrors(errorListener.errors); |
| 3573 } |
| 3574 |
| 3575 /** |
| 3576 * Return a map from the names of the inputs of this kind of task to the task |
| 3577 * input descriptors describing those inputs for a task with the |
| 3578 * given [target]. |
| 3579 */ |
| 3580 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3581 LibrarySpecificUnit unit = target; |
| 3582 return <String, TaskInput>{ |
| 3583 LIBRARY_INPUT: LIBRARY_ELEMENT1.of(unit.library), |
| 3584 UNIT_INPUT: RESOLVED_UNIT1.of(unit), |
| 3585 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 3586 }; |
| 3587 } |
| 3588 |
| 3589 /** |
| 3590 * Create a [ResolveVariableReferencesTask] based on the given [target] in |
| 3591 * the given [context]. |
| 3592 */ |
| 3593 static ResolveVariableReferencesTask createTask( |
| 3594 AnalysisContext context, AnalysisTarget target) { |
| 3595 return new ResolveVariableReferencesTask(context, target); |
| 3596 } |
| 3597 } |
| 3598 |
| 3599 /** |
| 3600 * A task that scans the content of a file, producing a set of Dart tokens. |
| 3601 */ |
| 3602 class ScanDartTask extends SourceBasedAnalysisTask { |
| 3603 /** |
| 3604 * The name of the input whose value is the content of the file. |
| 3605 */ |
| 3606 static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; |
| 3607 |
| 3608 /** |
| 3609 * The task descriptor describing this kind of task. |
| 3610 */ |
| 3611 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 3612 'ScanDartTask', |
| 3613 createTask, |
| 3614 buildInputs, |
| 3615 <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM]); |
| 3616 |
| 3617 /** |
| 3618 * Initialize a newly created task to access the content of the source |
| 3619 * associated with the given [target] in the given [context]. |
| 3620 */ |
| 3621 ScanDartTask(InternalAnalysisContext context, AnalysisTarget target) |
| 3622 : super(context, target); |
| 3623 |
| 3624 @override |
| 3625 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3626 |
| 3627 @override |
| 3628 void internalPerform() { |
| 3629 Source source = getRequiredSource(); |
| 3630 |
| 3631 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3632 if (context.getModificationStamp(target.source) < 0) { |
| 3633 String message = 'Content could not be read'; |
| 3634 if (context is InternalAnalysisContext) { |
| 3635 CacheEntry entry = |
| 3636 (context as InternalAnalysisContext).getCacheEntry(target); |
| 3637 CaughtException exception = entry.exception; |
| 3638 if (exception != null) { |
| 3639 message = exception.toString(); |
| 3640 } |
| 3641 } |
| 3642 errorListener.onError(new AnalysisError( |
| 3643 source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])); |
| 3644 } |
| 3645 if (target is DartScript) { |
| 3646 DartScript script = target; |
| 3647 List<ScriptFragment> fragments = script.fragments; |
| 3648 if (fragments.length < 1) { |
| 3649 throw new AnalysisException('Cannot scan scripts with no fragments'); |
| 3650 } else if (fragments.length > 1) { |
| 3651 throw new AnalysisException( |
| 3652 'Cannot scan scripts with multiple fragments'); |
| 3653 } |
| 3654 ScriptFragment fragment = fragments[0]; |
| 3655 |
| 3656 Scanner scanner = new Scanner( |
| 3657 source, |
| 3658 new SubSequenceReader(fragment.content, fragment.offset), |
| 3659 errorListener); |
| 3660 scanner.setSourceStart(fragment.line, fragment.column); |
| 3661 scanner.preserveComments = context.analysisOptions.preserveComments; |
| 3662 |
| 3663 outputs[TOKEN_STREAM] = scanner.tokenize(); |
| 3664 outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| 3665 outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors); |
| 3666 } else if (target is Source) { |
| 3667 String content = getRequiredInput(CONTENT_INPUT_NAME); |
| 3668 |
| 3669 Scanner scanner = |
| 3670 new Scanner(source, new CharSequenceReader(content), errorListener); |
| 3671 scanner.preserveComments = context.analysisOptions.preserveComments; |
| 3672 |
| 3673 outputs[TOKEN_STREAM] = scanner.tokenize(); |
| 3674 outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| 3675 outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors); |
| 3676 } else { |
| 3677 throw new AnalysisException( |
| 3678 'Cannot scan Dart code from a ${target.runtimeType}'); |
| 3679 } |
| 3680 } |
| 3681 |
| 3682 /** |
| 3683 * Return a map from the names of the inputs of this kind of task to the task |
| 3684 * input descriptors describing those inputs for a task with the given |
| 3685 * [source]. |
| 3686 */ |
| 3687 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3688 if (target is Source) { |
| 3689 return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(target)}; |
| 3690 } else if (target is DartScript) { |
| 3691 // This task does not use the following input; it is included only to add |
| 3692 // a dependency between this value and the containing source so that when |
| 3693 // the containing source is modified these results will be invalidated. |
| 3694 return <String, TaskInput>{'-': DART_SCRIPTS.of(target.source)}; |
| 3695 } |
| 3696 throw new AnalysisException( |
| 3697 'Cannot build inputs for a ${target.runtimeType}'); |
| 3698 } |
| 3699 |
| 3700 /** |
| 3701 * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| 3702 */ |
| 3703 static ScanDartTask createTask( |
| 3704 AnalysisContext context, AnalysisTarget target) { |
| 3705 return new ScanDartTask(context, target); |
| 3706 } |
| 3707 } |
| 3708 |
| 3709 /** |
| 3710 * A task that builds [VERIFY_ERRORS] for a unit. |
| 3711 */ |
| 3712 class VerifyUnitTask extends SourceBasedAnalysisTask { |
| 3713 /** |
| 3714 * The name of the [RESOLVED_UNIT] input. |
| 3715 */ |
| 3716 static const String UNIT_INPUT = 'UNIT_INPUT'; |
| 3717 |
| 3718 /** |
| 3719 * The name of the [TYPE_PROVIDER] input. |
| 3720 */ |
| 3721 static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT'; |
| 3722 |
| 3723 /** |
| 3724 * The task descriptor describing this kind of task. |
| 3725 */ |
| 3726 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('VerifyUnitTask', |
| 3727 createTask, buildInputs, <ResultDescriptor>[VERIFY_ERRORS]); |
| 3728 |
| 3729 /** |
| 3730 * The [ErrorReporter] to report errors to. |
| 3731 */ |
| 3732 ErrorReporter errorReporter; |
| 3733 |
| 3734 VerifyUnitTask(InternalAnalysisContext context, AnalysisTarget target) |
| 3735 : super(context, target); |
| 3736 |
| 3737 @override |
| 3738 TaskDescriptor get descriptor => DESCRIPTOR; |
| 3739 |
| 3740 @override |
| 3741 void internalPerform() { |
| 3742 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 3743 Source source = getRequiredSource(); |
| 3744 errorReporter = new ErrorReporter(errorListener, source); |
| 3745 // |
| 3746 // Prepare inputs. |
| 3747 // |
| 3748 TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT); |
| 3749 CompilationUnit unit = getRequiredInput(UNIT_INPUT); |
| 3750 CompilationUnitElement unitElement = unit.element; |
| 3751 LibraryElement libraryElement = unitElement.library; |
| 3752 // |
| 3753 // Validate the directives. |
| 3754 // |
| 3755 validateDirectives(unit); |
| 3756 // |
| 3757 // Use the ConstantVerifier to compute errors. |
| 3758 // |
| 3759 ConstantVerifier constantVerifier = new ConstantVerifier( |
| 3760 errorReporter, libraryElement, typeProvider, context.declaredVariables); |
| 3761 unit.accept(constantVerifier); |
| 3762 // |
| 3763 // Use the ErrorVerifier to compute errors. |
| 3764 // |
| 3765 ErrorVerifier errorVerifier = new ErrorVerifier( |
| 3766 errorReporter, |
| 3767 libraryElement, |
| 3768 typeProvider, |
| 3769 new InheritanceManager(libraryElement), |
| 3770 context.analysisOptions.enableSuperMixins); |
| 3771 unit.accept(errorVerifier); |
| 3772 // |
| 3773 // Record outputs. |
| 3774 // |
| 3775 outputs[VERIFY_ERRORS] = removeDuplicateErrors(errorListener.errors); |
| 3776 } |
| 3777 |
| 3778 /** |
| 3779 * Check each directive in the given [unit] to see if the referenced source |
| 3780 * exists and report an error if it does not. |
| 3781 */ |
| 3782 void validateDirectives(CompilationUnit unit) { |
| 3783 for (Directive directive in unit.directives) { |
| 3784 if (directive is UriBasedDirective) { |
| 3785 validateReferencedSource(directive); |
| 3786 } |
| 3787 } |
| 3788 } |
| 3789 |
| 3790 /** |
| 3791 * Check the given [directive] to see if the referenced source exists and |
| 3792 * report an error if it does not. |
| 3793 */ |
| 3794 void validateReferencedSource(UriBasedDirective directive) { |
| 3795 Source source = directive.source; |
| 3796 if (source != null) { |
| 3797 if (context.exists(source)) { |
| 3798 return; |
| 3799 } |
| 3800 } else { |
| 3801 // Don't report errors already reported by ParseDartTask.resolveDirective |
| 3802 if (directive.validate() != null) { |
| 3803 return; |
| 3804 } |
| 3805 } |
| 3806 StringLiteral uriLiteral = directive.uri; |
| 3807 errorReporter.reportErrorForNode(CompileTimeErrorCode.URI_DOES_NOT_EXIST, |
| 3808 uriLiteral, [directive.uriContent]); |
| 3809 } |
| 3810 |
| 3811 /** |
| 3812 * Return a map from the names of the inputs of this kind of task to the task |
| 3813 * input descriptors describing those inputs for a task with the |
| 3814 * given [target]. |
| 3815 */ |
| 3816 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 3817 LibrarySpecificUnit unit = target; |
| 3818 return <String, TaskInput>{ |
| 3819 'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE |
| 3820 .of(unit.library) |
| 3821 .toMapOf(UNITS) |
| 3822 .toFlattenList((Source library, Source unit) => |
| 3823 RESOLVED_UNIT.of(new LibrarySpecificUnit(library, unit))), |
| 3824 UNIT_INPUT: RESOLVED_UNIT.of(unit), |
| 3825 TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request) |
| 3826 }; |
| 3827 } |
| 3828 |
| 3829 /** |
| 3830 * Create a [VerifyUnitTask] based on the given [target] in |
| 3831 * the given [context]. |
| 3832 */ |
| 3833 static VerifyUnitTask createTask( |
| 3834 AnalysisContext context, AnalysisTarget target) { |
| 3835 return new VerifyUnitTask(context, target); |
| 3836 } |
| 3837 } |
| 3838 |
| 3839 /** |
| 3840 * A [TaskInput] whose value is a list of library sources exported directly |
| 3841 * or indirectly by the target [Source]. |
| 3842 * |
| 3843 * [resultDescriptor] is the type of result which should be produced for each |
| 3844 * target [Source]. |
| 3845 */ |
| 3846 class _ExportSourceClosureTaskInput extends TaskInputImpl<List<Source>> { |
| 3847 final Source target; |
| 3848 final ResultDescriptor resultDescriptor; |
| 3849 |
| 3850 _ExportSourceClosureTaskInput(this.target, this.resultDescriptor); |
| 3851 |
| 3852 @override |
| 3853 TaskInputBuilder<List<Source>> createBuilder() => |
| 3854 new _SourceClosureTaskInputBuilder( |
| 3855 target, _SourceClosureKind.EXPORT, resultDescriptor); |
| 3856 } |
| 3857 |
| 3858 /** |
| 3859 * A [TaskInput] whose value is a list of library sources imported or exported, |
| 3860 * directly or indirectly by the target [Source]. |
| 3861 * |
| 3862 * [resultDescriptor] is the type of result which should be produced for each |
| 3863 * target [Source]. |
| 3864 */ |
| 3865 class _ImportExportSourceClosureTaskInput extends TaskInputImpl<List<Source>> { |
| 3866 final Source target; |
| 3867 final ResultDescriptor resultDescriptor; |
| 3868 |
| 3869 _ImportExportSourceClosureTaskInput(this.target, this.resultDescriptor); |
| 3870 |
| 3871 @override |
| 3872 TaskInputBuilder<List<Source>> createBuilder() => |
| 3873 new _SourceClosureTaskInputBuilder( |
| 3874 target, _SourceClosureKind.IMPORT_EXPORT, resultDescriptor); |
| 3875 } |
| 3876 |
| 3877 /** |
| 3878 * A [TaskInput] whose value is a list of library sources imported directly |
| 3879 * or indirectly by the target [Source]. |
| 3880 * |
| 3881 * [resultDescriptor] is the type of result which should be produced for each |
| 3882 * target [Source]. |
| 3883 */ |
| 3884 class _ImportSourceClosureTaskInput extends TaskInputImpl<List<Source>> { |
| 3885 final Source target; |
| 3886 final ResultDescriptor resultDescriptor; |
| 3887 |
| 3888 _ImportSourceClosureTaskInput(this.target, this.resultDescriptor); |
| 3889 |
| 3890 @override |
| 3891 TaskInputBuilder<List<Source>> createBuilder() => |
| 3892 new _SourceClosureTaskInputBuilder( |
| 3893 target, _SourceClosureKind.IMPORT, resultDescriptor); |
| 3894 } |
| 3895 |
| 3896 /** |
| 3897 * The kind of the source closure to build. |
| 3898 */ |
| 3899 enum _SourceClosureKind { IMPORT, EXPORT, IMPORT_EXPORT } |
| 3900 |
| 3901 /** |
| 3902 * A [TaskInputBuilder] to build values for [_ImportSourceClosureTaskInput]. |
| 3903 */ |
| 3904 class _SourceClosureTaskInputBuilder implements TaskInputBuilder<List<Source>> { |
| 3905 final _SourceClosureKind kind; |
| 3906 final Set<LibraryElement> _libraries = new HashSet<LibraryElement>(); |
| 3907 final List<Source> _newSources = <Source>[]; |
| 3908 |
| 3909 @override |
| 3910 final ResultDescriptor currentResult; |
| 3911 |
| 3912 Source currentTarget; |
| 3913 |
| 3914 _SourceClosureTaskInputBuilder( |
| 3915 Source librarySource, this.kind, this.currentResult) { |
| 3916 _newSources.add(librarySource); |
| 3917 } |
| 3918 |
| 3919 @override |
| 3920 void set currentValue(Object value) { |
| 3921 LibraryElement library = value; |
| 3922 if (_libraries.add(library)) { |
| 3923 if (kind == _SourceClosureKind.IMPORT || |
| 3924 kind == _SourceClosureKind.IMPORT_EXPORT) { |
| 3925 for (ImportElement importElement in library.imports) { |
| 3926 Source importedSource = importElement.importedLibrary.source; |
| 3927 _newSources.add(importedSource); |
| 3928 } |
| 3929 } |
| 3930 if (kind == _SourceClosureKind.EXPORT || |
| 3931 kind == _SourceClosureKind.IMPORT_EXPORT) { |
| 3932 for (ExportElement exportElement in library.exports) { |
| 3933 Source exportedSource = exportElement.exportedLibrary.source; |
| 3934 _newSources.add(exportedSource); |
| 3935 } |
| 3936 } |
| 3937 } |
| 3938 } |
| 3939 |
| 3940 @override |
| 3941 List<Source> get inputValue { |
| 3942 return _libraries.map((LibraryElement library) => library.source).toList(); |
| 3943 } |
| 3944 |
| 3945 @override |
| 3946 void currentValueNotAvailable() { |
| 3947 // Nothing needs to be done. moveNext() will simply go on to the next new |
| 3948 // source. |
| 3949 } |
| 3950 |
| 3951 @override |
| 3952 bool moveNext() { |
| 3953 if (_newSources.isEmpty) { |
| 3954 return false; |
| 3955 } |
| 3956 currentTarget = _newSources.removeLast(); |
| 3957 return true; |
| 3958 } |
| 3959 } |
OLD | NEW |