[lldb][NFC] Move NameSearchContext to own header/source files

The class is large enough to be in its own file. This patch also removes the cyclic
dependency between ClangASTSource <-> NameSearchContext.
This commit is contained in:
Raphael Isemann
2020-02-25 12:05:46 +01:00
parent 555d5ad85a
commit defd0e24aa
7 changed files with 311 additions and 272 deletions

View File

@@ -271,7 +271,6 @@ class WatchpointList;
class WatchpointOptions;
struct CompilerContext;
struct LineEntry;
struct NameSearchContext;
struct PropertyDefinition;
struct ScriptSummaryFormat;
struct StringSummaryFormat;

View File

@@ -26,6 +26,7 @@ add_lldb_library(lldbPluginExpressionParserClang
CxxModuleHandler.cpp
IRForTarget.cpp
IRDynamicChecks.cpp
NameSearchContext.cpp
DEPENDS
${tablegen_deps}

View File

@@ -140,7 +140,7 @@ bool ClangASTSource::FindExternalVisibleDeclsByName(
case DeclarationName::ObjCMultiArgSelector: {
llvm::SmallVector<NamedDecl *, 1> method_decls;
NameSearchContext method_search_context(*this, method_decls,
NameSearchContext method_search_context(*m_clang_ast_context, method_decls,
clang_decl_name, decl_ctx);
FindObjCMethodDecls(method_search_context);
@@ -183,8 +183,8 @@ bool ClangASTSource::FindExternalVisibleDeclsByName(
// printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth,
// uniqued_const_decl_name);
llvm::SmallVector<NamedDecl *, 4> name_decls;
NameSearchContext name_search_context(*this, name_decls, clang_decl_name,
decl_ctx);
NameSearchContext name_search_context(*m_clang_ast_context, name_decls,
clang_decl_name, decl_ctx);
FindExternalVisibleDecls(name_search_context);
SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, name_decls);
// --g_depth;
@@ -1760,170 +1760,3 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) {
return m_clang_ast_context->GetType(copied_qual_type);
}
clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) {
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
return nullptr;
TypeSystemClang *lldb_ast =
llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
if (!lldb_ast)
return nullptr;
IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
clang::ASTContext &ast = lldb_ast->getASTContext();
clang::NamedDecl *Decl = VarDecl::Create(
ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(),
SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static);
m_decls.push_back(Decl);
return Decl;
}
clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
bool extern_c) {
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
return nullptr;
if (m_function_types.count(type))
return nullptr;
TypeSystemClang *lldb_ast =
llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
if (!lldb_ast)
return nullptr;
m_function_types.insert(type);
QualType qual_type(ClangUtil::GetQualType(type));
clang::ASTContext &ast = lldb_ast->getASTContext();
const bool isInlineSpecified = false;
const bool hasWrittenPrototype = true;
const bool isConstexprSpecified = false;
clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context);
if (extern_c) {
context = LinkageSpecDecl::Create(
ast, context, SourceLocation(), SourceLocation(),
clang::LinkageSpecDecl::LanguageIDs::lang_c, false);
}
// Pass the identifier info for functions the decl_name is needed for
// operators
clang::DeclarationName decl_name =
m_decl_name.getNameKind() == DeclarationName::Identifier
? m_decl_name.getAsIdentifierInfo()
: m_decl_name;
clang::FunctionDecl *func_decl = FunctionDecl::Create(
ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype,
isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
// We have to do more than just synthesize the FunctionDecl. We have to
// synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do
// this, we raid the function's FunctionProtoType for types.
const FunctionProtoType *func_proto_type =
qual_type.getTypePtr()->getAs<FunctionProtoType>();
if (func_proto_type) {
unsigned NumArgs = func_proto_type->getNumParams();
unsigned ArgIndex;
SmallVector<ParmVarDecl *, 5> parm_var_decls;
for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) {
QualType arg_qual_type(func_proto_type->getParamType(ArgIndex));
parm_var_decls.push_back(
ParmVarDecl::Create(ast, const_cast<DeclContext *>(context),
SourceLocation(), SourceLocation(), nullptr,
arg_qual_type, nullptr, SC_Static, nullptr));
}
func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls));
} else {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
LLDB_LOG(log, "Function type wasn't a FunctionProtoType");
}
// If this is an operator (e.g. operator new or operator==), only insert the
// declaration we inferred from the symbol if we can provide the correct
// number of arguments. We shouldn't really inject random decl(s) for
// functions that are analyzed semantically in a special way, otherwise we
// will crash in clang.
clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
if (func_proto_type &&
TypeSystemClang::IsOperator(decl_name.getAsString().c_str(), op_kind)) {
if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
false, op_kind, func_proto_type->getNumParams()))
return nullptr;
}
m_decls.push_back(func_decl);
return func_decl;
}
clang::NamedDecl *NameSearchContext::AddGenericFunDecl() {
FunctionProtoType::ExtProtoInfo proto_info;
proto_info.Variadic = true;
QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType(
m_ast_source.m_ast_context->UnknownAnyTy, // result
ArrayRef<QualType>(), // argument types
proto_info));
return AddFunDecl(
m_ast_source.m_clang_ast_context->GetType(generic_function_type), true);
}
clang::NamedDecl *
NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
if (ClangUtil::IsClangType(clang_type)) {
QualType qual_type = ClangUtil::GetQualType(clang_type);
if (const TypedefType *typedef_type =
llvm::dyn_cast<TypedefType>(qual_type)) {
TypedefNameDecl *typedef_name_decl = typedef_type->getDecl();
m_decls.push_back(typedef_name_decl);
return (NamedDecl *)typedef_name_decl;
} else if (const TagType *tag_type = qual_type->getAs<TagType>()) {
TagDecl *tag_decl = tag_type->getDecl();
m_decls.push_back(tag_decl);
return tag_decl;
} else if (const ObjCObjectType *objc_object_type =
qual_type->getAs<ObjCObjectType>()) {
ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
m_decls.push_back((NamedDecl *)interface_decl);
return (NamedDecl *)interface_decl;
}
}
return nullptr;
}
void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) {
for (clang::NamedDecl *decl : result)
m_decls.push_back(decl);
}
void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) {
m_decls.push_back(decl);
}

