14aee81c4SRaphael Isemann //===-- ClangExpressionDeclMapTest.cpp ------------------------------------===//
24aee81c4SRaphael Isemann //
34aee81c4SRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44aee81c4SRaphael Isemann // See https://llvm.org/LICENSE.txt for license information.
54aee81c4SRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64aee81c4SRaphael Isemann //
74aee81c4SRaphael Isemann //===----------------------------------------------------------------------===//
84aee81c4SRaphael Isemann
94aee81c4SRaphael Isemann #include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
108be30215SAlex Langford #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
125dca0596SRaphael Isemann #include "TestingSupport/SubsystemRAII.h"
13aaa34bc0SRaphael Isemann #include "TestingSupport/Symbol/ClangTestUtils.h"
144aee81c4SRaphael Isemann #include "lldb/Host/FileSystem.h"
154aee81c4SRaphael Isemann #include "lldb/Host/HostInfo.h"
164aee81c4SRaphael Isemann #include "lldb/lldb-defines.h"
174aee81c4SRaphael Isemann #include "gtest/gtest.h"
184aee81c4SRaphael Isemann
194aee81c4SRaphael Isemann using namespace lldb_private;
204aee81c4SRaphael Isemann using namespace lldb;
214aee81c4SRaphael Isemann
22d8a31949SRaphael Isemann namespace {
23d8a31949SRaphael Isemann struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap {
FakeClangExpressionDeclMap__anonf50977ec0111::FakeClangExpressionDeclMap247c9ebdd3SAlex Langford FakeClangExpressionDeclMap(const std::shared_ptr<ClangASTImporter> &importer)
25d8a31949SRaphael Isemann : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer,
26d8a31949SRaphael Isemann nullptr) {
276eaedbb5SAdrian Prantl m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
286eaedbb5SAdrian Prantl m_scratch_context = m_holder->GetAST();
29d8a31949SRaphael Isemann }
306eaedbb5SAdrian Prantl std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
316eaedbb5SAdrian Prantl TypeSystemClang *m_scratch_context;
32d8a31949SRaphael Isemann /// Adds a persistent decl that can be found by the ClangExpressionDeclMap
33d8a31949SRaphael Isemann /// via GetPersistentDecl.
AddPersistentDeclForTest__anonf50977ec0111::FakeClangExpressionDeclMap34d8a31949SRaphael Isemann void AddPersistentDeclForTest(clang::NamedDecl *d) {
35d8a31949SRaphael Isemann // The declaration needs to have '$' prefix in its name like every
36d8a31949SRaphael Isemann // persistent declaration and must be inside the scratch AST context.
37d8a31949SRaphael Isemann assert(d);
38*744f3891SKazu Hirata assert(d->getName().starts_with("$"));
39f9f49d35SRaphael Isemann assert(&d->getASTContext() == &m_scratch_context->getASTContext());
40d8a31949SRaphael Isemann m_persistent_decls[d->getName()] = d;
41d8a31949SRaphael Isemann }
42d8a31949SRaphael Isemann
43d8a31949SRaphael Isemann protected:
44d8a31949SRaphael Isemann // ClangExpressionDeclMap hooks.
45d8a31949SRaphael Isemann
GetPersistentDecl__anonf50977ec0111::FakeClangExpressionDeclMap46d8a31949SRaphael Isemann clang::NamedDecl *GetPersistentDecl(ConstString name) override {
47d8a31949SRaphael Isemann // ClangExpressionDeclMap wants to know if there is a persistent decl
48d8a31949SRaphael Isemann // with the given name. Check the
49d8a31949SRaphael Isemann return m_persistent_decls.lookup(name.GetStringRef());
50d8a31949SRaphael Isemann }
51d8a31949SRaphael Isemann
52d8a31949SRaphael Isemann private:
53d8a31949SRaphael Isemann /// The persistent decls in this test with their names as keys.
54d8a31949SRaphael Isemann llvm::DenseMap<llvm::StringRef, clang::NamedDecl *> m_persistent_decls;
55d8a31949SRaphael Isemann };
56d8a31949SRaphael Isemann } // namespace
57d8a31949SRaphael Isemann
584aee81c4SRaphael Isemann namespace {
594aee81c4SRaphael Isemann struct ClangExpressionDeclMapTest : public testing::Test {
605dca0596SRaphael Isemann SubsystemRAII<FileSystem, HostInfo> subsystems;
614aee81c4SRaphael Isemann
62d8a31949SRaphael Isemann /// The ClangASTImporter used during the test.
637c9ebdd3SAlex Langford std::shared_ptr<ClangASTImporter> importer;
64d8a31949SRaphael Isemann /// The ExpressionDeclMap for the current test case.
65d8a31949SRaphael Isemann std::unique_ptr<FakeClangExpressionDeclMap> decl_map;
66d8a31949SRaphael Isemann
676eaedbb5SAdrian Prantl std::unique_ptr<clang_utils::TypeSystemClangHolder> holder;
686eaedbb5SAdrian Prantl
69d8a31949SRaphael Isemann /// The target AST that lookup results should be imported to.
706eaedbb5SAdrian Prantl TypeSystemClang *target_ast;
71d8a31949SRaphael Isemann
SetUp__anonf50977ec0211::ClangExpressionDeclMapTest72d8a31949SRaphael Isemann void SetUp() override {
73d8a31949SRaphael Isemann importer = std::make_shared<ClangASTImporter>();
74d8a31949SRaphael Isemann decl_map = std::make_unique<FakeClangExpressionDeclMap>(importer);
756eaedbb5SAdrian Prantl holder = std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");
766eaedbb5SAdrian Prantl target_ast = holder->GetAST();
7749b206f9SRaphael Isemann decl_map->InstallASTContext(*target_ast);
78d8a31949SRaphael Isemann }
79d8a31949SRaphael Isemann
TearDown__anonf50977ec0211::ClangExpressionDeclMapTest80d8a31949SRaphael Isemann void TearDown() override {
81d8a31949SRaphael Isemann importer.reset();
82d8a31949SRaphael Isemann decl_map.reset();
836eaedbb5SAdrian Prantl holder.reset();
844aee81c4SRaphael Isemann }
854aee81c4SRaphael Isemann };
864aee81c4SRaphael Isemann } // namespace
874aee81c4SRaphael Isemann
TEST_F(ClangExpressionDeclMapTest,TestUnknownIdentifierLookup)88d8a31949SRaphael Isemann TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
89d8a31949SRaphael Isemann // Tests looking up an identifier that can't be found anywhere.
904aee81c4SRaphael Isemann
91d8a31949SRaphael Isemann // Setup a NameSearchContext for 'foo'.
924aee81c4SRaphael Isemann llvm::SmallVector<clang::NamedDecl *, 16> decls;
93aaa34bc0SRaphael Isemann clang::DeclarationName name =
94aaa34bc0SRaphael Isemann clang_utils::getDeclarationName(*target_ast, "foo");
95d8a31949SRaphael Isemann const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
96defd0e24SRaphael Isemann NameSearchContext search(*target_ast, decls, name, dc);
974aee81c4SRaphael Isemann
98d8a31949SRaphael Isemann decl_map->FindExternalVisibleDecls(search);
994aee81c4SRaphael Isemann
100d8a31949SRaphael Isemann // This shouldn't exist so we should get no lookups.
1014aee81c4SRaphael Isemann EXPECT_EQ(0U, decls.size());
1024aee81c4SRaphael Isemann }
103d8a31949SRaphael Isemann
TEST_F(ClangExpressionDeclMapTest,TestPersistentDeclLookup)104d8a31949SRaphael Isemann TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
105d8a31949SRaphael Isemann // Tests looking up a persistent decl from the scratch AST context.
106d8a31949SRaphael Isemann
107d8a31949SRaphael Isemann // Create a '$persistent_class' record and add it as a persistent variable
108d8a31949SRaphael Isemann // to the scratch AST context.
109d8a31949SRaphael Isemann llvm::StringRef decl_name = "$persistent_class";
110d8a31949SRaphael Isemann CompilerType persistent_type =
111aaa34bc0SRaphael Isemann clang_utils::createRecord(*decl_map->m_scratch_context, decl_name);
112d8a31949SRaphael Isemann decl_map->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type));
113d8a31949SRaphael Isemann
114d8a31949SRaphael Isemann // Setup a NameSearchContext for $persistent_class;
115d8a31949SRaphael Isemann llvm::SmallVector<clang::NamedDecl *, 16> decls;
116aaa34bc0SRaphael Isemann clang::DeclarationName name =
117aaa34bc0SRaphael Isemann clang_utils::getDeclarationName(*target_ast, decl_name);
118d8a31949SRaphael Isemann const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
119defd0e24SRaphael Isemann NameSearchContext search(*target_ast, decls, name, dc);
120d8a31949SRaphael Isemann
121d8a31949SRaphael Isemann // Search and check that we found $persistent_class.
122d8a31949SRaphael Isemann decl_map->FindExternalVisibleDecls(search);
123d8a31949SRaphael Isemann EXPECT_EQ(1U, decls.size());
124d8a31949SRaphael Isemann EXPECT_EQ(decl_name, decls.front()->getQualifiedNameAsString());
125d8a31949SRaphael Isemann auto *record = llvm::cast<clang::RecordDecl>(decls.front());
126d8a31949SRaphael Isemann // The class was minimally imported from the scratch AST context.
127d8a31949SRaphael Isemann EXPECT_TRUE(record->hasExternalLexicalStorage());
128d8a31949SRaphael Isemann }
129