blob: 6fac168462b3c6cac82f344855ccb4ed81c47c27 [file] [log] [blame]
Raphael Isemann4aee81c2019-12-17 13:38:07 +01001//===-- ClangExpressionDeclMapTest.cpp ------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
10#include "TestingSupport/TestUtilities.h"
11#include "lldb/Host/FileSystem.h"
12#include "lldb/Host/HostInfo.h"
13#include "lldb/Symbol/ClangASTContext.h"
Raphael Isemannd8a31942019-12-17 16:12:07 +010014#include "lldb/Symbol/ClangUtil.h"
Raphael Isemann4aee81c2019-12-17 13:38:07 +010015#include "lldb/lldb-defines.h"
16#include "gtest/gtest.h"
17
18using namespace lldb_private;
19using namespace lldb;
20
Raphael Isemannd8a31942019-12-17 16:12:07 +010021static std::unique_ptr<ClangASTContext> createAST() {
22 return std::make_unique<ClangASTContext>(HostInfo::GetTargetTriple());
23}
24
25namespace {
26struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap {
27 FakeClangExpressionDeclMap(const ClangASTImporterSP &importer)
28 : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer,
29 nullptr) {
30 m_scratch_context = createAST();
31 }
32 std::unique_ptr<ClangASTContext> m_scratch_context;
33 /// Adds a persistent decl that can be found by the ClangExpressionDeclMap
34 /// via GetPersistentDecl.
35 void AddPersistentDeclForTest(clang::NamedDecl *d) {
36 // The declaration needs to have '$' prefix in its name like every
37 // persistent declaration and must be inside the scratch AST context.
38 assert(d);
39 assert(d->getName().startswith("$"));
40 assert(&d->getASTContext() == m_scratch_context->getASTContext());
41 m_persistent_decls[d->getName()] = d;
42 }
43
44protected:
45 // ClangExpressionDeclMap hooks.
46
47 clang::NamedDecl *GetPersistentDecl(ConstString name) override {
48 // ClangExpressionDeclMap wants to know if there is a persistent decl
49 // with the given name. Check the
50 return m_persistent_decls.lookup(name.GetStringRef());
51 }
52
53private:
54 /// The persistent decls in this test with their names as keys.
55 llvm::DenseMap<llvm::StringRef, clang::NamedDecl *> m_persistent_decls;
56};
57} // namespace
58
Raphael Isemann4aee81c2019-12-17 13:38:07 +010059namespace {
60struct ClangExpressionDeclMapTest : public testing::Test {
61 static void SetUpTestCase() {
62 FileSystem::Initialize();
63 HostInfo::Initialize();
64 }
65 static void TearDownTestCase() {
66 HostInfo::Terminate();
67 FileSystem::Terminate();
68 }
69
Raphael Isemannd8a31942019-12-17 16:12:07 +010070 /// The ClangASTImporter used during the test.
71 ClangASTImporterSP importer;
72 /// The ExpressionDeclMap for the current test case.
73 std::unique_ptr<FakeClangExpressionDeclMap> decl_map;
74
75 /// The target AST that lookup results should be imported to.
76 std::unique_ptr<ClangASTContext> target_ast;
77
78 void SetUp() override {
79 importer = std::make_shared<ClangASTImporter>();
80 decl_map = std::make_unique<FakeClangExpressionDeclMap>(importer);
81 target_ast = createAST();
82 decl_map->InstallASTContext(*target_ast, *target_ast->getFileManager());
83 }
84
85 void TearDown() override {
86 importer.reset();
87 decl_map.reset();
88 target_ast.reset();
Raphael Isemann4aee81c2019-12-17 13:38:07 +010089 }
90
91 clang::DeclarationName getDeclarationName(ClangASTContext &ast,
92 llvm::StringRef name) {
93 clang::IdentifierInfo &II = ast.getIdentifierTable()->get(name);
94 return ast.getASTContext()->DeclarationNames.getIdentifier(&II);
95 }
Raphael Isemannd8a31942019-12-17 16:12:07 +010096
97 CompilerType createRecord(ClangASTContext &ast, llvm::StringRef name) {
98 CompilerType t = ast.CreateRecordType(ast.getASTContext()->getTranslationUnitDecl(),
99 lldb::AccessType::eAccessPublic, name, 0,
100 lldb::LanguageType::eLanguageTypeC);
101 ClangASTContext::StartTagDeclarationDefinition(t);
102 ClangASTContext::CompleteTagDeclarationDefinition(t);
103 return t;
104 }
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100105};
106} // namespace
107
Raphael Isemannd8a31942019-12-17 16:12:07 +0100108TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
109 // Tests looking up an identifier that can't be found anywhere.
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100110
Raphael Isemannd8a31942019-12-17 16:12:07 +0100111 // Setup a NameSearchContext for 'foo'.
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100112 llvm::SmallVector<clang::NamedDecl *, 16> decls;
Raphael Isemannd8a31942019-12-17 16:12:07 +0100113 clang::DeclarationName name = getDeclarationName(*target_ast, "foo");
114 const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
115 NameSearchContext search(*decl_map, decls, name, dc);
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100116
Raphael Isemannd8a31942019-12-17 16:12:07 +0100117 decl_map->FindExternalVisibleDecls(search);
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100118
Raphael Isemannd8a31942019-12-17 16:12:07 +0100119 // This shouldn't exist so we should get no lookups.
Raphael Isemann4aee81c2019-12-17 13:38:07 +0100120 EXPECT_EQ(0U, decls.size());
121}
Raphael Isemannd8a31942019-12-17 16:12:07 +0100122
123TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
124 // Tests looking up a persistent decl from the scratch AST context.
125
126 // Create a '$persistent_class' record and add it as a persistent variable
127 // to the scratch AST context.
128 llvm::StringRef decl_name = "$persistent_class";
129 CompilerType persistent_type =
130 createRecord(*decl_map->m_scratch_context, decl_name);
131 decl_map->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type));
132
133 // Setup a NameSearchContext for $persistent_class;
134 llvm::SmallVector<clang::NamedDecl *, 16> decls;
135 clang::DeclarationName name = getDeclarationName(*target_ast, decl_name);
136 const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
137 NameSearchContext search(*decl_map, decls, name, dc);
138
139 // Search and check that we found $persistent_class.
140 decl_map->FindExternalVisibleDecls(search);
141 EXPECT_EQ(1U, decls.size());
142 EXPECT_EQ(decl_name, decls.front()->getQualifiedNameAsString());
143 auto *record = llvm::cast<clang::RecordDecl>(decls.front());
144 // The class was minimally imported from the scratch AST context.
145 EXPECT_TRUE(record->hasExternalLexicalStorage());
146}