28class NoDeleteChecker :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
30 mutable BugReporter *BR =
nullptr;
31 mutable TrivialFunctionAnalysis TFA;
36 "Incorrect [[clang::annotate_type(\"webkit.nodelete\")]] "
38 "WebKit coding guidelines") {}
40 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
41 BugReporter &BRArg)
const {
48 const NoDeleteChecker *Checker;
49 Decl *DeclWithIssue{
nullptr};
51 explicit LocalVisitor(
const NoDeleteChecker *Checker) : Checker(Checker) {
53 ShouldVisitTemplateInstantiations =
true;
54 ShouldWalkTypesOfTypeLocs =
true;
55 ShouldVisitImplicitCode =
false;
56 ShouldVisitLambdaBody =
true;
59 bool VisitFunctionDecl(
const FunctionDecl *FD)
override {
60 Checker->visitFunctionDecl(FD);
65 LocalVisitor visitor(
this);
66 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
69 void visitFunctionDecl(
const FunctionDecl *FD)
const {
80 NamedDecl *ParamDecl =
nullptr;
82 if (!TFA.hasTrivialDtor(D)) {
88 const FieldDecl *
Field =
nullptr;
89 const Stmt *OffendingInit =
nullptr;
92 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
94 Field = TFA.fieldWithNonTrivialCtor(Ctor->getParent());
96 for (
auto *CtorInit : Ctor->inits()) {
97 auto *
Init = CtorInit->getInit();
98 if (!TFA.isTrivial(
Init)) {
104 }
else if (
auto *Dtor = dyn_cast<CXXDestructorDecl>(FD)) {
106 Field = TFA.fieldWithNonTrivialDtor(
Dtor->getParent());
109 if (!ParamDecl && !Field && !OffendingInit && TFA.isTrivial(Body))
112 SmallString<100> Buf;
113 llvm::raw_svector_ostream Os(Buf);
116 Os <<
"A constructor ";
118 Os <<
"A destructor ";
123 Os <<
" has [[clang::annotate_type(\"webkit.nodelete\")]] but it ";
126 else if (IsDtor && Field)
130 SourceLocation SrcLocToReport;
132 NonTrivialityReason Reason;
134 Os <<
"a parameter ";
136 Os <<
" which could destruct an object.";
139 }
else if (Field && !OffendingInit) {
140 Os <<
"a member variable ";
142 Os <<
" that could destruct an object.";
147 OffendingInit ? OffendingInit : Body);
148 Os <<
"code that could destruct an object.";
154 PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
155 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
157 Report->setDeclWithIssue(FD);
158 addCallStackNotes(*
Report, Reason);
159 BR->emitReport(std::move(
Report));
162 static const FunctionDecl *getDirectCallee(
const Stmt *S) {
163 if (
const auto *CE = dyn_cast_or_null<CallExpr>(S))
164 return CE->getDirectCallee();
165 if (
const auto *CE = dyn_cast_or_null<CXXConstructExpr>(S))
166 return CE->getConstructor();
174 void addCallStackNotes(BasicBugReport &
Report,
175 const NonTrivialityReason &Reason)
const {
176 ArrayRef<NonTrivialityReason::Frame> CallStack = Reason.
CallStack;
177 if (CallStack.empty())
183 const auto &
First = CallStack.front();
185 if (CallStack.size() == 1 && !
First.OffendingStmt && Callee &&
186 Callee->getCanonicalDecl() ==
First.Callee->getCanonicalDecl())
189 for (
size_t I = 0; I < CallStack.size(); ++I) {
190 const FunctionDecl *
Fn = CallStack[I].Callee;
191 const Stmt *Offender = CallStack[I].OffendingStmt;
193 if (!Offender && !
Fn->getLocation().isValid())
196 SmallString<100> Buf;
197 llvm::raw_svector_ostream Os(Buf);
201 if (I + 1 < CallStack.size()) {
204 }
else if (
Fn->doesThisDeclarationHaveABody()) {
205 Os <<
"Could destruct an object";
208 Os <<
" has no visible definition here, so it is assumed to destruct "
209 "an object. Annotate it with "
210 "[[clang::annotate_type(\"webkit.nodelete\")]] if it does not.";
218 Os.str(), PathDiagnosticLocation(Loc, BR->getSourceManager()), Range);
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::SourceLocation class and associated facilities.
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
SourceLocation getBeginLoc() const LLVM_READONLY
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
ArrayRef< ParmVarDecl * > parameters() const
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
static NonTrivialityReason computeReason(const Stmt *S)
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Top level wrappers for InstallAPI frontend operations.
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
DynamicRecursiveASTVisitorBase< true > ConstDynamicRecursiveASTVisitor
bool isNoDeleteFunction(const FunctionDecl *F)
const Stmt * OffendingStmt
The innermost non-trivial statement inside the analyzed function's own body.
llvm::SmallVector< Frame > CallStack
The callees that could not be proven free of destruction, outermost first: the first frame is called ...