Skip to content

Commit

Permalink
fix(cxx_indexer): dereference member templates (#5381)
Browse files Browse the repository at this point in the history
* fix(cxx_indexer): dereference member templates

This PR also cleans up BuildNodeIdForTemplateName, since it
no longer has to dereference member templates itself.

* fix: address comments
  • Loading branch information
zrlk authored Sep 16, 2022
1 parent 134d58a commit a57e0fd
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 27 deletions.
24 changes: 6 additions & 18 deletions kythe/cxx/indexer/cxx/IndexerASTHooks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ bool ConstructorOverridesInitializer(const clang::CXXConstructorDecl* Ctor,

/// \return true if `D` should not be visited because its name will never be
/// uttered due to aliasing rules.
bool SkipAliasedDecl(const clang::Decl* D) {
bool SkipAliasedDecl(const clang::Decl* D, bool absnodes) {
return absl::GetFlag(FLAGS_experimental_alias_template_instantiations) &&
(FindSpecializedTemplate(D) != D);
(FindSpecializedTemplate(D, !absnodes) != D);
}

bool IsObjCForwardDecl(const clang::ObjCInterfaceDecl* decl) {
Expand Down Expand Up @@ -2589,7 +2589,7 @@ IndexerASTVisitor::BuildTemplateArgumentList(
}

bool IndexerASTVisitor::VisitVarDecl(const clang::VarDecl* Decl) {
if (SkipAliasedDecl(Decl)) {
if (SkipAliasedDecl(Decl, options_.AbsNodes)) {
return true;
}
if (isa<clang::ParmVarDecl>(Decl)) {
Expand Down Expand Up @@ -3192,7 +3192,7 @@ GraphObserver::NodeId IndexerASTVisitor::RecordTemplate(
}

bool IndexerASTVisitor::VisitRecordDecl(const clang::RecordDecl* Decl) {
if (SkipAliasedDecl(Decl)) {
if (SkipAliasedDecl(Decl, options_.AbsNodes)) {
return true;
}
if (Decl->isInjectedClassName()) {
Expand Down Expand Up @@ -3337,7 +3337,7 @@ bool IndexerASTVisitor::VisitRecordDecl(const clang::RecordDecl* Decl) {
}

bool IndexerASTVisitor::VisitFunctionDecl(clang::FunctionDecl* Decl) {
if (SkipAliasedDecl(Decl)) {
if (SkipAliasedDecl(Decl, options_.AbsNodes)) {
return true;
}
// Add the decl to the cache. This helps if a declaration is annotated, its
Expand Down Expand Up @@ -3994,7 +3994,7 @@ GraphObserver::NodeId IndexerASTVisitor::BuildNodeIdForDecl(
// the IDs given to class definitions (in part because of the language rules).

if (absl::GetFlag(FLAGS_experimental_alias_template_instantiations)) {
Decl = FindSpecializedTemplate(Decl);
Decl = FindSpecializedTemplate(Decl, !options_.AbsNodes);
}

if (const auto* IFD = dyn_cast<clang::IndirectFieldDecl>(Decl)) {
Expand Down Expand Up @@ -4265,18 +4265,6 @@ IndexerASTVisitor::BuildNodeIdForTemplateName(const clang::TemplateName& Name) {
// Direct references to function templates to the outer function
// template shell.
decl = Name.getAsTemplateDecl();
} else if (absl::GetFlag(
FLAGS_experimental_alias_template_instantiations)) {
// Point to the original member function template.
// This solves problems with aliasing when dealing with nested
// templates.
if (const auto* FTD = dyn_cast<clang::FunctionTemplateDecl>(
Name.getAsTemplateDecl())) {
while ((FTD = FTD->getInstantiatedFromMemberTemplate())) {
if (FTD->getTemplatedDecl() != nullptr)
decl = FTD->getTemplatedDecl();
}
}
}
return BuildNodeIdForDecl(decl);
} else if (const auto* VD = dyn_cast<clang::VarDecl>(UnderlyingDecl)) {
Expand Down
79 changes: 71 additions & 8 deletions kythe/cxx/indexer/cxx/clang_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "kythe/cxx/indexer/cxx/clang_utils.h"

#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Lexer.h"
#include "glog/logging.h"
Expand Down Expand Up @@ -45,12 +46,74 @@ clang::SourceLocation GetLocForEndOfToken(
source_manager, lang_options);
}

// TODO(zarko): Update this to handle member specializations.
const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl) {
namespace {
class DereferenceMemberTemplatesDeclVisitor
: public clang::ConstDeclVisitor<DereferenceMemberTemplatesDeclVisitor,
void> {
public:
DereferenceMemberTemplatesDeclVisitor() = default;

const clang::Decl* Visit(const clang::Decl* decl) {
decl_ = decl;
ConstDeclVisitor::Visit(decl);
return decl_;
}

void VisitFunctionTemplateDecl(const clang::FunctionTemplateDecl* ft) {
while ((ft = ft->getInstantiatedFromMemberTemplate())) {
if (ft->getTemplatedDecl() != nullptr) decl_ = ft->getTemplatedDecl();
}
}

void VisitClassTemplateDecl(const clang::ClassTemplateDecl* ct) {
while ((ct = ct->getInstantiatedFromMemberTemplate())) {
if (ct->getTemplatedDecl() != nullptr) decl_ = ct->getTemplatedDecl();
}
}

void VisitClassTemplatePartialSpecializationDecl(
const clang::ClassTemplatePartialSpecializationDecl* ctp) {
while ((ctp = ctp->getInstantiatedFromMemberTemplate())) {
decl_ = ctp;
}
}

void VisitVarTemplatePartialSpecializationDecl(
const clang::VarTemplatePartialSpecializationDecl* vtp) {
while ((vtp = vtp->getInstantiatedFromMember())) {
decl_ = vtp;
}
}

void VisitVarTemplateDecl(const clang::VarTemplateDecl* vt) {
while ((vt = vt->getInstantiatedFromMemberTemplate())) {
if (vt->getTemplatedDecl() != nullptr) decl_ = vt->getTemplatedDecl();
}
}

void VisitTypeAliasTemplateDecl(const clang::TypeAliasTemplateDecl* at) {
while ((at = at->getInstantiatedFromMemberTemplate())) {
if (at->getTemplatedDecl() != nullptr) decl_ = at->getTemplatedDecl();
}
}

private:
const clang::Decl* decl_;
};

} // anonymous namespace

const clang::Decl* DereferenceMemberTemplates(const clang::Decl* decl,
bool use_mts) {
return use_mts ? DereferenceMemberTemplatesDeclVisitor().Visit(decl) : decl;
}

const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl,
bool use_mts) {
if (const auto* FD = llvm::dyn_cast<const clang::FunctionDecl>(decl)) {
if (auto* ftsi = FD->getTemplateSpecializationInfo()) {
if (!ftsi->isExplicitInstantiationOrSpecialization()) {
return ftsi->getTemplate();
return DereferenceMemberTemplates(ftsi->getTemplate(), use_mts);
}
}
} else if (const auto* ctsd =
Expand All @@ -61,10 +124,10 @@ const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl) {
if (const auto* partial =
primary_or_partial
.dyn_cast<clang::ClassTemplatePartialSpecializationDecl*>()) {
return partial;
return DereferenceMemberTemplates(partial, use_mts);
} else if (const auto* primary =
primary_or_partial.dyn_cast<clang::ClassTemplateDecl*>()) {
return primary;
return DereferenceMemberTemplates(primary, use_mts);
}
}
} else if (const auto* vtsd =
Expand All @@ -75,14 +138,14 @@ const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl) {
if (const auto* partial =
primary_or_partial
.dyn_cast<clang::VarTemplatePartialSpecializationDecl*>()) {
return partial;
return DereferenceMemberTemplates(partial, use_mts);
} else if (const auto* primary =
primary_or_partial.dyn_cast<clang::VarTemplateDecl*>()) {
return primary;
return DereferenceMemberTemplates(primary, use_mts);
}
}
}
return decl;
return DereferenceMemberTemplates(decl, use_mts);
}

bool ShouldHaveBlameContext(const clang::Decl* decl) {
Expand Down
12 changes: 11 additions & 1 deletion kythe/cxx/indexer/cxx/clang_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@ bool isObjCSelector(const clang::DeclarationName& DN);
/// \brief If `decl` is an implicit template instantiation or specialization,
/// returns the primary template or the partial specialization being
/// instantiated. Otherwise, returns `decl`.
const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl);
/// \param use_mts If true, also dereference member templates.
/// (This parameter is temporary and is used for the abs deprecation.)
const clang::Decl* FindSpecializedTemplate(const clang::Decl* decl,
bool use_mts);

/// \brief Finds the root member template starting at `decl` (which can be
/// any decl; if it's not a member template, returns `decl`).
/// \param use_mts If false, always return `decl`. (This parameter is temporary
/// and is used for the abs deprecation.)
const clang::Decl* DereferenceMemberTemplates(const clang::Decl* decl,
bool use_mts);

/// \return true if a reference to `decl` should be given blame context.
bool ShouldHaveBlameContext(const clang::Decl* decl);
Expand Down
20 changes: 20 additions & 0 deletions kythe/cxx/indexer/cxx/testdata/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2024,6 +2024,26 @@ cc_indexer_test(
tags = ["template"],
)

cc_indexer_test(
name = "template_alias_tvar_class",
srcs = ["template/template_alias_tvar_class.cc"],
check_for_singletons = True,
experimental_alias_template_instantiations = True,
experimental_use_abs_nodes = False,
ignore_dups = True,
tags = ["template"],
)

cc_indexer_test(
name = "template_alias_tvar_alias",
srcs = ["template/template_alias_tvar_alias.cc"],
check_for_singletons = True,
experimental_alias_template_instantiations = True,
experimental_use_abs_nodes = False,
ignore_dups = True,
tags = ["template"],
)

cc_indexer_test(
name = "template_arg_multiple_typename",
srcs = ["template/template_arg_multiple_typename.cc"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
template <typename T2>
class C {
public:
template <typename T>
//- @A defines/binding ADef
using A = T;
};

void g() {
//- @A ref ADef
C<int>::A<int> x;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
template <typename T2>
class C {
public:
template <typename T>
//- @S defines/binding SDef
struct S {};
};

void g() {
//- @S ref SDef
C<int>::S<int> s;
}

0 comments on commit a57e0fd

Please sign in to comment.