Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2138)

Side by Side Diff: lib/devc.dart

Issue 1174643003: expose strong checker API, for use by analyzer_cli (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/config.dart ('k') | lib/src/analysis_context.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /// Command line tool to run the checker on a Dart program. 5 /// Command line tool to run the checker on a Dart program.
6 library dev_compiler.devc; 6 library dev_compiler.devc;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:convert'; 9 import 'dart:convert';
10 import 'dart:io'; 10 import 'dart:io';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 AnalysisContext get context; 46 AnalysisContext get context;
47 TypeRules get rules; 47 TypeRules get rules;
48 Uri get entryPointUri; 48 Uri get entryPointUri;
49 } 49 }
50 50
51 /// Encapsulates the logic to do a one-off compilation or a partial compilation 51 /// Encapsulates the logic to do a one-off compilation or a partial compilation
52 /// when the compiler is run as a development server. 52 /// when the compiler is run as a development server.
53 class Compiler implements AbstractCompiler { 53 class Compiler implements AbstractCompiler {
54 final CompilerOptions options; 54 final CompilerOptions options;
55 final AnalysisContext context; 55 final AnalysisContext context;
56 final CheckerReporter _reporter; 56 final CompilerReporter _reporter;
57 final TypeRules rules; 57 final TypeRules rules;
58 final CodeChecker _checker; 58 final CodeChecker _checker;
59 final SourceNode _entryNode; 59 final SourceNode _entryNode;
60 List<LibraryInfo> _libraries = <LibraryInfo>[]; 60 List<LibraryInfo> _libraries = <LibraryInfo>[];
61 final _generators = <CodeGenerator>[]; 61 final _generators = <CodeGenerator>[];
62 bool _hashing; 62 bool _hashing;
63 bool _failure = false; 63 bool _failure = false;
64 64
65 factory Compiler(CompilerOptions options, 65 factory Compiler(CompilerOptions options,
66 {AnalysisContext context, CheckerReporter reporter}) { 66 {AnalysisContext context, CompilerReporter reporter}) {
67 if (context == null) context = createAnalysisContext(options); 67 var strongOpts = options.strongOptions;
68 var sourceOpts = options.sourceOptions;
69 if (context == null) {
70 context = createAnalysisContextWithSources(strongOpts, sourceOpts);
71 }
68 72
69 if (reporter == null) { 73 if (reporter == null) {
70 reporter = options.dumpInfo 74 reporter = options.dumpInfo
71 ? new SummaryReporter(context, options.logLevel) 75 ? new SummaryReporter(context, options.logLevel)
72 : new LogReporter(context, useColors: options.useColors); 76 : new LogReporter(context, useColors: options.useColors);
73 } 77 }
74 var graph = new SourceGraph(context, reporter, options); 78 var graph = new SourceGraph(context, reporter, options);
75 var rules = new RestrictedRules(context.typeProvider, options: options); 79 var rules = new RestrictedRules(context.typeProvider,
76 var checker = new CodeChecker(rules, reporter, options); 80 options: options.strongOptions);
81 var checker = new CodeChecker(rules, reporter, strongOpts);
77 82
78 var inputFile = options.entryPointFile; 83 var inputFile = sourceOpts.entryPointFile;
79 var inputUri = inputFile.startsWith('dart:') || 84 var inputUri = inputFile.startsWith('dart:') ||
80 inputFile.startsWith('package:') 85 inputFile.startsWith('package:')
81 ? Uri.parse(inputFile) 86 ? Uri.parse(inputFile)
82 : new Uri.file(path.absolute(options.useImplicitHtml 87 : new Uri.file(path.absolute(sourceOpts.useImplicitHtml
83 ? ResolverOptions.implicitHtmlFile 88 ? SourceResolverOptions.implicitHtmlFile
84 : inputFile)); 89 : inputFile));
85 var entryNode = graph.nodeFromUri(inputUri); 90 var entryNode = graph.nodeFromUri(inputUri);
86 91
87 return new Compiler._( 92 return new Compiler._(
88 options, context, reporter, rules, checker, entryNode); 93 options, context, reporter, rules, checker, entryNode);
89 } 94 }
90 95
91 Compiler._(this.options, this.context, this._reporter, this.rules, 96 Compiler._(this.options, this.context, this._reporter, this.rules,
92 this._checker, this._entryNode) { 97 this._checker, this._entryNode) {
93 if (options.outputDir != null) { 98 if (outputDir != null) {
94 _generators.add(new JSGenerator(this)); 99 _generators.add(new JSGenerator(this));
95 } 100 }
96 // TODO(sigmund): refactor to support hashing of the dart output? 101 // TODO(sigmund): refactor to support hashing of the dart output?
97 _hashing = options.enableHashing && _generators.length == 1; 102 _hashing = options.enableHashing && _generators.length == 1;
98 } 103 }
99 104
100 Uri get entryPointUri => _entryNode.uri; 105 Uri get entryPointUri => _entryNode.uri;
106 String get outputDir => options.codegenOptions.outputDir;
101 107
102 bool _buildSource(SourceNode node) { 108 bool _buildSource(SourceNode node) {
103 if (node is HtmlSourceNode) { 109 if (node is HtmlSourceNode) {
104 _buildHtmlFile(node); 110 _buildHtmlFile(node);
105 } else if (node is DartSourceNode) { 111 } else if (node is DartSourceNode) {
106 _buildDartLibrary(node); 112 _buildDartLibrary(node);
107 } else if (node is ResourceSourceNode) { 113 } else if (node is ResourceSourceNode) {
108 _buildResourceFile(node); 114 _buildResourceFile(node);
109 } else { 115 } else {
110 assert(false); // should not get a build request on PartSourceNode 116 assert(false); // should not get a build request on PartSourceNode
111 } 117 }
112 118
113 // TODO(sigmund): don't always return true. Use summarization to better 119 // TODO(sigmund): don't always return true. Use summarization to better
114 // determine when rebuilding is needed. 120 // determine when rebuilding is needed.
115 return true; 121 return true;
116 } 122 }
117 123
118 void _buildHtmlFile(HtmlSourceNode node) { 124 void _buildHtmlFile(HtmlSourceNode node) {
119 if (options.outputDir == null) return; 125 if (outputDir == null) return;
120 var uri = node.source.uri; 126 var uri = node.source.uri;
121 _reporter.enterHtml(uri); 127 _reporter.enterHtml(uri);
122 var output = generateEntryHtml(node, options); 128 var output = generateEntryHtml(node, options);
123 if (output == null) { 129 if (output == null) {
124 _failure = true; 130 _failure = true;
125 return; 131 return;
126 } 132 }
127 _reporter.leaveHtml(); 133 _reporter.leaveHtml();
128 var filename = path.basename(node.uri.path); 134 var filename = path.basename(node.uri.path);
129 String outputFile = path.join(options.outputDir, filename); 135 String outputFile = path.join(outputDir, filename);
130 new File(outputFile).writeAsStringSync(output); 136 new File(outputFile).writeAsStringSync(output);
131 } 137 }
132 138
133 void _buildResourceFile(ResourceSourceNode node) { 139 void _buildResourceFile(ResourceSourceNode node) {
134 // ResourceSourceNodes files that just need to be copied over to the output 140 // ResourceSourceNodes files that just need to be copied over to the output
135 // location. These can be external dependencies or pieces of the 141 // location. These can be external dependencies or pieces of the
136 // dev_compiler runtime. 142 // dev_compiler runtime.
137 if (options.outputDir == null) return; 143 if (outputDir == null) return;
138 var filepath = resourceOutputPath(node.uri, _entryNode.uri); 144 var filepath = resourceOutputPath(node.uri, _entryNode.uri);
139 assert(filepath != null); 145 assert(filepath != null);
140 filepath = path.join(options.outputDir, filepath); 146 filepath = path.join(outputDir, filepath);
141 var dir = path.dirname(filepath); 147 var dir = path.dirname(filepath);
142 new Directory(dir).createSync(recursive: true); 148 new Directory(dir).createSync(recursive: true);
143 new File.fromUri(node.source.uri).copySync(filepath); 149 new File.fromUri(node.source.uri).copySync(filepath);
144 if (_hashing) node.cachingHash = computeHashFromFile(filepath); 150 if (_hashing) node.cachingHash = computeHashFromFile(filepath);
145 } 151 }
146 152
147 bool _isEntry(DartSourceNode node) { 153 bool _isEntry(DartSourceNode node) {
148 if (_entryNode is DartSourceNode) return _entryNode == node; 154 if (_entryNode is DartSourceNode) return _entryNode == node;
149 return (_entryNode as HtmlSourceNode).scripts.contains(node); 155 return (_entryNode as HtmlSourceNode).scripts.contains(node);
150 } 156 }
(...skipping 24 matching lines...) Expand all
175 var unitSource = unit.element.source; 181 var unitSource = unit.element.source;
176 _reporter.enterCompilationUnit(unit); 182 _reporter.enterCompilationUnit(unit);
177 // TODO(sigmund): integrate analyzer errors with static-info (issue #6). 183 // TODO(sigmund): integrate analyzer errors with static-info (issue #6).
178 failureInLib = logErrors(unitSource) || failureInLib; 184 failureInLib = logErrors(unitSource) || failureInLib;
179 _checker.visitCompilationUnit(unit); 185 _checker.visitCompilationUnit(unit);
180 if (_checker.failure) failureInLib = true; 186 if (_checker.failure) failureInLib = true;
181 _reporter.leaveCompilationUnit(); 187 _reporter.leaveCompilationUnit();
182 } 188 }
183 if (failureInLib) { 189 if (failureInLib) {
184 _failure = true; 190 _failure = true;
185 if (!options.forceCompile) return; 191 if (!options.codegenOptions.forceCompile) return;
186 } 192 }
187 193
188 for (var cg in _generators) { 194 for (var cg in _generators) {
189 var hash = cg.generateLibrary(libraryUnit, current); 195 var hash = cg.generateLibrary(libraryUnit, current);
190 if (_hashing) node.cachingHash = hash; 196 if (_hashing) node.cachingHash = hash;
191 } 197 }
192 _reporter.leaveLibrary(); 198 _reporter.leaveLibrary();
193 } 199 }
194 200
195 /// Log any errors encountered when resolving [source] and return whether any 201 /// Log any errors encountered when resolving [source] and return whether any
(...skipping 18 matching lines...) Expand all
214 // dependency_graph now detects broken imports or unsupported features 220 // dependency_graph now detects broken imports or unsupported features
215 // like more than one script tag (see .severe messages in 221 // like more than one script tag (see .severe messages in
216 // dependency_graph.dart). Such failures should be reported back 222 // dependency_graph.dart). Such failures should be reported back
217 // here so we can mark failure=true in the CheckerResutls. 223 // here so we can mark failure=true in the CheckerResutls.
218 rebuild(_entryNode, _buildSource); 224 rebuild(_entryNode, _buildSource);
219 _dumpInfoIfRequested(); 225 _dumpInfoIfRequested();
220 clock.stop(); 226 clock.stop();
221 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2); 227 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
222 _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n'); 228 _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n');
223 return new CheckerResults( 229 return new CheckerResults(
224 _libraries, rules, _failure || options.forceCompile); 230 _libraries, rules, _failure || options.codegenOptions.forceCompile);
225 } 231 }
226 232
227 void _runAgain() { 233 void _runAgain() {
228 var clock = new Stopwatch()..start(); 234 var clock = new Stopwatch()..start();
229 _libraries = <LibraryInfo>[]; 235 _libraries = <LibraryInfo>[];
230 int changed = 0; 236 int changed = 0;
231 237
232 // TODO(sigmund): propagate failures here (see TODO in run). 238 // TODO(sigmund): propagate failures here (see TODO in run).
233 rebuild(_entryNode, (n) { 239 rebuild(_entryNode, (n) {
234 changed++; 240 changed++;
235 return _buildSource(n); 241 return _buildSource(n);
236 }); 242 });
237 clock.stop(); 243 clock.stop();
238 if (changed > 0) _dumpInfoIfRequested(); 244 if (changed > 0) _dumpInfoIfRequested();
239 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2); 245 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
240 _log.fine("Compiled ${changed} libraries in ${time} s\n"); 246 _log.fine("Compiled ${changed} libraries in ${time} s\n");
241 } 247 }
242 248
243 _dumpInfoIfRequested() { 249 _dumpInfoIfRequested() {
244 if (!options.dumpInfo || _reporter is! SummaryReporter) return; 250 if (!options.dumpInfo || _reporter is! SummaryReporter) return;
245 var result = (_reporter as SummaryReporter).result; 251 var result = (_reporter as SummaryReporter).result;
246 if (!options.serverMode) print(summaryToString(result)); 252 if (!options.serverMode) print(summaryToString(result));
247 var filepath = options.serverMode 253 var filepath = options.serverMode
248 ? path.join(options.outputDir, 'messages.json') 254 ? path.join(outputDir, 'messages.json')
249 : options.dumpInfoFile; 255 : options.dumpInfoFile;
250 if (filepath == null) return; 256 if (filepath == null) return;
251 new File(filepath).writeAsStringSync(JSON.encode(result.toJsonMap())); 257 new File(filepath).writeAsStringSync(JSON.encode(result.toJsonMap()));
252 } 258 }
253 } 259 }
254 260
255 class CompilerServer { 261 class CompilerServer {
256 final Compiler compiler; 262 final Compiler compiler;
257 final String outDir; 263 final String outDir;
258 final String host; 264 final String host;
259 final int port; 265 final int port;
260 final String _entryPath; 266 final String _entryPath;
261 267
262 factory CompilerServer(CompilerOptions options) { 268 factory CompilerServer(CompilerOptions options) {
263 var entryPath = path.basename(options.entryPointFile); 269 var entryPath = path.basename(options.sourceOptions.entryPointFile);
264 var extension = path.extension(entryPath); 270 var extension = path.extension(entryPath);
265 if (extension != '.html' && !options.useImplicitHtml) { 271 if (extension != '.html' && !options.sourceOptions.useImplicitHtml) {
266 print('error: devc in server mode requires an HTML or Dart entry point.'); 272 print('error: devc in server mode requires an HTML or Dart entry point.');
267 exit(1); 273 exit(1);
268 } 274 }
269 275
270 // TODO(sigmund): allow running without a dir, but keep output in memory? 276 // TODO(sigmund): allow running without a dir, but keep output in memory?
271 var outDir = options.outputDir; 277 var outDir = options.codegenOptions.outputDir;
272 if (outDir == null) { 278 if (outDir == null) {
273 print('error: devc in server mode also requires specifying and ' 279 print('error: devc in server mode also requires specifying and '
274 'output location for generated code.'); 280 'output location for generated code.');
275 exit(1); 281 exit(1);
276 } 282 }
277 var port = options.port; 283 var port = options.port;
278 var host = options.host; 284 var host = options.host;
279 var compiler = new Compiler(options); 285 var compiler = new Compiler(options);
280 return new CompilerServer._(compiler, outDir, host, port, entryPath); 286 return new CompilerServer._(compiler, outDir, host, port, entryPath);
281 } 287 }
282 288
283 CompilerServer._( 289 CompilerServer._(
284 Compiler compiler, this.outDir, this.host, this.port, String entryPath) 290 Compiler compiler, this.outDir, this.host, this.port, String entryPath)
285 : this.compiler = compiler, 291 : this.compiler = compiler,
286 this._entryPath = compiler.options.useImplicitHtml 292 // TODO(jmesserly): this logic is duplicated in a few places
287 ? ResolverOptions.implicitHtmlFile 293 this._entryPath = compiler.options.sourceOptions.useImplicitHtml
294 ? SourceResolverOptions.implicitHtmlFile
288 : entryPath; 295 : entryPath;
289 296
290 Future start() async { 297 Future start() async {
291 // Create output directory if needed. shelf_static will fail otherwise. 298 // Create output directory if needed. shelf_static will fail otherwise.
292 var out = new Directory(outDir); 299 var out = new Directory(outDir);
293 if (!await out.exists()) await out.create(recursive: true); 300 if (!await out.exists()) await out.create(recursive: true);
294 301
295 var handler = const shelf.Pipeline() 302 var handler = const shelf.Pipeline()
296 .addMiddleware(rebuildAndCache) 303 .addMiddleware(rebuildAndCache)
297 .addHandler(shelf_static.createStaticHandler(outDir, 304 .addHandler(shelf_static.createStaticHandler(outDir,
(...skipping 21 matching lines...) Expand all
319 // Note: the cache-control header should be enough, but this doesn't hurt 326 // Note: the cache-control header should be enough, but this doesn't hurt
320 // and can help renew the policy after it expires. 327 // and can help renew the policy after it expires.
321 headers['ETag'] = hash; 328 headers['ETag'] = hash;
322 } 329 }
323 return response.change(headers: headers); 330 return response.change(headers: headers);
324 }; 331 };
325 } 332 }
326 333
327 final _log = new Logger('dev_compiler'); 334 final _log = new Logger('dev_compiler');
328 final _earlyErrorResult = new CheckerResults(const [], null, true); 335 final _earlyErrorResult = new CheckerResults(const [], null, true);
OLDNEW
« no previous file with comments | « lib/config.dart ('k') | lib/src/analysis_context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698