Skip to content
Open
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
43 changes: 43 additions & 0 deletions clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1040,5 +1040,48 @@ bool isExpandedFromParameterPack(const ParmVarDecl *D) {
return getUnderlyingPackType(D) != nullptr;
}

bool isLikelyForwardingFunction(FunctionTemplateDecl *FT) {
const auto *FD = FT->getTemplatedDecl();
const auto NumParams = FD->getNumParams();
// Check whether its last parameter is a parameter pack...
if (NumParams > 0) {
const auto *LastParam = FD->getParamDecl(NumParams - 1);
if (const auto *PET = dyn_cast<PackExpansionType>(LastParam->getType())) {
// ... of the type T&&... or T...
const auto BaseType = PET->getPattern().getNonReferenceType();
if (const auto *TTPT =
dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {
// ... whose template parameter comes from the function directly
if (FT->getTemplateParameters()->getDepth() == TTPT->getDepth()) {
return true;
}
}
}
}
return false;
}

bool ForwardingToConstructorVisitor::VisitCallExpr(CallExpr *E) {
if (auto *FD = E->getDirectCallee()) {
if (auto *PT = FD->getPrimaryTemplate();
PT && isLikelyForwardingFunction(PT)) {
ForwardingToConstructorVisitor Visitor{};
Visitor.TraverseStmt(FD->getBody());
std::move(Visitor.Constructors.begin(), Visitor.Constructors.end(),
std::back_inserter(Constructors));
}
}
return true;
}

bool ForwardingToConstructorVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
if (auto *CE = E->getConstructExpr()) {
if (auto *Callee = CE->getConstructor()) {
Constructors.push_back(Callee);
}
}
return true;
}

} // namespace clangd
} // namespace clang
18 changes: 18 additions & 0 deletions clang-tools-extra/clangd/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/MacroInfo.h"
Expand Down Expand Up @@ -253,6 +254,23 @@ resolveForwardingParameters(const FunctionDecl *D, unsigned MaxDepth = 10);
/// reference to one (e.g. `Args&...` or `Args&&...`).
bool isExpandedFromParameterPack(const ParmVarDecl *D);

/// Heuristic that checks if FT is forwarding a parameter pack to another
/// function (e.g. `make_unique`).
bool isLikelyForwardingFunction(FunctionTemplateDecl *FT);

class ForwardingToConstructorVisitor
: public RecursiveASTVisitor<ForwardingToConstructorVisitor> {
public:
ForwardingToConstructorVisitor() {}

bool VisitCallExpr(CallExpr *E);

bool VisitCXXNewExpr(CXXNewExpr *E);

// Output of this visitor
std::vector<CXXConstructorDecl *> Constructors{};
};

} // namespace clangd
} // namespace clang

Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ParsedAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ class ParsedAST {
return Resolver.get();
}

/// Cache for constructors called through forwarding, e.g. make_unique
llvm::DenseMap<const FunctionDecl *, std::vector<CXXConstructorDecl *>>
ForwardingToConstructorCache;

private:
ParsedAST(PathRef TUPath, llvm::StringRef Version,
std::shared_ptr<const PreambleData> Preamble,
Expand Down
22 changes: 1 addition & 21 deletions clang-tools-extra/clangd/Preamble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Preamble.h"
#include "AST.h"
#include "CollectMacros.h"
#include "Compiler.h"
#include "Config.h"
Expand Down Expand Up @@ -166,27 +167,6 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
collectPragmaMarksCallback(*SourceMgr, Marks));
}

static bool isLikelyForwardingFunction(FunctionTemplateDecl *FT) {
const auto *FD = FT->getTemplatedDecl();
const auto NumParams = FD->getNumParams();
// Check whether its last parameter is a parameter pack...
if (NumParams > 0) {
const auto *LastParam = FD->getParamDecl(NumParams - 1);
if (const auto *PET = dyn_cast<PackExpansionType>(LastParam->getType())) {
// ... of the type T&&... or T...
const auto BaseType = PET->getPattern().getNonReferenceType();
if (const auto *TTPT =
dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) {
// ... whose template parameter comes from the function directly
if (FT->getTemplateParameters()->getDepth() == TTPT->getDepth()) {
return true;
}
}
}
}
return false;
}

bool shouldSkipFunctionBody(Decl *D) override {
// Usually we don't need to look inside the bodies of header functions
// to understand the program. However when forwarding function like
Expand Down
52 changes: 48 additions & 4 deletions clang-tools-extra/clangd/XRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,12 +929,16 @@ class ReferenceFinder : public index::IndexDataConsumer {
}
};

