22#include "llvm/ADT/DenseSet.h"
23#include "llvm/Support/SaveAndRestore.h"
30class ForwardDeclChecker :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
32 mutable BugReporter *BR =
nullptr;
33 mutable RetainTypeChecker RTC;
34 mutable llvm::DenseSet<const Type *> SystemTypes;
38 : Bug(this,
"Forward declared member or local variable or parameter",
39 "WebKit coding guidelines") {}
41 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
42 BugReporter &BRArg)
const {
48 struct LocalVisitor :
public RecursiveASTVisitor<LocalVisitor> {
49 using Base = RecursiveASTVisitor<LocalVisitor>;
51 const ForwardDeclChecker *Checker;
52 Decl *DeclWithIssue{
nullptr};
54 explicit LocalVisitor(
const ForwardDeclChecker *Checker)
59 bool shouldVisitTemplateInstantiations()
const {
return true; }
60 bool shouldVisitImplicitCode()
const {
return false; }
62 bool VisitTypedefDecl(TypedefDecl *TD) {
63 Checker->visitTypedef(TD);
67 bool VisitRecordDecl(
const RecordDecl *RD) {
68 Checker->visitRecordDecl(RD, DeclWithIssue);
72 bool TraverseDecl(Decl *D) {
73 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
76 return Base::TraverseDecl(D);
79 bool VisitVarDecl(VarDecl *
V) {
80 if (
V->isLocalVarDecl())
81 Checker->visitVarDecl(
V, DeclWithIssue);
85 bool VisitCallExpr(
const CallExpr *CE) {
86 Checker->visitCallExpr(CE, DeclWithIssue);
90 bool VisitCXXConstructExpr(
const CXXConstructExpr *CE) {
91 Checker->visitConstructExpr(CE, DeclWithIssue);
95 bool VisitObjCMessageExpr(
const ObjCMessageExpr *ObjCMsgExpr) {
96 Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
101 LocalVisitor visitor(
this);
102 RTC.visitTranslationUnitDecl(TUD);
103 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
106 void visitTypedef(
const TypedefDecl *TD)
const {
107 RTC.visitTypedef(TD);
109 assert(BR &&
"expected nonnull BugReporter");
110 if (BR->getSourceManager().isInSystemHeader(TD->
getBeginLoc())) {
111 if (
auto *
Type = QT.getTypePtrOrNull())
112 SystemTypes.insert(
Type);
116 bool isUnknownType(QualType QT)
const {
124 auto *
R = PointeeType->getAsCXXRecordDecl();
127 auto Name =
R->getName();
128 if (
R->hasDefinition())
131 if (
auto *
Specialization = dyn_cast<ClassTemplateSpecializationDecl>(R)) {
133 for (S = S->getMostRecentDecl(); S; S = S->getPreviousDecl()) {
134 if (S->isThisDeclarationADefinition())
139 return !RTC.isUnretained(QT) && !SystemTypes.contains(CanonicalType) &&
140 !SystemTypes.contains(PointeeType) && !Name.starts_with(
"Opaque") &&
144 void visitRecordDecl(
const RecordDecl *RD,
const Decl *DeclWithIssue)
const {
152 if (!RDLocation.isValid())
156 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
159 assert(BR &&
"expected nonnull BugReporter");
160 if (BR->getSourceManager().isInSystemHeader(RDLocation))
165 auto R = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
170 auto QT =
Member->getType();
171 if (isUnknownType(QT)) {
172 SmallString<100> Buf;
173 llvm::raw_svector_ostream Os(Buf);
176 Os <<
"Member variable ";
178 Os <<
" uses a forward declared type '" <<
TypeName <<
"'";
180 const SourceLocation SrcLocToReport =
Member->getBeginLoc();
181 PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
182 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
184 Report->setDeclWithIssue(DeclWithIssue);
185 BR->emitReport(std::move(
Report));
190 void visitVarDecl(
const VarDecl *
V,
const Decl *DeclWithIssue)
const {
191 assert(BR &&
"expected nonnull BugReporter");
192 if (BR->getSourceManager().isInSystemHeader(
V->getBeginLoc()))
195 auto QT =
V->getType();
196 if (!isUnknownType(QT))
199 SmallString<100> Buf;
200 llvm::raw_svector_ostream Os(Buf);
201 Os <<
"Local variable ";
204 reportBug(
V->getBeginLoc(),
V->getSourceRange(), DeclWithIssue, Os.str(),
208 void visitCallExpr(
const CallExpr *CE,
const Decl *DeclWithIssue)
const {
209 assert(BR &&
"expected nonnull BugReporter");
210 if (BR->getSourceManager().isInSystemHeader(CE->
getExprLoc()))
218 for (
auto P = F->param_begin();
219 P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
220 visitCallArg(CE->
getArg(ArgIdx), *P, DeclWithIssue);
224 void visitConstructExpr(
const CXXConstructExpr *CE,
225 const Decl *DeclWithIssue)
const {
226 assert(BR &&
"expected nonnull BugReporter");
227 if (BR->getSourceManager().isInSystemHeader(CE->
getExprLoc()))
232 for (
auto P = F->param_begin();
233 P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
234 visitCallArg(CE->
getArg(ArgIdx), *P, DeclWithIssue);
238 void visitObjCMessageExpr(
const ObjCMessageExpr *E,
239 const Decl *DeclWithIssue)
const {
240 assert(BR &&
"expected nonnull BugReporter");
241 if (BR->getSourceManager().isInSystemHeader(E->
getExprLoc()))
245 Receiver = Receiver->IgnoreParenCasts();
247 reportUnknownReceiverType(Receiver, DeclWithIssue);
255 for (
unsigned i = 0; i < ArgCount && i < MethodDecl->param_size(); ++i)
256 visitCallArg(E->
getArg(i), MethodDecl->getParamDecl(i), DeclWithIssue);
259 void visitCallArg(
const Expr *Arg,
const ParmVarDecl *Param,
260 const Decl *DeclWithIssue)
const {
263 ArgExpr = ArgExpr->IgnoreParenCasts();
264 if (
auto *InnerCE = dyn_cast<CallExpr>(ArgExpr)) {
265 if (
auto *InnerCallee = InnerCE->getDirectCallee()) {
267 ArgExpr = InnerCE->getArg(0);
272 if (
auto *UO = dyn_cast<UnaryOperator>(ArgExpr)) {
273 auto OpCode = UO->getOpcode();
274 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
275 ArgExpr = UO->getSubExpr();
282 if (
auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(ArgExpr)) {
287 if (
auto *OpCE = dyn_cast<CXXOperatorCallExpr>(ArgExpr)) {
288 auto *
Method = dyn_cast_or_null<CXXMethodDecl>(OpCE->getDirectCallee());
290 if (OpCE->getOperator() == OO_Star && OpCE->getNumArgs() == 1)
299 if (
auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {
300 if (
auto *ValDecl = DRE->getDecl()) {
306 QualType ArgType = Param->
getType();
307 if (!isUnknownType(ArgType))
310 reportUnknownArgType(Arg, Param, DeclWithIssue);
313 void reportUnknownArgType(
const Expr *CA,
const ParmVarDecl *Param,
314 const Decl *DeclWithIssue)
const {
317 SmallString<100> Buf;
318 llvm::raw_svector_ostream Os(Buf);
321 Os <<
"Call argument";
322 if (!paramName.empty()) {
323 Os <<
" for parameter ";
331 void reportUnknownReceiverType(
const Expr *Receiver,
332 const Decl *DeclWithIssue)
const {
335 "Receiver", Receiver->
getType());
338 void reportBug(
const SourceLocation &SrcLoc,
const SourceRange &SrcRange,
339 const Decl *DeclWithIssue,
const StringRef &Description,
340 QualType
Type)
const {
341 SmallString<100> Buf;
342 llvm::raw_svector_ostream Os(Buf);
345 Os << Description <<
" uses a forward declared type '" <<
TypeName <<
"'";
347 assert(BR &&
"expected nonnull BugReporter");
348 PathDiagnosticLocation BSLoc(SrcLoc, BR->getSourceManager());
349 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
350 Report->addRange(SrcRange);
351 Report->setDeclWithIssue(DeclWithIssue);
352 BR->emitReport(std::move(
Report));
362bool ento::shouldRegisterForwardDeclChecker(
const CheckerManager &) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
const ObjCMethodDecl * getMethodDecl() const
QualType getReceiverType() const
Retrieve the receiver type to which this message is being directed.
unsigned getNumArgs() const
Return the number of actual arguments in this message, not counting the receiver.
QualType getCanonicalType() const
const Type * getTypePtrOrNull() const
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
bool isLambda() const
Determine whether this record is a class describing a lambda function object.
field_range fields() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isThisDeclarationADefinition() const
Return true if this declaration is a completion definition of the type.
TagKind getTagKind() const
SourceLocation getBeginLoc() const LLVM_READONLY
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
QualType getUnderlyingType() const
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.
bool isa(CodeGen::Address addr)
@ Specialization
We are substituting template parameters for template arguments in order to form a template specializa...
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
void printQuotedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
bool isOwnerPtr(const std::string &Name)
bool isRefCounted(const CXXRecordDecl *R)
bool isOwnerPtrType(const clang::QualType T)
bool isRetainPtrOrOSPtr(const std::string &Name)
std::string safeGetName(const T *ASTNode)
bool isNullPtr(const clang::Expr *E)
bool isCheckedPtr(const std::string &Name)
bool isStdOrWTFMove(const clang::FunctionDecl *F)