10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Analysis/CallGraph.h"
13#include "llvm/ADT/SCCIterator.h"
30 const llvm::SmallPtrSet<CallGraphNode *, SmallSCCSize> SCCElts(
31 llvm::from_range, SCC);
34 auto NodeIsPartOfSCC = [&SCCElts](CallGraphNode *N) {
35 return SCCElts.contains(N);
39 llvm::SmallSetVector<CallGraphNode::CallRecord, SmallCallStackSize>
43 CallGraphNode::CallRecord EntryNode(SCC.front(),
nullptr);
46 CallGraphNode::CallRecord *Node = &EntryNode;
49 if (!CallStackSet.insert(*Node))
53 Node = llvm::find_if(Node->Callee->callees(), NodeIsPartOfSCC);
59 CallStack.emplace_back(*Node);
65 Finder->addMatcher(translationUnitDecl().bind(
"TUDecl"),
this);
68void NoRecursionCheck::handleSCC(ArrayRef<CallGraphNode *> SCC) {
69 assert(!SCC.empty() &&
"Empty SCC does not make sense.");
72 for (
const CallGraphNode *N : SCC) {
73 const FunctionDecl *D = N->getDefinition();
74 diag(D->getLocation(),
"function %0 is within a recursive call chain") << D;
82 assert(!EventuallyCyclicCallStack.empty() &&
"We should've found the cycle");
87 const auto CyclicCallStack =
88 ArrayRef<CallGraphNode::CallRecord>(EventuallyCyclicCallStack)
89 .drop_until([LastNode = EventuallyCyclicCallStack.back()](
90 CallGraphNode::CallRecord FrontNode) {
91 return FrontNode == LastNode;
93 assert(CyclicCallStack.size() >= 2 &&
"Cycle requires at least 2 frames");
96 const FunctionDecl *CycleEntryFn =
97 CyclicCallStack.front().Callee->getDefinition();
100 diag(CycleEntryFn->getLocation(),
101 "example recursive call chain, starting from function %0",
104 for (
int CurFrame = 1, NumFrames = CyclicCallStack.size();
105 CurFrame != NumFrames; ++CurFrame) {
106 const CallGraphNode::CallRecord PrevNode = CyclicCallStack[CurFrame - 1];
107 const CallGraphNode::CallRecord CurrNode = CyclicCallStack[CurFrame];
109 Decl *PrevDecl = PrevNode.Callee->getDecl();
110 Decl *CurrDecl = CurrNode.Callee->getDecl();
112 diag(CurrNode.CallExpr->getBeginLoc(),
113 "Frame #%0: function %1 calls function %2 here:", DiagnosticIDs::Note)
114 << CurFrame << cast<NamedDecl>(PrevDecl) << cast<NamedDecl>(CurrDecl);
117 diag(CyclicCallStack.back().CallExpr->getBeginLoc(),
118 "... which was the starting point of the recursive call chain; there "
119 "may be other cycles",
120 DiagnosticIDs::Note);
125 const auto *TU = Result.Nodes.getNodeAs<TranslationUnitDecl>(
"TUDecl");
127 CG.addToCallGraph(
const_cast<TranslationUnitDecl *
>(TU));
131 for (llvm::scc_iterator<CallGraph *> SCCI = llvm::scc_begin(&CG),
132 SCCE = llvm::scc_end(&CG);
133 SCCI != SCCE; ++SCCI) {
134 if (!SCCI.hasCycle())
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
static constexpr unsigned SmallSCCSize
SmallVector< CallGraphNode::CallRecord, SmallCallStackSize > CallStackTy
static constexpr unsigned SmallCallStackSize
static CallStackTy pathfindSomeCycle(ArrayRef< CallGraphNode * > SCC)