View File

@@ -12,6 +12,7 @@
#include <set>
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "Plugins/ExpressionParser/Clang/NameSearchContext.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Target.h"
#include "clang/AST/ExternalASTSource.h"
@@ -382,105 +383,6 @@ protected:
std::set<const char *> m_active_lookups;
};
/// \class NameSearchContext ClangASTSource.h
/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a
/// single name lookup
///
/// LLDB needs to create Decls for entities it finds. This class communicates
/// what name is being searched for and provides helper functions to construct
/// Decls given appropriate type information.
struct NameSearchContext {
/// The AST source making the request.
ClangASTSource &m_ast_source;
/// The list of declarations already constructed.
llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls;
/// The mapping of all namespaces found for this request back to their
/// modules.
ClangASTImporter::NamespaceMapSP m_namespace_map;
/// The name being looked for.
const clang::DeclarationName &m_decl_name;
/// The DeclContext to put declarations into.
const clang::DeclContext *m_decl_context;
/// All the types of functions that have been reported, so we don't
/// report conflicts.
llvm::SmallSet<CompilerType, 5> m_function_types;
struct {
bool variable : 1;
bool function_with_type_info : 1;
bool function : 1;
bool local_vars_nsp : 1;
bool type : 1;
} m_found;
/// Constructor
///
/// Initializes class variables.
///
/// \param[in] astSource
/// A reference to the AST source making a request.
///
/// \param[in] decls
/// A reference to a list into which new Decls will be placed. This
/// list is typically empty when the function is called.
///
/// \param[in] name
/// The name being searched for (always an Identifier).
///
/// \param[in] dc
/// The DeclContext to register Decls in.
NameSearchContext(ClangASTSource &astSource,
llvm::SmallVectorImpl<clang::NamedDecl *> &decls,
clang::DeclarationName &name, const clang::DeclContext *dc)
: m_ast_source(astSource), m_decls(decls), m_decl_name(name),
m_decl_context(dc) {
memset(&m_found, 0, sizeof(m_found));
}
/// Create a VarDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] type
/// The opaque QualType for the VarDecl being registered.
clang::NamedDecl *AddVarDecl(const CompilerType &type);
/// Create a FunDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] type
/// The opaque QualType for the FunDecl being registered.
///
/// \param[in] extern_c
/// If true, build an extern "C" linkage specification for this.
clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false);
/// Create a FunDecl with the name being searched for and generic type (i.e.
/// intptr_t NAME_GOES_HERE(...)) and register it in the right places.
clang::NamedDecl *AddGenericFunDecl();
/// Create a TypeDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] compiler_type
/// The opaque QualType for the TypeDecl being registered.
clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type);
/// Add Decls from the provided DeclContextLookupResult to the list of
/// results.
///
/// \param[in] result
/// The DeclContextLookupResult, usually returned as the result
/// of querying a DeclContext.
void AddLookupResult(clang::DeclContextLookupResult result);
/// Add a NamedDecl to the list of results.
///
/// \param[in] decl
/// The NamedDecl, usually returned as the result
/// of querying a DeclContext.
void AddNamedDecl(clang::NamedDecl *decl);
};
} // namespace lldb_private
#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H

