diff --git a/tools/clang_tidy/lib/clang_tidy.dart b/tools/clang_tidy/lib/clang_tidy.dart index 2cdd81d8ec144..67599166046b9 100644 --- a/tools/clang_tidy/lib/clang_tidy.dart +++ b/tools/clang_tidy/lib/clang_tidy.dart @@ -110,7 +110,7 @@ class ClangTidy { final List buildCommandsData = jsonDecode( options.buildCommandsPath.readAsStringSync(), ) as List; - final List changedFileBuildCommands = getLintCommandsForChangedFiles( + final List changedFileBuildCommands = await getLintCommandsForChangedFiles( buildCommandsData, changedFiles, ); @@ -165,20 +165,20 @@ class ClangTidy { /// Given a build commands json file, and the files with local changes, /// compute the lint commands to run. @visibleForTesting - List getLintCommandsForChangedFiles( + Future> getLintCommandsForChangedFiles( List buildCommandsData, List changedFiles, - ) { - final List buildCommands = [ - for (final dynamic c in buildCommandsData) - Command.fromMap(c as Map), - ]; - - return [ - for (final Command c in buildCommands) - if (c.containsAny(changedFiles)) - c, - ]; + ) async { + final List buildCommands = []; + for (final dynamic data in buildCommandsData) { + final Command command = Command.fromMap(data as Map); + final LintAction lintAction = await command.lintAction; + // Short-circuit the expensive containsAny call for the many third_party files. + if (lintAction != LintAction.skipThirdParty && command.containsAny(changedFiles)) { + buildCommands.add(command); + } + } + return buildCommands; } Future<_ComputeJobsResult> _computeJobs( @@ -212,6 +212,9 @@ class ClangTidy { case LintAction.skipThirdParty: _outSink.writeln('🔷 ignoring $relativePath (third_party)'); break; + case LintAction.skipMissing: + _outSink.writeln('🔷 ignoring $relativePath (missing)'); + break; } } return _ComputeJobsResult(jobs, sawMalformed); @@ -239,5 +242,3 @@ class ClangTidy { return result; } } - - diff --git a/tools/clang_tidy/lib/src/command.dart b/tools/clang_tidy/lib/src/command.dart index 73cbca7f40dcb..d2566ee769754 100644 --- a/tools/clang_tidy/lib/src/command.dart +++ b/tools/clang_tidy/lib/src/command.dart @@ -26,6 +26,9 @@ enum LintAction { /// Fail due to a malformed FLUTTER_NOLINT comment. failMalformedNoLint, + + /// Ignore because the file doesn't exist locally. + skipMissing, } /// A compilation command and methods to generate the lint command and job for @@ -86,20 +89,20 @@ class Command { r'//\s*FLUTTER_NOLINT(: https://github.com/flutter/flutter/issues/\d+)?', ); - LintAction? _lintAction; - /// The type of lint that is appropriate for this command. - Future get lintAction async => - _lintAction ??= await getLintAction(filePath); + late final Future lintAction = getLintAction(filePath); /// Determine the lint action for the file at `path`. @visibleForTesting - static Future getLintAction(String filePath) { + static Future getLintAction(String filePath) async { if (path.split(filePath).contains('third_party')) { - return Future.value(LintAction.skipThirdParty); + return LintAction.skipThirdParty; } final io.File file = io.File(filePath); + if (!file.existsSync()) { + return LintAction.skipMissing; + } final Stream lines = file.openRead() .transform(utf8.decoder) .transform(const LineSplitter()); diff --git a/tools/clang_tidy/test/clang_tidy_test.dart b/tools/clang_tidy/test/clang_tidy_test.dart index 9ca27010c4732..4656f33926e98 100644 --- a/tools/clang_tidy/test/clang_tidy_test.dart +++ b/tools/clang_tidy/test/clang_tidy_test.dart @@ -105,8 +105,8 @@ Future main(List args) async { final ClangTidy clangTidy = ClangTidy.fromCommandLine( [ '--compile-commands', - // This just has to exist. - io.Platform.executable, + // This file needs to exist, and be UTF8 line-parsable. + io.Platform.script.path, '--repo', '/does/not/exist', ], @@ -168,7 +168,7 @@ Future main(List args) async { 'file': filePath, }, ]; - final List commands = clangTidy.getLintCommandsForChangedFiles( + final List commands = await clangTidy.getLintCommandsForChangedFiles( buildCommandsData, [], ); @@ -186,7 +186,9 @@ Future main(List args) async { outSink: outBuffer, errSink: errBuffer, ); - const String filePath = '/path/to/a/source_file.cc'; + + // This file needs to exist, and be UTF8 line-parsable. + final String filePath = io.Platform.script.path; final List buildCommandsData = >[ { 'directory': '/unused', @@ -194,7 +196,7 @@ Future main(List args) async { 'file': filePath, }, ]; - final List commands = clangTidy.getLintCommandsForChangedFiles( + final List commands = await clangTidy.getLintCommandsForChangedFiles( buildCommandsData, [io.File(filePath)], ); @@ -220,6 +222,14 @@ Future main(List args) async { expect(lintAction, equals(LintAction.skipThirdParty)); }); + test('Command getLintAction flags missing files', () async { + final LintAction lintAction = await Command.getLintAction( + '/does/not/exist', + ); + + expect(lintAction, equals(LintAction.skipMissing)); + }); + test('Command getLintActionFromContents flags FLUTTER_NOLINT', () async { final LintAction lintAction = await Command.lintActionFromContents( Stream.fromIterable([