[llvm] Reduce false positives in ids-check workflow (PR #194878)
Fabrice de Gans via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 08:15:08 PDT 2026
https://github.com/Steelskin updated https://github.com/llvm/llvm-project/pull/194878
>From e7d87ff0f1795d79b898b0c4f69d497f8886a184 Mon Sep 17 00:00:00 2001
From: Fabrice de Gans <fabrice at thebrowser.company>
Date: Wed, 29 Apr 2026 16:28:25 +0200
Subject: [PATCH] Reduce false positives in ids-check workflow
The ids-check workflow is meant to signal when LLVM APIs are missing
from a header modified in a PR. However, there were a few issues with
the initial implementation:
* LLVM_ABI annotations were incorrectly suggested for headers that
should not have them.
* Unmodified headers were also signaled as missing LLVM_ABI annotations.
These changes attempt to remedy the situation by excluding whole
categories of headers for which the workflow does not work properly and
improving the way headers are parsed.
These changes do not re-enable the workflow yet. This will be done
after all of the missing LLVM_ABI annotations have been added, using the
changes to the script.
---
.github/workflows/ids-check.yml | 59 ++++--
llvm/include/llvm/Support/CommandLine.h | 4 +-
llvm/utils/git/ids-check-helper.py | 259 ++++++++++++++++++++++--
3 files changed, 293 insertions(+), 29 deletions(-)
diff --git a/.github/workflows/ids-check.yml b/.github/workflows/ids-check.yml
index f4c3c8a8453bf..d1e3ec27c0c4f 100644
--- a/.github/workflows/ids-check.yml
+++ b/.github/workflows/ids-check.yml
@@ -3,8 +3,8 @@ name: "Check LLVM ABI annotations"
# TODO(https://github.com/llvm/llvm-project/issues/109483): Re-enable on pull
# requests once the workflow is less diruptive.
on:
- # pull_request:
- workflow_dispatch:
+ pull_request:
+ # workflow_dispatch:
permissions:
contents: read
@@ -18,7 +18,7 @@ jobs:
if: github.repository_owner == 'llvm'
name: Check LLVM_ABI annotations with ids
runs-on: ubuntu-24.04
- timeout-minutes: 10
+ timeout-minutes: 30
steps:
- uses: actions/checkout at de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -46,7 +46,16 @@ jobs:
- name: Install dependencies
run: |
- sudo apt install -y clang-19 ninja-build libclang-19-dev
+ # Pull a recent clang from LLVM's apt repo so idt's parser stays in
+ # sync with the C++ language features used by current LLVM source.
+ sudo install -d -m 0755 /etc/apt/keyrings
+ wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \
+ | sudo gpg --dearmor -o /etc/apt/keyrings/llvm.gpg
+ echo "deb [signed-by=/etc/apt/keyrings/llvm.gpg] http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main" \
+ | sudo tee /etc/apt/sources.list.d/llvm.list
+ sudo apt update
+ # oprofile provides opagent.h, used by llvm/ExecutionEngine/OProfileWrapper.h
+ sudo apt install -y clang-22 lld-22 ninja-build libclang-22-dev oprofile
pip install --require-hashes -r ${{ github.workspace }}/llvm-project/llvm/utils/git/requirements.txt
- name: Configure and build minimal LLVM for use by ids
@@ -54,26 +63,50 @@ jobs:
cmake -B ${{ github.workspace }}/llvm-project/build/ \
-S ${{ github.workspace }}/llvm-project/llvm/ \
-D CMAKE_BUILD_TYPE=Release \
- -D CMAKE_C_COMPILER=clang \
- -D CMAKE_CXX_COMPILER=clang++ \
+ -D CMAKE_C_COMPILER=clang-22 \
+ -D CMAKE_CXX_COMPILER=clang++-22 \
-D LLVM_ENABLE_PROJECTS=clang \
-D LLVM_TARGETS_TO_BUILD="host" \
+ -D LLVM_INCLUDE_TESTS=OFF \
+ -D LLVM_INCLUDE_BENCHMARKS=OFF \
-D CMAKE_EXPORT_COMPILE_COMMANDS=ON \
+ -D CMAKE_DISABLE_PRECOMPILE_HEADERS=ON \
-G Ninja
- cd ${{ github.workspace }}/llvm-project/build/
- ninja -t targets all | grep "CommonTableGen: phony$" | grep -v "/" | sed 's/:.*//'
+
+ # Build the generated-header prerequisites that idt needs to parse
+ # LLVM source.
+ BUILD_DIR=${{ github.workspace }}/llvm-project/build
+ ninja -C "$BUILD_DIR" \
+ llvm_vcsrevision_h \
+ intrinsics_gen omp_gen acc_gen analysis_gen target_parser_gen vt_gen \
+ DllOptionsTableGen LibOptionsTableGen \
+ clang-tablegen-targets \
+ lib/ExecutionEngine/JITLink/COFFOptions.inc
+
+ # Build per-target tablegen output for every enabled target.
+ # Each enabled target exposes a top-level `<Target>CommonTableGen`
+ # phony rule (e.g. `X86CommonTableGen`); discover them from the
+ # ninja graph.
+ TABLEGEN_TARGETS=$(ninja -C "$BUILD_DIR" -t targets all \
+ | awk -F: '
+ $2 ~ /phony/ && # phony rules only
+ $1 !~ /\// && # top-level (skip nested paths)
+ $1 ~ /CommonTableGen$/ { # per-target tablegen aggregator
+ print $1
+ }')
+ ninja -C "$BUILD_DIR" $TABLEGEN_TARGETS
- name: Configure ids
run: |
cmake -B ${{ github.workspace }}/ids/build/ \
-S ${{ github.workspace }}/ids/ \
-D CMAKE_BUILD_TYPE=Release \
- -D CMAKE_C_COMPILER=clang \
- -D CMAKE_CXX_COMPILER=clang++ \
+ -D CMAKE_C_COMPILER=clang-22 \
+ -D CMAKE_CXX_COMPILER=clang++-22 \
-D CMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld \
- -D LLVM_DIR=/usr/lib/llvm-19/lib/cmake/llvm/ \
- -D Clang_DIR=/usr/lib/llvm-19/lib/cmake/clang/ \
- -D FILECHECK_EXECUTABLE=$(which FileCheck-19) \
+ -D LLVM_DIR=/usr/lib/llvm-22/lib/cmake/llvm/ \
+ -D Clang_DIR=/usr/lib/llvm-22/lib/cmake/clang/ \
+ -D FILECHECK_EXECUTABLE=$(which FileCheck-22) \
-D LIT_EXECUTABLE=$(which lit) \
-G Ninja
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index be754f3c159ca..911411e0a457d 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -206,8 +206,8 @@ class SubCommand {
StringRef Description;
protected:
- LLVM_ABI void registerSubCommand();
- LLVM_ABI void unregisterSubCommand();
+ void registerSubCommand();
+ void unregisterSubCommand();
public:
SubCommand(StringRef Name, StringRef Description = "")
diff --git a/llvm/utils/git/ids-check-helper.py b/llvm/utils/git/ids-check-helper.py
index 1f0b983fb2261..1e030f67b00cd 100755
--- a/llvm/utils/git/ids-check-helper.py
+++ b/llvm/utils/git/ids-check-helper.py
@@ -8,6 +8,7 @@
import os
import subprocess
import sys
+from pathlib import Path
from typing import List, Optional
"""
@@ -27,9 +28,124 @@
You can control the exact path to idt and compile_commands.json with the
following environment variables: $IDT_PATH and $COMPILE_COMMANDS_PATH.
+
+Implementation notes:
+- idt is a libclang-based tool. It can only parse files that are listed in
+ compile_commands.json (or have a discoverable compile command). LLVM does
+ not list headers as compile units, so we run idt on a *source* file that
+ includes the changed header, not on the header directly.
+- idt processes the entire translation unit, including transitively-included
+ headers. To prevent it from applying changes to headers in OTHER ABI
+ categories (e.g., adding LLVM_C_ABI to a C++ symbol in llvm/IR/), we pass
+ `-Xclang --system-header-prefix=...` so clang's `isInSystemHeader` filter
+ excludes them. After idt runs, we also revert any modifications outside
+ the current category as a safety net (handles e.g. private llvm/lib/*
+ headers, which can't be filtered by include path prefix).
"""
+# Headers we skip outright. Each entry is matched against the changed-file
+# path with `startswith`, so it can be either a directory prefix (trailing /)
+# or a specific file path.
+SKIP_HEADERS = [
+ # PDB DIA requires Windows ATL (atlbase.h), unbuildable on Linux runners.
+ "llvm/include/llvm/DebugInfo/PDB/DIA/",
+ # No in-tree non-tools/non-target source #includes these headers, so we
+ # can't run idt on a TU that pulls them in.
+ "llvm/include/llvm/ExecutionEngine/Interpreter.h", # only lli.cpp
+ "llvm/include/llvm/Support/DebugLog.h", # only lib/Target/RISCV/
+ "llvm/include/llvm/Support/TargetSelect.h", # only target-registration sources
+]
+
+
+# Manual header -> source mappings for headers that don't fit the conventional
+# `llvm/include/llvm/<Subsystem>/<Bar>.h` -> `llvm/lib/<Subsystem>/<Bar>.cpp`
+# layout. Used when neither the direct mapping nor the same-subdirectory
+# grep fallback finds a workable source.
+HEADER_SOURCE_OVERRIDES = {
+ # LLVM-C headers
+ "llvm/include/llvm-c/Analysis.h": "llvm/lib/Analysis/Analysis.cpp",
+ "llvm/include/llvm-c/BitReader.h": "llvm/lib/Bitcode/Reader/BitReader.cpp",
+ "llvm/include/llvm-c/BitWriter.h": "llvm/lib/Bitcode/Writer/BitWriter.cpp",
+ "llvm/include/llvm-c/Comdat.h": "llvm/lib/IR/Comdat.cpp",
+ "llvm/include/llvm-c/Core.h": "llvm/lib/IR/Core.cpp",
+ "llvm/include/llvm-c/DebugInfo.h": "llvm/lib/IR/DebugInfo.cpp",
+ "llvm/include/llvm-c/Disassembler.h": "llvm/lib/MC/MCDisassembler/Disassembler.cpp",
+ "llvm/include/llvm-c/ErrorHandling.h": "llvm/lib/Support/ErrorHandling.cpp",
+ "llvm/include/llvm-c/ExecutionEngine.h": "llvm/lib/ExecutionEngine/ExecutionEngineBindings.cpp",
+ "llvm/include/llvm-c/IRReader.h": "llvm/lib/IRReader/IRReader.cpp",
+ "llvm/include/llvm-c/LLJIT.h": "llvm/lib/ExecutionEngine/Orc/LLJITUtilsCBindings.cpp",
+ "llvm/include/llvm-c/LLJITUtils.h": "llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp",
+ "llvm/include/llvm-c/Linker.h": "llvm/lib/Linker/LinkModules.cpp",
+ "llvm/include/llvm-c/Object.h": "llvm/lib/Object/Object.cpp",
+ "llvm/include/llvm-c/Orc.h": "llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp",
+ "llvm/include/llvm-c/OrcEE.h": "llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp",
+ "llvm/include/llvm-c/Remarks.h": "llvm/lib/Remarks/RemarkParser.cpp",
+ "llvm/include/llvm-c/Support.h": "llvm/lib/Support/CommandLine.cpp",
+ "llvm/include/llvm-c/Target.h": "llvm/lib/Target/Target.cpp",
+ "llvm/include/llvm-c/TargetMachine.h": "llvm/lib/Target/TargetMachineC.cpp",
+ "llvm/include/llvm-c/Transforms/PassBuilder.h": "llvm/lib/Passes/PassBuilderBindings.cpp",
+ "llvm/include/llvm-c/Types.h": "llvm/lib/IR/Core.cpp",
+ "llvm/include/llvm-c/lto.h": "llvm/tools/lto/lto.cpp",
+
+ # Top-level llvm/ headers
+ "llvm/include/llvm/Pass.h": "llvm/lib/IR/Pass.cpp",
+ "llvm/include/llvm/PassAnalysisSupport.h": "llvm/lib/IR/Pass.cpp",
+ "llvm/include/llvm/PassRegistry.h": "llvm/lib/IR/PassRegistry.cpp",
+ "llvm/include/llvm/PassSupport.h": "llvm/lib/IR/Pass.cpp",
+ "llvm/include/llvm/InitializePasses.h": "llvm/lib/Analysis/Analysis.cpp",
+ "llvm/include/llvm/LinkAllIR.h": "llvm/lib/IR/Core.cpp",
+ "llvm/include/llvm/LinkAllPasses.h": "llvm/lib/IR/Pass.cpp",
+
+ # Headers under llvm/include/llvm/Target/ whose same-subdir grep fallback
+ # picks per-target sources (e.g. X86, AArch64). Redirect to lib/CodeGen/
+ # sources.
+ "llvm/include/llvm/Target/CGPassBuilderOption.h": "llvm/lib/CodeGen/TargetPassConfig.cpp",
+ "llvm/include/llvm/Target/TargetOptions.h": "llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp",
+
+ # Headers pulled in transitively by a small set of "umbrella" sources.
+ "llvm/include/llvm/ADT/ilist_node_base.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/Analysis/SimplifyQuery.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/CodeGenTypes/MachineValueType.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/IR/Analysis.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/IR/ConstantFolder.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/IR/FMF.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/IR/GenericFloatingPointPredicateUtils.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/IR/IRBuilderFolder.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm/Support/Recycler.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm-c/Error.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+ "llvm/include/llvm-c/Visibility.h": "llvm/lib/CodeGen/CodeGenPrepare.cpp",
+
+ # DTLTO drags in Any/LTO/FormatVariadic.
+ "llvm/include/llvm/ADT/Any.h": "llvm/lib/DTLTO/DTLTO.cpp",
+ "llvm/include/llvm/LTO/Config.h": "llvm/lib/DTLTO/DTLTO.cpp",
+ "llvm/include/llvm/Support/FormatVariadicDetails.h": "llvm/lib/DTLTO/DTLTO.cpp",
+
+ # Orc debugging / executor-side helpers.
+ "llvm/include/llvm/DebugInfo/DWARF/LowLevel/DWARFDataExtractorSimple.h":
+ "llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp",
+ "llvm/include/llvm/ExecutionEngine/Orc/MaterializationUnit.h":
+ "llvm/lib/ExecutionEngine/Orc/Debugging/DebugInfoSupport.cpp",
+ "llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h":
+ "llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp",
+ "llvm/include/llvm-c/blake3.h":
+ "llvm/lib/ExecutionEngine/Orc/TargetProcess/ExecutorSharedMemoryMapperService.cpp",
+
+ # AsmPrinter handler shim.
+ "llvm/include/llvm/CodeGen/AsmPrinterHandler.h":
+ "llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp",
+}
+
+
+# When the include subdir doesn't match a lib subdir, redirect lookups.
+# ADT is mostly templates and has no `llvm/lib/ADT/` — the few non-inline
+# implementations (`SmallVector.cpp`, `StringRef.cpp`, `Triple.cpp`, ...)
+# live under `llvm/lib/Support/`, so look there instead.
+INCLUDE_TO_LIB_SUBDIR = {
+ "ADT": "Support",
+}
+
+
class IdsCheckArgs:
start_rev: str = ""
end_rev: str = ""
@@ -130,31 +246,52 @@ def update_pr(
elif create_new:
self.comment = {"body": comment_text}
- # Define the file categories and their corresponding configurations
+ # File categories with their corresponding ABI configurations.
+ #
+ # `system_header_prefixes` and `no_system_header_prefixes` are passed to
+ # clang via `-Xclang --system-header-prefix=` (and the negative form) so
+ # that headers in *other* categories are treated as system headers, which
+ # idt's `isInSystemHeader` filter then excludes. This prevents
+ # cross-category contamination (e.g., adding LLVM_C_ABI to a C++ symbol when
+ # processing an LLVM-C header).
FILE_CATEGORIES = [
{
"name": "LLVM headers",
"patterns": ["llvm/include/llvm/**/*.h"],
+ "category_prefix": "llvm/include/llvm/",
"excludes": [
"llvm/include/llvm/Debuginfod/",
"llvm/include/llvm/Demangle/",
+ "llvm/include/llvm-c/",
],
"export_macro": "LLVM_ABI",
"include_header": "llvm/Support/Compiler.h",
+ "system_header_prefixes": [
+ "llvm-c/",
+ "llvm/Demangle/",
+ "llvm/Debuginfod/",
+ ],
+ "no_system_header_prefixes": [],
},
{
"name": "LLVM-C headers",
"patterns": ["llvm/include/llvm-c/**/*.h"],
+ "category_prefix": "llvm/include/llvm-c/",
"excludes": [],
"export_macro": "LLVM_C_ABI",
"include_header": "llvm-c/Visibility.h",
+ "system_header_prefixes": ["llvm/"],
+ "no_system_header_prefixes": [],
},
{
"name": "LLVM Demangle headers",
"patterns": ["llvm/include/llvm/Demangle/**/*.h"],
+ "category_prefix": "llvm/include/llvm/Demangle/",
"excludes": [],
"export_macro": "DEMANGLE_ABI",
"include_header": "llvm/Demangle/Visibility.h",
+ "system_header_prefixes": ["llvm/", "llvm-c/"],
+ "no_system_header_prefixes": ["llvm/Demangle/"],
},
]
@@ -177,17 +314,71 @@ def filter_files_for_category(
continue
# Check if file should be excluded
- excluded = False
- for exclude in category["excludes"]:
- if path.startswith(exclude):
- excluded = True
- break
+ if any(path.startswith(p) for p in category["excludes"]):
+ continue
+ if any(path.startswith(p) for p in SKIP_HEADERS):
+ continue
- if not excluded:
- filtered.append(path)
+ filtered.append(path)
return filtered
+ def find_source_for_header(
+ self, header: str, args: IdsCheckArgs
+ ) -> Optional[str]:
+ """Return a source file (relative path) that includes the given header,
+ or None if no good match. We need a source because LLVM doesn't list
+ headers in compile_commands.json — running idt on a header directly
+ produces wrong AST (no compile command, default flags).
+
+ Resolution order:
+ 1. Manual override in HEADER_SOURCE_OVERRIDES.
+ 2. Direct mapping: llvm/include/llvm/Foo/Bar.h → llvm/lib/Foo/Bar.cpp.
+ 3. Same-subdirectory grep: any .cpp under llvm/lib/Foo/ that
+ `#include`s the header. Constrained to the matching subdirectory
+ rather than all of llvm/lib so we don't accidentally pick a
+ target-specific or test-only source as a generic fallback.
+ 4. Bail (returns None; the header is silently skipped).
+ """
+ # 1. Manual override.
+ if header in HEADER_SOURCE_OVERRIDES:
+ return HEADER_SOURCE_OVERRIDES[header]
+
+ # 2. Direct mapping.
+ if header.startswith("llvm/include/llvm/"):
+ sub = header[len("llvm/include/llvm/"):]
+ first_part, _, rest = sub.partition("/")
+ remap = INCLUDE_TO_LIB_SUBDIR.get(first_part)
+ sub_remapped = f"{remap}/{rest}" if remap and rest else sub
+ for ext in (".cpp", ".cc"):
+ candidate = Path("llvm/lib") / Path(sub_remapped).with_suffix(ext)
+ if candidate.exists():
+ return str(candidate)
+
+ # 3. Same-subdirectory grep fallback.
+ if header.startswith("llvm/include/llvm/"):
+ sub = header[len("llvm/include/llvm/"):]
+ first_part = sub.split("/")[0]
+ first_part = INCLUDE_TO_LIB_SUBDIR.get(first_part, first_part)
+ lib_subdir = f"llvm/lib/{first_part}"
+ if Path(lib_subdir).is_dir():
+ inc = header.removeprefix("llvm/include/")
+ try:
+ result = subprocess.run(
+ ["git", "grep", "-l", f'#include "{inc}"',
+ "--", lib_subdir],
+ capture_output=True, text=True, timeout=15,
+ )
+ except subprocess.TimeoutExpired:
+ return None
+ if result.returncode == 0 and result.stdout:
+ for line in result.stdout.splitlines():
+ if line.endswith((".cpp", ".cc")):
+ return line
+
+ # 4. Bail.
+ return None
+
def run_idt_on_files(
self,
files: List[str],
@@ -196,7 +387,13 @@ def run_idt_on_files(
idt_path: str,
compile_commands: str,
) -> bool:
- """Run idt tool on the given files with category-specific configuration."""
+ """Run idt on the given headers and post-filter the resulting changes.
+
+ For each changed header, we look up a corresponding source file (the
+ header itself isn't in compile_commands.json), run idt on the source,
+ then revert any modifications to files outside the current category
+ (e.g., private llvm/lib/* headers, headers in other categories that
+ slipped through despite system-header-prefix)."""
if not files:
return True
@@ -206,25 +403,59 @@ def run_idt_on_files(
file=sys.stderr,
)
- for file in files:
+ category_prefix = category["category_prefix"]
+ category_excludes = category["excludes"]
+
+ for header in files:
+ source = self.find_source_for_header(header, args)
+ if source is None:
+ if args.verbose:
+ print(f" Skipping {header}: no matching source", file=sys.stderr)
+ continue
+
cmd = [
idt_path,
- "-p",
- compile_commands,
+ "-p", compile_commands,
"--apply-fixits",
"--inplace",
f"--export-macro={category['export_macro']}",
f"--include-header={category['include_header']}",
f"--extra-arg=-D{category['export_macro']}={self.MACRO_DEFINITION}",
"--extra-arg=-Wno-macro-redefined",
- file,
]
+ for prefix in category.get("system_header_prefixes", []):
+ cmd += ["--extra-arg=-Xclang",
+ f"--extra-arg=--system-header-prefix={prefix}"]
+ for prefix in category.get("no_system_header_prefixes", []):
+ cmd += ["--extra-arg=-Xclang",
+ f"--extra-arg=--no-system-header-prefix={prefix}"]
+ cmd.append(source)
+
if args.verbose:
- print(f"Running: {' '.join(cmd)}", file=sys.stderr)
+ print(f"Running on source {source} for header {header}",
+ file=sys.stderr)
subprocess.run(cmd)
+ # Post-filter: revert any modifications to files outside this
+ # category. idt may have touched private llvm/lib/* implementation
+ # headers (which it shouldn't — they aren't part of the public ABI)
+ # or other-category headers via paths that escaped the prefix
+ # filter. Drop those.
+ modified = subprocess.run(
+ ["git", "diff", "--name-only"],
+ capture_output=True, text=True,
+ ).stdout.splitlines()
+ revert = [
+ f for f in modified
+ if not f.startswith(category_prefix)
+ or any(f.startswith(ex) for ex in category_excludes)
+ ]
+ if revert:
+ subprocess.run(["git", "checkout", "--"] + revert,
+ capture_output=True)
+
return True
def get_changed_files(self, args: IdsCheckArgs) -> List[str]:
More information about the llvm-commits
mailing list