View File

@@ -0,0 +1,179 @@
//===-- NameSearchContext.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "NameSearchContext.h"
#include "ClangUtil.h"
using namespace clang;
using namespace lldb_private;
clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) {
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
return nullptr;
TypeSystemClang *lldb_ast =
llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
if (!lldb_ast)
return nullptr;
IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
clang::ASTContext &ast = lldb_ast->getASTContext();
clang::NamedDecl *Decl = VarDecl::Create(
ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(),
SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static);
m_decls.push_back(Decl);
return Decl;
}
clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
bool extern_c) {
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
return nullptr;
if (m_function_types.count(type))
return nullptr;
TypeSystemClang *lldb_ast =
llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
if (!lldb_ast)
return nullptr;
m_function_types.insert(type);
QualType qual_type(ClangUtil::GetQualType(type));
clang::ASTContext &ast = lldb_ast->getASTContext();
const bool isInlineSpecified = false;
const bool hasWrittenPrototype = true;
const bool isConstexprSpecified = false;
clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context);
if (extern_c) {
context = LinkageSpecDecl::Create(
ast, context, SourceLocation(), SourceLocation(),
clang::LinkageSpecDecl::LanguageIDs::lang_c, false);
}
// Pass the identifier info for functions the decl_name is needed for
// operators
clang::DeclarationName decl_name =
m_decl_name.getNameKind() == DeclarationName::Identifier
? m_decl_name.getAsIdentifierInfo()
: m_decl_name;
clang::FunctionDecl *func_decl = FunctionDecl::Create(
ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype,
isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
// We have to do more than just synthesize the FunctionDecl. We have to
// synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do
// this, we raid the function's FunctionProtoType for types.
const FunctionProtoType *func_proto_type =
qual_type.getTypePtr()->getAs<FunctionProtoType>();
if (func_proto_type) {
unsigned NumArgs = func_proto_type->getNumParams();
unsigned ArgIndex;
SmallVector<ParmVarDecl *, 5> parm_var_decls;
for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) {
QualType arg_qual_type(func_proto_type->getParamType(ArgIndex));
parm_var_decls.push_back(
ParmVarDecl::Create(ast, const_cast<DeclContext *>(context),
SourceLocation(), SourceLocation(), nullptr,
arg_qual_type, nullptr, SC_Static, nullptr));
}
func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls));
} else {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
LLDB_LOG(log, "Function type wasn't a FunctionProtoType");
}
// If this is an operator (e.g. operator new or operator==), only insert the
// declaration we inferred from the symbol if we can provide the correct
// number of arguments. We shouldn't really inject random decl(s) for
// functions that are analyzed semantically in a special way, otherwise we
// will crash in clang.
clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
if (func_proto_type &&
TypeSystemClang::IsOperator(decl_name.getAsString().c_str(), op_kind)) {
if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
false, op_kind, func_proto_type->getNumParams()))
return nullptr;
}
m_decls.push_back(func_decl);
return func_decl;
}
clang::NamedDecl *NameSearchContext::AddGenericFunDecl() {
FunctionProtoType::ExtProtoInfo proto_info;
proto_info.Variadic = true;
QualType generic_function_type(
GetASTContext().getFunctionType(GetASTContext().UnknownAnyTy, // result
ArrayRef<QualType>(), // argument types
proto_info));
return AddFunDecl(m_clang_ts.GetType(generic_function_type), true);
}
clang::NamedDecl *
NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
if (ClangUtil::IsClangType(clang_type)) {
QualType qual_type = ClangUtil::GetQualType(clang_type);
if (const TypedefType *typedef_type =
llvm::dyn_cast<TypedefType>(qual_type)) {
TypedefNameDecl *typedef_name_decl = typedef_type->getDecl();
m_decls.push_back(typedef_name_decl);
return (NamedDecl *)typedef_name_decl;
} else if (const TagType *tag_type = qual_type->getAs<TagType>()) {
TagDecl *tag_decl = tag_type->getDecl();
m_decls.push_back(tag_decl);
return tag_decl;
} else if (const ObjCObjectType *objc_object_type =
qual_type->getAs<ObjCObjectType>()) {
ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
m_decls.push_back((NamedDecl *)interface_decl);
return (NamedDecl *)interface_decl;
}
}
return nullptr;
}
void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) {
for (clang::NamedDecl *decl : result)
m_decls.push_back(decl);
}
void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) {
m_decls.push_back(decl);
}

