================ @@ -0,0 +1,521 @@ +//===-- HeuristicResolverTests.cpp --------------------------*- C++ -*-----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "HeuristicResolver.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gmock/gmock-matchers.h" +#include "gtest/gtest.h" + +using namespace clang::ast_matchers; +using clang::clangd::HeuristicResolver; +using testing::ElementsAre; + +namespace clang { +namespace { + +// Helper for matching a sequence of elements with a variadic list of matchers. +// Usage: `ElementsAre(matchAdapter(Vs, MatchFunction)...)`, where `Vs...` is +// a variadic list of matchers. +// For each `V` in `Vs`, this will match the corresponding element `E` if +// `MatchFunction(V, E)` is true. +MATCHER_P2(matchAdapter, MatcherForElement, MatchFunction, "matchAdapter") { + return MatchFunction(MatcherForElement, arg); +} + +template <typename InputNode> +using ResolveFnT = std::function<std::vector<const NamedDecl *>( + const HeuristicResolver *, const InputNode *)>; + +// Test heuristic resolution on `Code` using the resolution procedure +// `ResolveFn`, which takes a `HeuristicResolver` and an input AST node of type +// `InputNode` and returns a `std::vector<const NamedDecl *>`. +// `InputMatcher` should be an AST matcher that matches a single node to pass as +// input to `ResolveFn`, bound to the ID "input". `OutputMatchers` should be AST +// matchers that each match a single node, bound to the ID "output". +template <typename InputNode, typename InputMatcher, typename... OutputMatchers> +void expectResolution(llvm::StringRef Code, ResolveFnT<InputNode> ResolveFn, + const InputMatcher &IM, const OutputMatchers &...OMS) { + auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); + auto &Ctx = TU->getASTContext(); + auto InputMatches = match(IM, Ctx); + ASSERT_EQ(1u, InputMatches.size()); + const auto *Input = InputMatches[0].template getNodeAs<InputNode>("input"); + ASSERT_TRUE(Input); + + auto OutputNodeMatches = [&](auto &OutputMatcher, auto &Actual) { + auto OutputMatches = match(OutputMatcher, Ctx); + if (OutputMatches.size() != 1u) + return false; + const auto *ExpectedOutput = + OutputMatches[0].template getNodeAs<NamedDecl>("output"); + if (!ExpectedOutput) + return false; + return ExpectedOutput == Actual; + }; + + HeuristicResolver H(Ctx); + auto Results = ResolveFn(&H, Input); + EXPECT_THAT(Results, ElementsAre(matchAdapter(OMS, OutputNodeMatches)...)); +} + +// Wrapper for the above that accepts a HeuristicResolver member function +// pointer directly. +template <typename InputNode, typename InputMatcher, typename... OutputMatchers> +void expectResolution(llvm::StringRef Code, + std::vector<const NamedDecl *> ( + HeuristicResolver::*ResolveFn)(const InputNode *) + const, + const InputMatcher &IM, const OutputMatchers &...OMS) { + expectResolution(Code, ResolveFnT<InputNode>(std::mem_fn(ResolveFn)), IM, + OMS...); +} + +TEST(HeuristicResolver, MemberExpr) { + std::string Code = R"cpp( + template <typename T> + struct S { + void bar() {} + }; + + template <typename T> + void foo(S<T> arg) { + arg.bar(); + } + )cpp"; + // Test resolution of "bar" in "arg.bar()". + expectResolution(Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr().bind("input"), ---------------- HighCommander4 wrote:
Never mind, I _was_ overlooking something: there is a `hasMemberName()` matcher that works with `CXXDependentScopeMemberExpr`. I'll look at using that. https://github.com/llvm/llvm-project/pull/121313 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits