1 //===-- ClangExpressionDeclMapTest.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
10 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
11 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12 #include "TestingSupport/SubsystemRAII.h"
13 #include "TestingSupport/Symbol/ClangTestUtils.h"
14 #include "lldb/Host/FileSystem.h"
15 #include "lldb/Host/HostInfo.h"
16 #include "lldb/lldb-defines.h"
17 #include "gtest/gtest.h"
19 using namespace lldb_private
;
23 struct FakeClangExpressionDeclMap
: public ClangExpressionDeclMap
{
24 FakeClangExpressionDeclMap(const std::shared_ptr
<ClangASTImporter
> &importer
)
25 : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer
,
27 m_scratch_context
= clang_utils::createAST();
29 std::unique_ptr
<TypeSystemClang
> m_scratch_context
;
30 /// Adds a persistent decl that can be found by the ClangExpressionDeclMap
31 /// via GetPersistentDecl.
32 void AddPersistentDeclForTest(clang::NamedDecl
*d
) {
33 // The declaration needs to have '$' prefix in its name like every
34 // persistent declaration and must be inside the scratch AST context.
36 assert(d
->getName().startswith("$"));
37 assert(&d
->getASTContext() == &m_scratch_context
->getASTContext());
38 m_persistent_decls
[d
->getName()] = d
;
42 // ClangExpressionDeclMap hooks.
44 clang::NamedDecl
*GetPersistentDecl(ConstString name
) override
{
45 // ClangExpressionDeclMap wants to know if there is a persistent decl
46 // with the given name. Check the
47 return m_persistent_decls
.lookup(name
.GetStringRef());
51 /// The persistent decls in this test with their names as keys.
52 llvm::DenseMap
<llvm::StringRef
, clang::NamedDecl
*> m_persistent_decls
;
57 struct ClangExpressionDeclMapTest
: public testing::Test
{
58 SubsystemRAII
<FileSystem
, HostInfo
> subsystems
;
60 /// The ClangASTImporter used during the test.
61 std::shared_ptr
<ClangASTImporter
> importer
;
62 /// The ExpressionDeclMap for the current test case.
63 std::unique_ptr
<FakeClangExpressionDeclMap
> decl_map
;
65 /// The target AST that lookup results should be imported to.
66 std::unique_ptr
<TypeSystemClang
> target_ast
;
68 void SetUp() override
{
69 importer
= std::make_shared
<ClangASTImporter
>();
70 decl_map
= std::make_unique
<FakeClangExpressionDeclMap
>(importer
);
71 target_ast
= clang_utils::createAST();
72 decl_map
->InstallASTContext(*target_ast
);
75 void TearDown() override
{
83 TEST_F(ClangExpressionDeclMapTest
, TestUnknownIdentifierLookup
) {
84 // Tests looking up an identifier that can't be found anywhere.
86 // Setup a NameSearchContext for 'foo'.
87 llvm::SmallVector
<clang::NamedDecl
*, 16> decls
;
88 clang::DeclarationName name
=
89 clang_utils::getDeclarationName(*target_ast
, "foo");
90 const clang::DeclContext
*dc
= target_ast
->GetTranslationUnitDecl();
91 NameSearchContext
search(*target_ast
, decls
, name
, dc
);
93 decl_map
->FindExternalVisibleDecls(search
);
95 // This shouldn't exist so we should get no lookups.
96 EXPECT_EQ(0U, decls
.size());
99 TEST_F(ClangExpressionDeclMapTest
, TestPersistentDeclLookup
) {
100 // Tests looking up a persistent decl from the scratch AST context.
102 // Create a '$persistent_class' record and add it as a persistent variable
103 // to the scratch AST context.
104 llvm::StringRef decl_name
= "$persistent_class";
105 CompilerType persistent_type
=
106 clang_utils::createRecord(*decl_map
->m_scratch_context
, decl_name
);
107 decl_map
->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type
));
109 // Setup a NameSearchContext for $persistent_class;
110 llvm::SmallVector
<clang::NamedDecl
*, 16> decls
;
111 clang::DeclarationName name
=
112 clang_utils::getDeclarationName(*target_ast
, decl_name
);
113 const clang::DeclContext
*dc
= target_ast
->GetTranslationUnitDecl();
114 NameSearchContext
search(*target_ast
, decls
, name
, dc
);
116 // Search and check that we found $persistent_class.
117 decl_map
->FindExternalVisibleDecls(search
);
118 EXPECT_EQ(1U, decls
.size());
119 EXPECT_EQ(decl_name
, decls
.front()->getQualifiedNameAsString());
120 auto *record
= llvm::cast
<clang::RecordDecl
>(decls
.front());
121 // The class was minimally imported from the scratch AST context.
122 EXPECT_TRUE(record
->hasExternalLexicalStorage());