blob: 41a4868fa8211d77a1911a9220275b658d9cc764 [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"
Raphael Isemann5dca0592019-12-23 10:38:12 +010010#include "TestingSupport/SubsystemRAII.h"
Raphael Isemannaaa34bc2019-12-20 15:09:40 +010011#include "TestingSupport/Symbol/ClangTestUtils.h"
Raphael Isemann4aee81c2019-12-17 13:38:07 +010012#include "lldb/Host/FileSystem.h"
13#include "lldb/Host/HostInfo.h"
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +010014#include "lldb/Symbol/TypeSystemClang.h"
Raphael Isemannd8a31942019-12-17 16:12:07 +010015#include "lldb/Symbol/ClangUtil.h"
Raphael Isemann4aee81c2019-12-17 13:38:07 +010016#include "lldb/lldb-defines.h"
17#include "gtest/gtest.h"
18
19using namespace lldb_private;
20using namespace lldb;
21
Raphael Isemannd8a31942019-12-17 16:12:07 +010022namespace {
23struct FakeClangExpressionDeclMap : public ClangExpressionDeclMap {
24 FakeClangExpressionDeclMap(const ClangASTImporterSP &importer)
25 : ClangExpressionDeclMap(false, nullptr, lldb::TargetSP(), importer,
26 nullptr) {
Raphael Isemann6be76f42019-12-20 18:44:39 +010027 m_scratch_context = clang_utils::createAST();
Raphael Isemannd8a31942019-12-17 16:12:07 +010028 }
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +010029 std::unique_ptr<TypeSystemClang> m_scratch_context;
Raphael Isemannd8a31942019-12-17 16:12:07 +010030 /// 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.
35 assert(d);
36 assert(d->getName().startswith("$"));
Raphael Isemannf9f49d32019-12-21 22:40:52 +010037 assert(&d->getASTContext() == &m_scratch_context->getASTContext());
Raphael Isemannd8a31942019-12-17 16:12:07 +010038 m_persistent_decls[d->getName()] = d;
39 }
40
41protected:
42 // ClangExpressionDeclMap hooks.
43
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());
48 }
49
50private:
51 /// The persistent decls in this test with their names as keys.
52 llvm::DenseMap<llvm::StringRef, clang::NamedDecl *> m_persistent_decls;
53};
54} // namespace
55
Raphael Isemann4aee81c2019-12-17 13:38:07 +010056namespace {
57struct ClangExpressionDeclMapTest : public testing::Test {
Raphael Isemann5dca0592019-12-23 10:38:12 +010058 SubsystemRAII<FileSystem, HostInfo> subsystems;
Raphael Isemann4aee81c2019-12-17 13:38:07 +010059
Raphael Isemannd8a31942019-12-17 16:12:07 +010060 /// The ClangASTImporter used during the test.
61 ClangASTImporterSP importer;
62 /// The ExpressionDeclMap for the current test case.
63 std::unique_ptr<FakeClangExpressionDeclMap> decl_map;
64
65 /// The target AST that lookup results should be imported to.
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +010066 std::unique_ptr<TypeSystemClang> target_ast;
Raphael Isemannd8a31942019-12-17 16:12:07 +010067
68 void SetUp() override {
69 importer = std::make_shared<ClangASTImporter>();
70 decl_map = std::make_unique<FakeClangExpressionDeclMap>(importer);
Raphael Isemannaaa34bc2019-12-20 15:09:40 +010071 target_ast = clang_utils::createAST();
Raphael Isemann49b206f2019-12-21 15:26:24 +010072 decl_map->InstallASTContext(*target_ast);
Raphael Isemannd8a31942019-12-17 16:12:07 +010073 }
74
75 void TearDown() override {
76 importer.reset();
77 decl_map.reset();
78 target_ast.reset();
Raphael Isemann4aee81c2019-12-17 13:38:07 +010079 }
Raphael Isemann4aee81c2019-12-17 13:38:07 +010080};
81} // namespace
82
Raphael Isemannd8a31942019-12-17 16:12:07 +010083TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
84 // Tests looking up an identifier that can't be found anywhere.
Raphael Isemann4aee81c2019-12-17 13:38:07 +010085
Raphael Isemannd8a31942019-12-17 16:12:07 +010086 // Setup a NameSearchContext for 'foo'.
Raphael Isemann4aee81c2019-12-17 13:38:07 +010087 llvm::SmallVector<clang::NamedDecl *, 16> decls;
Raphael Isemannaaa34bc2019-12-20 15:09:40 +010088 clang::DeclarationName name =
89 clang_utils::getDeclarationName(*target_ast, "foo");
Raphael Isemannd8a31942019-12-17 16:12:07 +010090 const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
91 NameSearchContext search(*decl_map, decls, name, dc);
Raphael Isemann4aee81c2019-12-17 13:38:07 +010092
Raphael Isemannd8a31942019-12-17 16:12:07 +010093 decl_map->FindExternalVisibleDecls(search);
Raphael Isemann4aee81c2019-12-17 13:38:07 +010094
Raphael Isemannd8a31942019-12-17 16:12:07 +010095 // This shouldn't exist so we should get no lookups.
Raphael Isemann4aee81c2019-12-17 13:38:07 +010096 EXPECT_EQ(0U, decls.size());
97}
Raphael Isemannd8a31942019-12-17 16:12:07 +010098
99TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
100 // Tests looking up a persistent decl from the scratch AST context.
101
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 =
Raphael Isemannaaa34bc2019-12-20 15:09:40 +0100106 clang_utils::createRecord(*decl_map->m_scratch_context, decl_name);
Raphael Isemannd8a31942019-12-17 16:12:07 +0100107 decl_map->AddPersistentDeclForTest(ClangUtil::GetAsTagDecl(persistent_type));
108
109 // Setup a NameSearchContext for $persistent_class;
110 llvm::SmallVector<clang::NamedDecl *, 16> decls;
Raphael Isemannaaa34bc2019-12-20 15:09:40 +0100111 clang::DeclarationName name =
112 clang_utils::getDeclarationName(*target_ast, decl_name);
Raphael Isemannd8a31942019-12-17 16:12:07 +0100113 const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
114 NameSearchContext search(*decl_map, decls, name, dc);
115
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());
123}