View File

@@ -0,0 +1,125 @@
//===-- NameSearchContext.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H
#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H
#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Symbol/CompilerType.h"
#include "llvm/ADT/SmallSet.h"
namespace lldb_private {
/// \class NameSearchContext ClangASTSource.h
/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a
/// single name lookup
///
/// LLDB needs to create Decls for entities it finds. This class communicates
/// what name is being searched for and provides helper functions to construct
/// Decls given appropriate type information.
struct NameSearchContext {
/// The type system of the AST from which the lookup originated.
TypeSystemClang &m_clang_ts;
/// The list of declarations already constructed.
llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls;
/// The mapping of all namespaces found for this request back to their
/// modules.
ClangASTImporter::NamespaceMapSP m_namespace_map;
/// The name being looked for.
const clang::DeclarationName &m_decl_name;
/// The DeclContext to put declarations into.
const clang::DeclContext *m_decl_context;
/// All the types of functions that have been reported, so we don't
/// report conflicts.
llvm::SmallSet<CompilerType, 5> m_function_types;
struct {
bool variable : 1;
bool function_with_type_info : 1;
bool function : 1;
bool local_vars_nsp : 1;
bool type : 1;
} m_found;
/// Constructor
///
/// Initializes class variables.
///
/// \param[in] astSource
/// A reference to the AST source making a request.
///
/// \param[in] decls
/// A reference to a list into which new Decls will be placed. This
/// list is typically empty when the function is called.
///
/// \param[in] name
/// The name being searched for (always an Identifier).
///
/// \param[in] dc
/// The DeclContext to register Decls in.
NameSearchContext(TypeSystemClang &clang_ts,
llvm::SmallVectorImpl<clang::NamedDecl *> &decls,
clang::DeclarationName &name, const clang::DeclContext *dc)
: m_clang_ts(clang_ts), m_decls(decls), m_decl_name(name),
m_decl_context(dc) {
memset(&m_found, 0, sizeof(m_found));
}
/// Create a VarDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] type
/// The opaque QualType for the VarDecl being registered.
clang::NamedDecl *AddVarDecl(const CompilerType &type);
/// Create a FunDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] type
/// The opaque QualType for the FunDecl being registered.
///
/// \param[in] extern_c
/// If true, build an extern "C" linkage specification for this.
clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false);
/// Create a FunDecl with the name being searched for and generic type (i.e.
/// intptr_t NAME_GOES_HERE(...)) and register it in the right places.
clang::NamedDecl *AddGenericFunDecl();
/// Create a TypeDecl with the name being searched for and the provided type
/// and register it in the right places.
///
/// \param[in] compiler_type
/// The opaque QualType for the TypeDecl being registered.
clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type);
/// Add Decls from the provided DeclContextLookupResult to the list of
/// results.
///
/// \param[in] result
/// The DeclContextLookupResult, usually returned as the result
/// of querying a DeclContext.
void AddLookupResult(clang::DeclContextLookupResult result);
/// Add a NamedDecl to the list of results.
///
/// \param[in] decl
/// The NamedDecl, usually returned as the result
/// of querying a DeclContext.
void AddNamedDecl(clang::NamedDecl *decl);
private:
clang::ASTContext &GetASTContext() const {
return m_clang_ts.getASTContext();
}
};
} // namespace lldb_private
#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H

View File

@@ -88,7 +88,7 @@ TEST_F(ClangExpressionDeclMapTest, TestUnknownIdentifierLookup) {
clang::DeclarationName name =
clang_utils::getDeclarationName(*target_ast, "foo");
const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
NameSearchContext search(*decl_map, decls, name, dc);
NameSearchContext search(*target_ast, decls, name, dc);
decl_map->FindExternalVisibleDecls(search);
@@ -111,7 +111,7 @@ TEST_F(ClangExpressionDeclMapTest, TestPersistentDeclLookup) {
clang::DeclarationName name =
clang_utils::getDeclarationName(*target_ast, decl_name);
const clang::DeclContext *dc = target_ast->GetTranslationUnitDecl();
NameSearchContext search(*decl_map, decls, name, dc);
NameSearchContext search(*target_ast, decls, name, dc);
// Search and check that we found $persistent_class.
decl_map->FindExternalVisibleDecls(search);