blob: d18bd072a304395f1b330034f42068df35bad601 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/string_source.dart';
import 'package:dartfmt_extras/dartfmt_extras.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:path/path.dart' as path;
import 'package:source_span/source_span.dart';
Future<Null> main(List<String> args) async {
// Expect to get exactly one argument.
if (args.length < 3) {
stderr.writeln('Usage: pub run bin/main.dart '
'<check|fix> <base_path> <list of dart files...>');
exit(1);
}
// Command name check.
if (!<String>['check', 'fix'].contains(args[0])) {
stderr.writeln('The first argument should be either "check" or "fix".');
exit(1);
}
Command cmd = args[0] == 'check' ? Command.check : Command.fix;
bool error = false;
String basePath = args[1];
await Future.forEach(args.skip(2), (String relativePath) async {
// Existence check.
String fullPath = path.join(basePath, relativePath);
File dartFile = new File(fullPath);
if (!dartFile.existsSync()) {
stderr.writeln('The file ${args[0]} does not exist.');
exit(1);
}
SourceFile src = new SourceFile.fromString(
await dartFile.readAsString(),
url: relativePath,
);
try {
CompilationUnit cu = _parseCompilationUnit(src.getText(0), relativePath);
error = await processDoubleQuotes(cmd, dartFile, src, cu) || error;
error = await processDirectives(cmd, dartFile, src, cu) || error;
} on AnalyzerErrorGroup catch (e) {
stderr.writeln('Unable to parse file "$relativePath".');
for (AnalyzerError ae in e.errors) {
int line = src.getLine(ae.error.offset);
int col = src.getColumn(ae.error.offset);
stderr.writeln('[$line, $col] ${ae.error.message}');
}
exit(1);
}
});
exitCode = error ? 1 : 0;
}
/// Parse the compilation unit with the assert initializer feature enabled.
CompilationUnit _parseCompilationUnit(String contents, String name) {
Source source = new StringSource(contents, name);
CharSequenceReader reader = new CharSequenceReader(contents);
_ErrorCollector errorCollector = new _ErrorCollector();
Scanner scanner = new Scanner(source, reader, errorCollector);
Token token = scanner.tokenize();
Parser parser = new Parser(source, errorCollector)
..parseFunctionBodies = true;
CompilationUnit unit = parser.parseCompilationUnit(token)
..lineInfo = new LineInfo(scanner.lineStarts);
if (errorCollector.hasErrors) {
throw errorCollector.group;
}
return unit;
}
/// A simple error listener that collects errors into an [AnalyzerErrorGroup].
class _ErrorCollector extends AnalysisErrorListener {
final List<AnalysisError> _errors = <AnalysisError>[];
_ErrorCollector();
/// The group of errors collected.
AnalyzerErrorGroup get group =>
new AnalyzerErrorGroup.fromAnalysisErrors(_errors);
bool get hasErrors => _errors.isNotEmpty;
@override
void onError(AnalysisError error) => _errors.add(error);
}