Skip to content

Commit 6ed1d54

Browse files
committed
WIP
1 parent 0319a79 commit 6ed1d54

File tree

9 files changed

+154
-0
lines changed

9 files changed

+154
-0
lines changed

clang-tools-extra/clangd/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ endif()
6060

6161
include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}/../clang-tidy")
6262
include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/../include-cleaner/include")
63+
include_directories(BEFORE "${CMAKE_CURRENT_SOURCE_DIR}/../clang-query")
6364

6465
add_clang_library(clangDaemon STATIC
6566
AST.cpp
@@ -183,6 +184,7 @@ target_link_libraries(clangDaemon
183184
${LLVM_PTHREAD_LIB}
184185

185186
clangIncludeCleaner
187+
clangQuery
186188
clangTidy
187189
clangTidyUtils
188190

clang-tools-extra/clangd/ClangdLSPServer.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ std::optional<int64_t> decodeVersion(llvm::StringRef Encoded) {
7676
const llvm::StringLiteral ApplyFixCommand = "clangd.applyFix";
7777
const llvm::StringLiteral ApplyTweakCommand = "clangd.applyTweak";
7878
const llvm::StringLiteral ApplyRenameCommand = "clangd.applyRename";
79+
constexpr llvm::StringLiteral SearchASTCommand = "clangd.searchAST";
7980

8081
CodeAction toCodeAction(const ClangdServer::CodeActionResult::Rename &R,
8182
const URIForFile &File) {
@@ -852,6 +853,18 @@ void ClangdLSPServer::onCommandApplyRename(const RenameParams &R,
852853
});
853854
}
854855

856+
void ClangdLSPServer::onCommandSearchAST(const SearchASTArgs &Args,
857+
Callback<llvm::json::Value> Reply) {
858+
Server->findAST(Args, [Reply = std::move(Reply)](
859+
llvm::Expected<std::vector<std::vector<ASTNode>>>
860+
BoundNodes) mutable {
861+
if (!BoundNodes)
862+
return Reply(BoundNodes.takeError());
863+
auto v = llvm::json::Value(*BoundNodes);
864+
return Reply(*BoundNodes);
865+
});
866+
}
867+
855868
void ClangdLSPServer::applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
856869
Callback<llvm::json::Value> Reply) {
857870
ApplyWorkspaceEditParams Edit;
@@ -1728,6 +1741,7 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind,
17281741
Bind.command(ApplyFixCommand, this, &ClangdLSPServer::onCommandApplyEdit);
17291742
Bind.command(ApplyTweakCommand, this, &ClangdLSPServer::onCommandApplyTweak);
17301743
Bind.command(ApplyRenameCommand, this, &ClangdLSPServer::onCommandApplyRename);
1744+
Bind.command(SearchASTCommand, this, &ClangdLSPServer::onCommandSearchAST);
17311745

17321746
ApplyWorkspaceEdit = Bind.outgoingMethod("workspace/applyEdit");
17331747
PublishDiagnostics = Bind.outgoingNotification("textDocument/publishDiagnostics");

clang-tools-extra/clangd/ClangdLSPServer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class ClangdLSPServer : private ClangdServer::Callbacks,
186186
void onCommandApplyEdit(const WorkspaceEdit &, Callback<llvm::json::Value>);
187187
void onCommandApplyTweak(const TweakArgs &, Callback<llvm::json::Value>);
188188
void onCommandApplyRename(const RenameParams &, Callback<llvm::json::Value>);
189+
void onCommandSearchAST(const SearchASTArgs &, Callback<llvm::json::Value>);
189190

190191
/// Outgoing LSP calls.
191192
LSPBinder::OutgoingMethod<ApplyWorkspaceEditParams,

clang-tools-extra/clangd/ClangdServer.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,42 @@ void ClangdServer::locateSymbolAt(PathRef File, Position Pos,
810810
WorkScheduler->runWithAST("Definitions", File, std::move(Action));
811811
}
812812

813+
void ClangdServer::findAST(SearchASTArgs const &Args,
814+
Callback<std::vector<std::vector<ASTNode>>> CB) {
815+
auto Action =
816+
[Args, CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable {
817+
if (!InpAST)
818+
return CB(InpAST.takeError());
819+
auto BoundNodes = clangd::locateASTQuery(InpAST->AST, Args);
820+
if (BoundNodes.empty())
821+
return CB(error("No matching AST nodes found"));
822+
823+
auto &&AST = InpAST->AST;
824+
// Convert BoundNodes to a vector of vectors to ASTNode's.
825+
std::vector<std::vector<ASTNode>> Result;
826+
Result.reserve(BoundNodes.size());
827+
for (auto &&BN : BoundNodes) {
828+
auto &&Map = BN.getMap();
829+
std::vector<ASTNode> Nodes;
830+
Nodes.reserve(Map.size());
831+
for (const auto &[Key, Value] : Map) {
832+
auto Node = dumpAST(Value, AST.getTokens(), AST.getASTContext());
833+
Nodes.push_back(std::move(Node));
834+
}
835+
if (Nodes.empty())
836+
continue;
837+
Result.push_back(std::move(Nodes));
838+
}
839+
if (Result.empty()) {
840+
return CB(error("No AST nodes found for the query"));
841+
}
842+
CB(std::move(Result));
843+
};
844+
845+
WorkScheduler->runWithAST("Definitions", Args.textDocument.uri.file(),
846+
std::move(Action));
847+
}
848+
813849
void ClangdServer::switchSourceHeader(
814850
PathRef Path, Callback<std::optional<clangd::Path>> CB) {
815851
// We want to return the result as fast as possible, strategy is:

clang-tools-extra/clangd/ClangdServer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "support/MemoryTree.h"
3131
#include "support/Path.h"
3232
#include "support/ThreadsafeFS.h"
33+
#include "clang/ASTMatchers/ASTMatchFinder.h"
34+
#include "clang/ASTMatchers/ASTMatchers.h"
3335
#include "clang/Tooling/Core/Replacement.h"
3436
#include "llvm/ADT/ArrayRef.h"
3537
#include "llvm/ADT/FunctionExtras.h"
@@ -260,6 +262,9 @@ class ClangdServer {
260262
void locateSymbolAt(PathRef File, Position Pos,
261263
Callback<std::vector<LocatedSymbol>> CB);
262264

265+
void findAST(const SearchASTArgs &Args,
266+
Callback<std::vector<std::vector<ASTNode>>> CB);
267+
263268
/// Switch to a corresponding source file when given a header file, and vice
264269
/// versa.
265270
void switchSourceHeader(PathRef Path,

clang-tools-extra/clangd/Protocol.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "Protocol.h"
1414
#include "URI.h"
1515
#include "support/Logger.h"
16+
#include "clang/AST/ASTTypeTraits.h"
1617
#include "clang/Basic/LLVM.h"
1718
#include "clang/Index/IndexSymbol.h"
1819
#include "llvm/ADT/StringExtras.h"
@@ -1650,6 +1651,15 @@ bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S,
16501651
O.map("positions", S.positions);
16511652
}
16521653

1654+
bool fromJSON(const llvm::json::Value &Params, SearchASTArgs &Args, llvm::json::Path P) {
1655+
llvm::json::ObjectMapper O(Params, P);
1656+
return O && O.map("query", Args.searchQuery)
1657+
&& O.map("textDocument", Args.textDocument)
1658+
// && O.map("bindRoot", Args.bindRoot); TODO: add bindRoot to extend this feature
1659+
// && O.map("traversalKind", Args.tk); TODO: add traversalKind to extend this feature
1660+
;
1661+
}
1662+
16531663
llvm::json::Value toJSON(const SelectionRange &Out) {
16541664
if (Out.parent) {
16551665
return llvm::json::Object{{"range", Out.range},

clang-tools-extra/clangd/Protocol.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "URI.h"
2727
#include "index/SymbolID.h"
2828
#include "support/MemoryTree.h"
29+
#include "clang/AST/ASTTypeTraits.h"
2930
#include "clang/Index/IndexSymbol.h"
3031
#include "llvm/ADT/SmallVector.h"
3132
#include "llvm/Support/JSON.h"
@@ -1451,6 +1452,18 @@ struct RenameParams {
14511452
bool fromJSON(const llvm::json::Value &, RenameParams &, llvm::json::Path);
14521453
llvm::json::Value toJSON(const RenameParams &);
14531454

1455+
struct SearchASTArgs {
1456+
std::string searchQuery;
1457+
TextDocumentIdentifier textDocument;
1458+
1459+
// Todo (extend feature): make them members and modifiable:
1460+
/// wheter the whole query is shown
1461+
static auto constexpr BindRoot = true;
1462+
/// Simplify things for users; default for now.
1463+
static auto constexpr Tk = TraversalKind::TK_IgnoreUnlessSpelledInSource;
1464+
};
1465+
bool fromJSON(const llvm::json::Value &, SearchASTArgs &, llvm::json::Path);
1466+
14541467
struct PrepareRenameResult {
14551468
/// Range of the string to rename.
14561469
Range range;

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "ParsedAST.h"
1515
#include "Protocol.h"
1616
#include "Quality.h"
17+
#include "Query.h"
18+
#include "QuerySession.h"
1719
#include "Selection.h"
1820
#include "SourceCode.h"
1921
#include "URI.h"
@@ -41,6 +43,10 @@
4143
#include "clang/AST/StmtCXX.h"
4244
#include "clang/AST/StmtVisitor.h"
4345
#include "clang/AST/Type.h"
46+
#include "clang/ASTMatchers/ASTMatchFinder.h"
47+
#include "clang/ASTMatchers/ASTMatchers.h"
48+
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
49+
#include "clang/ASTMatchers/Dynamic/Parser.h"
4450
#include "clang/Basic/LLVM.h"
4551
#include "clang/Basic/LangOptions.h"
4652
#include "clang/Basic/SourceLocation.h"
@@ -52,6 +58,7 @@
5258
#include "clang/Index/IndexingOptions.h"
5359
#include "clang/Index/USRGeneration.h"
5460
#include "clang/Lex/Lexer.h"
61+
#include "clang/Parse/Parser.h"
5562
#include "clang/Sema/HeuristicResolver.h"
5663
#include "clang/Tooling/Syntax/Tokens.h"
5764
#include "llvm/ADT/ArrayRef.h"
@@ -66,6 +73,7 @@
6673
#include "llvm/Support/ErrorHandling.h"
6774
#include "llvm/Support/Path.h"
6875
#include "llvm/Support/raw_ostream.h"
76+
#include <cmath>
6977
#include <optional>
7078
#include <string>
7179
#include <vector>
@@ -773,6 +781,61 @@ const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,
773781
return BestTok;
774782
}
775783

784+
auto locateASTQuery(ParsedAST &AST, SearchASTArgs const &Query)
785+
-> std::vector<ast_matchers::BoundNodes> {
786+
using namespace ast_matchers;
787+
using namespace ast_matchers::dynamic;
788+
using ast_matchers::dynamic::Parser;
789+
790+
Diagnostics Diag;
791+
auto MatcherSource = llvm::StringRef(Query.searchQuery).ltrim();
792+
auto OrigMatcherSource = MatcherSource;
793+
794+
std::optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
795+
MatcherSource,
796+
nullptr /* is this sema instance usefull, to reduce overhead?*/,
797+
nullptr /*we currently don't support let*/, &Diag);
798+
if (!Matcher) {
799+
elog("Not a valid top-level matcher.\n");
800+
return {/* TODO */};
801+
}
802+
auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() -
803+
MatcherSource.size());
804+
auto *Q = new query::MatchQuery(ActualSource, *Matcher);
805+
Q->RemainingContent = MatcherSource;
806+
807+
// Q->run(AST);:
808+
//==
809+
810+
struct CollectBoundNodes : MatchFinder::MatchCallback {
811+
std::vector<BoundNodes> &Bindings;
812+
CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
813+
void run(const MatchFinder::MatchResult &Result) override {
814+
Bindings.push_back(Result.Nodes);
815+
}
816+
};
817+
818+
MatchFinder Finder;
819+
std::vector<BoundNodes> Matches;
820+
DynTypedMatcher MaybeBoundMatcher = *Matcher;
821+
if (Query.BindRoot) {
822+
std::optional<DynTypedMatcher> M = Matcher->tryBind("root");
823+
if (M)
824+
MaybeBoundMatcher = *M;
825+
}
826+
CollectBoundNodes Collect(Matches);
827+
if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
828+
log("Not a valid top-level matcher.\n");
829+
return {/* TODO */};
830+
}
831+
832+
ASTContext &Ctx = AST.getASTContext();
833+
Ctx.getParentMapContext().setTraversalKind(Query.Tk);
834+
Finder.matchAST(Ctx);
835+
836+
return Matches;
837+
}
838+
776839
std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
777840
const SymbolIndex *Index) {
778841
const auto &SM = AST.getSourceManager();

clang-tools-extra/clangd/XRefs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "index/SymbolID.h"
2020
#include "support/Path.h"
2121
#include "clang/AST/ASTTypeTraits.h"
22+
#include "clang/ASTMatchers/ASTMatchers.h"
2223
#include "llvm/ADT/StringRef.h"
2324
#include "llvm/Support/raw_ostream.h"
2425
#include <optional>
@@ -32,6 +33,15 @@ class TokenBuffer;
3233
namespace clangd {
3334
class ParsedAST;
3435

36+
struct LocatedAST {
37+
ast_matchers::BoundNodes &AST;
38+
};
39+
40+
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const LocatedAST &);
41+
42+
auto locateASTQuery(ParsedAST &AST, SearchASTArgs const &)
43+
-> std::vector<ast_matchers::BoundNodes>;
44+
3545
// Describes where a symbol is declared and defined (as far as clangd knows).
3646
// There are three cases:
3747
// - a declaration only, no definition is known (e.g. only header seen)

0 commit comments

Comments
 (0)