Make analyzer_cli batch mode asynchronous.

R=brianwilkerson@google.com
BUG=

Review-Url: https://codereview.chromium.org/2659463003 .
This commit is contained in:
Konstantin Shcheglov 2017-01-26 07:25:23 -08:00
parent 12191284aa
commit d142d80af7
3 changed files with 55 additions and 43 deletions

View file

@ -4,6 +4,7 @@
library analyzer_cli.src.analyzer_impl;
import 'dart:async';
import 'dart:collection';
import 'dart:io';
@ -37,6 +38,7 @@ class AnalyzerImpl {
final CommandLineOptions options;
final int startTime;
final AnalysisOptions analysisOptions;
final AnalysisContext context;
/// Accumulated analysis statistics.
@ -61,8 +63,8 @@ class AnalyzerImpl {
/// specified the "--package-warnings" option.
String _selfPackageName;
AnalyzerImpl(this.context, this.librarySource, this.options, this.stats,
this.startTime);
AnalyzerImpl(this.analysisOptions, this.context, this.librarySource,
this.options, this.stats, this.startTime);
/// Returns the maximal [ErrorSeverity] of the recorded errors.
ErrorSeverity get maxErrorSeverity {
@ -111,24 +113,27 @@ class AnalyzerImpl {
}
}
/// Treats the [sourcePath] as the top level library and analyzes it using a
/// synchronous algorithm over the analysis engine. If [printMode] is `0`,
/// then no error or performance information is printed. If [printMode] is `1`,
/// then both will be printed. If [printMode] is `2`, then only performance
/// information will be printed, and it will be marked as being for a cold VM.
ErrorSeverity analyzeSync({int printMode: 1}) {
/// Treats the [sourcePath] as the top level library and analyzes it using
/// the analysis engine. If [printMode] is `0`, then no error or performance
/// information is printed. If [printMode] is `1`, then both will be printed.
/// If [printMode] is `2`, then only performance information will be printed,
/// and it will be marked as being for a cold VM.
Future<ErrorSeverity> analyze({int printMode: 1}) async {
setupForAnalysis();
return _analyzeSync(printMode);
return await _analyze(printMode);
}
/// Fills [errorInfos] using [sources].
void prepareErrors() {
return _prepareErrorsTag.makeCurrentWhile(() {
Future<Null> prepareErrors() async {
PerformanceTag previous = _prepareErrorsTag.makeCurrent();
try {
for (Source source in sources) {
context.computeErrors(source);
errorInfos.add(context.getErrors(source));
}
});
} finally {
previous.makeCurrent();
}
}
/// Fills [sources].
@ -148,8 +153,7 @@ class AnalyzerImpl {
}
}
/// The sync version of analysis.
ErrorSeverity _analyzeSync(int printMode) {
Future<ErrorSeverity> _analyze(int printMode) async {
// Don't try to analyze parts.
if (context.computeKindOf(librarySource) == SourceKind.PART) {
stderr.writeln("Only libraries can be analyzed.");
@ -157,9 +161,9 @@ class AnalyzerImpl {
"${librarySource.fullName} is a part and can not be analyzed.");
return ErrorSeverity.ERROR;
}
var libraryElement = _resolveLibrary();
LibraryElement libraryElement = await _resolveLibrary();
prepareSources(libraryElement);
prepareErrors();
await prepareErrors();
// Print errors and performance numbers.
if (printMode == 1) {
@ -240,12 +244,15 @@ class AnalyzerImpl {
}
ProcessedSeverity _processError(AnalysisError error) =>
processError(error, options, context);
processError(error, options, analysisOptions);
LibraryElement _resolveLibrary() {
return _resolveLibraryTag.makeCurrentWhile(() {
Future<LibraryElement> _resolveLibrary() async {
PerformanceTag previous = _resolveLibraryTag.makeCurrent();
try {
return context.computeLibraryElement(librarySource);
});
} finally {
previous.makeCurrent();
}
}
/// Compute the severity of the error; however:
@ -255,10 +262,10 @@ class AnalyzerImpl {
/// * if [options.lintsAreFatal] is true, escalate lints to errors.
static ErrorSeverity computeSeverity(
AnalysisError error, CommandLineOptions options,
[AnalysisContext context]) {
if (context != null) {
[AnalysisOptions analysisOptions]) {
if (analysisOptions != null) {
ErrorProcessor processor =
ErrorProcessor.getProcessor(context.analysisOptions, error);
ErrorProcessor.getProcessor(analysisOptions, error);
// If there is a processor for this error, defer to it.
if (processor != null) {
return processor.severity;
@ -296,8 +303,8 @@ class AnalyzerImpl {
/// Check various configuration options to get a desired severity for this
/// [error] (or `null` if it's to be suppressed).
static ProcessedSeverity processError(AnalysisError error,
CommandLineOptions options, AnalysisContext context) {
ErrorSeverity severity = computeSeverity(error, options, context);
CommandLineOptions options, AnalysisOptions analysisOptions) {
ErrorSeverity severity = computeSeverity(error, options, analysisOptions);
bool isOverridden = false;
// Skip TODOs categorically (unless escalated to ERROR or HINT.)

View file

@ -225,8 +225,8 @@ class BuildMode {
for (Source source in explicitSources) {
AnalysisErrorInfo errorInfo = context.getErrors(source);
for (AnalysisError error in errorInfo.errors) {
ProcessedSeverity processedSeverity =
AnalyzerImpl.processError(error, options, context);
ProcessedSeverity processedSeverity = AnalyzerImpl.processError(
error, options, context.analysisOptions);
if (processedSeverity != null) {
maxSeverity = maxSeverity.max(processedSeverity.severity);
}
@ -319,7 +319,7 @@ class BuildMode {
options,
stats,
(AnalysisError error) =>
AnalyzerImpl.processError(error, options, context));
AnalyzerImpl.processError(error, options, context.analysisOptions));
for (Source source in explicitSources) {
AnalysisErrorInfo errorInfo = context.getErrors(source);
formatter.formatErrors([errorInfo]);

View file

@ -68,7 +68,7 @@ bool containsLintRuleEntry(Map<String, YamlNode> options) {
return linterNode is YamlMap && linterNode.containsKey('rules');
}
typedef ErrorSeverity _BatchRunnerHandler(List<String> args);
typedef Future<ErrorSeverity> _BatchRunnerHandler(List<String> args);
class Driver implements CommandLineStarter {
static final PerformanceTag _analyzeAllTag =
@ -114,7 +114,7 @@ class Driver implements CommandLineStarter {
}
@override
void start(List<String> args) {
Future<Null> start(List<String> args) async {
if (_context != null) {
throw new StateError("start() can only be called once");
}
@ -140,7 +140,7 @@ class Driver implements CommandLineStarter {
return _analyzeAll(options);
});
} else {
ErrorSeverity severity = _analyzeAll(options);
ErrorSeverity severity = await _analyzeAll(options);
// In case of error propagate exit code.
if (severity == ErrorSeverity.ERROR) {
io.exitCode = severity.ordinal;
@ -158,14 +158,17 @@ class Driver implements CommandLineStarter {
}
}
ErrorSeverity _analyzeAll(CommandLineOptions options) {
return _analyzeAllTag.makeCurrentWhile(() {
return _analyzeAllImpl(options);
});
Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
PerformanceTag previous = _analyzeAllTag.makeCurrent();
try {
return await _analyzeAllImpl(options);
} finally {
previous.makeCurrent();
}
}
/// Perform analysis according to the given [options].
ErrorSeverity _analyzeAllImpl(CommandLineOptions options) {
Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async {
if (!options.machineFormat) {
outSink.writeln("Analyzing ${options.sourceFiles}...");
}
@ -217,7 +220,7 @@ class Driver implements CommandLineStarter {
parts.add(source);
continue;
}
ErrorSeverity status = _runAnalyzer(source, options);
ErrorSeverity status = await _runAnalyzer(source, options);
allResult = allResult.max(status);
libUris.add(source.uri);
}
@ -536,6 +539,7 @@ class Driver implements CommandLineStarter {
});
_context.sourceFactory = sourceFactory;
if (sdkBundle != null) {
_context.resultProvider =
new InputPackagesResultProvider(_context, summaryDataStore);
@ -633,11 +637,12 @@ class Driver implements CommandLineStarter {
}
/// Analyze a single source.
ErrorSeverity _runAnalyzer(Source source, CommandLineOptions options) {
Future<ErrorSeverity> _runAnalyzer(
Source source, CommandLineOptions options) async {
int startTime = currentTimeMillis();
AnalyzerImpl analyzer =
new AnalyzerImpl(_context, source, options, stats, startTime);
var errorSeverity = analyzer.analyzeSync();
AnalyzerImpl analyzer = new AnalyzerImpl(
_context.analysisOptions, _context, source, options, stats, startTime);
ErrorSeverity errorSeverity = await analyzer.analyze();
if (errorSeverity == ErrorSeverity.ERROR) {
io.exitCode = errorSeverity.ordinal;
}
@ -809,7 +814,7 @@ class _BatchRunner {
// Read line from stdin.
Stream cmdLine =
io.stdin.transform(UTF8.decoder).transform(new LineSplitter());
cmdLine.listen((String line) {
cmdLine.listen((String line) async {
// Maybe finish.
if (line.isEmpty) {
var time = stopwatch.elapsedMilliseconds;
@ -827,7 +832,7 @@ class _BatchRunner {
// Analyze single set of arguments.
try {
totalTests++;
ErrorSeverity result = handler(args);
ErrorSeverity result = await handler(args);
bool resultPass = result != ErrorSeverity.ERROR;
if (!resultPass) {
testsFailed++;