ReferenceFinder(const ParsedAST &AST,
ReferenceFinder(ParsedAST &AST,
const llvm::ArrayRef<const NamedDecl *> Targets,
bool PerToken)
: PerToken(PerToken), AST(AST) {
for (const NamedDecl *ND : Targets)
for (const NamedDecl *ND : Targets) {
TargetDecls.insert(ND->getCanonicalDecl());
if (auto *Constructor = llvm::dyn_cast<clang::CXXConstructorDecl>(ND)) {
TargetConstructors.insert(Constructor);
}
}
}

std::vector<Reference> take() && {
Expand All @@ -955,13 +959,51 @@ class ReferenceFinder : public index::IndexDataConsumer {
return std::move(References);
}

bool forwardsToConstructor(const Decl *D) {
if (TargetConstructors.empty()) {
return false;
}
auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
if (FD == nullptr || !FD->isTemplateInstantiation()) {
return false;
}
if (auto *PT = FD->getPrimaryTemplate();
PT == nullptr || !isLikelyForwardingFunction(PT)) {
return false;
}
std::vector<CXXConstructorDecl *> *Constructors = nullptr;
if (auto Entry = AST.ForwardingToConstructorCache.find(FD);
Entry != AST.ForwardingToConstructorCache.end()) {
Constructors = &Entry->getSecond();
}
if (Constructors == nullptr) {
ForwardingToConstructorVisitor Visitor{};
Visitor.TraverseStmt(FD->getBody());
auto Iter = AST.ForwardingToConstructorCache.try_emplace(
FD, std::move(Visitor.Constructors));
if (Iter.second) {
Constructors = &Iter.first->getSecond();
}
}
if (Constructors != nullptr) {
for (auto *Constructor : *Constructors) {
if (TargetConstructors.contains(Constructor)) {
return true;
}
}
}
return false;
}

bool
handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,
llvm::ArrayRef<index::SymbolRelation> Relations,
SourceLocation Loc,
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
if (!TargetDecls.contains(D->getCanonicalDecl()))
if (!TargetDecls.contains(D->getCanonicalDecl()) &&
!forwardsToConstructor(ASTNode.OrigD)) {
return true;
}
const SourceManager &SM = AST.getSourceManager();
if (!isInsideMainFile(Loc, SM))
return true;
Expand Down Expand Up @@ -1000,8 +1042,10 @@ class ReferenceFinder : public index::IndexDataConsumer {
private:
bool PerToken; // If true, report 3 references for split ObjC selector names.
std::vector<Reference> References;
const ParsedAST &AST;
ParsedAST &AST;
llvm::DenseSet<const Decl *> TargetDecls;
// Constructors need special handling since they can be hidden behind forwards
llvm::DenseSet<const CXXConstructorDecl *> TargetConstructors;
};

std::vector<ReferenceFinder::Reference>
Expand Down
42 changes: 40 additions & 2 deletions clang-tools-extra/clangd/index/SymbolCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "index/SymbolLocation.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
Expand All @@ -51,6 +52,7 @@
#include <optional>
#include <string>
#include <utility>
#include <vector>

namespace clang {
namespace clangd {
Expand Down Expand Up @@ -576,6 +578,30 @@ SymbolCollector::getRefContainer(const Decl *Enclosing,
return Enclosing;
}

std::vector<CXXConstructorDecl *>
SymbolCollector::findIndirectConstructors(const Decl *D) {
auto *FD = llvm::dyn_cast<clang::FunctionDecl>(D);
if (FD == nullptr || !FD->isTemplateInstantiation()) {
return {};
}
if (auto *PT = FD->getPrimaryTemplate();
PT == nullptr || !isLikelyForwardingFunction(PT)) {
return {};
}
if (auto Entry = ForwardingToConstructorCache.find(FD);
Entry != ForwardingToConstructorCache.end()) {
return Entry->getSecond();
}
ForwardingToConstructorVisitor Visitor{};
Visitor.TraverseStmt(FD->getBody());
auto Iter = ForwardingToConstructorCache.try_emplace(
FD, std::move(Visitor.Constructors));
if (Iter.second) {
return Iter.first->getSecond();
}
return {};
}

// Always return true to continue indexing.
bool SymbolCollector::handleDeclOccurrence(
const Decl *D, index::SymbolRoleSet Roles,
Expand Down Expand Up @@ -666,9 +692,21 @@ bool SymbolCollector::handleDeclOccurrence(
auto FileLoc = SM.getFileLoc(Loc);
auto FID = SM.getFileID(FileLoc);
if (Opts.RefsInHeaders || FID == SM.getMainFileID()) {
auto *Container = getRefContainer(ASTNode.Parent, Opts);
addRef(ID, SymbolRef{FileLoc, FID, Roles, index::getSymbolInfo(ND).Kind,
getRefContainer(ASTNode.Parent, Opts),
isSpelled(FileLoc, *ND)});
Container, isSpelled(FileLoc, *ND)});
// Also collect indirect constructor calls like `make_unique`
for (auto *Constructor : findIndirectConstructors(ASTNode.OrigD)) {
if (!shouldCollectSymbol(*Constructor, *ASTCtx, Opts, IsMainFileOnly)) {
continue;
}
if (auto ConstructorID = getSymbolIDCached(Constructor)) {
addRef(ConstructorID,
SymbolRef{FileLoc, FID, Roles,
index::getSymbolInfo(Constructor).Kind, Container,
isSpelled(FileLoc, *Constructor)});
}
}
}
}
// Don't continue indexing if this is a mere reference.
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/index/SymbolCollector.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ class SymbolCollector : public index::IndexDataConsumer {
void finish() override;

private:
std::vector<CXXConstructorDecl *> findIndirectConstructors(const Decl *D);

const Symbol *addDeclaration(const NamedDecl &, SymbolID,
bool IsMainFileSymbol);
void addDefinition(const NamedDecl &, const Symbol &DeclSymbol,
Expand Down Expand Up @@ -230,6 +232,8 @@ class SymbolCollector : public index::IndexDataConsumer {
std::unique_ptr<HeaderFileURICache> HeaderFileURIs;
llvm::DenseMap<const Decl *, SymbolID> DeclToIDCache;
llvm::DenseMap<const MacroInfo *, SymbolID> MacroToIDCache;
llvm::DenseMap<const FunctionDecl *, std::vector<CXXConstructorDecl *>>
ForwardingToConstructorCache;
};

} // namespace clangd
Expand Down
Loading
Loading