Chromium Code Reviews| Index: lib/devc.dart |
| diff --git a/lib/devc.dart b/lib/devc.dart |
| index 66627e826b0630b0b4e0080cea1ec00e22cdc96b..c046ebaba83bba5b93d7248c17f00e27cc9eeb82 100644 |
| --- a/lib/devc.dart |
| +++ b/lib/devc.dart |
| @@ -9,7 +9,10 @@ import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| -import 'package:analyzer/src/generated/engine.dart' show ChangeSet; |
| +import 'package:analyzer/src/generated/error.dart' as analyzer; |
| +import 'package:analyzer/src/generated/engine.dart' |
| + show AnalysisContext, ChangeSet; |
| +import 'package:analyzer/src/generated/source.dart' show Source; |
| import 'package:logging/logging.dart' show Level, Logger, LogRecord; |
| import 'package:path/path.dart' as path; |
| import 'package:shelf/shelf.dart' as shelf; |
| @@ -39,19 +42,25 @@ StreamSubscription setupLogger(Level level, printFn) { |
| }); |
| } |
| +abstract class CompilerContext { |
|
Jennifer Messerly
2015/05/13 23:21:16
these 4 things get passed around together a lot
vsm
2015/05/14 22:02:08
"Context" is a bit overloaded here with CompilerCo
Jennifer Messerly
2015/05/14 23:42:21
yeah, the idea was to be our equivalent of Analysi
|
| + CompilerOptions get options; |
| + AnalysisContext get context; |
| + TypeRules get rules; |
| + Uri get entryPointUri; |
| +} |
| + |
| /// Encapsulates the logic to do a one-off compilation or a partial compilation |
| /// when the compiler is run as a development server. |
| -class Compiler { |
| - final CompilerOptions _options; |
| - final TypeResolver _resolver; |
| +class Compiler implements CompilerContext { |
| + final CompilerOptions options; |
| + final AnalysisContext context; |
| final CheckerReporter _reporter; |
| - final TypeRules _rules; |
| + final TypeRules rules; |
| final CodeChecker _checker; |
| - final SourceGraph _graph; |
| final SourceNode _entryNode; |
| List<LibraryInfo> _libraries = <LibraryInfo>[]; |
| - final List<CodeGenerator> _generators; |
| - final bool _hashing; |
| + final List _generators = <CodeGenerator>[]; |
|
vsm
2015/05/14 22:02:08
Could drop the lhs type.
Jennifer Messerly
2015/05/14 23:42:21
Done.
|
| + bool _hashing; |
| bool _failure = false; |
| factory Compiler(CompilerOptions options, |
| @@ -61,15 +70,15 @@ class Compiler { |
| ? new TypeResolver.fromMock(mockSdkSources, options) |
| : new TypeResolver.fromDir(options.dartSdkPath, options); |
| } |
| + var context = resolver.context; |
| if (reporter == null) { |
| reporter = options.dumpInfo |
| - ? new SummaryReporter() |
| - : new LogReporter(options.useColors); |
| + ? new SummaryReporter(context) |
| + : new LogReporter(context, useColors: options.useColors); |
| } |
| - var graph = new SourceGraph(resolver.context, reporter, options); |
| - var rules = |
| - new RestrictedRules(resolver.context.typeProvider, options: options); |
| + var graph = new SourceGraph(context, reporter, options); |
| + var rules = new RestrictedRules(context.typeProvider, options: options); |
| var checker = new CodeChecker(rules, reporter, options); |
| var inputFile = options.entryPointFile; |
| var uri = inputFile.startsWith('dart:') || inputFile.startsWith('package:') |
| @@ -77,26 +86,25 @@ class Compiler { |
| : new Uri.file(path.absolute(inputFile)); |
| var entryNode = graph.nodeFromUri(uri); |
| - var outputDir = options.outputDir; |
| - var generators = <CodeGenerator>[]; |
| + return new Compiler._( |
| + options, context, reporter, rules, checker, entryNode); |
| + } |
| + |
| + Compiler._(this.options, this.context, this._reporter, this.rules, |
| + this._checker, this._entryNode) { |
| if (options.dumpSrcDir != null) { |
| - generators.add(new EmptyDartGenerator( |
| - options.dumpSrcDir, entryNode.uri, rules, options)); |
| + _generators.add(new EmptyDartGenerator(this)); |
| } |
| - if (outputDir != null) { |
| - generators.add(options.outputDart |
| - ? new DartGenerator(outputDir, entryNode.uri, rules, options) |
| - : new JSGenerator(outputDir, entryNode.uri, rules, options)); |
| + if (options.outputDir != null) { |
| + _generators.add( |
| + options.outputDart ? new DartGenerator(this) : new JSGenerator(this)); |
| } |
| - return new Compiler._(options, resolver, reporter, rules, checker, graph, |
| - entryNode, generators, |
| - // TODO(sigmund): refactor to support hashing of the dart output? |
| - options.enableHashing && generators.length == 1 && !options.outputDart); |
| + // TODO(sigmund): refactor to support hashing of the dart output? |
| + _hashing = |
| + options.enableHashing && _generators.length == 1 && !options.outputDart; |
| } |
| - Compiler._(this._options, this._resolver, this._reporter, this._rules, |
| - this._checker, this._graph, this._entryNode, this._generators, |
| - this._hashing); |
| + Uri get entryPointUri => _entryNode.uri; |
| bool _buildSource(SourceNode node) { |
| if (node is HtmlSourceNode) { |
| @@ -115,30 +123,30 @@ class Compiler { |
| } |
| void _buildHtmlFile(HtmlSourceNode node) { |
| - if (_options.outputDir == null) return; |
| + if (options.outputDir == null) return; |
| var uri = node.source.uri; |
| _reporter.enterHtml(uri); |
| - var output = generateEntryHtml(node, _options); |
| + var output = generateEntryHtml(node, options); |
| if (output == null) { |
| _failure = true; |
| return; |
| } |
| _reporter.leaveHtml(); |
| var filename = path.basename(node.uri.path); |
| - String outputFile = path.join(_options.outputDir, filename); |
| + String outputFile = path.join(options.outputDir, filename); |
| new File(outputFile).writeAsStringSync(output); |
| - if (_options.outputDart) return; |
| + if (options.outputDart) return; |
| } |
| void _buildResourceFile(ResourceSourceNode node) { |
| // ResourceSourceNodes files that just need to be copied over to the output |
| // location. These can be external dependencies or pieces of the |
| // dev_compiler runtime. |
| - if (_options.outputDir == null || _options.outputDart) return; |
| + if (options.outputDir == null || options.outputDart) return; |
| var filepath = resourceOutputPath(node.uri, _entryNode.uri); |
| assert(filepath != null); |
| - filepath = path.join(_options.outputDir, filepath); |
| + filepath = path.join(options.outputDir, filepath); |
| var dir = path.dirname(filepath); |
| new Directory(dir).createSync(recursive: true); |
| new File.fromUri(node.source.uri).copySync(filepath); |
| @@ -153,10 +161,10 @@ class Compiler { |
| void _buildDartLibrary(DartSourceNode node) { |
| var source = node.source; |
| // TODO(sigmund): find out from analyzer team if there is a better way |
| - _resolver.context.applyChanges(new ChangeSet()..changedSource(source)); |
| - var entryUnit = _resolver.context.resolveCompilationUnit2(source, source); |
| + context.applyChanges(new ChangeSet()..changedSource(source)); |
| + var entryUnit = context.resolveCompilationUnit2(source, source); |
| var lib = entryUnit.element.enclosingElement; |
| - if (!_options.checkSdk && lib.isInSdk) return; |
| + if (!options.checkSdk && lib.isInSdk) return; |
| var current = node.info; |
| if (current != null) { |
| assert(current.library == lib); |
| @@ -165,25 +173,25 @@ class Compiler { |
| } |
| _reporter.enterLibrary(source.uri); |
| _libraries.add(current); |
| - _rules.currentLibraryInfo = current; |
| + rules.currentLibraryInfo = current; |
| var resolvedParts = node.parts |
| - .map((p) => _resolver.context.resolveCompilationUnit2(p.source, source)) |
| + .map((p) => context.resolveCompilationUnit2(p.source, source)) |
| .toList(growable: false); |
| var libraryUnit = new LibraryUnit(entryUnit, resolvedParts); |
| bool failureInLib = false; |
| for (var unit in libraryUnit.libraryThenParts) { |
| var unitSource = unit.element.source; |
| - _reporter.enterSource(unitSource); |
| + _reporter.enterCompilationUnit(unit); |
| // TODO(sigmund): integrate analyzer errors with static-info (issue #6). |
| - failureInLib = _resolver.logErrors(unitSource, _reporter) || failureInLib; |
| + failureInLib = logErrors(unitSource) || failureInLib; |
| _checker.visitCompilationUnit(unit); |
| if (_checker.failure) failureInLib = true; |
| - _reporter.leaveSource(); |
| + _reporter.leaveCompilationUnit(); |
| } |
| if (failureInLib) { |
| _failure = true; |
| - if (!_options.forceCompile) return; |
| + if (!options.forceCompile) return; |
| } |
| for (var cg in _generators) { |
| @@ -193,6 +201,21 @@ class Compiler { |
| _reporter.leaveLibrary(); |
| } |
| + /// Log any errors encountered when resolving [source] and return whether any |
| + /// errors were found. |
| + bool logErrors(Source source) { |
|
Jennifer Messerly
2015/05/13 23:21:16
moved from "TypeResolver"
|
| + List<analyzer.AnalysisError> errors = context.getErrors(source).errors; |
| + bool failure = false; |
| + if (errors.isNotEmpty) { |
| + for (var error in errors) { |
| + var message = new AnalyzerError.from(error); |
| + if (message.level == Level.SEVERE) failure = true; |
| + _reporter.log(message); |
| + } |
| + } |
| + return failure; |
| + } |
| + |
| CheckerResults run() { |
| var clock = new Stopwatch()..start(); |
| @@ -201,13 +224,13 @@ class Compiler { |
| // like more than one script tag (see .severe messages in |
| // dependency_graph.dart). Such failures should be reported back |
| // here so we can mark failure=true in the CheckerResutls. |
| - rebuild(_entryNode, _graph, _buildSource); |
| + rebuild(_entryNode, _buildSource); |
| _dumpInfoIfRequested(); |
| clock.stop(); |
| var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2); |
| _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n'); |
| return new CheckerResults( |
| - _libraries, _rules, _failure || _options.forceCompile); |
| + _libraries, rules, _failure || options.forceCompile); |
| } |
| void _runAgain() { |
| @@ -216,7 +239,7 @@ class Compiler { |
| int changed = 0; |
| // TODO(sigmund): propagate failures here (see TODO in run). |
| - rebuild(_entryNode, _graph, (n) { |
| + rebuild(_entryNode, (n) { |
| changed++; |
| return _buildSource(n); |
| }); |
| @@ -227,12 +250,12 @@ class Compiler { |
| } |
| _dumpInfoIfRequested() { |
| - if (!_options.dumpInfo || _reporter is! SummaryReporter) return; |
| + if (!options.dumpInfo || _reporter is! SummaryReporter) return; |
| var result = (_reporter as SummaryReporter).result; |
| - if (!_options.serverMode) print(summaryToString(result)); |
| - var filepath = _options.serverMode |
| - ? path.join(_options.outputDir, 'messages.json') |
| - : _options.dumpInfoFile; |
| + if (!options.serverMode) print(summaryToString(result)); |
| + var filepath = options.serverMode |
| + ? path.join(options.outputDir, 'messages.json') |
| + : options.dumpInfoFile; |
| if (filepath == null) return; |
| new File(filepath).writeAsStringSync(JSON.encode(result.toJsonMap())); |
| } |
| @@ -313,3 +336,17 @@ class CompilerServer { |
| final _log = new Logger('dev_compiler'); |
| final _earlyErrorResult = new CheckerResults(const [], null, true); |
| + |
| +class AnalyzerError extends Message { |
|
vsm
2015/05/14 22:02:08
Perhaps this would fit better in info.dart where w
Jennifer Messerly
2015/05/14 23:42:21
good idea, done!
|
| + factory AnalyzerError.from(analyzer.AnalysisError error) { |
| + var severity = error.errorCode.type.severity; |
| + var isError = severity == analyzer.ErrorSeverity.ERROR; |
| + var level = isError ? Level.SEVERE : Level.WARNING; |
| + int begin = error.offset; |
| + int end = begin + error.length; |
| + return new AnalyzerError(error.message, level, begin, end); |
| + } |
| + |
| + const AnalyzerError(String message, Level level, int begin, int end) |
| + : super('[from analyzer]: $message', level, begin, end); |
| +} |