Chromium Code Reviews| 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 compiltion unit of a library. | |
|
Brian Wilkerson
2015/03/11 14:16:01
"compiltion" --> "compilation"
scheglov
2015/03/11 16:55:07
Done.
| |
| 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 String ENTRY_POINT_NAME = "main"; | |
|
Brian Wilkerson
2015/03/11 14:16:01
Perhaps this should be moved to FunctionElement so
scheglov
2015/03/11 16:55:06
Will do in the next CL.
| |
| 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 PropertyInducingElementImpl variable = getter.variable; | |
| 312 variable.setter = setter; | |
| 313 setter.variable = variable; | |
|
Brian Wilkerson
2015/03/11 14:16:01
I think we need to remove the setter's previous va
scheglov
2015/03/11 16:55:06
Done.
| |
| 314 } | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 /** | |
| 319 * Return a map from the names of the inputs of this kind of task to the task | |
| 320 * input descriptors describing those inputs for a task with the given | |
| 321 * [target]. | |
| 322 */ | |
| 323 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { | |
| 324 return <String, TaskInput>{ | |
| 325 DEFINING_BUILT_UNIT_INPUT_NAME: new SimpleTaskInput(target, BUILT_UNIT), | |
| 326 PART_BUILT_UNITS_INPUT_NAME: | |
| 327 new ListBasedTaskInput<List<Source>, CompilationUnit>( | |
| 328 new SimpleTaskInput<List<Source>>(target, INCLUDED_PARTS), | |
| 329 (Source includedSource) => new SimpleTaskInput<CompilationUnit>( | |
| 330 includedSource, BUILT_UNIT)) | |
| 331 }; | |
| 332 } | |
| 333 | |
| 334 /** | |
| 335 * Create a [BuildLibraryElementTask] based on the given [target] in the | |
| 336 * given [context]. | |
| 337 */ | |
| 338 static BuildLibraryElementTask createTask( | |
| 339 AnalysisContext context, AnalysisTarget target) { | |
| 340 return new BuildLibraryElementTask(context, target); | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 /** | |
| 89 * A task that parses the content of a Dart file, producing an AST structure. | 345 * A task that parses the content of a Dart file, producing an AST structure. |
| 90 */ | 346 */ |
| 91 class ParseDartTask extends SourceBasedAnalysisTask { | 347 class ParseDartTask extends SourceBasedAnalysisTask { |
| 92 /** | 348 /** |
| 93 * The name of the input whose value is the line information produced for the | 349 * The name of the input whose value is the line information produced for the |
| 94 * file. | 350 * file. |
| 95 */ | 351 */ |
| 96 static const String LINE_INFO_INPUT_NAME = "lineInfo"; | 352 static const String LINE_INFO_INPUT_NAME = "lineInfo"; |
| 97 | 353 |
| 98 /** | 354 /** |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 } | 549 } |
| 294 | 550 |
| 295 /** | 551 /** |
| 296 * Create a [ScanDartTask] based on the given [target] in the given [context]. | 552 * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| 297 */ | 553 */ |
| 298 static ScanDartTask createTask( | 554 static ScanDartTask createTask( |
| 299 AnalysisContext context, AnalysisTarget target) { | 555 AnalysisContext context, AnalysisTarget target) { |
| 300 return new ScanDartTask(context, target); | 556 return new ScanDartTask(context, target); |
| 301 } | 557 } |
| 302 } | 558 } |
| OLD | NEW |