21#include "llvm/ADT/DenseSet.h"
22#include "llvm/Support/SaveAndRestore.h"
29class ForwardDeclChecker :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
31 mutable BugReporter *BR =
nullptr;
32 mutable RetainTypeChecker RTC;
33 mutable llvm::DenseSet<const Type *> SystemTypes;
37 : Bug(this,
"Forward declared member or local variable or parameter",
38 "WebKit coding guidelines") {}
40 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
41 BugReporter &BRArg)
const {
47 struct LocalVisitor :
public RecursiveASTVisitor<LocalVisitor> {
48 using Base = RecursiveASTVisitor<LocalVisitor>;
50 const ForwardDeclChecker *Checker;
51 Decl *DeclWithIssue{
nullptr};
53 explicit LocalVisitor(
const ForwardDeclChecker *Checker)
58 bool shouldVisitTemplateInstantiations()
const {
return true; }
59 bool shouldVisitImplicitCode()
const {
return false; }
61 bool VisitTypedefDecl(TypedefDecl *TD) {
62 Checker->visitTypedef(TD);
66 bool VisitRecordDecl(
const RecordDecl *RD) {
67 Checker->visitRecordDecl(RD, DeclWithIssue);
71 bool TraverseDecl(Decl *D) {
72 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
75 return Base::TraverseDecl(D);
78 bool VisitVarDecl(VarDecl *
V) {
79 if (
V->isLocalVarDecl())
80 Checker->visitVarDecl(
V, DeclWithIssue);
84 bool VisitCallExpr(
const CallExpr *CE) {
85 Checker->visitCallExpr(CE, DeclWithIssue);
89 bool VisitCXXConstructExpr(
const CXXConstructExpr *CE) {
90 Checker->visitConstructExpr(CE, DeclWithIssue);
94 bool VisitObjCMessageExpr(
const ObjCMessageExpr *ObjCMsgExpr) {
95 Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
100 LocalVisitor visitor(
this);
101 RTC.visitTranslationUnitDecl(TUD);
102 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
105 void visitTypedef(
const TypedefDecl *TD)
const {
106 RTC.visitTypedef(TD);
108 assert(BR &&
"expected nonnull BugReporter");
109 if (BR->getSourceManager().isInSystemHeader(TD->
getBeginLoc())) {
110 if (
auto *
Type = QT.getTypePtrOrNull())
111 SystemTypes.insert(
Type);
115 bool isUnknownType(QualType QT)
const {
123 auto *
R = PointeeType->getAsCXXRecordDecl();
126 auto Name =
R->getName();
127 if (
R->hasDefinition())
130 if (
auto *
Specialization = dyn_cast<ClassTemplateSpecializationDecl>(R)) {
132 for (S = S->getMostRecentDecl(); S; S = S->getPreviousDecl()) {
133 if (S->isThisDeclarationADefinition())
138 return !RTC.isUnretained(QT) && !SystemTypes.contains(CanonicalType) &&
139 !SystemTypes.contains(PointeeType) && !Name.starts_with(
"Opaque") &&
143 void visitRecordDecl(
const RecordDecl *RD,
const Decl *DeclWithIssue)
const {
151 if (!RDLocation.isValid())
155 if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
158 assert(BR &&
"expected nonnull BugReporter");
159 if (BR->getSourceManager().isInSystemHeader(RDLocation))
164 auto R = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
169 auto QT =
Member->getType();
170 if (isUnknownType(QT)) {
171 SmallString<100> Buf;
172 llvm::raw_svector_ostream Os(Buf);
175 Os <<
"Member variable ";
177 Os <<
" uses a forward declared type '" <<
TypeName <<
"'";
179 const SourceLocation SrcLocToReport =
Member->getBeginLoc();
180 PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
181 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
183 Report->setDeclWithIssue(DeclWithIssue);
184 BR->emitReport(std::move(
Report));
189 void visitVarDecl(
const VarDecl *
V,
const Decl *DeclWithIssue)
const {
190 assert(BR &&
"expected nonnull BugReporter");
191 if (BR->getSourceManager().isInSystemHeader(
V->getBeginLoc()))
194 auto QT =
V->getType();
195 if (!isUnknownType(QT))
198 SmallString<100> Buf;
199 llvm::raw_svector_ostream Os(Buf);
200 Os <<
"Local variable ";
203 reportBug(
V->getBeginLoc(),
V->getSourceRange(), DeclWithIssue, Os.str(),
207 void visitCallExpr(
const CallExpr *CE,
const Decl *DeclWithIssue)
const {
208 assert(BR &&
"expected nonnull BugReporter");
209 if (BR->getSourceManager().isInSystemHeader(CE->
getExprLoc()))
217 for (
auto P = F->param_begin();
218 P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
219 visitCallArg(CE->
getArg(ArgIdx), *P, DeclWithIssue);
223 void visitConstructExpr(
const CXXConstructExpr *CE,
224 const Decl *DeclWithIssue)
const {
225 assert(BR &&
"expected nonnull BugReporter");
226 if (BR->getSourceManager().isInSystemHeader(CE->
getExprLoc()))
231 for (
auto P = F->param_begin();
232 P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
233 visitCallArg(CE->
getArg(ArgIdx), *P, DeclWithIssue);
237 void visitObjCMessageExpr(
const ObjCMessageExpr *E,
238 const Decl *DeclWithIssue)
const {
239 assert(BR &&
"expected nonnull BugReporter");
240 if (BR->getSourceManager().isInSystemHeader(E->
getExprLoc()))
244 Receiver = Receiver->IgnoreParenCasts();
246 reportUnknownReceiverType(Receiver, DeclWithIssue);
254 for (
unsigned i = 0; i < ArgCount && i < MethodDecl->param_size(); ++i)
255 visitCallArg(E->
getArg(i), MethodDecl->getParamDecl(i), DeclWithIssue);
258 void visitCallArg(
const Expr *Arg,
const ParmVarDecl *Param,
259 const Decl *DeclWithIssue)
const {
262 ArgExpr = ArgExpr->IgnoreParenCasts();
263 if (
auto *InnerCE = dyn_cast<CallExpr>(ArgExpr)) {
264 if (
auto *InnerCallee = InnerCE->getDirectCallee()) {
266 ArgExpr = InnerCE->getArg(0);
271 if (
auto *UO = dyn_cast<UnaryOperator>(ArgExpr)) {
272 auto OpCode = UO->getOpcode();
273 if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
274 ArgExpr = UO->getSubExpr();
281 if (
auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(ArgExpr)) {
286 if (
auto *OpCE = dyn_cast<CXXOperatorCallExpr>(ArgExpr)) {
287 auto *
Method = dyn_cast_or_null<CXXMethodDecl>(OpCE->getDirectCallee());
289 if (OpCE->getOperator() == OO_Star && OpCE->getNumArgs() == 1)
298 if (
auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {
299 if (
auto *ValDecl = DRE->getDecl()) {
305 QualType ArgType = Param->
getType();
306 if (!isUnknownType(ArgType))
309 reportUnknownArgType(Arg, Param, DeclWithIssue);
312 void reportUnknownArgType(
const Expr *CA,
const ParmVarDecl *Param,
313 const Decl *DeclWithIssue)
const {
316 SmallString<100> Buf;
317 llvm::raw_svector_ostream Os(Buf);
320 Os <<
"Call argument";
321 if (!paramName.empty()) {
322 Os <<
" for parameter ";
330 void reportUnknownReceiverType(
const Expr *Receiver,
331 const Decl *DeclWithIssue)
const {
334 "Receiver", Receiver->
getType());
337 void reportBug(
const SourceLocation &SrcLoc,
const SourceRange &SrcRange,
338 const Decl *DeclWithIssue,
const StringRef &Description,
339 QualType
Type)
const {
340 SmallString<100> Buf;
341 llvm::raw_svector_ostream Os(Buf);
344 Os << Description <<
" uses a forward declared type '" <<
TypeName <<
"'";
346 assert(BR &&
"expected nonnull BugReporter");
347 PathDiagnosticLocation BSLoc(SrcLoc, BR->getSourceManager());
348 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
349 Report->addRange(SrcRange);
350 Report->setDeclWithIssue(DeclWithIssue);
351 BR->emitReport(std::move(
Report));
361bool 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.
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.
The JSON file list parser is used to communicate input to InstallAPI.
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)
@ Type
The name was classified as a type.
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)