xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1a9ac8606Spatrick //=======- UncountedLambdaCapturesChecker.cpp --------------------*- C++ -*-==//
2a9ac8606Spatrick //
3a9ac8606Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9ac8606Spatrick // See https://llvm.org/LICENSE.txt for license information.
5a9ac8606Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9ac8606Spatrick //
7a9ac8606Spatrick //===----------------------------------------------------------------------===//
8a9ac8606Spatrick 
9a9ac8606Spatrick #include "DiagOutputUtils.h"
10a9ac8606Spatrick #include "PtrTypesSemantics.h"
11a9ac8606Spatrick #include "clang/AST/CXXInheritance.h"
12a9ac8606Spatrick #include "clang/AST/RecursiveASTVisitor.h"
13a9ac8606Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14a9ac8606Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
15a9ac8606Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16a9ac8606Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
17*12c85518Srobert #include <optional>
18a9ac8606Spatrick 
19a9ac8606Spatrick using namespace clang;
20a9ac8606Spatrick using namespace ento;
21a9ac8606Spatrick 
22a9ac8606Spatrick namespace {
23a9ac8606Spatrick class UncountedLambdaCapturesChecker
24a9ac8606Spatrick     : public Checker<check::ASTDecl<TranslationUnitDecl>> {
25a9ac8606Spatrick private:
26a9ac8606Spatrick   BugType Bug{this, "Lambda capture of uncounted variable",
27a9ac8606Spatrick               "WebKit coding guidelines"};
28a9ac8606Spatrick   mutable BugReporter *BR;
29a9ac8606Spatrick 
30a9ac8606Spatrick public:
checkASTDecl(const TranslationUnitDecl * TUD,AnalysisManager & MGR,BugReporter & BRArg) const31a9ac8606Spatrick   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
32a9ac8606Spatrick                     BugReporter &BRArg) const {
33a9ac8606Spatrick     BR = &BRArg;
34a9ac8606Spatrick 
35a9ac8606Spatrick     // The calls to checkAST* from AnalysisConsumer don't
36a9ac8606Spatrick     // visit template instantiations or lambda classes. We
37a9ac8606Spatrick     // want to visit those, so we make our own RecursiveASTVisitor.
38a9ac8606Spatrick     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
39a9ac8606Spatrick       const UncountedLambdaCapturesChecker *Checker;
40a9ac8606Spatrick       explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker)
41a9ac8606Spatrick           : Checker(Checker) {
42a9ac8606Spatrick         assert(Checker);
43a9ac8606Spatrick       }
44a9ac8606Spatrick 
45a9ac8606Spatrick       bool shouldVisitTemplateInstantiations() const { return true; }
46a9ac8606Spatrick       bool shouldVisitImplicitCode() const { return false; }
47a9ac8606Spatrick 
48a9ac8606Spatrick       bool VisitLambdaExpr(LambdaExpr *L) {
49a9ac8606Spatrick         Checker->visitLambdaExpr(L);
50a9ac8606Spatrick         return true;
51a9ac8606Spatrick       }
52a9ac8606Spatrick     };
53a9ac8606Spatrick 
54a9ac8606Spatrick     LocalVisitor visitor(this);
55a9ac8606Spatrick     visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
56a9ac8606Spatrick   }
57a9ac8606Spatrick 
visitLambdaExpr(LambdaExpr * L) const58a9ac8606Spatrick   void visitLambdaExpr(LambdaExpr *L) const {
59a9ac8606Spatrick     for (const LambdaCapture &C : L->captures()) {
60a9ac8606Spatrick       if (C.capturesVariable()) {
61*12c85518Srobert         ValueDecl *CapturedVar = C.getCapturedVar();
62a9ac8606Spatrick         if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
63*12c85518Srobert             std::optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
64a9ac8606Spatrick             if (IsUncountedPtr && *IsUncountedPtr) {
65a9ac8606Spatrick                 reportBug(C, CapturedVar, CapturedVarType);
66a9ac8606Spatrick             }
67a9ac8606Spatrick         }
68a9ac8606Spatrick       }
69a9ac8606Spatrick     }
70a9ac8606Spatrick   }
71a9ac8606Spatrick 
reportBug(const LambdaCapture & Capture,ValueDecl * CapturedVar,const Type * T) const72*12c85518Srobert   void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
73a9ac8606Spatrick                  const Type *T) const {
74a9ac8606Spatrick     assert(CapturedVar);
75a9ac8606Spatrick 
76a9ac8606Spatrick     SmallString<100> Buf;
77a9ac8606Spatrick     llvm::raw_svector_ostream Os(Buf);
78a9ac8606Spatrick 
79a9ac8606Spatrick     if (Capture.isExplicit()) {
80a9ac8606Spatrick       Os << "Captured ";
81a9ac8606Spatrick     } else {
82a9ac8606Spatrick       Os << "Implicitly captured ";
83a9ac8606Spatrick     }
84a9ac8606Spatrick     if (T->isPointerType()) {
85a9ac8606Spatrick       Os << "raw-pointer ";
86a9ac8606Spatrick     } else {
87a9ac8606Spatrick       assert(T->isReferenceType());
88a9ac8606Spatrick       Os << "reference ";
89a9ac8606Spatrick     }
90a9ac8606Spatrick 
91a9ac8606Spatrick     printQuotedQualifiedName(Os, Capture.getCapturedVar());
92a9ac8606Spatrick     Os << " to uncounted type is unsafe.";
93a9ac8606Spatrick 
94a9ac8606Spatrick     PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager());
95a9ac8606Spatrick     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
96a9ac8606Spatrick     BR->emitReport(std::move(Report));
97a9ac8606Spatrick   }
98a9ac8606Spatrick };
99a9ac8606Spatrick } // namespace
100a9ac8606Spatrick 
registerUncountedLambdaCapturesChecker(CheckerManager & Mgr)101a9ac8606Spatrick void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) {
102a9ac8606Spatrick   Mgr.registerChecker<UncountedLambdaCapturesChecker>();
103a9ac8606Spatrick }
104a9ac8606Spatrick 
shouldRegisterUncountedLambdaCapturesChecker(const CheckerManager & mgr)105a9ac8606Spatrick bool ento::shouldRegisterUncountedLambdaCapturesChecker(
106a9ac8606Spatrick     const CheckerManager &mgr) {
107a9ac8606Spatrick   return true;
108a9ac8606Spatrick }
109