[clang] [Tooling] Fix misleading progress report when files have multiple compile commands (PR #169640)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 9 12:57:24 PST 2025
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/169640
>From 0bcc0a061e4c03f85a2f7481591e97779785f731 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Mon, 24 Nov 2025 10:14:58 +0800
Subject: [PATCH 1/7] [Tooling] Fix misleading progress report when files have
multiple compile commands
---
clang/lib/Tooling/Tooling.cpp | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 9bae12454d2dc..491294b731e85 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -37,6 +37,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -96,7 +97,7 @@ static bool ignoreExtraCC1Commands(const driver::Compilation *Compilation) {
OffloadCompilation = true;
if (Jobs.size() > 1) {
- for (auto *A : Actions){
+ for (auto *A : Actions) {
// On MacOSX real actions may end up being wrapped in BindArchAction
if (isa<driver::BindArchAction>(A))
A = *A->input_begin();
@@ -413,8 +414,8 @@ bool ToolInvocation::run() {
Driver->BuildCompilation(llvm::ArrayRef(Argv)));
if (!Compilation)
return false;
- const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
- &*Diagnostics, Compilation.get());
+ const llvm::opt::ArgStringList *const CC1Args =
+ getCC1Arguments(&*Diagnostics, Compilation.get());
if (!CC1Args)
return false;
std::unique_ptr<CompilerInvocation> Invocation(
@@ -497,9 +498,7 @@ void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster));
}
-void ClangTool::clearArgumentsAdjusters() {
- ArgsAdjuster = nullptr;
-}
+void ClangTool::clearArgumentsAdjusters() { ArgsAdjuster = nullptr; }
static void injectResourceDir(CommandLineArguments &Args, const char *Argv0,
void *MainAddr) {
@@ -555,8 +554,9 @@ int ClangTool::run(ToolAction *Action) {
}
size_t NumOfTotalFiles = AbsolutePaths.size();
- unsigned ProcessedFileCounter = 0;
+ unsigned CurrentFileIndex = 0;
for (llvm::StringRef File : AbsolutePaths) {
+ ++CurrentFileIndex; // Increment file counter once per file.
// Currently implementations of CompilationDatabase::getCompileCommands can
// change the state of the file system (e.g. prepare generated headers), so
// this method needs to run right before we invoke the tool, as the next
@@ -571,6 +571,7 @@ int ClangTool::run(ToolAction *Action) {
FileSkipped = true;
continue;
}
+ unsigned CurrentCommandIndexForFile = 0;
for (CompileCommand &CompileCommand : CompileCommandsForFile) {
// If the 'directory' field of the compilation database is empty, display
// an error and use the working directory instead.
@@ -617,12 +618,16 @@ int ClangTool::run(ToolAction *Action) {
// pass in made-up names here. Make sure this works on other platforms.
injectResourceDir(CommandLine, "clang_tool", &StaticSymbol);
+ ++CurrentCommandIndexForFile;
+
// FIXME: We need a callback mechanism for the tool writer to output a
// customized message for each file.
- if (NumOfTotalFiles > 1)
- llvm::errs() << "[" + std::to_string(++ProcessedFileCounter) + "/" +
- std::to_string(NumOfTotalFiles) +
- "] Processing file " + File
+ if (NumOfTotalFiles > 1 || CompileCommandsForFile.size() > 1)
+ llvm::errs() << "[" + std::to_string(CurrentFileIndex) + "/" +
+ std::to_string(NumOfTotalFiles) + "] (" +
+ std::to_string(CurrentCommandIndexForFile) + "/" +
+ std::to_string(CompileCommandsForFile.size()) +
+ ") Processing file " + File
<< ".\n";
ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
PCHContainerOps);
>From 3df57dec9880788efb6dbd50892fdf5f8a0d3b79 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Thu, 27 Nov 2025 18:14:10 +0800
Subject: [PATCH 2/7] Fix printing format
---
clang/lib/Tooling/Tooling.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 491294b731e85..2914da9a21888 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -556,7 +556,7 @@ int ClangTool::run(ToolAction *Action) {
size_t NumOfTotalFiles = AbsolutePaths.size();
unsigned CurrentFileIndex = 0;
for (llvm::StringRef File : AbsolutePaths) {
- ++CurrentFileIndex; // Increment file counter once per file.
+ ++CurrentFileIndex;
// Currently implementations of CompilationDatabase::getCompileCommands can
// change the state of the file system (e.g. prepare generated headers), so
// this method needs to run right before we invoke the tool, as the next
@@ -622,13 +622,17 @@ int ClangTool::run(ToolAction *Action) {
// FIXME: We need a callback mechanism for the tool writer to output a
// customized message for each file.
- if (NumOfTotalFiles > 1 || CompileCommandsForFile.size() > 1)
+ if (NumOfTotalFiles > 1 || CompileCommandsForFile.size() > 1) {
llvm::errs() << "[" + std::to_string(CurrentFileIndex) + "/" +
- std::to_string(NumOfTotalFiles) + "] (" +
- std::to_string(CurrentCommandIndexForFile) + "/" +
- std::to_string(CompileCommandsForFile.size()) +
- ") Processing file " + File
- << ".\n";
+ std::to_string(NumOfTotalFiles) + "]";
+ if (CompileCommandsForFile.size() > 1) {
+ llvm::errs() << " (" + std::to_string(CurrentCommandIndexForFile) +
+ "/" +
+ std::to_string(CompileCommandsForFile.size()) +
+ ")";
+ }
+ llvm::errs() << " Processing file " + File << ".\n";
+ }
ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(),
PCHContainerOps);
Invocation.setDiagnosticConsumer(DiagConsumer);
>From 9ee5bf8a9fa8d7227a65d3be9da602958c9cd0e7 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Fri, 28 Nov 2025 15:55:14 +0800
Subject: [PATCH 3/7] Remove header
---
clang/lib/Tooling/Tooling.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 2914da9a21888..1e5c71da960e8 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -37,7 +37,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
>From 32238aaf19a6e7bd9045b6e098c227ecbce478a1 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Sun, 7 Dec 2025 19:21:27 +0800
Subject: [PATCH 4/7] Add testcases
---
clang/unittests/Tooling/ToolingTest.cpp | 188 ++++++++++++++++++++++++
1 file changed, 188 insertions(+)
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index 25e1d67eb2294..4fe4598c89a81 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -20,6 +20,7 @@
#include "clang/Testing/CommandLineArgs.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/JSONCompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Path.h"
@@ -1034,5 +1035,192 @@ TEST(runToolOnCode, TestResetDiagnostics) {
"void func() { long x; Foo f(x); }"));
}
+TEST(ClangToolTest, ProgressReportSingleFile) {
+ SmallString<32> BaseDir;
+ llvm::sys::path::system_temp_directory(false, BaseDir);
+ llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
+ std::string BaseDirStr(BaseDir);
+
+ std::string File = BaseDirStr + "/test.cpp";
+
+ std::string ErrorMessage;
+ std::string JSONDatabase = R"json([
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test.cpp",
+ "file": "test.cpp"
+ }])json";
+
+ {
+ size_t Pos = JSONDatabase.find("%DIR%");
+ ASSERT_NE(Pos, std::string::npos);
+ JSONDatabase.replace(Pos, 5, BaseDirStr);
+ }
+
+ std::unique_ptr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu));
+ ASSERT_TRUE(Database);
+
+ ClangTool Tool(*Database, {File});
+ Tool.mapVirtualFile(File, "int x;");
+
+ testing::internal::CaptureStderr();
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
+ std::string Output = testing::internal::GetCapturedStderr();
+
+ EXPECT_TRUE(Output.empty());
+}
+
+TEST(ClangToolTest, ProgressReportMultipleFiles) {
+ SmallString<32> BaseDir;
+ llvm::sys::path::system_temp_directory(false, BaseDir);
+ llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
+ std::string BaseDirStr(BaseDir);
+
+ std::string File1 = BaseDirStr + "/test1.cpp";
+ std::string File2 = BaseDirStr + "/test2.cpp";
+
+ std::string ErrorMessage;
+ std::string JSONDatabase = R"json([
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test1.cpp",
+ "file": "test1.cpp"
+ },
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test2.cpp",
+ "file": "test2.cpp"
+ }])json";
+
+ for (size_t Pos = 0;
+ (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
+ JSONDatabase.replace(Pos, 5, BaseDirStr);
+ Pos += BaseDirStr.size();
+ }
+
+ std::unique_ptr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu));
+ ASSERT_TRUE(Database);
+
+ ClangTool Tool(*Database, {File1, File2});
+ Tool.mapVirtualFile(File1, "int x;");
+ Tool.mapVirtualFile(File2, "int y;");
+
+ testing::internal::CaptureStderr();
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
+ std::string Output = testing::internal::GetCapturedStderr();
+
+ std::string Expected = "[1/2] Processing file " + File1 + ".\n" +
+ "[2/2] Processing file " + File2 + ".\n";
+ EXPECT_EQ(Output, Expected);
+}
+
+TEST(ClangToolTest, ProgressReportMultipleCommands) {
+ SmallString<32> BaseDir;
+ llvm::sys::path::system_temp_directory(false, BaseDir);
+ llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
+ std::string BaseDirStr(BaseDir);
+
+ std::string File = BaseDirStr + "/test.cpp";
+
+ std::string ErrorMessage;
+ std::string JSONDatabase = R"json([
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test.cpp -DCMD1",
+ "file": "test.cpp"
+ },
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test.cpp -DCMD2",
+ "file": "test.cpp"
+ }])json";
+
+ for (size_t Pos = 0;
+ (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
+ JSONDatabase.replace(Pos, 5, BaseDirStr);
+ Pos += BaseDirStr.size();
+ }
+
+ std::unique_ptr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu));
+ ASSERT_TRUE(Database);
+
+ ClangTool Tool(*Database, {File});
+ Tool.mapVirtualFile(File, "int x;");
+
+ testing::internal::CaptureStderr();
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
+ std::string Output = testing::internal::GetCapturedStderr();
+
+ std::string Expected = "[1/1] (1/2) Processing file " + File + ".\n" +
+ "[1/1] (2/2) Processing file " + File + ".\n";
+ EXPECT_EQ(Output, Expected);
+}
+
+TEST(ClangToolTest, ProgressReportMixed) {
+ SmallString<32> BaseDir;
+ llvm::sys::path::system_temp_directory(false, BaseDir);
+ llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
+ std::string BaseDirStr(BaseDir);
+
+ std::string File1 = BaseDirStr + "/test1.cpp";
+ std::string File2 = BaseDirStr + "/test2.cpp";
+ std::string File3 = BaseDirStr + "/test3.cpp";
+
+ std::string ErrorMessage;
+ std::string JSONDatabase = R"json([
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test1.cpp",
+ "file": "test1.cpp"
+ },
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test2.cpp -DCMD1",
+ "file": "test2.cpp"
+ },
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test2.cpp -DCMD2",
+ "file": "test2.cpp"
+ },
+ {
+ "directory": "%DIR%",
+ "command": "clang++ -c test3.cpp",
+ "file": "test3.cpp"
+ }])json";
+
+ for (size_t Pos = 0;
+ (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
+ JSONDatabase.replace(Pos, 5, BaseDirStr);
+ Pos += BaseDirStr.size();
+ }
+
+ std::unique_ptr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCommandLineSyntax::Gnu));
+ ASSERT_TRUE(Database);
+
+ ClangTool Tool(*Database, {File1, File2, File3});
+ Tool.mapVirtualFile(File1, "int x;");
+ Tool.mapVirtualFile(File2, "int y;");
+ Tool.mapVirtualFile(File3, "int z;");
+
+ testing::internal::CaptureStderr();
+ Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
+ std::string Output = testing::internal::GetCapturedStderr();
+
+ std::string Expected = "[1/3] Processing file " + File1 + ".\n" +
+ "[2/3] (1/2) Processing file " + File2 + ".\n" +
+ "[2/3] (2/2) Processing file " + File2 + ".\n" +
+ "[3/3] Processing file " + File3 + ".\n";
+ EXPECT_EQ(Output, Expected);
+}
+
} // end namespace tooling
} // end namespace clang
>From 5c469cd476e56ceaefbed581737dec6b51fc119d Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Sun, 7 Dec 2025 22:01:28 +0800
Subject: [PATCH 5/7] Fix test on Windows
---
clang/unittests/Tooling/ToolingTest.cpp | 31 ++++++++++++++++++-------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index 4fe4598c89a81..bb33f98a1ff23 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -1113,8 +1113,13 @@ TEST(ClangToolTest, ProgressReportMultipleFiles) {
Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
std::string Output = testing::internal::GetCapturedStderr();
- std::string Expected = "[1/2] Processing file " + File1 + ".\n" +
- "[2/2] Processing file " + File2 + ".\n";
+ SmallString<32> NativeFile1(File1);
+ llvm::sys::path::native(NativeFile1);
+ SmallString<32> NativeFile2(File2);
+ llvm::sys::path::native(NativeFile2);
+ std::string Expected = "[1/2] Processing file " + std::string(NativeFile1) +
+ ".\n" + "[2/2] Processing file " +
+ std::string(NativeFile2) + ".\n";
EXPECT_EQ(Output, Expected);
}
@@ -1157,8 +1162,11 @@ TEST(ClangToolTest, ProgressReportMultipleCommands) {
Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
std::string Output = testing::internal::GetCapturedStderr();
- std::string Expected = "[1/1] (1/2) Processing file " + File + ".\n" +
- "[1/1] (2/2) Processing file " + File + ".\n";
+ SmallString<32> NativeFile(File);
+ llvm::sys::path::native(NativeFile);
+ std::string Expected =
+ "[1/1] (1/2) Processing file " + std::string(NativeFile) + ".\n" +
+ "[1/1] (2/2) Processing file " + std::string(NativeFile) + ".\n";
EXPECT_EQ(Output, Expected);
}
@@ -1215,10 +1223,17 @@ TEST(ClangToolTest, ProgressReportMixed) {
Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
std::string Output = testing::internal::GetCapturedStderr();
- std::string Expected = "[1/3] Processing file " + File1 + ".\n" +
- "[2/3] (1/2) Processing file " + File2 + ".\n" +
- "[2/3] (2/2) Processing file " + File2 + ".\n" +
- "[3/3] Processing file " + File3 + ".\n";
+ SmallString<32> NativeFile1(File1);
+ llvm::sys::path::native(NativeFile1);
+ SmallString<32> NativeFile2(File2);
+ llvm::sys::path::native(NativeFile2);
+ SmallString<32> NativeFile3(File3);
+ llvm::sys::path::native(NativeFile3);
+ std::string Expected =
+ "[1/3] Processing file " + std::string(NativeFile1) + ".\n" +
+ "[2/3] (1/2) Processing file " + std::string(NativeFile2) + ".\n" +
+ "[2/3] (2/2) Processing file " + std::string(NativeFile2) + ".\n" +
+ "[3/3] Processing file " + std::string(NativeFile3) + ".\n";
EXPECT_EQ(Output, Expected);
}
>From bcc74bbf7b1f2ccef345e4c2eaec1fc485a1836d Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Wed, 10 Dec 2025 04:39:30 +0800
Subject: [PATCH 6/7] cleanup
---
clang/unittests/Tooling/ToolingTest.cpp | 285 +++++++++---------------
1 file changed, 110 insertions(+), 175 deletions(-)
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index bb33f98a1ff23..64e85e57f4671 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -23,6 +23,7 @@
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Host.h"
@@ -56,15 +57,16 @@ class TestAction : public clang::ASTFrontendAction {
};
class FindTopLevelDeclConsumer : public clang::ASTConsumer {
- public:
+public:
explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
: FoundTopLevelDecl(FoundTopLevelDecl) {}
bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
*FoundTopLevelDecl = true;
return true;
}
- private:
- bool * const FoundTopLevelDecl;
+
+private:
+ bool *const FoundTopLevelDecl;
};
} // end namespace
@@ -79,26 +81,27 @@ TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
namespace {
class FindClassDeclXConsumer : public clang::ASTConsumer {
- public:
+public:
FindClassDeclXConsumer(bool *FoundClassDeclX)
: FoundClassDeclX(FoundClassDeclX) {}
bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
- if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
- *GroupRef.begin())) {
+ if (CXXRecordDecl *Record =
+ dyn_cast<clang::CXXRecordDecl>(*GroupRef.begin())) {
if (Record->getName() == "X") {
*FoundClassDeclX = true;
}
}
return true;
}
- private:
+
+private:
bool *FoundClassDeclX;
};
bool FindClassDeclX(ASTUnit *AST) {
for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
e = AST->top_level_end();
i != e; ++i) {
- if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
+ if (CXXRecordDecl *Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
if (Record->getName() == "X") {
return true;
}
@@ -563,12 +566,14 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
std::make_unique<SkipBodyAction>(),
"struct skipMe { skipMe() : an_error() { more error } };", Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
- "skipMe::skipMe() : an_error([](){;}) { more error }",
+ std::make_unique<SkipBodyAction>(),
+ "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error([](){;}) { more error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
- "skipMe::skipMe() : an_error{[](){;}} { more error }",
+ std::make_unique<SkipBodyAction>(),
+ "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error{[](){;}} { more error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
@@ -576,12 +581,12 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
"skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe() : bases()... { error } };",
- Args));
+ std::make_unique<SkipBodyAction>(),
+ "struct skipMe { skipMe() : bases()... { error } };", Args));
EXPECT_FALSE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(), "struct skipMeNot { skipMeNot() : an_error() { } };",
- Args));
+ std::make_unique<SkipBodyAction>(),
+ "struct skipMeNot { skipMeNot() : an_error() { } };", Args));
EXPECT_FALSE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(),
"struct skipMeNot { skipMeNot(); };"
"skipMeNot::skipMeNot() : an_error() { }",
@@ -603,9 +608,10 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
"void skipMe() try something;")); // don't crash while parsing
// Template
- EXPECT_TRUE(runToolOnCode(
- std::make_unique<SkipBodyAction>(), "template<typename T> int skipMe() { an_error_here }"
- "int x = skipMe<int>();"));
+ EXPECT_TRUE(
+ runToolOnCode(std::make_unique<SkipBodyAction>(),
+ "template<typename T> int skipMe() { an_error_here }"
+ "int x = skipMe<int>();"));
EXPECT_FALSE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
"template<typename T> int skipMeNot() { an_error_here }", Args2));
@@ -626,7 +632,8 @@ TEST(runToolOnCodeWithArgs, TestNoDepFile) {
Args.push_back(std::string(DepFilePath.str()));
Args.push_back("-MF");
Args.push_back(std::string(DepFilePath.str()));
- EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args));
+ EXPECT_TRUE(
+ runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args));
EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
}
@@ -684,11 +691,11 @@ TEST(ClangToolTest, ArgumentAdjusters) {
bool Ran = false;
ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
[&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) {
- Ran = true;
- if (llvm::is_contained(Args, "-fsyntax-only"))
- Found = true;
- return Args;
- };
+ Ran = true;
+ if (llvm::is_contained(Args, "-fsyntax-only"))
+ Found = true;
+ return Args;
+ };
Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
Tool.run(Action.get());
EXPECT_TRUE(Ran);
@@ -792,10 +799,10 @@ TEST(ClangToolTest, StripDependencyFileAdjuster) {
CommandLineArguments FinalArgs;
ArgumentsAdjuster CheckFlagsAdjuster =
- [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
- FinalArgs = Args;
- return Args;
- };
+ [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
+ FinalArgs = Args;
+ return Args;
+ };
Tool.clearArgumentsAdjusters();
Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
@@ -1035,88 +1042,82 @@ TEST(runToolOnCode, TestResetDiagnostics) {
"void func() { long x; Foo f(x); }"));
}
-TEST(ClangToolTest, ProgressReportSingleFile) {
- SmallString<32> BaseDir;
- llvm::sys::path::system_temp_directory(false, BaseDir);
- llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
- std::string BaseDirStr(BaseDir);
-
- std::string File = BaseDirStr + "/test.cpp";
+namespace {
+struct TestCommand {
+ llvm::StringRef File;
+ llvm::StringRef Command;
+};
+std::string runToolWithProgress(llvm::ArrayRef<TestCommand> Commands,
+ llvm::StringRef BaseDir) {
std::string ErrorMessage;
- std::string JSONDatabase = R"json([
- {
- "directory": "%DIR%",
- "command": "clang++ -c test.cpp",
- "file": "test.cpp"
- }])json";
-
- {
- size_t Pos = JSONDatabase.find("%DIR%");
- ASSERT_NE(Pos, std::string::npos);
- JSONDatabase.replace(Pos, 5, BaseDirStr);
+
+ llvm::json::Array Entries;
+ for (const auto &Cmd : Commands) {
+ Entries.push_back(llvm::json::Object{
+ {"directory", BaseDir}, {"command", Cmd.Command}, {"file", Cmd.File}});
}
+ std::string DatabaseContent;
+ llvm::raw_string_ostream OS(DatabaseContent);
+ OS << llvm::json::Value(std::move(Entries));
std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
+ JSONCompilationDatabase::loadFromBuffer(DatabaseContent, ErrorMessage,
JSONCommandLineSyntax::Gnu));
- ASSERT_TRUE(Database);
+ if (!Database) {
+ ADD_FAILURE() << "Failed to load compilation database: " << ErrorMessage;
+ return "";
+ }
- ClangTool Tool(*Database, {File});
- Tool.mapVirtualFile(File, "int x;");
+ std::vector<std::string> AbsoluteFiles;
+ for (const auto &Cmd : Commands) {
+ SmallString<32> NativeFile(BaseDir);
+ llvm::sys::path::append(NativeFile, Cmd.File);
+ llvm::sys::path::native(NativeFile);
+ std::string AbsPath = std::string(NativeFile);
+ if (AbsoluteFiles.empty() || AbsoluteFiles.back() != AbsPath) {
+ AbsoluteFiles.push_back(AbsPath);
+ }
+ }
+
+ ClangTool Tool(*Database, AbsoluteFiles);
+ for (const auto &F : AbsoluteFiles) {
+ Tool.mapVirtualFile(F, "int x;");
+ }
testing::internal::CaptureStderr();
Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
- std::string Output = testing::internal::GetCapturedStderr();
-
- EXPECT_TRUE(Output.empty());
+ return testing::internal::GetCapturedStderr();
}
+} // namespace
-TEST(ClangToolTest, ProgressReportMultipleFiles) {
+TEST(ClangToolTest, ProgressReportSingleFile) {
SmallString<32> BaseDir;
llvm::sys::path::system_temp_directory(false, BaseDir);
llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
- std::string BaseDirStr(BaseDir);
-
- std::string File1 = BaseDirStr + "/test1.cpp";
- std::string File2 = BaseDirStr + "/test2.cpp";
-
- std::string ErrorMessage;
- std::string JSONDatabase = R"json([
- {
- "directory": "%DIR%",
- "command": "clang++ -c test1.cpp",
- "file": "test1.cpp"
- },
- {
- "directory": "%DIR%",
- "command": "clang++ -c test2.cpp",
- "file": "test2.cpp"
- }])json";
-
- for (size_t Pos = 0;
- (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
- JSONDatabase.replace(Pos, 5, BaseDirStr);
- Pos += BaseDirStr.size();
- }
- std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
- JSONCommandLineSyntax::Gnu));
- ASSERT_TRUE(Database);
+ EXPECT_TRUE(
+ runToolWithProgress({{"test.cpp", "clang++ -c test.cpp"}}, BaseDir)
+ .empty());
+}
- ClangTool Tool(*Database, {File1, File2});
- Tool.mapVirtualFile(File1, "int x;");
- Tool.mapVirtualFile(File2, "int y;");
+TEST(ClangToolTest, ProgressReportMultipleFiles) {
+ SmallString<32> BaseDir;
+ llvm::sys::path::system_temp_directory(false, BaseDir);
+ llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
- testing::internal::CaptureStderr();
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
- std::string Output = testing::internal::GetCapturedStderr();
+ std::string Output =
+ runToolWithProgress({{"test1.cpp", "clang++ -c test1.cpp"},
+ {"test2.cpp", "clang++ -c test2.cpp"}},
+ BaseDir);
- SmallString<32> NativeFile1(File1);
+ SmallString<32> NativeFile1(BaseDir);
+ llvm::sys::path::append(NativeFile1, "test1.cpp");
llvm::sys::path::native(NativeFile1);
- SmallString<32> NativeFile2(File2);
+ SmallString<32> NativeFile2(BaseDir);
+ llvm::sys::path::append(NativeFile2, "test2.cpp");
llvm::sys::path::native(NativeFile2);
+
std::string Expected = "[1/2] Processing file " + std::string(NativeFile1) +
".\n" + "[2/2] Processing file " +
std::string(NativeFile2) + ".\n";
@@ -1127,42 +1128,14 @@ TEST(ClangToolTest, ProgressReportMultipleCommands) {
SmallString<32> BaseDir;
llvm::sys::path::system_temp_directory(false, BaseDir);
llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
- std::string BaseDirStr(BaseDir);
-
- std::string File = BaseDirStr + "/test.cpp";
-
- std::string ErrorMessage;
- std::string JSONDatabase = R"json([
- {
- "directory": "%DIR%",
- "command": "clang++ -c test.cpp -DCMD1",
- "file": "test.cpp"
- },
- {
- "directory": "%DIR%",
- "command": "clang++ -c test.cpp -DCMD2",
- "file": "test.cpp"
- }])json";
-
- for (size_t Pos = 0;
- (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
- JSONDatabase.replace(Pos, 5, BaseDirStr);
- Pos += BaseDirStr.size();
- }
-
- std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
- JSONCommandLineSyntax::Gnu));
- ASSERT_TRUE(Database);
- ClangTool Tool(*Database, {File});
- Tool.mapVirtualFile(File, "int x;");
+ std::string Output =
+ runToolWithProgress({{"test.cpp", "clang++ -c test.cpp -DCMD1"},
+ {"test.cpp", "clang++ -c test.cpp -DCMD2"}},
+ BaseDir);
- testing::internal::CaptureStderr();
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
- std::string Output = testing::internal::GetCapturedStderr();
-
- SmallString<32> NativeFile(File);
+ SmallString<32> NativeFile(BaseDir);
+ llvm::sys::path::append(NativeFile, "test.cpp");
llvm::sys::path::native(NativeFile);
std::string Expected =
"[1/1] (1/2) Processing file " + std::string(NativeFile) + ".\n" +
@@ -1174,61 +1147,24 @@ TEST(ClangToolTest, ProgressReportMixed) {
SmallString<32> BaseDir;
llvm::sys::path::system_temp_directory(false, BaseDir);
llvm::sys::path::native(BaseDir, llvm::sys::path::Style::posix);
- std::string BaseDirStr(BaseDir);
-
- std::string File1 = BaseDirStr + "/test1.cpp";
- std::string File2 = BaseDirStr + "/test2.cpp";
- std::string File3 = BaseDirStr + "/test3.cpp";
-
- std::string ErrorMessage;
- std::string JSONDatabase = R"json([
- {
- "directory": "%DIR%",
- "command": "clang++ -c test1.cpp",
- "file": "test1.cpp"
- },
- {
- "directory": "%DIR%",
- "command": "clang++ -c test2.cpp -DCMD1",
- "file": "test2.cpp"
- },
- {
- "directory": "%DIR%",
- "command": "clang++ -c test2.cpp -DCMD2",
- "file": "test2.cpp"
- },
- {
- "directory": "%DIR%",
- "command": "clang++ -c test3.cpp",
- "file": "test3.cpp"
- }])json";
-
- for (size_t Pos = 0;
- (Pos = JSONDatabase.find("%DIR%", Pos)) != std::string::npos;) {
- JSONDatabase.replace(Pos, 5, BaseDirStr);
- Pos += BaseDirStr.size();
- }
-
- std::unique_ptr<CompilationDatabase> Database(
- JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage,
- JSONCommandLineSyntax::Gnu));
- ASSERT_TRUE(Database);
- ClangTool Tool(*Database, {File1, File2, File3});
- Tool.mapVirtualFile(File1, "int x;");
- Tool.mapVirtualFile(File2, "int y;");
- Tool.mapVirtualFile(File3, "int z;");
+ std::string Output =
+ runToolWithProgress({{"test1.cpp", "clang++ -c test1.cpp"},
+ {"test2.cpp", "clang++ -c test2.cpp -DCMD1"},
+ {"test2.cpp", "clang++ -c test2.cpp -DCMD2"},
+ {"test3.cpp", "clang++ -c test3.cpp"}},
+ BaseDir);
- testing::internal::CaptureStderr();
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>().get());
- std::string Output = testing::internal::GetCapturedStderr();
-
- SmallString<32> NativeFile1(File1);
+ SmallString<32> NativeFile1(BaseDir);
+ llvm::sys::path::append(NativeFile1, "test1.cpp");
llvm::sys::path::native(NativeFile1);
- SmallString<32> NativeFile2(File2);
+ SmallString<32> NativeFile2(BaseDir);
+ llvm::sys::path::append(NativeFile2, "test2.cpp");
llvm::sys::path::native(NativeFile2);
- SmallString<32> NativeFile3(File3);
+ SmallString<32> NativeFile3(BaseDir);
+ llvm::sys::path::append(NativeFile3, "test3.cpp");
llvm::sys::path::native(NativeFile3);
+
std::string Expected =
"[1/3] Processing file " + std::string(NativeFile1) + ".\n" +
"[2/3] (1/2) Processing file " + std::string(NativeFile2) + ".\n" +
@@ -1236,6 +1172,5 @@ TEST(ClangToolTest, ProgressReportMixed) {
"[3/3] Processing file " + std::string(NativeFile3) + ".\n";
EXPECT_EQ(Output, Expected);
}
-
} // end namespace tooling
} // end namespace clang
>From 2e0cda0a0f8e3cc590cccf60238740ffe8669ed9 Mon Sep 17 00:00:00 2001
From: mtx <mitchell.xu2 at gmail.com>
Date: Wed, 10 Dec 2025 04:45:39 +0800
Subject: [PATCH 7/7] reduce noise
---
clang/unittests/Tooling/ToolingTest.cpp | 65 ++++++++++++-------------
1 file changed, 30 insertions(+), 35 deletions(-)
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index 64e85e57f4671..9a7559405c43c 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -57,16 +57,15 @@ class TestAction : public clang::ASTFrontendAction {
};
class FindTopLevelDeclConsumer : public clang::ASTConsumer {
-public:
+ public:
explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
: FoundTopLevelDecl(FoundTopLevelDecl) {}
bool HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) override {
*FoundTopLevelDecl = true;
return true;
}
-
-private:
- bool *const FoundTopLevelDecl;
+ private:
+ bool * const FoundTopLevelDecl;
};
} // end namespace
@@ -81,27 +80,26 @@ TEST(runToolOnCode, FindsNoTopLevelDeclOnEmptyCode) {
namespace {
class FindClassDeclXConsumer : public clang::ASTConsumer {
-public:
+ public:
FindClassDeclXConsumer(bool *FoundClassDeclX)
: FoundClassDeclX(FoundClassDeclX) {}
bool HandleTopLevelDecl(clang::DeclGroupRef GroupRef) override {
- if (CXXRecordDecl *Record =
- dyn_cast<clang::CXXRecordDecl>(*GroupRef.begin())) {
+ if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(
+ *GroupRef.begin())) {
if (Record->getName() == "X") {
*FoundClassDeclX = true;
}
}
return true;
}
-
-private:
+ private:
bool *FoundClassDeclX;
};
bool FindClassDeclX(ASTUnit *AST) {
for (std::vector<Decl *>::iterator i = AST->top_level_begin(),
e = AST->top_level_end();
i != e; ++i) {
- if (CXXRecordDecl *Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
+ if (CXXRecordDecl* Record = dyn_cast<clang::CXXRecordDecl>(*i)) {
if (Record->getName() == "X") {
return true;
}
@@ -566,14 +564,12 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
std::make_unique<SkipBodyAction>(),
"struct skipMe { skipMe() : an_error() { more error } };", Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(),
- "struct skipMe { skipMe(); };"
- "skipMe::skipMe() : an_error([](){;}) { more error }",
+ std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error([](){;}) { more error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(),
- "struct skipMe { skipMe(); };"
- "skipMe::skipMe() : an_error{[](){;}} { more error }",
+ std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe(); };"
+ "skipMe::skipMe() : an_error{[](){;}} { more error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
@@ -581,12 +577,12 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
"skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }",
Args));
EXPECT_TRUE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(),
- "struct skipMe { skipMe() : bases()... { error } };", Args));
+ std::make_unique<SkipBodyAction>(), "struct skipMe { skipMe() : bases()... { error } };",
+ Args));
EXPECT_FALSE(runToolOnCodeWithArgs(
- std::make_unique<SkipBodyAction>(),
- "struct skipMeNot { skipMeNot() : an_error() { } };", Args));
+ std::make_unique<SkipBodyAction>(), "struct skipMeNot { skipMeNot() : an_error() { } };",
+ Args));
EXPECT_FALSE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(),
"struct skipMeNot { skipMeNot(); };"
"skipMeNot::skipMeNot() : an_error() { }",
@@ -608,10 +604,9 @@ TEST(runToolOnCode, TestSkipFunctionBody) {
"void skipMe() try something;")); // don't crash while parsing
// Template
- EXPECT_TRUE(
- runToolOnCode(std::make_unique<SkipBodyAction>(),
- "template<typename T> int skipMe() { an_error_here }"
- "int x = skipMe<int>();"));
+ EXPECT_TRUE(runToolOnCode(
+ std::make_unique<SkipBodyAction>(), "template<typename T> int skipMe() { an_error_here }"
+ "int x = skipMe<int>();"));
EXPECT_FALSE(runToolOnCodeWithArgs(
std::make_unique<SkipBodyAction>(),
"template<typename T> int skipMeNot() { an_error_here }", Args2));
@@ -632,8 +627,7 @@ TEST(runToolOnCodeWithArgs, TestNoDepFile) {
Args.push_back(std::string(DepFilePath.str()));
Args.push_back("-MF");
Args.push_back(std::string(DepFilePath.str()));
- EXPECT_TRUE(
- runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args));
+ EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<SkipBodyAction>(), "", Args));
EXPECT_FALSE(llvm::sys::fs::exists(DepFilePath.str()));
EXPECT_FALSE(llvm::sys::fs::remove(DepFilePath.str()));
}
@@ -691,11 +685,11 @@ TEST(ClangToolTest, ArgumentAdjusters) {
bool Ran = false;
ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
[&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) {
- Ran = true;
- if (llvm::is_contained(Args, "-fsyntax-only"))
- Found = true;
- return Args;
- };
+ Ran = true;
+ if (llvm::is_contained(Args, "-fsyntax-only"))
+ Found = true;
+ return Args;
+ };
Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
Tool.run(Action.get());
EXPECT_TRUE(Ran);
@@ -799,10 +793,10 @@ TEST(ClangToolTest, StripDependencyFileAdjuster) {
CommandLineArguments FinalArgs;
ArgumentsAdjuster CheckFlagsAdjuster =
- [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
- FinalArgs = Args;
- return Args;
- };
+ [&FinalArgs](const CommandLineArguments &Args, StringRef /*unused*/) {
+ FinalArgs = Args;
+ return Args;
+ };
Tool.clearArgumentsAdjusters();
Tool.appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
Tool.appendArgumentsAdjuster(CheckFlagsAdjuster);
@@ -1172,5 +1166,6 @@ TEST(ClangToolTest, ProgressReportMixed) {
"[3/3] Processing file " + std::string(NativeFile3) + ".\n";
EXPECT_EQ(Output, Expected);
}
+
} // end namespace tooling
} // end namespace clang
More information about the cfe-commits
mailing list