OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'dart:async'; |
5 import 'dart:collection' show HashSet, Queue; | 6 import 'dart:collection' show HashSet, Queue; |
6 import 'dart:convert' show JSON; | 7 import 'dart:convert' show JSON; |
7 import 'dart:io' show File; | 8 import 'dart:io' show File; |
8 | 9 |
9 import 'package:analyzer/analyzer.dart' | 10 import 'package:analyzer/analyzer.dart' |
10 show AnalysisError, CompilationUnit, ErrorSeverity; | 11 show AnalysisError, CompilationUnit, ErrorSeverity; |
| 12 import 'package:analyzer/context/declared_variables.dart'; |
11 import 'package:analyzer/dart/element/element.dart' show LibraryElement; | 13 import 'package:analyzer/dart/element/element.dart' show LibraryElement; |
12 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; | 14 import 'package:analyzer/file_system/file_system.dart' show ResourceProvider; |
13 import 'package:analyzer/file_system/physical_file_system.dart' | 15 import 'package:analyzer/file_system/physical_file_system.dart' |
14 show PhysicalResourceProvider; | 16 show PhysicalResourceProvider; |
15 import 'package:analyzer/src/context/builder.dart' show ContextBuilder; | 17 import 'package:analyzer/src/context/builder.dart' show ContextBuilder; |
16 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl; | 18 import 'package:analyzer/src/dart/analysis/driver.dart'; |
| 19 import 'package:analyzer/src/dart/analysis/file_state.dart'; |
17 import 'package:analyzer/src/error/codes.dart' show StaticTypeWarningCode; | 20 import 'package:analyzer/src/error/codes.dart' show StaticTypeWarningCode; |
18 import 'package:analyzer/src/generated/engine.dart' | 21 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine; |
19 show AnalysisContext, AnalysisEngine; | 22 import 'package:analyzer/src/generated/resolver.dart'; |
20 import 'package:analyzer/src/generated/sdk.dart' show DartSdkManager; | 23 import 'package:analyzer/src/generated/sdk.dart' show DartSdkManager; |
21 import 'package:analyzer/src/generated/source.dart' | 24 import 'package:analyzer/src/generated/source.dart' |
22 show ContentCache, DartUriResolver; | 25 show ContentCache, DartUriResolver, LineInfo; |
23 import 'package:analyzer/src/generated/source_io.dart' | 26 import 'package:analyzer/src/generated/source_io.dart' |
24 show Source, SourceKind, UriResolver; | 27 show Source, SourceKind, UriResolver; |
25 import 'package:analyzer/src/summary/package_bundle_reader.dart' | 28 import 'package:analyzer/src/summary/package_bundle_reader.dart' |
26 show InSummarySource, InputPackagesResultProvider, SummaryDataStore; | 29 show InSummarySource, SummaryDataStore; |
27 import 'package:args/args.dart' show ArgParser, ArgResults; | 30 import 'package:args/args.dart' show ArgParser, ArgResults; |
28 import 'package:args/src/usage_exception.dart' show UsageException; | 31 import 'package:args/src/usage_exception.dart' show UsageException; |
| 32 import 'package:front_end/src/base/performace_logger.dart'; |
| 33 import 'package:front_end/src/incremental/byte_store.dart'; |
29 import 'package:func/func.dart' show Func1; | 34 import 'package:func/func.dart' show Func1; |
30 import 'package:path/path.dart' as path; | 35 import 'package:path/path.dart' as path; |
31 import 'package:source_maps/source_maps.dart'; | 36 import 'package:source_maps/source_maps.dart'; |
32 | 37 |
33 import '../analyzer/context.dart' show AnalyzerOptions, createSourceFactory; | 38 import '../analyzer/context.dart' show AnalyzerOptions, createSourceFactory; |
34 import '../js_ast/js_ast.dart' as JS; | 39 import '../js_ast/js_ast.dart' as JS; |
35 import '../js_ast/js_ast.dart' show js; | 40 import '../js_ast/js_ast.dart' show js; |
36 import 'code_generator.dart' show CodeGenerator; | 41 import 'code_generator.dart' show CodeGenerator; |
37 import 'error_helpers.dart' show errorSeverity, formatError, sortErrors; | 42 import 'error_helpers.dart' show errorSeverity, formatError, sortErrors; |
38 import 'extension_types.dart' show ExtensionTypeSet; | 43 import 'extension_types.dart' show ExtensionTypeSet; |
39 import 'js_names.dart' as JS; | 44 import 'js_names.dart' as JS; |
40 import 'module_builder.dart' show transformModuleFormat, ModuleFormat; | 45 import 'module_builder.dart' show transformModuleFormat, ModuleFormat; |
41 import 'source_map_printer.dart' show SourceMapPrintingContext; | 46 import 'source_map_printer.dart' show SourceMapPrintingContext; |
42 | 47 |
43 /// Compiles a set of Dart files into a single JavaScript module. | 48 /// Compiles a set of Dart files into a single JavaScript module. |
44 /// | 49 /// |
45 /// For a single [BuildUnit] definition, this will produce a [JSModuleFile]. | 50 /// For a single [BuildUnit] definition, this will produce a [JSModuleFile]. |
46 /// Those objects are record types that record the data consumed and produced | 51 /// Those objects are record types that record the data consumed and produced |
47 /// for a single compile. | 52 /// for a single compile. |
48 /// | 53 /// |
49 /// This class exists to cache global state associated with a single in-memory | 54 /// This class exists to cache global state associated with a single in-memory |
50 /// AnalysisContext, such as information about extension types in the Dart SDK. | 55 /// [AnalysisDriver], such as information about extension types in the Dart SDK. |
51 /// It can be used once to produce a single module, or reused to save warm-up | 56 /// It can be used once to produce a single module, or reused to save warm-up |
52 /// time. (Currently there is no warm up, but there may be in the future.) | 57 /// time. (Currently there is no warm up, but there may be in the future.) |
53 /// | 58 /// |
54 /// The SDK source code is assumed to be immutable for the life of this class. | 59 /// The SDK source code is assumed to be immutable for the life of this class. |
55 /// | 60 /// |
56 /// For all other files, it is up to the [AnalysisContext] to decide whether or | 61 /// For all other files, it is up to the [AnalysisDriver] to decide whether or |
57 /// not any caching is performed. By default an analysis context will assume | 62 /// not any caching is performed. By default an analysis context will assume |
58 /// sources are immutable for the life of the context, and cache information | 63 /// sources are immutable for the life of the context, and cache information |
59 /// about them. | 64 /// about them. |
60 class ModuleCompiler { | 65 class ModuleCompiler { |
61 final AnalysisContext context; | 66 final AnalysisDriver driver; |
62 final SummaryDataStore summaryData; | 67 final SummaryDataStore summaryData; |
63 final ExtensionTypeSet _extensionTypes; | |
64 | 68 |
65 ModuleCompiler._(AnalysisContext context, this.summaryData) | 69 final Map<String, LibraryElement> _dartLibraries = {}; |
66 : context = context, | 70 TypeProviderImpl _typeProvider; |
67 _extensionTypes = new ExtensionTypeSet(context); | 71 |
| 72 ExtensionTypeSet _extensionTypes; |
| 73 |
| 74 ModuleCompiler._(this.driver, this.summaryData); |
68 | 75 |
69 factory ModuleCompiler(AnalyzerOptions options, | 76 factory ModuleCompiler(AnalyzerOptions options, |
70 {ResourceProvider resourceProvider, | 77 {ResourceProvider resourceProvider, |
71 String analysisRoot, | 78 String analysisRoot, |
72 List<UriResolver> fileResolvers, | 79 List<UriResolver> fileResolvers, |
73 SummaryDataStore summaryData}) { | 80 SummaryDataStore summaryData}) { |
74 // TODO(danrubel): refactor with analyzer CLI into analyzer common code | 81 // TODO(danrubel): refactor with analyzer CLI into analyzer common code |
75 AnalysisEngine.instance.processRequiredPlugins(); | 82 AnalysisEngine.instance.processRequiredPlugins(); |
76 | 83 |
77 resourceProvider ??= PhysicalResourceProvider.INSTANCE; | 84 resourceProvider ??= PhysicalResourceProvider.INSTANCE; |
(...skipping 19 matching lines...) Expand all Loading... |
97 if (sdkSummaryBundle != null) { | 104 if (sdkSummaryBundle != null) { |
98 summaryData.addBundle(null, sdkSummaryBundle); | 105 summaryData.addBundle(null, sdkSummaryBundle); |
99 } | 106 } |
100 | 107 |
101 var srcFactory = createSourceFactory(options, | 108 var srcFactory = createSourceFactory(options, |
102 sdkResolver: sdkResolver, | 109 sdkResolver: sdkResolver, |
103 fileResolvers: fileResolvers, | 110 fileResolvers: fileResolvers, |
104 summaryData: summaryData, | 111 summaryData: summaryData, |
105 resourceProvider: resourceProvider); | 112 resourceProvider: resourceProvider); |
106 | 113 |
107 var context = | 114 var declaredVariables = new DeclaredVariables(); |
108 AnalysisEngine.instance.createAnalysisContext() as AnalysisContextImpl; | 115 options.declaredVariables.forEach(declaredVariables.define); |
109 context.analysisOptions = analysisOptions; | 116 declaredVariables.define('dart.isVM', 'false'); |
110 context.sourceFactory = srcFactory; | 117 // TODO(vsm): Should this be hardcoded? |
111 if (sdkSummaryBundle != null) { | 118 declaredVariables.define('dart.library.html', 'true'); |
112 context.resultProvider = | 119 declaredVariables.define('dart.library.io', 'false'); |
113 new InputPackagesResultProvider(context, summaryData); | 120 |
| 121 if (!analysisOptions.strongMode) { |
| 122 throw new ArgumentError('AnalysisOptions must be strong mode'); |
114 } | 123 } |
115 options.declaredVariables.forEach(context.declaredVariables.define); | 124 if (!srcFactory.dartSdk.context.analysisOptions.strongMode) { |
116 context.declaredVariables.define('dart.isVM', 'false'); | 125 throw new ArgumentError('AnalysisOptions must have strong mode SDK'); |
117 | |
118 // TODO(vsm): Should this be hardcoded? | |
119 context.declaredVariables.define('dart.library.html', 'true'); | |
120 context.declaredVariables.define('dart.library.io', 'false'); | |
121 | |
122 if (!context.analysisOptions.strongMode) { | |
123 throw new ArgumentError('AnalysisContext must be strong mode'); | |
124 } | |
125 if (!context.sourceFactory.dartSdk.context.analysisOptions.strongMode) { | |
126 throw new ArgumentError('AnalysisContext must have strong mode SDK'); | |
127 } | 126 } |
128 | 127 |
129 return new ModuleCompiler._(context, summaryData); | 128 AnalysisDriver driver; |
| 129 { |
| 130 var logger = new PerformanceLog(new StringBuffer()); |
| 131 var scheduler = new AnalysisDriverScheduler(logger); |
| 132 driver = new AnalysisDriver( |
| 133 scheduler, |
| 134 logger, |
| 135 resourceProvider, |
| 136 new MemoryByteStore(), |
| 137 new FileContentOverlay(), |
| 138 null, |
| 139 srcFactory, |
| 140 analysisOptions, |
| 141 disableChangesAndCacheAllResults: true, |
| 142 externalSummaries: summaryData); |
| 143 scheduler.start(); |
| 144 } |
| 145 |
| 146 return new ModuleCompiler._(driver, summaryData); |
130 } | 147 } |
131 | 148 |
132 bool _isFatalError(AnalysisError e, CompilerOptions options) { | 149 bool _isFatalError(AnalysisError e, CompilerOptions options) { |
133 if (errorSeverity(context, e) != ErrorSeverity.ERROR) return false; | 150 if (errorSeverity(driver.analysisOptions, e) != ErrorSeverity.ERROR) |
| 151 return false; |
134 | 152 |
135 // These errors are not fatal in the REPL compile mode as we | 153 // These errors are not fatal in the REPL compile mode as we |
136 // allow access to private members across library boundaries | 154 // allow access to private members across library boundaries |
137 // and those accesses will show up as undefined members unless | 155 // and those accesses will show up as undefined members unless |
138 // additional analyzer changes are made to support them. | 156 // additional analyzer changes are made to support them. |
139 // TODO(jacobr): consider checking that the identifier name | 157 // TODO(jacobr): consider checking that the identifier name |
140 // referenced by the error is private. | 158 // referenced by the error is private. |
141 return !options.replCompile || | 159 return !options.replCompile || |
142 (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER && | 160 (e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER && |
143 e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER && | 161 e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER && |
144 e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD); | 162 e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD); |
145 } | 163 } |
146 | 164 |
147 /// Compiles a single Dart build unit into a JavaScript module. | 165 /// Compiles a single Dart build unit into a JavaScript module. |
148 /// | 166 /// |
149 /// *Warning* - this may require resolving the entire world. | 167 /// *Warning* - this may require resolving the entire world. |
150 /// If that is not desired, the analysis context must be pre-configured using | 168 /// If that is not desired, the analysis context must be pre-configured using |
151 /// summaries before calling this method. | 169 /// summaries before calling this method. |
152 JSModuleFile compile(BuildUnit unit, CompilerOptions options) { | 170 Future<JSModuleFile> compile(BuildUnit unit, CompilerOptions options) async { |
153 var trees = <CompilationUnit>[]; | 171 var trees = <CompilationUnit>[]; |
154 var errors = <AnalysisError>[]; | 172 var errors = <AnalysisError>[]; |
| 173 var lineInfoMap = <String, LineInfo>{}; |
155 | 174 |
156 var librariesToCompile = new Queue<LibraryElement>(); | 175 var librariesToCompile = new Queue<LibraryElement>(); |
157 | 176 |
158 var compilingSdk = false; | 177 var compilingSdk = false; |
159 for (var sourcePath in unit.sources) { | 178 for (var sourceUriStr in unit.sources) { |
160 var sourceUri = _sourceToUri(sourcePath); | 179 var sourceUri = _sourceToUri(sourceUriStr); |
161 if (sourceUri.scheme == "dart") { | 180 if (sourceUri.scheme == "dart") { |
162 compilingSdk = true; | 181 compilingSdk = true; |
163 } | 182 } |
164 var source = context.sourceFactory.forUri2(sourceUri); | 183 var source = driver.sourceFactory.forUri2(sourceUri); |
| 184 String sourcePath = source.fullName; |
165 | 185 |
166 var fileUsage = 'You need to pass at least one existing .dart file as an' | 186 var fileUsage = 'You need to pass at least one existing .dart file as an' |
167 ' argument.'; | 187 ' argument.'; |
168 if (source == null) { | 188 if (source == null) { |
169 throw new UsageException( | 189 throw new UsageException( |
170 'Could not create a source for "$sourcePath". The file name is in' | 190 'Could not create a source for "$sourceUriStr". The file name is in' |
171 ' the wrong format or was not found.', | 191 ' the wrong format or was not found.', |
172 fileUsage); | 192 fileUsage); |
173 } else if (!source.exists()) { | 193 } else if (!source.exists()) { |
174 throw new UsageException( | 194 throw new UsageException( |
175 'Given file "$sourcePath" does not exist.', fileUsage); | 195 'Given file "$sourceUriStr" does not exist.', fileUsage); |
176 } | 196 } |
177 | 197 |
178 // Ignore parts. They need to be handled in the context of their library. | 198 // Ignore parts. They need to be handled in the context of their library. |
179 if (context.computeKindOf(source) == SourceKind.PART) { | 199 SourceKind sourceKind = await driver.getSourceKind(sourcePath); |
| 200 if (sourceKind == SourceKind.PART) { |
180 continue; | 201 continue; |
181 } | 202 } |
182 | 203 |
183 librariesToCompile.add(context.computeLibraryElement(source)); | 204 UnitElementResult unitResult = await driver.getUnitElement(sourcePath); |
| 205 LibraryElement library = unitResult.element.library; |
| 206 librariesToCompile.add(library); |
184 } | 207 } |
185 | 208 |
186 var libraries = new HashSet<LibraryElement>(); | 209 var libraries = new HashSet<LibraryElement>(); |
187 while (librariesToCompile.isNotEmpty) { | 210 while (librariesToCompile.isNotEmpty) { |
188 var library = librariesToCompile.removeFirst(); | 211 var library = librariesToCompile.removeFirst(); |
189 if (library.source is InSummarySource) continue; | 212 if (library.source is InSummarySource) continue; |
190 if (!compilingSdk && library.source.isInSystemLibrary) continue; | 213 if (!compilingSdk && library.source.isInSystemLibrary) continue; |
191 if (!libraries.add(library)) continue; | 214 if (!libraries.add(library)) continue; |
192 | 215 |
193 librariesToCompile.addAll(library.importedLibraries); | 216 librariesToCompile.addAll(library.importedLibraries); |
194 librariesToCompile.addAll(library.exportedLibraries); | 217 librariesToCompile.addAll(library.exportedLibraries); |
195 | 218 |
196 var tree = context.resolveCompilationUnit(library.source, library); | 219 var definingResult = await driver.getResult(library.source.fullName); |
197 trees.add(tree); | 220 trees.add(definingResult.unit); |
198 errors.addAll(context.computeErrors(library.source)); | 221 errors.addAll(definingResult.errors); |
| 222 lineInfoMap[definingResult.path] = definingResult.lineInfo; |
199 | 223 |
200 for (var part in library.parts) { | 224 for (var part in library.parts) { |
201 trees.add(context.resolveCompilationUnit(part.source, library)); | 225 var partResult = await driver.getResult(part.source.fullName); |
202 errors.addAll(context.computeErrors(part.source)); | 226 trees.add(partResult.unit); |
| 227 errors.addAll(partResult.errors); |
| 228 lineInfoMap[partResult.path] = partResult.lineInfo; |
203 } | 229 } |
204 } | 230 } |
205 | 231 |
206 sortErrors(context, errors); | 232 sortErrors(driver.analysisOptions, errors); |
| 233 |
| 234 LibraryElement coreLibrary = await _getDartLibrary('dart:core'); |
| 235 LibraryElement asyncLibrary = await _getDartLibrary('dart:async'); |
| 236 _typeProvider ??= new TypeProviderImpl(coreLibrary, asyncLibrary); |
| 237 _extensionTypes ??= await _newExtensionTypeSet(); |
207 | 238 |
208 var messages = <String>[]; | 239 var messages = <String>[]; |
209 for (var e in errors) { | 240 for (AnalysisError e in errors) { |
210 var m = formatError(context, e); | 241 var lineInfo = lineInfoMap[e.source.fullName]; |
| 242 var m = formatError(driver.analysisOptions, lineInfo, e); |
211 if (m != null) messages.add(m); | 243 if (m != null) messages.add(m); |
212 } | 244 } |
213 | 245 |
214 if (!options.unsafeForceCompile && | 246 if (!options.unsafeForceCompile && |
215 errors.any((e) => _isFatalError(e, options))) { | 247 errors.any((e) => _isFatalError(e, options))) { |
216 return new JSModuleFile.invalid(unit.name, messages, options); | 248 return new JSModuleFile.invalid(unit.name, messages, options); |
217 } | 249 } |
218 | 250 |
219 try { | 251 try { |
220 var codeGenerator = | 252 var codeGenerator = new CodeGenerator( |
221 new CodeGenerator(context, summaryData, options, _extensionTypes); | 253 driver, summaryData, options, _extensionTypes, |
| 254 types: _typeProvider, |
| 255 coreLibrary: coreLibrary, |
| 256 asyncLibrary: asyncLibrary, |
| 257 interceptorsLibrary: await _getDartLibrary('dart:_interceptors'), |
| 258 internalLibrary: await _getDartLibrary('dart:_internal'), |
| 259 jsLibrary: await _getDartLibrary('dart:js')); |
222 return codeGenerator.compile(unit, trees, messages); | 260 return codeGenerator.compile(unit, trees, messages); |
223 } catch (e) { | 261 } catch (e) { |
224 if (errors.any((e) => _isFatalError(e, options))) { | 262 if (errors.any((e) => _isFatalError(e, options))) { |
225 // Force compilation failed. Suppress the exception and report | 263 // Force compilation failed. Suppress the exception and report |
226 // the static errors instead. | 264 // the static errors instead. |
227 assert(options.unsafeForceCompile); | 265 assert(options.unsafeForceCompile); |
228 return new JSModuleFile.invalid(unit.name, messages, options); | 266 return new JSModuleFile.invalid(unit.name, messages, options); |
229 } | 267 } |
230 rethrow; | 268 rethrow; |
231 } | 269 } |
232 } | 270 } |
| 271 |
| 272 Future<LibraryElement> _getDartLibrary(String uri) async { |
| 273 assert(uri.startsWith('dart:')); |
| 274 LibraryElement library = _dartLibraries[uri]; |
| 275 if (library == null) { |
| 276 library = await driver.getLibraryByUri(uri); |
| 277 _dartLibraries[uri] = library; |
| 278 } |
| 279 return library; |
| 280 } |
| 281 |
| 282 Future<ExtensionTypeSet> _newExtensionTypeSet() async { |
| 283 return new ExtensionTypeSet( |
| 284 coreLibrary: await _getDartLibrary('dart:core'), |
| 285 collectionLibrary: await _getDartLibrary('dart:collection'), |
| 286 mathLibrary: await _getDartLibrary('dart:math'), |
| 287 htmlLibrary: await _getDartLibrary('dart:html'), |
| 288 indexedDbLibrary: await _getDartLibrary('dart:indexed_db'), |
| 289 svgLibrary: await _getDartLibrary('dart:svg'), |
| 290 webAudioLibrary: await _getDartLibrary('dart:web_audio'), |
| 291 webGlLibrary: await _getDartLibrary('dart:web_gl'), |
| 292 webSqlLibrary: await _getDartLibrary('dart:web_sql'), |
| 293 interceptorsLibrary: await _getDartLibrary('dart:_interceptors'), |
| 294 nativeTypedDataLibrary: |
| 295 await _getDartLibrary('dart:_native_typed_data')); |
| 296 } |
233 } | 297 } |
234 | 298 |
235 class CompilerOptions { | 299 class CompilerOptions { |
236 /// Whether to emit the source mapping file. | 300 /// Whether to emit the source mapping file. |
237 /// | 301 /// |
238 /// This supports debugging the original source code instead of the generated | 302 /// This supports debugging the original source code instead of the generated |
239 /// code. | 303 /// code. |
240 final bool sourceMap; | 304 final bool sourceMap; |
241 | 305 |
242 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment | 306 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 case "dart": | 691 case "dart": |
628 case "package": | 692 case "package": |
629 case "file": | 693 case "file": |
630 // A valid URI. | 694 // A valid URI. |
631 return uri; | 695 return uri; |
632 default: | 696 default: |
633 // Assume a file path. | 697 // Assume a file path. |
634 return new Uri.file(path.absolute(source)); | 698 return new Uri.file(path.absolute(source)); |
635 } | 699 } |
636 } | 700 } |
OLD | NEW |