https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/90603
>From 9b1fe59633b5404281b5b9fd754b8a81fae411d0 Mon Sep 17 00:00:00 2001 From: Chris Warner <cwar...@esri.com> Date: Tue, 23 Apr 2024 10:48:44 -0700 Subject: [PATCH 1/5] Load queries and matchers from file during REPL cycle The clang-query tool has the ability to execute or pre-load queries from a file when the tool is started, but doesn't have the ability to do the same from the interactive REPL prompt. Because the prompt also doesn't seem to allow multi-line matchers, this can make prototyping and iterating on more complicated matchers difficult. Supporting a dynamic load at REPL time allows the cost of reading the compilation database and building the AST to be imposed just once, and allows faster prototyping. --- clang-tools-extra/clang-query/Query.cpp | 22 +++++++++++++++++++ clang-tools-extra/clang-query/Query.h | 18 ++++++++++++++- clang-tools-extra/clang-query/QueryParser.cpp | 10 +++++++-- .../clang-query/tool/ClangQuery.cpp | 18 ++------------- .../test/clang-query/Inputs/file.script | 1 + .../clang-query/Inputs/runtime_file.script | 1 + .../test/clang-query/file-query.c | 11 ++++++++++ .../unittests/clang-query/QueryParserTest.cpp | 4 +++- 8 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 clang-tools-extra/test/clang-query/Inputs/file.script create mode 100644 clang-tools-extra/test/clang-query/Inputs/runtime_file.script create mode 100644 clang-tools-extra/test/clang-query/file-query.c diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp index c436d6fa94986..9d5807a52fa8e 100644 --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Query.h" +#include "QueryParser.h" #include "QuerySession.h" #include "clang/AST/ASTDumper.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -281,5 +282,26 @@ const QueryKind SetQueryKind<bool>::value; const QueryKind SetQueryKind<OutputKind>::value; #endif +bool FileQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { + auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim()); + if (!Buffer) { + if (Prefix.has_value()) + llvm::errs() << *Prefix << ": "; + llvm::errs() << "cannot open " << File << ": " + << Buffer.getError().message() << "\n"; + return false; + } + + StringRef FileContentRef(Buffer.get()->getBuffer()); + + while (!FileContentRef.empty()) { + QueryRef Q = QueryParser::parse(FileContentRef, QS); + if (!Q->run(llvm::outs(), QS)) + return false; + FileContentRef = Q->RemainingContent; + } + return true; +} + } // namespace query } // namespace clang diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h index 7aefa6bb5ee0d..7242479633c24 100644 --- a/clang-tools-extra/clang-query/Query.h +++ b/clang-tools-extra/clang-query/Query.h @@ -30,7 +30,8 @@ enum QueryKind { QK_SetTraversalKind, QK_EnableOutputKind, QK_DisableOutputKind, - QK_Quit + QK_Quit, + QK_File }; class QuerySession; @@ -188,6 +189,21 @@ struct DisableOutputQuery : SetNonExclusiveOutputQuery { } }; +struct FileQuery : Query { + FileQuery(StringRef File, StringRef Prefix = StringRef()) + : Query(QK_File), File(File), + Prefix(!Prefix.empty() ? std::optional<std::string>(Prefix) + : std::nullopt) {} + + bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; + + static bool classof(const Query *Q) { return Q->Kind == QK_File; } + +private: + std::string File; + std::optional<std::string> Prefix; +}; + } // namespace query } // namespace clang diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp index 162acc1a598dd..85a442bdd7ded 100644 --- a/clang-tools-extra/clang-query/QueryParser.cpp +++ b/clang-tools-extra/clang-query/QueryParser.cpp @@ -183,7 +183,8 @@ enum ParsedQueryKind { PQK_Unlet, PQK_Quit, PQK_Enable, - PQK_Disable + PQK_Disable, + PQK_File }; enum ParsedQueryVariable { @@ -222,12 +223,14 @@ QueryRef QueryParser::doParse() { .Case("let", PQK_Let) .Case("m", PQK_Match, /*IsCompletion=*/false) .Case("match", PQK_Match) - .Case("q", PQK_Quit, /*IsCompletion=*/false) + .Case("q", PQK_Quit, /*IsCompletion=*/false) .Case("quit", PQK_Quit) .Case("set", PQK_Set) .Case("enable", PQK_Enable) .Case("disable", PQK_Disable) .Case("unlet", PQK_Unlet) + .Case("f", PQK_File, /*IsCompletion=*/false) + .Case("file", PQK_File) .Default(PQK_Invalid); switch (QKind) { @@ -351,6 +354,9 @@ QueryRef QueryParser::doParse() { return endQuery(new LetQuery(Name, VariantValue())); } + case PQK_File: + return new FileQuery(Line); + case PQK_Invalid: return new InvalidQuery("unknown command: " + CommandStr); } diff --git a/clang-tools-extra/clang-query/tool/ClangQuery.cpp b/clang-tools-extra/clang-query/tool/ClangQuery.cpp index da7ac27014480..a2de7a2dced86 100644 --- a/clang-tools-extra/clang-query/tool/ClangQuery.cpp +++ b/clang-tools-extra/clang-query/tool/ClangQuery.cpp @@ -74,22 +74,8 @@ static cl::opt<std::string> PreloadFile( bool runCommandsInFile(const char *ExeName, std::string const &FileName, QuerySession &QS) { - auto Buffer = llvm::MemoryBuffer::getFile(FileName); - if (!Buffer) { - llvm::errs() << ExeName << ": cannot open " << FileName << ": " - << Buffer.getError().message() << "\n"; - return true; - } - - StringRef FileContentRef(Buffer.get()->getBuffer()); - - while (!FileContentRef.empty()) { - QueryRef Q = QueryParser::parse(FileContentRef, QS); - if (!Q->run(llvm::outs(), QS)) - return true; - FileContentRef = Q->RemainingContent; - } - return false; + FileQuery Query(FileName, ExeName); + return !Query.run(llvm::errs(), QS); } int main(int argc, const char **argv) { diff --git a/clang-tools-extra/test/clang-query/Inputs/file.script b/clang-tools-extra/test/clang-query/Inputs/file.script new file mode 100644 index 0000000000000..b58e7bbc24bfb --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/file.script @@ -0,0 +1 @@ +f DIRECTORY/runtime_file.script diff --git a/clang-tools-extra/test/clang-query/Inputs/runtime_file.script b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script new file mode 100644 index 0000000000000..5272580f4c965 --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script @@ -0,0 +1 @@ +m functionDecl() diff --git a/clang-tools-extra/test/clang-query/file-query.c b/clang-tools-extra/test/clang-query/file-query.c new file mode 100644 index 0000000000000..6bd3fd204cb8a --- /dev/null +++ b/clang-tools-extra/test/clang-query/file-query.c @@ -0,0 +1,11 @@ +// RUN: rm -rf %/t +// RUN: mkdir %/t +// RUN: cp %/S/Inputs/file.script %/t/file.script +// RUN: cp %/S/Inputs/runtime_file.script %/t/runtime_file.script +// Need to embed the correct temp path in the actual JSON-RPC requests. +// RUN: sed -e "s|DIRECTORY|%/t|" %/t/file.script > %/t/file.script.temp + +// RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s + +// CHECK: file-query.c:11:1: note: "root" binds here +void bar(void) {} diff --git a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp index 06b0d7b365904..b561e2bb98332 100644 --- a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp +++ b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp @@ -197,7 +197,7 @@ TEST_F(QueryParserTest, Comment) { TEST_F(QueryParserTest, Complete) { std::vector<llvm::LineEditor::Completion> Comps = QueryParser::complete("", 0, QS); - ASSERT_EQ(8u, Comps.size()); + ASSERT_EQ(9u, Comps.size()); EXPECT_EQ("help ", Comps[0].TypedText); EXPECT_EQ("help", Comps[0].DisplayText); EXPECT_EQ("let ", Comps[1].TypedText); @@ -214,6 +214,8 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("disable", Comps[6].DisplayText); EXPECT_EQ("unlet ", Comps[7].TypedText); EXPECT_EQ("unlet", Comps[7].DisplayText); + EXPECT_EQ("file ", Comps[8].TypedText); + EXPECT_EQ("file", Comps[8].DisplayText); Comps = QueryParser::complete("set o", 5, QS); ASSERT_EQ(1u, Comps.size()); >From 38f7f6f597d9baa5e02cce6f046d69474b0bf8fe Mon Sep 17 00:00:00 2001 From: Chris Warner <cwar...@esri.com> Date: Thu, 9 May 2024 16:49:24 -0700 Subject: [PATCH 2/5] CR: add tests for non-existant or empty file --- clang-tools-extra/test/clang-query/Inputs/empty.script | 1 + clang-tools-extra/test/clang-query/errors.c | 2 ++ clang-tools-extra/test/clang-query/file-empty.c | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 clang-tools-extra/test/clang-query/Inputs/empty.script create mode 100644 clang-tools-extra/test/clang-query/file-empty.c diff --git a/clang-tools-extra/test/clang-query/Inputs/empty.script b/clang-tools-extra/test/clang-query/Inputs/empty.script new file mode 100644 index 0000000000000..3c30abd1ae5d1 --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/empty.script @@ -0,0 +1 @@ +# This file intentionally has no queries diff --git a/clang-tools-extra/test/clang-query/errors.c b/clang-tools-extra/test/clang-query/errors.c index bbb742125744f..3b9059ab0257f 100644 --- a/clang-tools-extra/test/clang-query/errors.c +++ b/clang-tools-extra/test/clang-query/errors.c @@ -1,10 +1,12 @@ // RUN: not clang-query -c foo -c bar %s -- | FileCheck %s // RUN: not clang-query -f %S/Inputs/foo.script %s -- | FileCheck %s // RUN: not clang-query -f %S/Inputs/nonexistent.script %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT %s +// RUN: not clang-query -c 'file %S/Inputs/nonexistent.script' %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT-FILEQUERY %s // RUN: not clang-query -c foo -f foo %s -- 2>&1 | FileCheck --check-prefix=CHECK-BOTH %s // CHECK: unknown command: foo // CHECK-NOT: unknown command: bar // CHECK-NONEXISTENT: cannot open {{.*}}nonexistent.script +// CHECK-NONEXISTENT-FILEQUERY: cannot open {{.*}}nonexistent.script // CHECK-BOTH: cannot specify both -c and -f diff --git a/clang-tools-extra/test/clang-query/file-empty.c b/clang-tools-extra/test/clang-query/file-empty.c new file mode 100644 index 0000000000000..15137c57e915e --- /dev/null +++ b/clang-tools-extra/test/clang-query/file-empty.c @@ -0,0 +1,2 @@ +// RUN: clang-query -c 'file %S/Inputs/empty.script' %s -- +// COM: no output expected; nothing to CHECK >From 5e3b8f2cedf2829f85ae83068376151fbf13851d Mon Sep 17 00:00:00 2001 From: Chris Warner <cwar...@esri.com> Date: Thu, 9 May 2024 16:50:06 -0700 Subject: [PATCH 3/5] CR: add additional commands to dyn file --- .../test/clang-query/Inputs/runtime_file.script | 6 +++++- clang-tools-extra/test/clang-query/file-query.c | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/test/clang-query/Inputs/runtime_file.script b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script index 5272580f4c965..714d7f03b1bf6 100644 --- a/clang-tools-extra/test/clang-query/Inputs/runtime_file.script +++ b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script @@ -1 +1,5 @@ -m functionDecl() +set bind-root false + +l func functionDecl(hasName("bar")) +m func.bind("f") +m varDecl().bind("v") \ No newline at end of file diff --git a/clang-tools-extra/test/clang-query/file-query.c b/clang-tools-extra/test/clang-query/file-query.c index 6bd3fd204cb8a..2824865558ba9 100644 --- a/clang-tools-extra/test/clang-query/file-query.c +++ b/clang-tools-extra/test/clang-query/file-query.c @@ -7,5 +7,8 @@ // RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s -// CHECK: file-query.c:11:1: note: "root" binds here +// CHECK: file-query.c:11:1: note: "f" binds here void bar(void) {} + +// CHECK: file-query.c:14:1: note: "v" binds here +int baz{1}; \ No newline at end of file >From e199cbc755246883fab15a0a8d4c2c8150f12d94 Mon Sep 17 00:00:00 2001 From: Chris Warner <cwar...@esri.com> Date: Thu, 9 May 2024 16:50:48 -0700 Subject: [PATCH 4/5] CR: add release note --- clang-tools-extra/docs/ReleaseNotes.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 28840b9beae88..30558f55d4995 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -87,7 +87,9 @@ Improvements to clang-doc Improvements to clang-query --------------------------- -The improvements are... +- Added the `file` command to dynamically load a list of commands and matchers + from an external file, allowing the cost of reading the compilation database + and building the AST to be imposed just once for faster prototyping. Improvements to clang-rename ---------------------------- >From 478f0482658c034e0cb00507f3d197684486740c Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Mon, 13 May 2024 08:10:40 -0400 Subject: [PATCH 5/5] Update clang-tools-extra/test/clang-query/file-query.c --- clang-tools-extra/test/clang-query/file-query.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-query/file-query.c b/clang-tools-extra/test/clang-query/file-query.c index 2824865558ba9..10a44e7aaccf2 100644 --- a/clang-tools-extra/test/clang-query/file-query.c +++ b/clang-tools-extra/test/clang-query/file-query.c @@ -11,4 +11,4 @@ void bar(void) {} // CHECK: file-query.c:14:1: note: "v" binds here -int baz{1}; \ No newline at end of file +int baz{1}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits