xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //=======- ForwardDeclChecker.cpp --------------------------------*- C++ -*-==//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "ASTUtils.h"
10*700637cbSDimitry Andric #include "DiagOutputUtils.h"
11*700637cbSDimitry Andric #include "PtrTypesSemantics.h"
12*700637cbSDimitry Andric #include "clang/AST/Decl.h"
13*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
14*700637cbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
15*700637cbSDimitry Andric #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16*700637cbSDimitry Andric #include "clang/Basic/SourceLocation.h"
17*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20*700637cbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
21*700637cbSDimitry Andric #include "llvm/ADT/DenseSet.h"
22*700637cbSDimitry Andric #include "llvm/Support/SaveAndRestore.h"
23*700637cbSDimitry Andric 
24*700637cbSDimitry Andric using namespace clang;
25*700637cbSDimitry Andric using namespace ento;
26*700637cbSDimitry Andric 
27*700637cbSDimitry Andric namespace {
28*700637cbSDimitry Andric 
29*700637cbSDimitry Andric class ForwardDeclChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
30*700637cbSDimitry Andric   BugType Bug;
31*700637cbSDimitry Andric   mutable BugReporter *BR = nullptr;
32*700637cbSDimitry Andric   mutable RetainTypeChecker RTC;
33*700637cbSDimitry Andric   mutable llvm::DenseSet<const Type *> SystemTypes;
34*700637cbSDimitry Andric 
35*700637cbSDimitry Andric public:
ForwardDeclChecker()36*700637cbSDimitry Andric   ForwardDeclChecker()
37*700637cbSDimitry Andric       : Bug(this, "Forward declared member or local variable or parameter",
38*700637cbSDimitry Andric             "WebKit coding guidelines") {}
39*700637cbSDimitry Andric 
checkASTDecl(const TranslationUnitDecl * TUD,AnalysisManager & MGR,BugReporter & BRArg) const40*700637cbSDimitry Andric   void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR,
41*700637cbSDimitry Andric                     BugReporter &BRArg) const {
42*700637cbSDimitry Andric     BR = &BRArg;
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric     // The calls to checkAST* from AnalysisConsumer don't
45*700637cbSDimitry Andric     // visit template instantiations or lambda classes. We
46*700637cbSDimitry Andric     // want to visit those, so we make our own RecursiveASTVisitor.
47*700637cbSDimitry Andric     struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> {
48*700637cbSDimitry Andric       using Base = RecursiveASTVisitor<LocalVisitor>;
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric       const ForwardDeclChecker *Checker;
51*700637cbSDimitry Andric       Decl *DeclWithIssue{nullptr};
52*700637cbSDimitry Andric 
53*700637cbSDimitry Andric       explicit LocalVisitor(const ForwardDeclChecker *Checker)
54*700637cbSDimitry Andric           : Checker(Checker) {
55*700637cbSDimitry Andric         assert(Checker);
56*700637cbSDimitry Andric       }
57*700637cbSDimitry Andric 
58*700637cbSDimitry Andric       bool shouldVisitTemplateInstantiations() const { return true; }
59*700637cbSDimitry Andric       bool shouldVisitImplicitCode() const { return false; }
60*700637cbSDimitry Andric 
61*700637cbSDimitry Andric       bool VisitTypedefDecl(TypedefDecl *TD) {
62*700637cbSDimitry Andric         Checker->visitTypedef(TD);
63*700637cbSDimitry Andric         return true;
64*700637cbSDimitry Andric       }
65*700637cbSDimitry Andric 
66*700637cbSDimitry Andric       bool VisitRecordDecl(const RecordDecl *RD) {
67*700637cbSDimitry Andric         Checker->visitRecordDecl(RD, DeclWithIssue);
68*700637cbSDimitry Andric         return true;
69*700637cbSDimitry Andric       }
70*700637cbSDimitry Andric 
71*700637cbSDimitry Andric       bool TraverseDecl(Decl *D) {
72*700637cbSDimitry Andric         llvm::SaveAndRestore SavedDecl(DeclWithIssue);
73*700637cbSDimitry Andric         if (D && (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)))
74*700637cbSDimitry Andric           DeclWithIssue = D;
75*700637cbSDimitry Andric         return Base::TraverseDecl(D);
76*700637cbSDimitry Andric       }
77*700637cbSDimitry Andric 
78*700637cbSDimitry Andric       bool VisitVarDecl(VarDecl *V) {
79*700637cbSDimitry Andric         if (V->isLocalVarDecl())
80*700637cbSDimitry Andric           Checker->visitVarDecl(V, DeclWithIssue);
81*700637cbSDimitry Andric         return true;
82*700637cbSDimitry Andric       }
83*700637cbSDimitry Andric 
84*700637cbSDimitry Andric       bool VisitCallExpr(const CallExpr *CE) {
85*700637cbSDimitry Andric         Checker->visitCallExpr(CE, DeclWithIssue);
86*700637cbSDimitry Andric         return true;
87*700637cbSDimitry Andric       }
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric       bool VisitCXXConstructExpr(const CXXConstructExpr *CE) {
90*700637cbSDimitry Andric         Checker->visitConstructExpr(CE, DeclWithIssue);
91*700637cbSDimitry Andric         return true;
92*700637cbSDimitry Andric       }
93*700637cbSDimitry Andric 
94*700637cbSDimitry Andric       bool VisitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr) {
95*700637cbSDimitry Andric         Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue);
96*700637cbSDimitry Andric         return true;
97*700637cbSDimitry Andric       }
98*700637cbSDimitry Andric     };
99*700637cbSDimitry Andric 
100*700637cbSDimitry Andric     LocalVisitor visitor(this);
101*700637cbSDimitry Andric     RTC.visitTranslationUnitDecl(TUD);
102*700637cbSDimitry Andric     visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD));
103*700637cbSDimitry Andric   }
104*700637cbSDimitry Andric 
visitTypedef(const TypedefDecl * TD) const105*700637cbSDimitry Andric   void visitTypedef(const TypedefDecl *TD) const {
106*700637cbSDimitry Andric     RTC.visitTypedef(TD);
107*700637cbSDimitry Andric     auto QT = TD->getUnderlyingType().getCanonicalType();
108*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
109*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(TD->getBeginLoc())) {
110*700637cbSDimitry Andric       if (auto *Type = QT.getTypePtrOrNull())
111*700637cbSDimitry Andric         SystemTypes.insert(Type);
112*700637cbSDimitry Andric     }
113*700637cbSDimitry Andric   }
114*700637cbSDimitry Andric 
isUnknownType(QualType QT) const115*700637cbSDimitry Andric   bool isUnknownType(QualType QT) const {
116*700637cbSDimitry Andric     auto *CanonicalType = QT.getCanonicalType().getTypePtrOrNull();
117*700637cbSDimitry Andric     if (!CanonicalType)
118*700637cbSDimitry Andric       return false;
119*700637cbSDimitry Andric     auto PointeeQT = CanonicalType->getPointeeType();
120*700637cbSDimitry Andric     auto *PointeeType = PointeeQT.getTypePtrOrNull();
121*700637cbSDimitry Andric     if (!PointeeType)
122*700637cbSDimitry Andric       return false;
123*700637cbSDimitry Andric     auto *R = PointeeType->getAsCXXRecordDecl();
124*700637cbSDimitry Andric     if (!R) // Forward declaration of a Objective-C interface is safe.
125*700637cbSDimitry Andric       return false;
126*700637cbSDimitry Andric     auto Name = R->getName();
127*700637cbSDimitry Andric     if (R->hasDefinition())
128*700637cbSDimitry Andric       return false;
129*700637cbSDimitry Andric     // Find a definition amongst template declarations.
130*700637cbSDimitry Andric     if (auto *Specialization = dyn_cast<ClassTemplateSpecializationDecl>(R)) {
131*700637cbSDimitry Andric       if (auto *S = Specialization->getSpecializedTemplate()) {
132*700637cbSDimitry Andric         for (S = S->getMostRecentDecl(); S; S = S->getPreviousDecl()) {
133*700637cbSDimitry Andric           if (S->isThisDeclarationADefinition())
134*700637cbSDimitry Andric             return false;
135*700637cbSDimitry Andric         }
136*700637cbSDimitry Andric       }
137*700637cbSDimitry Andric     }
138*700637cbSDimitry Andric     return !RTC.isUnretained(QT) && !SystemTypes.contains(CanonicalType) &&
139*700637cbSDimitry Andric            !SystemTypes.contains(PointeeType) && !Name.starts_with("Opaque") &&
140*700637cbSDimitry Andric            Name != "_NSZone";
141*700637cbSDimitry Andric   }
142*700637cbSDimitry Andric 
visitRecordDecl(const RecordDecl * RD,const Decl * DeclWithIssue) const143*700637cbSDimitry Andric   void visitRecordDecl(const RecordDecl *RD, const Decl *DeclWithIssue) const {
144*700637cbSDimitry Andric     if (!RD->isThisDeclarationADefinition())
145*700637cbSDimitry Andric       return;
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric     if (RD->isImplicit() || RD->isLambda())
148*700637cbSDimitry Andric       return;
149*700637cbSDimitry Andric 
150*700637cbSDimitry Andric     const auto RDLocation = RD->getLocation();
151*700637cbSDimitry Andric     if (!RDLocation.isValid())
152*700637cbSDimitry Andric       return;
153*700637cbSDimitry Andric 
154*700637cbSDimitry Andric     const auto Kind = RD->getTagKind();
155*700637cbSDimitry Andric     if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
156*700637cbSDimitry Andric       return;
157*700637cbSDimitry Andric 
158*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
159*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(RDLocation))
160*700637cbSDimitry Andric       return;
161*700637cbSDimitry Andric 
162*700637cbSDimitry Andric     // Ref-counted smartpointers actually have raw-pointer to uncounted type as
163*700637cbSDimitry Andric     // a member but we trust them to handle it correctly.
164*700637cbSDimitry Andric     auto R = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
165*700637cbSDimitry Andric     if (!R || isRefCounted(R) || isCheckedPtr(R) || isRetainPtr(R))
166*700637cbSDimitry Andric       return;
167*700637cbSDimitry Andric 
168*700637cbSDimitry Andric     for (auto *Member : RD->fields()) {
169*700637cbSDimitry Andric       auto QT = Member->getType();
170*700637cbSDimitry Andric       if (isUnknownType(QT)) {
171*700637cbSDimitry Andric         SmallString<100> Buf;
172*700637cbSDimitry Andric         llvm::raw_svector_ostream Os(Buf);
173*700637cbSDimitry Andric 
174*700637cbSDimitry Andric         const std::string TypeName = QT.getAsString();
175*700637cbSDimitry Andric         Os << "Member variable ";
176*700637cbSDimitry Andric         printQuotedName(Os, Member);
177*700637cbSDimitry Andric         Os << " uses a forward declared type '" << TypeName << "'";
178*700637cbSDimitry Andric 
179*700637cbSDimitry Andric         const SourceLocation SrcLocToReport = Member->getBeginLoc();
180*700637cbSDimitry Andric         PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager());
181*700637cbSDimitry Andric         auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
182*700637cbSDimitry Andric         Report->addRange(Member->getSourceRange());
183*700637cbSDimitry Andric         Report->setDeclWithIssue(DeclWithIssue);
184*700637cbSDimitry Andric         BR->emitReport(std::move(Report));
185*700637cbSDimitry Andric       }
186*700637cbSDimitry Andric     }
187*700637cbSDimitry Andric   }
188*700637cbSDimitry Andric 
visitVarDecl(const VarDecl * V,const Decl * DeclWithIssue) const189*700637cbSDimitry Andric   void visitVarDecl(const VarDecl *V, const Decl *DeclWithIssue) const {
190*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
191*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(V->getBeginLoc()))
192*700637cbSDimitry Andric       return;
193*700637cbSDimitry Andric 
194*700637cbSDimitry Andric     auto QT = V->getType();
195*700637cbSDimitry Andric     if (!isUnknownType(QT))
196*700637cbSDimitry Andric       return;
197*700637cbSDimitry Andric 
198*700637cbSDimitry Andric     SmallString<100> Buf;
199*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
200*700637cbSDimitry Andric     Os << "Local variable ";
201*700637cbSDimitry Andric     printQuotedQualifiedName(Os, V);
202*700637cbSDimitry Andric 
203*700637cbSDimitry Andric     reportBug(V->getBeginLoc(), V->getSourceRange(), DeclWithIssue, Os.str(),
204*700637cbSDimitry Andric               QT);
205*700637cbSDimitry Andric   }
206*700637cbSDimitry Andric 
visitCallExpr(const CallExpr * CE,const Decl * DeclWithIssue) const207*700637cbSDimitry Andric   void visitCallExpr(const CallExpr *CE, const Decl *DeclWithIssue) const {
208*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
209*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
210*700637cbSDimitry Andric       return;
211*700637cbSDimitry Andric 
212*700637cbSDimitry Andric     if (auto *F = CE->getDirectCallee()) {
213*700637cbSDimitry Andric       // Skip the first argument for overloaded member operators (e. g. lambda
214*700637cbSDimitry Andric       // or std::function call operator).
215*700637cbSDimitry Andric       unsigned ArgIdx =
216*700637cbSDimitry Andric           isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F);
217*700637cbSDimitry Andric 
218*700637cbSDimitry Andric       for (auto P = F->param_begin();
219*700637cbSDimitry Andric            P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
220*700637cbSDimitry Andric         visitCallArg(CE->getArg(ArgIdx), *P, DeclWithIssue);
221*700637cbSDimitry Andric     }
222*700637cbSDimitry Andric   }
223*700637cbSDimitry Andric 
visitConstructExpr(const CXXConstructExpr * CE,const Decl * DeclWithIssue) const224*700637cbSDimitry Andric   void visitConstructExpr(const CXXConstructExpr *CE,
225*700637cbSDimitry Andric                           const Decl *DeclWithIssue) const {
226*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
227*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))
228*700637cbSDimitry Andric       return;
229*700637cbSDimitry Andric 
230*700637cbSDimitry Andric     if (auto *F = CE->getConstructor()) {
231*700637cbSDimitry Andric       // Skip the first argument for overloaded member operators (e. g. lambda
232*700637cbSDimitry Andric       // or std::function call operator).
233*700637cbSDimitry Andric       unsigned ArgIdx =
234*700637cbSDimitry Andric           isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F);
235*700637cbSDimitry Andric 
236*700637cbSDimitry Andric       for (auto P = F->param_begin();
237*700637cbSDimitry Andric            P < F->param_end() && ArgIdx < CE->getNumArgs(); ++P, ++ArgIdx)
238*700637cbSDimitry Andric         visitCallArg(CE->getArg(ArgIdx), *P, DeclWithIssue);
239*700637cbSDimitry Andric     }
240*700637cbSDimitry Andric   }
241*700637cbSDimitry Andric 
visitObjCMessageExpr(const ObjCMessageExpr * E,const Decl * DeclWithIssue) const242*700637cbSDimitry Andric   void visitObjCMessageExpr(const ObjCMessageExpr *E,
243*700637cbSDimitry Andric                             const Decl *DeclWithIssue) const {
244*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
245*700637cbSDimitry Andric     if (BR->getSourceManager().isInSystemHeader(E->getExprLoc()))
246*700637cbSDimitry Andric       return;
247*700637cbSDimitry Andric 
248*700637cbSDimitry Andric     if (auto *Receiver = E->getInstanceReceiver()) {
249*700637cbSDimitry Andric       Receiver = Receiver->IgnoreParenCasts();
250*700637cbSDimitry Andric       if (isUnknownType(E->getReceiverType()))
251*700637cbSDimitry Andric         reportUnknownRecieverType(Receiver, DeclWithIssue);
252*700637cbSDimitry Andric     }
253*700637cbSDimitry Andric 
254*700637cbSDimitry Andric     auto *MethodDecl = E->getMethodDecl();
255*700637cbSDimitry Andric     if (!MethodDecl)
256*700637cbSDimitry Andric       return;
257*700637cbSDimitry Andric 
258*700637cbSDimitry Andric     auto ArgCount = E->getNumArgs();
259*700637cbSDimitry Andric     for (unsigned i = 0; i < ArgCount && i < MethodDecl->param_size(); ++i)
260*700637cbSDimitry Andric       visitCallArg(E->getArg(i), MethodDecl->getParamDecl(i), DeclWithIssue);
261*700637cbSDimitry Andric   }
262*700637cbSDimitry Andric 
visitCallArg(const Expr * Arg,const ParmVarDecl * Param,const Decl * DeclWithIssue) const263*700637cbSDimitry Andric   void visitCallArg(const Expr *Arg, const ParmVarDecl *Param,
264*700637cbSDimitry Andric                     const Decl *DeclWithIssue) const {
265*700637cbSDimitry Andric     auto *ArgExpr = Arg->IgnoreParenCasts();
266*700637cbSDimitry Andric     if (auto *InnerCE = dyn_cast<CallExpr>(Arg)) {
267*700637cbSDimitry Andric       auto *InnerCallee = InnerCE->getDirectCallee();
268*700637cbSDimitry Andric       if (InnerCallee && InnerCallee->isInStdNamespace() &&
269*700637cbSDimitry Andric           safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) {
270*700637cbSDimitry Andric         ArgExpr = InnerCE->getArg(0);
271*700637cbSDimitry Andric         if (ArgExpr)
272*700637cbSDimitry Andric           ArgExpr = ArgExpr->IgnoreParenCasts();
273*700637cbSDimitry Andric       }
274*700637cbSDimitry Andric     }
275*700637cbSDimitry Andric     if (isa<CXXNullPtrLiteralExpr>(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
276*700637cbSDimitry Andric         isa<CXXDefaultArgExpr>(ArgExpr))
277*700637cbSDimitry Andric       return;
278*700637cbSDimitry Andric     if (auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {
279*700637cbSDimitry Andric       if (auto *ValDecl = DRE->getDecl()) {
280*700637cbSDimitry Andric         if (isa<ParmVarDecl>(ValDecl))
281*700637cbSDimitry Andric           return;
282*700637cbSDimitry Andric       }
283*700637cbSDimitry Andric     }
284*700637cbSDimitry Andric 
285*700637cbSDimitry Andric     QualType ArgType = Param->getType();
286*700637cbSDimitry Andric     if (!isUnknownType(ArgType))
287*700637cbSDimitry Andric       return;
288*700637cbSDimitry Andric 
289*700637cbSDimitry Andric     reportUnknownArgType(Arg, Param, DeclWithIssue);
290*700637cbSDimitry Andric   }
291*700637cbSDimitry Andric 
reportUnknownArgType(const Expr * CA,const ParmVarDecl * Param,const Decl * DeclWithIssue) const292*700637cbSDimitry Andric   void reportUnknownArgType(const Expr *CA, const ParmVarDecl *Param,
293*700637cbSDimitry Andric                             const Decl *DeclWithIssue) const {
294*700637cbSDimitry Andric     assert(CA);
295*700637cbSDimitry Andric 
296*700637cbSDimitry Andric     SmallString<100> Buf;
297*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
298*700637cbSDimitry Andric 
299*700637cbSDimitry Andric     const std::string paramName = safeGetName(Param);
300*700637cbSDimitry Andric     Os << "Call argument";
301*700637cbSDimitry Andric     if (!paramName.empty()) {
302*700637cbSDimitry Andric       Os << " for parameter ";
303*700637cbSDimitry Andric       printQuotedQualifiedName(Os, Param);
304*700637cbSDimitry Andric     }
305*700637cbSDimitry Andric 
306*700637cbSDimitry Andric     reportBug(CA->getExprLoc(), CA->getSourceRange(), DeclWithIssue, Os.str(),
307*700637cbSDimitry Andric               Param->getType());
308*700637cbSDimitry Andric   }
309*700637cbSDimitry Andric 
reportUnknownRecieverType(const Expr * Receiver,const Decl * DeclWithIssue) const310*700637cbSDimitry Andric   void reportUnknownRecieverType(const Expr *Receiver,
311*700637cbSDimitry Andric                                  const Decl *DeclWithIssue) const {
312*700637cbSDimitry Andric     assert(Receiver);
313*700637cbSDimitry Andric     reportBug(Receiver->getExprLoc(), Receiver->getSourceRange(), DeclWithIssue,
314*700637cbSDimitry Andric               "Receiver", Receiver->getType());
315*700637cbSDimitry Andric   }
316*700637cbSDimitry Andric 
reportBug(const SourceLocation & SrcLoc,const SourceRange & SrcRange,const Decl * DeclWithIssue,const StringRef & Description,QualType Type) const317*700637cbSDimitry Andric   void reportBug(const SourceLocation &SrcLoc, const SourceRange &SrcRange,
318*700637cbSDimitry Andric                  const Decl *DeclWithIssue, const StringRef &Description,
319*700637cbSDimitry Andric                  QualType Type) const {
320*700637cbSDimitry Andric     SmallString<100> Buf;
321*700637cbSDimitry Andric     llvm::raw_svector_ostream Os(Buf);
322*700637cbSDimitry Andric 
323*700637cbSDimitry Andric     const std::string TypeName = Type.getAsString();
324*700637cbSDimitry Andric     Os << Description << " uses a forward declared type '" << TypeName << "'";
325*700637cbSDimitry Andric 
326*700637cbSDimitry Andric     assert(BR && "expected nonnull BugReporter");
327*700637cbSDimitry Andric     PathDiagnosticLocation BSLoc(SrcLoc, BR->getSourceManager());
328*700637cbSDimitry Andric     auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
329*700637cbSDimitry Andric     Report->addRange(SrcRange);
330*700637cbSDimitry Andric     Report->setDeclWithIssue(DeclWithIssue);
331*700637cbSDimitry Andric     BR->emitReport(std::move(Report));
332*700637cbSDimitry Andric   }
333*700637cbSDimitry Andric };
334*700637cbSDimitry Andric 
335*700637cbSDimitry Andric } // namespace
336*700637cbSDimitry Andric 
registerForwardDeclChecker(CheckerManager & Mgr)337*700637cbSDimitry Andric void ento::registerForwardDeclChecker(CheckerManager &Mgr) {
338*700637cbSDimitry Andric   Mgr.registerChecker<ForwardDeclChecker>();
339*700637cbSDimitry Andric }
340*700637cbSDimitry Andric 
shouldRegisterForwardDeclChecker(const CheckerManager &)341*700637cbSDimitry Andric bool ento::shouldRegisterForwardDeclChecker(const CheckerManager &) {
342*700637cbSDimitry Andric   return true;
343*700637cbSDimitry Andric }
344