30bool isRefcountedStringsHack(
const VarDecl *
V) {
32 auto safeClass = [](
const std::string &className) {
33 return className ==
"String" || className ==
"AtomString" ||
34 className ==
"UniquedString" || className ==
"Identifier";
51bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
54 assert(MaybeGuardian);
59 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
64 !guardianAncestors.
empty();
69 for (
auto &guardianAncestor : guardianAncestors) {
70 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
71 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
75 if (guardiansClosestCompStmtAncestor)
79 if (!guardiansClosestCompStmtAncestor)
84 bool HaveSkippedFirstCompoundStmt =
false;
86 !guardedVarAncestors.
empty();
91 for (
auto &guardedVarAncestor : guardedVarAncestors) {
92 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
93 if (!HaveSkippedFirstCompoundStmt) {
94 HaveSkippedFirstCompoundStmt =
true;
97 if (CStmtAncestor == guardiansClosestCompStmtAncestor)
106class UncountedLocalVarsChecker
107 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
109 "Uncounted raw pointer or reference not provably backed by "
110 "ref-counted variable",
111 "WebKit coding guidelines"};
123 const UncountedLocalVarsChecker *
Checker;
129 explicit LocalVisitor(
const UncountedLocalVarsChecker *
Checker)
134 bool shouldVisitTemplateInstantiations()
const {
return true; }
135 bool shouldVisitImplicitCode()
const {
return false; }
142 bool TraverseIfStmt(
IfStmt *IS) {
144 return Base::TraverseIfStmt(IS);
148 bool TraverseForStmt(
ForStmt *FS) {
150 return Base::TraverseForStmt(FS);
156 return Base::TraverseCXXForRangeStmt(FRS);
162 return Base::TraverseWhileStmt(WS);
168 return Base::TraverseCompoundStmt(CS);
173 LocalVisitor visitor(
this);
177 void visitVarDecl(
const VarDecl *
V)
const {
178 if (shouldSkipVarDecl(
V))
181 const auto *ArgType =
V->getType().getTypePtr();
186 if (IsUncountedPtr && *IsUncountedPtr) {
187 const Expr *
const InitExpr =
V->getInit();
197 if (isa<CXXThisExpr>(InitArgOrigin))
200 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
201 if (
auto *MaybeGuardian =
202 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
203 const auto *MaybeGuardianArgType =
205 if (MaybeGuardianArgType) {
207 MaybeGuardianArgType->getAsCXXRecordDecl();
208 if (MaybeGuardianArgCXXRecord) {
211 isRefcountedStringsHack(MaybeGuardian)) &&
212 isGuardedScopeEmbeddedInGuardianScope(
V, MaybeGuardian))
219 if (isa<ParmVarDecl>(MaybeGuardian))
228 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
230 if (!
V->isLocalVarDecl())
236 void reportBug(
const VarDecl *
V)
const {
239 llvm::raw_svector_ostream Os(Buf);
241 Os <<
"Local variable ";
243 Os <<
" is uncounted and unsafe.";
246 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
247 Report->addRange(
V->getSourceRange());
253void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
257bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::SourceLocation class and associated facilities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents a C++ struct/union/class.
CompoundStmt - This represents a group of statements like { stmt stmt }.
ASTContext & getASTContext() const LLVM_READONLY
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
This represents one expression.
ForStmt - This represents a 'for (init;cond;inc)' stmt.
IfStmt - This represents an if/then/else.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
The top declaration context.
An inter-procedural analysis facility that detects functions with "trivial" behavior with respect to ...
bool isTrivial(const Decl *D) const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isPointerType() const
bool isReferenceType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Represents a variable declaration or definition.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
WhileStmt - This represents a 'while' stmt.
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
The JSON file list parser is used to communicate input to InstallAPI.
std::optional< bool > isUncountedPtr(const Type *T)
std::pair< const Expr *, bool > tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
bool isRefCounted(const CXXRecordDecl *R)
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)