| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.task.dart; | 5 library analyzer.src.task.dart; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/src/generated/ast.dart'; | 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; | 10 import 'package:analyzer/src/generated/element.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; | 11 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; |
| 12 import 'package:analyzer/src/generated/error.dart'; | 12 import 'package:analyzer/src/generated/error.dart'; |
| 13 import 'package:analyzer/src/generated/java_engine.dart'; | 13 import 'package:analyzer/src/generated/java_engine.dart'; |
| 14 import 'package:analyzer/src/generated/parser.dart'; | 14 import 'package:analyzer/src/generated/parser.dart'; |
| 15 import 'package:analyzer/src/generated/resolver.dart'; | 15 import 'package:analyzer/src/generated/resolver.dart'; |
| 16 import 'package:analyzer/src/generated/scanner.dart'; | 16 import 'package:analyzer/src/generated/scanner.dart'; |
| 17 import 'package:analyzer/src/generated/sdk.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; | 18 import 'package:analyzer/src/generated/source.dart'; |
| 18 import 'package:analyzer/src/task/general.dart'; | 19 import 'package:analyzer/src/task/general.dart'; |
| 20 import 'package:analyzer/src/task/inputs.dart'; |
| 19 import 'package:analyzer/task/dart.dart'; | 21 import 'package:analyzer/task/dart.dart'; |
| 20 import 'package:analyzer/task/general.dart'; | 22 import 'package:analyzer/task/general.dart'; |
| 21 import 'package:analyzer/task/model.dart'; | 23 import 'package:analyzer/task/model.dart'; |
| 22 | 24 |
| 23 /** | 25 /** |
| 24 * A task that builds a compilation unit element for a single compilation unit. | 26 * A task that builds a compilation unit element for a single compilation unit. |
| 25 */ | 27 */ |
| 26 class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask { | 28 class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask { |
| 27 /** | 29 /** |
| 28 * The name of the input whose value is the line information for the | 30 * The name of the input whose value is the line information for the |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 * Create a [BuildCompilationUnitElementTask] based on the given [target] in | 81 * Create a [BuildCompilationUnitElementTask] based on the given [target] in |
| 80 * the given [context]. | 82 * the given [context]. |
| 81 */ | 83 */ |
| 82 static BuildCompilationUnitElementTask createTask( | 84 static BuildCompilationUnitElementTask createTask( |
| 83 AnalysisContext context, AnalysisTarget target) { | 85 AnalysisContext context, AnalysisTarget target) { |
| 84 return new BuildCompilationUnitElementTask(context, target); | 86 return new BuildCompilationUnitElementTask(context, target); |
| 85 } | 87 } |
| 86 } | 88 } |
| 87 | 89 |
| 88 /** | 90 /** |
| 91 * A task that builds a library element for a Dart library. |
| 92 */ |
| 93 class BuildLibraryElementTask extends SourceBasedAnalysisTask { |
| 94 /** |
| 95 * The name of the input whose value is the built compilation unit of the |
| 96 * defining compilation unit of a library. |
| 97 */ |
| 98 static const String DEFINING_BUILT_UNIT_INPUT_NAME = 'definingBuiltUnit'; |
| 99 |
| 100 /** |
| 101 * The name of the input whose value is a list of built compilation units |
| 102 * of the parts sourced by a library. |
| 103 */ |
| 104 static const String PART_BUILT_UNITS_INPUT_NAME = 'partBuiltUnits'; |
| 105 |
| 106 /** |
| 107 * The name of the function used as an entry point. |
| 108 */ |
| 109 static const String ENTRY_POINT_NAME = "main"; |
| 110 |
| 111 /** |
| 112 * The task descriptor describing this kind of task. |
| 113 */ |
| 114 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( |
| 115 'BUILD_LIBRARY_ELEMENT', createTask, buildInputs, <ResultDescriptor>[ |
| 116 BUILD_LIBRARY_ERRORS, |
| 117 BUILT_LIBRARY_ELEMENT, |
| 118 IS_LAUNCHABLE, |
| 119 HAS_HTML_IMPORT |
| 120 ]); |
| 121 |
| 122 /** |
| 123 * Initialize a newly created task to build a library element for the given |
| 124 * [target] in the given [context]. |
| 125 */ |
| 126 BuildLibraryElementTask( |
| 127 InternalAnalysisContext context, AnalysisTarget target) |
| 128 : super(context, target); |
| 129 |
| 130 @override |
| 131 TaskDescriptor get descriptor => DESCRIPTOR; |
| 132 |
| 133 @override |
| 134 void internalPerform() { |
| 135 List<AnalysisError> errors = <AnalysisError>[]; |
| 136 // |
| 137 // Prepare inputs. |
| 138 // |
| 139 Source librarySource = getRequiredSource(); |
| 140 CompilationUnit definingCompilationUnit = |
| 141 getRequiredInput(DEFINING_BUILT_UNIT_INPUT_NAME); |
| 142 List<CompilationUnit> partUnits = |
| 143 getRequiredInput(PART_BUILT_UNITS_INPUT_NAME); |
| 144 // |
| 145 // Process inputs. |
| 146 // |
| 147 CompilationUnitElementImpl definingCompilationUnitElement = |
| 148 definingCompilationUnit.element; |
| 149 Map<Source, CompilationUnit> partUnitMap = |
| 150 new HashMap<Source, CompilationUnit>(); |
| 151 for (CompilationUnit partUnit in partUnits) { |
| 152 Source partSource = partUnit.element.source; |
| 153 partUnitMap[partSource] = partUnit; |
| 154 } |
| 155 Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML); |
| 156 // |
| 157 // Update "part" directives. |
| 158 // |
| 159 LibraryIdentifier libraryNameNode = null; |
| 160 bool hasHtmlImport = false; |
| 161 bool hasPartDirective = false; |
| 162 FunctionElement entryPoint = |
| 163 _findEntryPoint(definingCompilationUnitElement); |
| 164 List<Directive> directivesToResolve = <Directive>[]; |
| 165 List<CompilationUnitElementImpl> sourcedCompilationUnits = |
| 166 <CompilationUnitElementImpl>[]; |
| 167 for (Directive directive in definingCompilationUnit.directives) { |
| 168 if (directive is ImportDirective) { |
| 169 hasHtmlImport = hasHtmlImport || directive.source == htmlSource; |
| 170 } else if (directive is LibraryDirective) { |
| 171 if (libraryNameNode == null) { |
| 172 libraryNameNode = directive.name; |
| 173 directivesToResolve.add(directive); |
| 174 } |
| 175 } else if (directive is PartDirective) { |
| 176 PartDirective partDirective = directive; |
| 177 StringLiteral partUri = partDirective.uri; |
| 178 Source partSource = partDirective.source; |
| 179 if (context.exists(partSource)) { |
| 180 hasPartDirective = true; |
| 181 CompilationUnit partUnit = partUnitMap[partSource]; |
| 182 CompilationUnitElementImpl partElement = partUnit.element; |
| 183 partElement.uriOffset = partUri.offset; |
| 184 partElement.uriEnd = partUri.end; |
| 185 partElement.uri = partDirective.uriContent; |
| 186 // |
| 187 // Validate that the part contains a part-of directive with the same |
| 188 // name as the library. |
| 189 // |
| 190 String partLibraryName = |
| 191 _getPartLibraryName(partSource, partUnit, directivesToResolve); |
| 192 if (partLibraryName == null) { |
| 193 errors.add(new AnalysisError.con2(librarySource, partUri.offset, |
| 194 partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [ |
| 195 partUri.toSource() |
| 196 ])); |
| 197 } else if (libraryNameNode == null) { |
| 198 // TODO(brianwilkerson) Collect the names declared by the part. |
| 199 // If they are all the same then we can use that name as the |
| 200 // inferred name of the library and present it in a quick-fix. |
| 201 // partLibraryNames.add(partLibraryName); |
| 202 } else if (libraryNameNode.name != partLibraryName) { |
| 203 errors.add(new AnalysisError.con2(librarySource, partUri.offset, |
| 204 partUri.length, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [ |
| 205 libraryNameNode.name, |
| 206 partLibraryName |
| 207 ])); |
| 208 } |
| 209 if (entryPoint == null) { |
| 210 entryPoint = _findEntryPoint(partElement); |
| 211 } |
| 212 directive.element = partElement; |
| 213 sourcedCompilationUnits.add(partElement); |
| 214 } |
| 215 } |
| 216 } |
| 217 if (hasPartDirective && libraryNameNode == null) { |
| 218 errors.add(new AnalysisError.con1(librarySource, |
| 219 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART)); |
| 220 } |
| 221 // |
| 222 // Create and populate the library element. |
| 223 // |
| 224 LibraryElementImpl libraryElement = |
| 225 new LibraryElementImpl.forNode(context, libraryNameNode); |
| 226 libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
| 227 libraryElement.entryPoint = entryPoint; |
| 228 libraryElement.parts = sourcedCompilationUnits; |
| 229 for (Directive directive in directivesToResolve) { |
| 230 directive.element = libraryElement; |
| 231 } |
| 232 if (sourcedCompilationUnits.isNotEmpty) { |
| 233 _patchTopLevelAccessors(libraryElement); |
| 234 } |
| 235 // |
| 236 // Record outputs. |
| 237 // |
| 238 outputs[BUILD_LIBRARY_ERRORS] = errors; |
| 239 outputs[BUILT_LIBRARY_ELEMENT] = libraryElement; |
| 240 outputs[IS_LAUNCHABLE] = entryPoint != null; |
| 241 outputs[HAS_HTML_IMPORT] = hasHtmlImport; |
| 242 } |
| 243 |
| 244 /** |
| 245 * Add all of the non-synthetic [getters] and [setters] defined in the given |
| 246 * [unit] that have no corresponding accessor to one of the given collections. |
| 247 */ |
| 248 void _collectAccessors(Map<String, PropertyAccessorElement> getters, |
| 249 List<PropertyAccessorElement> setters, CompilationUnitElement unit) { |
| 250 for (PropertyAccessorElement accessor in unit.accessors) { |
| 251 if (accessor.isGetter) { |
| 252 if (!accessor.isSynthetic && accessor.correspondingSetter == null) { |
| 253 getters[accessor.displayName] = accessor; |
| 254 } |
| 255 } else { |
| 256 if (!accessor.isSynthetic && accessor.correspondingGetter == null) { |
| 257 setters.add(accessor); |
| 258 } |
| 259 } |
| 260 } |
| 261 } |
| 262 |
| 263 /** |
| 264 * Return the top-level [FunctionElement] entry point, or `null` if the given |
| 265 * [element] does not define an entry point. |
| 266 */ |
| 267 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) { |
| 268 for (FunctionElement function in element.functions) { |
| 269 if (function.name == ENTRY_POINT_NAME) { |
| 270 return function; |
| 271 } |
| 272 } |
| 273 return null; |
| 274 } |
| 275 |
| 276 /** |
| 277 * Return the name of the library that the given part is declared to be a |
| 278 * part of, or `null` if the part does not contain a part-of directive. |
| 279 */ |
| 280 String _getPartLibraryName(Source partSource, CompilationUnit partUnit, |
| 281 List<Directive> directivesToResolve) { |
| 282 for (Directive directive in partUnit.directives) { |
| 283 if (directive is PartOfDirective) { |
| 284 directivesToResolve.add(directive); |
| 285 LibraryIdentifier libraryName = directive.libraryName; |
| 286 if (libraryName != null) { |
| 287 return libraryName.name; |
| 288 } |
| 289 } |
| 290 } |
| 291 return null; |
| 292 } |
| 293 |
| 294 /** |
| 295 * Look through all of the compilation units defined for the given [library], |
| 296 * looking for getters and setters that are defined in different compilation |
| 297 * units but that have the same names. If any are found, make sure that they |
| 298 * have the same variable element. |
| 299 */ |
| 300 void _patchTopLevelAccessors(LibraryElementImpl library) { |
| 301 HashMap<String, PropertyAccessorElement> getters = |
| 302 new HashMap<String, PropertyAccessorElement>(); |
| 303 List<PropertyAccessorElement> setters = <PropertyAccessorElement>[]; |
| 304 _collectAccessors(getters, setters, library.definingCompilationUnit); |
| 305 for (CompilationUnitElement unit in library.parts) { |
| 306 _collectAccessors(getters, setters, unit); |
| 307 } |
| 308 for (PropertyAccessorElementImpl setter in setters) { |
| 309 PropertyAccessorElement getter = getters[setter.displayName]; |
| 310 if (getter != null) { |
| 311 TopLevelVariableElementImpl variable = getter.variable; |
| 312 TopLevelVariableElementImpl setterVariable = setter.variable; |
| 313 CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement; |
| 314 setterUnit.replaceTopLevelVariable(setterVariable, variable); |
| 315 variable.setter = setter; |
| 316 setter.variable = variable; |
| 317 } |
| 318 } |
| 319 } |
| 320 |
| 321 /** |
| 322 * Return a map from the names of the inputs of this kind of task to the task |
| 323 * input descriptors describing those inputs for a task with the given |
| 324 * [target]. |
| 325 */ |
| 326 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { |
| 327 return <String, TaskInput>{ |
| 328 DEFINING_BUILT_UNIT_INPUT_NAME: new SimpleTaskInput(target, BUILT_UNIT), |
| 329 PART_BUILT_UNITS_INPUT_NAME: |
| 330 new ListBasedTaskInput<List<Source>, CompilationUnit>( |
| 331 new SimpleTaskInput<List<Source>>(target, INCLUDED_PARTS), |
| 332 (Source includedSource) => new SimpleTaskInput<CompilationUnit>( |
| 333 includedSource, BUILT_UNIT)) |
| 334 }; |
| 335 } |
| 336 |
| 337 /** |
| 338 * Create a [BuildLibraryElementTask] based on the given [target] in the |
| 339 * given [context]. |
| 340 */ |
| 341 static BuildLibraryElementTask createTask( |
| 342 AnalysisContext context, AnalysisTarget target) { |
| 343 return new BuildLibraryElementTask(context, target); |
| 344 } |
| 345 } |
| 346 |
| 347 /** |
| 89 * A task that parses the content of a Dart file, producing an AST structure. | 348 * A task that parses the content of a Dart file, producing an AST structure. |
| 90 */ | 349 */ |
| 91 class ParseDartTask extends SourceBasedAnalysisTask { | 350 class ParseDartTask extends SourceBasedAnalysisTask { |
| 92 /** | 351 /** |
| 93 * The name of the input whose value is the line information produced for the | 352 * The name of the input whose value is the line information produced for the |
| 94 * file. | 353 * file. |
| 95 */ | 354 */ |
| 96 static const String LINE_INFO_INPUT_NAME = "lineInfo"; | 355 static const String LINE_INFO_INPUT_NAME = "lineInfo"; |
| 97 | 356 |
| 98 /** | 357 /** |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 } | 552 } |
| 294 | 553 |
| 295 /** | 554 /** |
| 296 * Create a [ScanDartTask] based on the given [target] in the given [context]. | 555 * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| 297 */ | 556 */ |
| 298 static ScanDartTask createTask( | 557 static ScanDartTask createTask( |
| 299 AnalysisContext context, AnalysisTarget target) { | 558 AnalysisContext context, AnalysisTarget target) { |
| 300 return new ScanDartTask(context, target); | 559 return new ScanDartTask(context, target); |
| 301 } | 560 } |
| 302 } | 561 } |
| OLD | NEW |