// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file // for details. 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 'dart:math'; import 'package:pool/pool.dart'; // "perfetto_build_flags.h" is included by some Perfetto headers that we // include, but it is generated at build-time. We prevent clang-tidy from // reporting a "file not found" error by ensuring that this file exists in // Iout/DebugX64/gen and passing // -Iout/DebugX64/gen/third_party/perfetto/build_config to clang-tidy below. Future generatePerfettoBuildFlags() async { final processResult = await Process.run('./tools/build.py', [ '-mdebug', '-ax64', 'third_party/perfetto/src/gn:gen_buildflags', ]); final int exitCode = processResult.exitCode; final String stdout = processResult.stdout.trim(); final String stderr = processResult.stderr.trim(); if (exitCode != 0) { print('exit-code: $exitCode'); print('stdout:'); print('${stdout}'); print('stderr:'); print('${stderr}'); } } const String clangTidy = './buildtools/linux-x64/clang/bin/clang-tidy'; List compilerFlagsForFile(String filepath) { String arch = "X64"; if (filepath.contains("_arm.")) arch = "ARM"; if (filepath.contains("_arm64.")) arch = "ARM64"; if (filepath.contains("_riscv.")) arch = "RISCV64"; // Skipping IA32 because it neither has a simulator nor works with crossword // and the host architecture is fixed. final flags = [ '-I.', '-Iruntime', '-Ithird_party', '-Iruntime/include', if (filepath.contains('samples/embedder')) '-Iruntime/engine', '-Ithird_party/boringssl/src/include', '-Ithird_party/perfetto/src/include', '-Ithird_party/zlib', '-Iout/DebugX64/gen/third_party/perfetto/src/build_config', '-DTARGET_ARCH_$arch', '-DTESTING', '-std=c++20', '-x', 'c++', ]; return flags; } final pool = new Pool(max(1, Platform.numberOfProcessors ~/ 2)); // Exclude running the linter on those files. final Set excludedFiles = Set.from([ // These files are not valid cc files but rather cc templates 'runtime/bin/abi_version_in.cc', 'runtime/bin/builtin_in.cc', 'runtime/bin/snapshot_in.cc', 'runtime/lib/libgen_in.cc', 'runtime/vm/version_in.cc', // These files cannot be analyzed by itself (must be included indirectly). 'runtime/bin/android.h', 'runtime/bin/eventhandler_android.h', 'runtime/bin/eventhandler_fuchsia.h', 'runtime/bin/eventhandler_linux.h', 'runtime/bin/eventhandler_macos.h', 'runtime/bin/eventhandler_win.h', 'runtime/bin/namespace_android.h', 'runtime/bin/namespace_fuchsia.h', 'runtime/bin/namespace_linux.h', 'runtime/bin/namespace_macos.h', 'runtime/bin/namespace_win.h', 'runtime/bin/platform_macos.h', 'runtime/bin/platform_macos_cocoa.h', 'runtime/bin/socket_base_android.h', 'runtime/bin/socket_base_fuchsia.h', 'runtime/bin/socket_base_linux.h', 'runtime/bin/socket_base_macos.h', 'runtime/bin/socket_base_win.h', 'runtime/bin/thread_absl.h', 'runtime/bin/thread_android.h', 'runtime/bin/thread_fuchsia.h', 'runtime/bin/thread_linux.h', 'runtime/bin/thread_macos.h', 'runtime/bin/thread_win.h', 'runtime/platform/atomic_android.h', 'runtime/platform/atomic_fuchsia.h', 'runtime/platform/atomic_linux.h', 'runtime/platform/atomic_macos.h', 'runtime/platform/atomic_win.h', 'runtime/platform/utils_android.h', 'runtime/platform/utils_fuchsia.h', 'runtime/platform/utils_linux.h', 'runtime/platform/utils_macos.h', 'runtime/platform/utils_win.h', 'runtime/vm/compiler/assembler/assembler_arm.h', 'runtime/vm/compiler/assembler/assembler_arm64.h', 'runtime/vm/compiler/assembler/assembler_ia32.h', 'runtime/vm/compiler/assembler/assembler_riscv.h', 'runtime/vm/compiler/assembler/assembler_x64.h', 'runtime/vm/compiler/runtime_offsets_extracted.h', 'runtime/vm/constants_arm.h', 'runtime/vm/constants_arm64.h', 'runtime/vm/constants_ia32.h', 'runtime/vm/constants_riscv.h', 'runtime/vm/constants_x64.h', 'runtime/vm/cpu_arm.h', 'runtime/vm/cpu_arm64.h', 'runtime/vm/cpu_ia32.h', 'runtime/vm/cpu_riscv.h', 'runtime/vm/cpu_x64.h', 'runtime/vm/instructions_arm.h', 'runtime/vm/instructions_arm64.h', 'runtime/vm/instructions_ia32.h', 'runtime/vm/instructions_riscv.h', 'runtime/vm/instructions_x64.h', 'runtime/vm/os_thread_absl.h', 'runtime/vm/os_thread_android.h', 'runtime/vm/os_thread_fuchsia.h', 'runtime/vm/os_thread_linux.h', 'runtime/vm/os_thread_macos.h', 'runtime/vm/os_thread_win.h', 'runtime/vm/regexp/regexp_assembler_bytecode_inl.h', 'runtime/vm/simulator_arm.h', 'runtime/vm/simulator_arm64.h', 'runtime/vm/simulator_riscv.h', 'runtime/vm/simulator_x64.h', 'runtime/vm/stack_frame_arm.h', 'runtime/vm/stack_frame_arm64.h', 'runtime/vm/stack_frame_ia32.h', 'runtime/vm/stack_frame_riscv.h', 'runtime/vm/stack_frame_x64.h', // Only available in special builds 'runtime/bin/io_service_no_ssl.h', 'runtime/bin/utils_win.h', 'runtime/vm/compiler/backend/locations_helpers_arm.h', 'runtime/vm/compiler/ffi/unit_test_custom_zone.cc', // V8 sources 'runtime/vm/regexp/base.h', 'runtime/vm/regexp/char-predicates-inl.h', 'runtime/vm/regexp/char-predicates.cc', 'runtime/vm/regexp/char-predicates.h', 'runtime/vm/regexp/flags.h', 'runtime/vm/regexp/gen-regexp-special-case.cc', 'runtime/vm/regexp/label.h', 'runtime/vm/regexp/memcopy.h', 'runtime/vm/regexp/regexp-ast.cc', 'runtime/vm/regexp/regexp-ast.h', 'runtime/vm/regexp/regexp-bytecode-generator-inl.h', 'runtime/vm/regexp/regexp-bytecode-generator.cc', 'runtime/vm/regexp/regexp-bytecode-generator.h', 'runtime/vm/regexp/regexp-bytecodes-inl.h', 'runtime/vm/regexp/regexp-bytecodes.h', 'runtime/vm/regexp/regexp-compiler-tonode.cc', 'runtime/vm/regexp/regexp-compiler.cc', 'runtime/vm/regexp/regexp-compiler.h', 'runtime/vm/regexp/regexp-error.cc', 'runtime/vm/regexp/regexp-error.h', 'runtime/vm/regexp/regexp-flags.h', 'runtime/vm/regexp/regexp-interpreter.cc', 'runtime/vm/regexp/regexp-interpreter.h', 'runtime/vm/regexp/regexp-macro-assembler.cc', 'runtime/vm/regexp/regexp-macro-assembler.h', 'runtime/vm/regexp/regexp-nodes.h', 'runtime/vm/regexp/regexp-parser.cc', 'runtime/vm/regexp/regexp-parser.h', 'runtime/vm/regexp/regexp-test.cc', 'runtime/vm/regexp/regexp-utils.cc', 'runtime/vm/regexp/regexp-utils.h', 'runtime/vm/regexp/regexp.cc', 'runtime/vm/regexp/regexp.h', 'runtime/vm/regexp/small-vector.h', 'runtime/vm/regexp/special-case.cc', 'runtime/vm/regexp/special-case.h', 'runtime/vm/regexp/unibrow-inl.h', 'runtime/vm/regexp/unibrow.cc', 'runtime/vm/regexp/unibrow.h', 'runtime/vm/regexp/vector.h', 'runtime/vm/regexp/zone-containers.h', 'runtime/vm/regexp/zone-list-inl.h', 'runtime/vm/regexp/zone-list.h', ]); final defineSets = [ ['-DDEBUG'], ['-DNDEBUG'], ['-DNDEBUG', '-DPRODUCT'], ['-DDART_PRECOMPILER', '-DDEBUG'], ['-DDART_PRECOMPILER', '-DNDEBUG'], ['-DDART_PRECOMPILER', '-DNDEBUG', '-DPRODUCT'], ]; main(List files) async { await generatePerfettoBuildFlags(); bool isFirstFailure = true; files = files.where((filepath) => !excludedFiles.contains(filepath)).toList(); // Analyze the [files] in parallel. for (List defines in defineSets) { await Future.wait( files.map((String filepath) async { // The `runtime/.clang-tidy` file has the enabled checks in it. final args = ['--allow-no-checks', '-quiet', filepath, '--'] ..addAll(compilerFlagsForFile(filepath)) ..addAll(defines); final processResult = await pool.withResource( () => Process.run(clangTidy, args), ); final int exitCode = processResult.exitCode; String stdout = processResult.stdout.trim(); final String stderr = processResult.stderr.trim(); if (stdout == 'No checks enabled.') { stdout = ''; } if (exitCode != 0 || stdout.isNotEmpty) { if (!isFirstFailure) { print(''); print( '------------------------------------------------------------', ); print(''); } isFirstFailure = false; } if (exitCode != 0) { print('command: $clangTidy ${args.join(" ")}'); print('exit-code: $exitCode'); print('stdout:'); print('${stdout}'); print('stderr:'); print('${stderr}'); } else if (stdout.isNotEmpty) { // The actual lints go to stdout. print(stdout); } }), ); } }