xref: /llvm-project/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp (revision 744f38913fa380580431df0ae89ef5fb3df30240)
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