| 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 /// 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'; |
| 11 | 11 |
| 12 import 'package:analyzer/src/generated/error.dart' | |
| 13 show AnalysisError, ErrorSeverity, ErrorType; | |
| 14 import 'package:analyzer/src/generated/engine.dart' | 12 import 'package:analyzer/src/generated/engine.dart' |
| 15 show AnalysisContext, ChangeSet; | 13 show AnalysisContext, ChangeSet; |
| 14 import 'package:analyzer/src/generated/error.dart' |
| 15 show AnalysisError, AnalysisErrorListener, ErrorSeverity, ErrorType; |
| 16 import 'package:analyzer/src/generated/source.dart' show Source; | 16 import 'package:analyzer/src/generated/source.dart' show Source; |
| 17 import 'package:logging/logging.dart' show Level, Logger, LogRecord; | 17 import 'package:logging/logging.dart' show Level, Logger, LogRecord; |
| 18 import 'package:path/path.dart' as path; | 18 import 'package:path/path.dart' as path; |
| 19 import 'package:shelf/shelf.dart' as shelf; | 19 import 'package:shelf/shelf.dart' as shelf; |
| 20 import 'package:shelf/shelf_io.dart' as shelf; | 20 import 'package:shelf/shelf_io.dart' as shelf; |
| 21 import 'package:shelf_static/shelf_static.dart' as shelf_static; | 21 import 'package:shelf_static/shelf_static.dart' as shelf_static; |
| 22 | 22 |
| 23 import 'src/analysis_context.dart'; | 23 import 'src/analysis_context.dart'; |
| 24 import 'src/checker/checker.dart'; | 24 import 'src/checker/checker.dart'; |
| 25 import 'src/checker/rules.dart'; | 25 import 'src/checker/rules.dart'; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 47 AnalysisContext get context; | 47 AnalysisContext get context; |
| 48 TypeRules get rules; | 48 TypeRules get rules; |
| 49 Uri get entryPointUri; | 49 Uri get entryPointUri; |
| 50 } | 50 } |
| 51 | 51 |
| 52 /// Encapsulates the logic to do a one-off compilation or a partial compilation | 52 /// Encapsulates the logic to do a one-off compilation or a partial compilation |
| 53 /// when the compiler is run as a development server. | 53 /// when the compiler is run as a development server. |
| 54 class Compiler implements AbstractCompiler { | 54 class Compiler implements AbstractCompiler { |
| 55 final CompilerOptions options; | 55 final CompilerOptions options; |
| 56 final AnalysisContext context; | 56 final AnalysisContext context; |
| 57 final CompilerReporter _reporter; | 57 final AnalysisErrorListener _reporter; |
| 58 final TypeRules rules; | 58 final TypeRules rules; |
| 59 final CodeChecker _checker; | 59 final CodeChecker _checker; |
| 60 final SourceNode _entryNode; | 60 final SourceNode _entryNode; |
| 61 List<LibraryInfo> _libraries = <LibraryInfo>[]; | 61 List<LibraryInfo> _libraries = <LibraryInfo>[]; |
| 62 final _generators = <CodeGenerator>[]; | 62 final _generators = <CodeGenerator>[]; |
| 63 bool _hashing; | 63 bool _hashing; |
| 64 bool _failure = false; | 64 bool _failure = false; |
| 65 | 65 |
| 66 factory Compiler(CompilerOptions options, | 66 factory Compiler(CompilerOptions options, |
| 67 {AnalysisContext context, CompilerReporter reporter}) { | 67 {AnalysisContext context, AnalysisErrorListener reporter}) { |
| 68 var strongOpts = options.strongOptions; | 68 var strongOpts = options.strongOptions; |
| 69 var sourceOpts = options.sourceOptions; | 69 var sourceOpts = options.sourceOptions; |
| 70 if (context == null) { | 70 if (context == null) { |
| 71 context = createAnalysisContextWithSources(strongOpts, sourceOpts); | 71 context = createAnalysisContextWithSources(strongOpts, sourceOpts); |
| 72 } | 72 } |
| 73 | 73 |
| 74 if (reporter == null) { | 74 if (reporter == null) { |
| 75 reporter = options.dumpInfo | 75 reporter = options.dumpInfo |
| 76 ? new SummaryReporter(context, options.logLevel) | 76 ? new SummaryReporter(context, options.logLevel) |
| 77 : new LogReporter(context, useColors: options.useColors); | 77 : new LogReporter(context, useColors: options.useColors); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 assert(false); // should not get a build request on PartSourceNode | 117 assert(false); // should not get a build request on PartSourceNode |
| 118 } | 118 } |
| 119 | 119 |
| 120 // TODO(sigmund): don't always return true. Use summarization to better | 120 // TODO(sigmund): don't always return true. Use summarization to better |
| 121 // determine when rebuilding is needed. | 121 // determine when rebuilding is needed. |
| 122 return true; | 122 return true; |
| 123 } | 123 } |
| 124 | 124 |
| 125 void _buildHtmlFile(HtmlSourceNode node) { | 125 void _buildHtmlFile(HtmlSourceNode node) { |
| 126 if (outputDir == null) return; | 126 if (outputDir == null) return; |
| 127 var uri = node.source.uri; | |
| 128 _reporter.enterHtml(uri); | |
| 129 var output = generateEntryHtml(node, options); | 127 var output = generateEntryHtml(node, options); |
| 130 if (output == null) { | 128 if (output == null) { |
| 131 _failure = true; | 129 _failure = true; |
| 132 return; | 130 return; |
| 133 } | 131 } |
| 134 _reporter.leaveHtml(); | |
| 135 var filename = path.basename(node.uri.path); | 132 var filename = path.basename(node.uri.path); |
| 136 String outputFile = path.join(outputDir, filename); | 133 String outputFile = path.join(outputDir, filename); |
| 137 new File(outputFile).writeAsStringSync(output); | 134 new File(outputFile).writeAsStringSync(output); |
| 138 } | 135 } |
| 139 | 136 |
| 140 void _buildResourceFile(ResourceSourceNode node) { | 137 void _buildResourceFile(ResourceSourceNode node) { |
| 141 // ResourceSourceNodes files that just need to be copied over to the output | 138 // ResourceSourceNodes files that just need to be copied over to the output |
| 142 // location. These can be external dependencies or pieces of the | 139 // location. These can be external dependencies or pieces of the |
| 143 // dev_compiler runtime. | 140 // dev_compiler runtime. |
| 144 if (outputDir == null) return; | 141 if (outputDir == null) return; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 162 context.applyChanges(new ChangeSet()..changedSource(source)); | 159 context.applyChanges(new ChangeSet()..changedSource(source)); |
| 163 var entryUnit = context.resolveCompilationUnit2(source, source); | 160 var entryUnit = context.resolveCompilationUnit2(source, source); |
| 164 var lib = entryUnit.element.enclosingElement; | 161 var lib = entryUnit.element.enclosingElement; |
| 165 if (!options.checkSdk && lib.source.uri.scheme == 'dart') return; | 162 if (!options.checkSdk && lib.source.uri.scheme == 'dart') return; |
| 166 var current = node.info; | 163 var current = node.info; |
| 167 if (current != null) { | 164 if (current != null) { |
| 168 assert(current.library == lib); | 165 assert(current.library == lib); |
| 169 } else { | 166 } else { |
| 170 node.info = current = new LibraryInfo(lib, _isEntry(node)); | 167 node.info = current = new LibraryInfo(lib, _isEntry(node)); |
| 171 } | 168 } |
| 172 _reporter.enterLibrary(source.uri); | |
| 173 _libraries.add(current); | 169 _libraries.add(current); |
| 174 rules.currentLibraryInfo = current; | 170 rules.currentLibraryInfo = current; |
| 175 | 171 |
| 176 var resolvedParts = node.parts | 172 var resolvedParts = node.parts |
| 177 .map((p) => context.resolveCompilationUnit2(p.source, source)) | 173 .map((p) => context.resolveCompilationUnit2(p.source, source)) |
| 178 .toList(growable: false); | 174 .toList(growable: false); |
| 179 var libraryUnit = new LibraryUnit(entryUnit, resolvedParts); | 175 var libraryUnit = new LibraryUnit(entryUnit, resolvedParts); |
| 180 bool failureInLib = false; | 176 bool failureInLib = false; |
| 181 for (var unit in libraryUnit.libraryThenParts) { | 177 for (var unit in libraryUnit.libraryThenParts) { |
| 182 var unitSource = unit.element.source; | 178 var unitSource = unit.element.source; |
| 183 _reporter.enterCompilationUnit(unit); | |
| 184 // TODO(sigmund): integrate analyzer errors with static-info (issue #6). | |
| 185 failureInLib = logErrors(unitSource) || failureInLib; | 179 failureInLib = logErrors(unitSource) || failureInLib; |
| 186 _checker.visitCompilationUnit(unit); | 180 _checker.visitCompilationUnit(unit); |
| 187 if (_checker.failure) failureInLib = true; | 181 if (_checker.failure) failureInLib = true; |
| 188 _reporter.leaveCompilationUnit(); | |
| 189 } | 182 } |
| 190 if (failureInLib) { | 183 if (failureInLib) { |
| 191 _failure = true; | 184 _failure = true; |
| 192 if (!options.codegenOptions.forceCompile) return; | 185 if (!options.codegenOptions.forceCompile) return; |
| 193 } | 186 } |
| 194 | 187 |
| 195 for (var cg in _generators) { | 188 for (var cg in _generators) { |
| 196 var hash = cg.generateLibrary(libraryUnit, current); | 189 var hash = cg.generateLibrary(libraryUnit, current); |
| 197 if (_hashing) node.cachingHash = hash; | 190 if (_hashing) node.cachingHash = hash; |
| 198 } | 191 } |
| 199 _reporter.leaveLibrary(); | |
| 200 } | 192 } |
| 201 | 193 |
| 202 /// Log any errors encountered when resolving [source] and return whether any | 194 /// Log any errors encountered when resolving [source] and return whether any |
| 203 /// errors were found. | 195 /// errors were found. |
| 204 bool logErrors(Source source) { | 196 bool logErrors(Source source) { |
| 205 context.computeErrors(source); | 197 context.computeErrors(source); |
| 206 List<AnalysisError> errors = context.getErrors(source).errors; | 198 List<AnalysisError> errors = context.getErrors(source).errors; |
| 207 bool failure = false; | 199 bool failure = false; |
| 208 if (errors.isNotEmpty) { | 200 if (errors.isNotEmpty) { |
| 209 for (var error in errors) { | 201 for (var error in errors) { |
| 210 // Always skip TODOs. | 202 // Always skip TODOs. |
| 211 if (error.errorCode.type == ErrorType.TODO) continue; | 203 if (error.errorCode.type == ErrorType.TODO) continue; |
| 212 | 204 |
| 213 // Skip hints for now. In the future these could be turned on via flags. | 205 // Skip hints for now. In the future these could be turned on via flags. |
| 214 if (error.errorCode.errorSeverity.ordinal < | 206 if (error.errorCode.errorSeverity.ordinal < |
| 215 ErrorSeverity.WARNING.ordinal) { | 207 ErrorSeverity.WARNING.ordinal) { |
| 216 continue; | 208 continue; |
| 217 } | 209 } |
| 218 | 210 |
| 219 var message = new AnalyzerMessage.from(error); | 211 // All analyzer warnings or errors are errors for DDC. |
| 220 if (message.level == Level.SEVERE) failure = true; | 212 failure = true; |
| 221 _reporter.log(message); | 213 _reporter.onError(error); |
| 222 } | 214 } |
| 223 } | 215 } |
| 224 return failure; | 216 return failure; |
| 225 } | 217 } |
| 226 | 218 |
| 227 CheckerResults run() { | 219 CheckerResults run() { |
| 228 var clock = new Stopwatch()..start(); | 220 var clock = new Stopwatch()..start(); |
| 229 | 221 |
| 230 // TODO(sigmund): we are missing a couple failures here. The | 222 // TODO(sigmund): we are missing a couple failures here. The |
| 231 // dependency_graph now detects broken imports or unsupported features | 223 // dependency_graph now detects broken imports or unsupported features |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 // Note: the cache-control header should be enough, but this doesn't hurt | 329 // Note: the cache-control header should be enough, but this doesn't hurt |
| 338 // and can help renew the policy after it expires. | 330 // and can help renew the policy after it expires. |
| 339 headers['ETag'] = hash; | 331 headers['ETag'] = hash; |
| 340 } | 332 } |
| 341 return response.change(headers: headers); | 333 return response.change(headers: headers); |
| 342 }; | 334 }; |
| 343 } | 335 } |
| 344 | 336 |
| 345 final _log = new Logger('dev_compiler'); | 337 final _log = new Logger('dev_compiler'); |
| 346 final _earlyErrorResult = new CheckerResults(const [], null, true); | 338 final _earlyErrorResult = new CheckerResults(const [], null, true); |
| OLD | NEW |