Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 199 additions & 5 deletions libcextract/Closure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include "Closure.hh"

#include "clang/AST/TemplateName.h"

/** Add a decl to the Dependencies set and all its previous declarations in the
AST. A function can have multiple definitions but its body may only be
defined later. */
Expand All @@ -38,6 +40,18 @@ bool ClosureSet::Add_Decl_And_Prevs(Decl *decl)
return inserted;
}

/** Add a single decl to the set. */
bool ClosureSet::Add_Single_Decl(Decl *decl)
{
/* Do not insert builtin decls. */
if (Is_Builtin_Decl(decl)) {
return false;
}

Dependencies.insert(decl);
return true;
}

void DeclClosureVisitor::Compute_Closure_Of_Symbols(const std::vector<std::string> &names,
std::unordered_set<std::string> *matched_names)
{
Expand All @@ -61,7 +75,7 @@ void DeclClosureVisitor::Compute_Closure_Of_Symbols(const std::vector<std::strin
continue;
}

const std::string &decl_name = decl->getName().str();
const std::string &decl_name = decl->getNameAsString();
/* If the symbol name is in the set... */
if (setof_names.find(decl_name) != setof_names.end()) {
/* Mark that name as matched. */
Expand All @@ -79,8 +93,8 @@ void DeclClosureVisitor::Compute_Closure_Of_Symbols(const std::vector<std::strin
if ((CALL_EXPR) == VISITOR_STOP) \
return VISITOR_STOP

#define DO_NOT_RUN_IF_ALREADY_ANALYZED(decl) \
if (Already_Analyzed(decl) == true) \
#define DO_NOT_RUN_IF_ALREADY_ANALYZED(decl) \
if (!decl || Already_Analyzed(decl) == true) \
return VISITOR_CONTINUE

bool DeclClosureVisitor::TraverseDecl(Decl *decl)
Expand Down Expand Up @@ -292,7 +306,7 @@ bool DeclClosureVisitor::VisitEnumConstantDecl(EnumConstantDecl *decl)
bool DeclClosureVisitor::VisitTypedefNameDecl(TypedefNameDecl *decl)
{
// FIXME: Do we need to analyze the previous decls?
TRY_TO(TraverseType(decl->getUnderlyingType()));
TRY_TO(TraverseTypeLoc(decl->getTypeSourceInfo()->getTypeLoc()));
Closure.Add_Single_Decl(decl);

TRY_TO(AnalyzeDeclsWithSameBeginlocHelper(decl));
Expand All @@ -302,6 +316,12 @@ bool DeclClosureVisitor::VisitTypedefNameDecl(TypedefNameDecl *decl)

bool DeclClosureVisitor::VisitVarDecl(VarDecl *decl)
{
/* Avoid running this visitor if this decl is actually a result of a
template, that means, do not add it into the Closure. */
if (isa<VarTemplateSpecializationDecl>(decl)) {
return VISITOR_CONTINUE;
}

/* Avoid adding variables that are not global. */
// FIXME: Do we need to analyze every previous decl?
if (decl->hasGlobalStorage()) {
Expand All @@ -311,6 +331,22 @@ bool DeclClosureVisitor::VisitVarDecl(VarDecl *decl)
return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitNamedDecl(NamedDecl *decl)
{
/* Make sure we recusively add the parent decls in order to output this
decl we marked as visited. For example where we need this see
c++-linkage-4.cpp, where the definition of align_val_t is inside a
LinkageDecl inside a NamespaceDecl. */
DeclContext *ctx = decl->getLexicalDeclContext();
while (ctx) {
Decl *d = cast<Decl>(ctx);
Closure.Add_Single_Decl(d);
ctx = ctx->getParent();
}

return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *decl)
{
Closure.Add_Decl_And_Prevs(decl);
Expand Down Expand Up @@ -347,6 +383,42 @@ bool DeclClosureVisitor::VisitCXXRecordDecl(CXXRecordDecl *decl)

bool DeclClosureVisitor::VisitClassTemplateDecl(ClassTemplateDecl *decl)
{
// FIXME: Not all specializations may be necessary, but there seems to be no
// straightfoward way of solvings expressions such as
// "__make_unsigned_selector<_Tp>::__type", which may point to a Decl defined
// in some of its specializations. Furthermore, there seems to not be a way
// to know partial specializations, for example:
//
//template<typename _Unqualified, bool _IsConst, bool _IsVol>
// struct __cv_selector;
//
//template<typename _Unqualified>
// struct __cv_selector<_Unqualified, false, false>
// { typedef _Unqualified __type; };
//
//template<typename _Qualified, typename _Unqualified,
// bool _IsConst = false,
// bool _IsVol = false>
// class __match_cv_qualifiers
// {
// typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match;
//
// public:
// typedef typename __match::__type __type;
// };
//
// Here there is no way to know that __match_cv_qualifiers<char, false, false>
// actually points to the second declaration, not the first one. Hence we
// add every partial template specification to the closure until we find a
// better way of finding such things.

for (ClassTemplateSpecializationDecl *spec : decl->specializations()) {
if (auto specialized = spec->getSpecializedTemplateOrPartial();
auto class_p = dyn_cast<ClassTemplatePartialSpecializationDecl*>(specialized)) {
TRY_TO(TraverseDecl(class_p));
}
}

Closure.Add_Decl_And_Prevs(decl);

return VISITOR_CONTINUE;
Expand All @@ -367,7 +439,25 @@ bool DeclClosureVisitor::VisitClassTemplateSpecializationDecl(
TRY_TO(TraverseTemplateArguments(decl->getTemplateArgs().asArray()));

/* This call will add the V to the closure. */
return VisitClassTemplateDecl(decl->getSpecializedTemplate());
TRY_TO(VisitClassTemplateDecl(decl->getSpecializedTemplate()));

Closure.Add_Decl_And_Prevs(decl);

return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitVarTemplateDecl(VarTemplateDecl *decl)
{
Closure.Add_Single_Decl(decl);

return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *decl)
{
TRY_TO(TraverseDecl(decl->getSpecializedTemplate()));

return VISITOR_CONTINUE;
}

/* ----------- Statements -------------- */
Expand Down Expand Up @@ -460,18 +550,122 @@ bool DeclClosureVisitor::VisitTypedefType(const TypedefType *type)
bool DeclClosureVisitor::VisitTemplateSpecializationType(
const TemplateSpecializationType *type)
{
const TemplateName &name = type->getTemplateName();

if (TemplateDecl *decl = name.getAsTemplateDecl()) {
/* We must be sure that we got the most recent decl, otherwise we may fail
to catch every redeclaration of this template. */
TRY_TO(TraverseDecl(decl->getMostRecentDecl()));
} else if (UsingShadowDecl *decl = name.getAsUsingShadowDecl()) {
TRY_TO(TraverseDecl(decl));
}

/* For some reason the Traverse do not run on the original template
C++ Record, only on its specializations. Hence do it here. */
return TraverseDecl(type->getAsCXXRecordDecl());
}

bool DeclClosureVisitor::VisitDependentNameType(const DependentNameType *type)
{
/* Attempt to find a template specialization which matches the type we want.
For example, in:

template<typename _Tp>
struct make_unsigned
{ typedef typename __make_unsigned_selector<_Tp>::__type type; };

this typedef will fail to find the correct typedef declaration:

template<typename _Tp,
bool _IsInt = is_integral<_Tp>::value,
bool _IsEnum = is_enum<_Tp>::value>
class __make_unsigned_selector;

template<typename _Tp>
class __make_unsigned_selector<_Tp, true, false>
{
using __unsigned_type
= typename __make_unsigned<__remove_cv_t<_Tp>>::__type;

public:
using __type
= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
};

The second one is correct, not the first. What we do here is to look for
the identifier in the set of template specifiers and check if there is a
match. If there is then we add it to the closure.

*/

NestedNameSpecifier *nns = type->getQualifier();
const IdentifierInfo *info = type->getIdentifier();

const clang::Type *ntype = nns->getAsType();

if (ntype == nullptr)
return VISITOR_CONTINUE;

const TemplateSpecializationType *template_type =
dyn_cast<TemplateSpecializationType>(ntype);

if (template_type == nullptr)
return VISITOR_CONTINUE;

TemplateDecl *decl = template_type->getTemplateName().getAsTemplateDecl();
ClassTemplateDecl *cdecl = dyn_cast<ClassTemplateDecl>(decl);

if (cdecl == nullptr)
return VISITOR_CONTINUE;

for (ClassTemplateSpecializationDecl *spec : cdecl->specializations()) {
if (auto specialized = spec->getSpecializedTemplateOrPartial();
auto class_p = dyn_cast<ClassTemplatePartialSpecializationDecl*>(specialized)) {

DeclContextLookupResult match = class_p->lookup(DeclarationName(info));
for (Decl *d : match) {
TRY_TO(TraverseDecl(d));
}

if (!match.empty()) {
TRY_TO(TraverseDecl(class_p));
}
}
}

return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *type)
{
TemplateName template_name = type->getTemplateName();
return TraverseDecl(template_name.getAsTemplateDecl());
}

bool DeclClosureVisitor::VisitUsingType(const UsingType *type)
{
UsingShadowDecl *decl = type->getFoundDecl();

// FIXME: Do we need a custom UsingShadowDeclVisitor?
TRY_TO(TraverseDecl(decl));

// Traverse the original decl that introduced the UsingDecl.
TRY_TO(TraverseDecl(decl->getIntroducer()));

// Analyze underlying type.
TRY_TO(TraverseType(type->getUnderlyingType()));

return VISITOR_CONTINUE;
}

bool DeclClosureVisitor::VisitBaseUsingDecl(BaseUsingDecl *decl)
{
Closure.Add_Single_Decl(decl);

return VISITOR_CONTINUE;
}

/* ----------- Other C++ stuff ----------- */

bool DeclClosureVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *nns)
Expand Down
23 changes: 13 additions & 10 deletions libcextract/Closure.hh
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,7 @@ class ClosureSet
bool Add_Decl_And_Prevs(Decl *decl);

/** Add a single decl to the set. */
bool Add_Single_Decl(Decl *decl)
{
/* Do not insert builtin decls. */
if (Is_Builtin_Decl(decl)) {
return false;
}

Dependencies.insert(decl);
return true;
}
bool Add_Single_Decl(Decl *decl);

inline std::unordered_set<Decl *> &Get_Set(void)
{
Expand Down Expand Up @@ -198,6 +189,8 @@ class DeclClosureVisitor : public RecursiveASTVisitor<DeclClosureVisitor>

bool VisitVarDecl(VarDecl *decl);

bool VisitNamedDecl(NamedDecl *decl);

/* --------- C++ Declarations ---------- */

bool VisitFunctionTemplateDecl(FunctionTemplateDecl *decl);
Expand All @@ -212,6 +205,12 @@ class DeclClosureVisitor : public RecursiveASTVisitor<DeclClosureVisitor>

bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *decl);

bool VisitVarTemplateDecl(VarTemplateDecl *decl);

bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *decl);

bool VisitBaseUsingDecl(BaseUsingDecl *decl);

/* ----------- Statements -------------- */

bool VisitDeclRefExpr(DeclRefExpr *expr);
Expand All @@ -236,6 +235,10 @@ class DeclClosureVisitor : public RecursiveASTVisitor<DeclClosureVisitor>
bool VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *type);

bool VisitDependentNameType(const DependentNameType *type);

bool VisitUsingType(const UsingType *type);

/* ----------- Other C++ stuff ----------- */
bool TraverseNestedNameSpecifier(NestedNameSpecifier *nns);

Expand Down
8 changes: 4 additions & 4 deletions libcextract/FunctionDepsFinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void FunctionDependencyFinder::Remove_Redundant_Decls(void)
PrettyPrint::Get_Source_Text(type_range) != "") {

/* Using .fullyContains() fails in some declarations. */
if (PrettyPrint::Contains_From_LineCol(range, type_range)) {
if (Range_Fully_Contains_Range(AST, range, type_range)) {
closure.Remove_Decl(typedecl);
}
}
Expand Down Expand Up @@ -195,7 +195,7 @@ void FunctionDependencyFinder::Remove_Redundant_Decls(void)
SourceRange type_range = typedecl->getSourceRange();

/* Using .fullyContains() fails in some declarations. */
if (PrettyPrint::Contains_From_LineCol(range, type_range)) {
if (Range_Fully_Contains_Range(AST, range, type_range)) {
closure.Remove_Decl(typedecl);
}
}
Expand Down Expand Up @@ -266,8 +266,8 @@ void FunctionDependencyFinder::Remove_Redundant_Decls(void)
*/
if (PrettyPrint::Get_Source_Text(decl->getSourceRange()) != "" &&
PrettyPrint::Get_Source_Text(prev->getSourceRange()) != "" &&
PrettyPrint::Contains_From_LineCol(decl->getSourceRange(),
prev->getSourceRange())) {
Range_Fully_Contains_Range(AST, decl->getSourceRange(),
prev->getSourceRange())) {
/*
* If the prev and the current decl have the same start LoC, but
* different ending, remove the prev from the closure and set the
Expand Down
11 changes: 11 additions & 0 deletions libcextract/LLVMMisc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,14 @@ bool Is_Decl_Equivalent_To(Decl *a, Decl *b)

return a_str == b_str;
}

bool Range_Fully_Contains_Range(ASTUnit *ast, const SourceRange &a,
const SourceRange &b)
{
SourceManager &SM = ast->getSourceManager();

SourceRange a_exp(SM.getExpansionLoc(a.getBegin()), SM.getExpansionLoc(a.getEnd()));
SourceRange b_exp(SM.getExpansionLoc(b.getBegin()), SM.getExpansionLoc(b.getEnd()));

return a_exp.fullyContains(b_exp);
}
3 changes: 3 additions & 0 deletions libcextract/LLVMMisc.hh
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,6 @@ DeclContextLookupResult Get_Decl_From_Symtab(ASTUnit *ast, const StringRef &name

/** Check if two Decls are equivalent. */
bool Is_Decl_Equivalent_To(Decl *a, Decl *b);

bool Range_Fully_Contains_Range(ASTUnit *ast, const SourceRange &a,
const SourceRange &b);
Loading
Loading