Skip to content

Commit 09f0acb

Browse files
committed
wip
1 parent 4adc600 commit 09f0acb

19 files changed

+416
-135
lines changed

clang-tools-extra/clangd/AST.cpp

Lines changed: 194 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#include "clang/AST/DeclCXX.h"
1717
#include "clang/AST/DeclObjC.h"
1818
#include "clang/AST/DeclTemplate.h"
19+
#include "clang/AST/DeclVisitor.h"
1920
#include "clang/AST/DeclarationName.h"
2021
#include "clang/AST/ExprCXX.h"
2122
#include "clang/AST/NestedNameSpecifier.h"
2223
#include "clang/AST/PrettyPrinter.h"
2324
#include "clang/AST/RecursiveASTVisitor.h"
2425
#include "clang/AST/Stmt.h"
26+
#include "clang/AST/StmtVisitor.h"
2527
#include "clang/AST/TemplateBase.h"
2628
#include "clang/AST/TypeLoc.h"
2729
#include "clang/Basic/Builtins.h"
@@ -636,7 +638,7 @@ static NamedDecl *getOnlyInstantiationImpl(TemplateDeclTy *TD) {
636638
return Only;
637639
}
638640

639-
NamedDecl *getOnlyInstantiation(NamedDecl *TemplatedDecl) {
641+
NamedDecl *getOnlyInstantiation(const NamedDecl *TemplatedDecl) {
640642
if (TemplateDecl *TD = TemplatedDecl->getDescribedTemplate()) {
641643
if (auto *CTD = llvm::dyn_cast<ClassTemplateDecl>(TD))
642644
return getOnlyInstantiationImpl(CTD);
@@ -648,6 +650,197 @@ NamedDecl *getOnlyInstantiation(NamedDecl *TemplatedDecl) {
648650
return nullptr;
649651
}
650652

653+
NamedDecl *getOnlyInstantiatedDecls(const NamedDecl *DependentDecl) {
654+
if (auto *Instantiation = getOnlyInstantiation(DependentDecl))
655+
return Instantiation;
656+
NamedDecl *OuterTemplate = nullptr;
657+
for (auto *DC = DependentDecl->getDeclContext(); isa<CXXRecordDecl>(DC);
658+
DC = DC->getParent()) {
659+
auto *RD = cast<CXXRecordDecl>(DC);
660+
if (auto *I = getOnlyInstantiation(RD)) {
661+
OuterTemplate = I;
662+
break;
663+
}
664+
}
665+
666+
if (!OuterTemplate)
667+
return nullptr;
668+
669+
struct Visitor : DeclVisitor<Visitor, NamedDecl *> {
670+
const NamedDecl *TemplatedDecl;
671+
Visitor(const NamedDecl *TemplatedDecl) : TemplatedDecl(TemplatedDecl) {}
672+
673+
NamedDecl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
674+
if (RD->getTemplateInstantiationPattern() == TemplatedDecl)
675+
return RD;
676+
for (auto *F : RD->decls()) {
677+
if (auto *Injected = llvm::dyn_cast<CXXRecordDecl>(F);
678+
Injected && Injected->isInjectedClassName())
679+
continue;
680+
if (NamedDecl *ND = Visit(F))
681+
return ND;
682+
}
683+
return nullptr;
684+
}
685+
686+
NamedDecl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
687+
unsigned Size = llvm::range_size(CTD->specializations());
688+
if (Size != 1)
689+
return nullptr;
690+
return Visit(*CTD->spec_begin());
691+
}
692+
693+
NamedDecl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
694+
unsigned Size = llvm::range_size(FTD->specializations());
695+
if (Size != 1)
696+
return nullptr;
697+
return Visit(*FTD->spec_begin());
698+
}
699+
700+
NamedDecl *VisitFunctionDecl(FunctionDecl *FD) {
701+
if (FD->getTemplateInstantiationPattern() == TemplatedDecl)
702+
return FD;
703+
return nullptr;
704+
}
705+
706+
NamedDecl *VisitVarDecl(VarDecl *VD) {
707+
if (VD->getCanonicalDecl()->getSourceRange() ==
708+
TemplatedDecl->getCanonicalDecl()->getSourceRange())
709+
return VD;
710+
return nullptr;
711+
}
712+
713+
NamedDecl *VisitFieldDecl(FieldDecl *FD) {
714+
if (FD->getCanonicalDecl()->getSourceRange() ==
715+
TemplatedDecl->getCanonicalDecl()->getSourceRange())
716+
return FD;
717+
return nullptr;
718+
}
719+
};
720+
return Visitor(DependentDecl).Visit(OuterTemplate);
721+
}
722+
723+
std::optional<DynTypedNode>
724+
getOnlyInstantiatedNode(const DeclContext *StartingPoint,
725+
const DynTypedNode &DependentNode) {
726+
if (auto *CTD = DependentNode.get<ClassTemplateDecl>())
727+
return getOnlyInstantiatedNode(
728+
StartingPoint, DynTypedNode::create(*CTD->getTemplatedDecl()));
729+
if (auto *FTD = DependentNode.get<FunctionTemplateDecl>())
730+
return getOnlyInstantiatedNode(
731+
StartingPoint, DynTypedNode::create(*FTD->getTemplatedDecl()));
732+
733+
if (auto *FD = DependentNode.get<FunctionDecl>()) {
734+
auto *ID = getOnlyInstantiatedDecls(FD);
735+
if (!ID)
736+
return std::nullopt;
737+
return DynTypedNode::create(*ID);
738+
}
739+
if (auto *RD = DependentNode.get<CXXRecordDecl>()) {
740+
auto *ID = getOnlyInstantiatedDecls(RD);
741+
if (!ID)
742+
return std::nullopt;
743+
return DynTypedNode::create(*ID);
744+
}
745+
746+
NamedDecl *InstantiatedEnclosingDecl = nullptr;
747+
for (auto *DC = StartingPoint; DC;
748+
DC = DC->getParent()) {
749+
auto *ND = llvm::dyn_cast<NamedDecl>(DC);
750+
if (!ND)
751+
continue;
752+
InstantiatedEnclosingDecl = getOnlyInstantiatedDecls(ND);
753+
if (InstantiatedEnclosingDecl)
754+
break;
755+
}
756+
757+
if (!InstantiatedEnclosingDecl)
758+
return std::nullopt;
759+
760+
auto *InstantiatedFunctionDecl =
761+
llvm::dyn_cast<FunctionDecl>(InstantiatedEnclosingDecl);
762+
if (!InstantiatedFunctionDecl)
763+
return std::nullopt;
764+
765+
struct FullExprVisitor : RecursiveASTVisitor<FullExprVisitor> {
766+
const DynTypedNode &DependentNode;
767+
Stmt *Result;
768+
FullExprVisitor(const DynTypedNode &DependentNode)
769+
: DependentNode(DependentNode), Result(nullptr) {}
770+
771+
bool shouldVisitTemplateInstantiations() const { return true; }
772+
773+
bool shouldVisitImplicitCode() const { return true; }
774+
775+
bool VisitStmt(Stmt *S) {
776+
if (S->getSourceRange() == DependentNode.getSourceRange()) {
777+
Result = S;
778+
return false;
779+
}
780+
return true;
781+
}
782+
};
783+
784+
FullExprVisitor Visitor(DependentNode);
785+
Visitor.TraverseFunctionDecl(InstantiatedFunctionDecl);
786+
if (Visitor.Result)
787+
return DynTypedNode::create(*Visitor.Result);
788+
return std::nullopt;
789+
}
790+
791+
NamedDecl *
792+
getOnlyInstantiationForMemberFunction(const CXXMethodDecl *TemplatedDecl) {
793+
if (auto *MemberInstantiation = getOnlyInstantiation(TemplatedDecl))
794+
return MemberInstantiation;
795+
NamedDecl *OuterTemplate = nullptr;
796+
for (auto *DC = TemplatedDecl->getDeclContext(); isa<CXXRecordDecl>(DC);
797+
DC = DC->getParent()) {
798+
auto *RD = cast<CXXRecordDecl>(DC);
799+
if (auto *I = getOnlyInstantiation(RD)) {
800+
OuterTemplate = I;
801+
break;
802+
}
803+
}
804+
if (!OuterTemplate)
805+
return nullptr;
806+
struct Visitor : DeclVisitor<Visitor, NamedDecl *> {
807+
const CXXMethodDecl *TD;
808+
Visitor(const CXXMethodDecl *TemplatedDecl) : TD(TemplatedDecl) {}
809+
NamedDecl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
810+
for (auto *F : RD->decls()) {
811+
if (!isa<NamedDecl>(F))
812+
continue;
813+
if (NamedDecl *ND = Visit(F))
814+
return ND;
815+
}
816+
return nullptr;
817+
}
818+
819+
NamedDecl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
820+
unsigned Size = llvm::range_size(CTD->specializations());
821+
if (Size != 1)
822+
return nullptr;
823+
return Visit(*CTD->spec_begin());
824+
}
825+
826+
NamedDecl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
827+
unsigned Size = llvm::range_size(FTD->specializations());
828+
if (Size != 1)
829+
return nullptr;
830+
return Visit(*FTD->spec_begin());
831+
}
832+
833+
NamedDecl *VisitCXXMethodDecl(CXXMethodDecl *MD) {
834+
auto *Pattern = MD->getTemplateInstantiationPattern();
835+
if (Pattern == TD)
836+
return MD;
837+
return nullptr;
838+
}
839+
840+
};
841+
return Visitor(TemplatedDecl).Visit(OuterTemplate);
842+
}
843+
651844
std::vector<const Attr *> getAttributes(const DynTypedNode &N) {
652845
std::vector<const Attr *> Result;
653846
if (const auto *TL = N.get<TypeLoc>()) {

clang-tools-extra/clangd/AST.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,14 @@ TemplateTypeParmTypeLoc getContainedAutoParamType(TypeLoc TL);
177177

178178
// If TemplatedDecl is the generic body of a template, and the template has
179179
// exactly one visible instantiation, return the instantiated body.
180-
NamedDecl *getOnlyInstantiation(NamedDecl *TemplatedDecl);
180+
NamedDecl *getOnlyInstantiation(const NamedDecl *TemplatedDecl);
181+
182+
NamedDecl *
183+
getOnlyInstantiationForMemberFunction(const CXXMethodDecl *TemplatedDecl);
184+
185+
std::optional<DynTypedNode>
186+
getOnlyInstantiatedNode(const DeclContext *StartingPoint,
187+
const DynTypedNode &DependentNode);
181188

182189
/// Return attributes attached directly to a node.
183190
std::vector<const Attr *> getAttributes(const DynTypedNode &);

0 commit comments

Comments
 (0)