xref: /minix3/external/bsd/llvm/dist/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines LLVMConventionsChecker, a bunch of small little checks
11f4a2713aSLionel Sambuc // for checking specific coding conventions in the LLVM/Clang codebase.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
16f4a2713aSLionel Sambuc #include "clang/AST/DeclTemplate.h"
17f4a2713aSLionel Sambuc #include "clang/AST/StmtVisitor.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
20f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
21f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
22f4a2713aSLionel Sambuc 
23f4a2713aSLionel Sambuc using namespace clang;
24f4a2713aSLionel Sambuc using namespace ento;
25f4a2713aSLionel Sambuc 
26f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
27f4a2713aSLionel Sambuc // Generic type checking routines.
28f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
29f4a2713aSLionel Sambuc 
IsLLVMStringRef(QualType T)30f4a2713aSLionel Sambuc static bool IsLLVMStringRef(QualType T) {
31f4a2713aSLionel Sambuc   const RecordType *RT = T->getAs<RecordType>();
32f4a2713aSLionel Sambuc   if (!RT)
33f4a2713aSLionel Sambuc     return false;
34f4a2713aSLionel Sambuc 
35f4a2713aSLionel Sambuc   return StringRef(QualType(RT, 0).getAsString()) ==
36f4a2713aSLionel Sambuc           "class StringRef";
37f4a2713aSLionel Sambuc }
38f4a2713aSLionel Sambuc 
39f4a2713aSLionel Sambuc /// Check whether the declaration is semantically inside the top-level
40f4a2713aSLionel Sambuc /// namespace named by ns.
InNamespace(const Decl * D,StringRef NS)41f4a2713aSLionel Sambuc static bool InNamespace(const Decl *D, StringRef NS) {
42f4a2713aSLionel Sambuc   const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
43f4a2713aSLionel Sambuc   if (!ND)
44f4a2713aSLionel Sambuc     return false;
45f4a2713aSLionel Sambuc   const IdentifierInfo *II = ND->getIdentifier();
46f4a2713aSLionel Sambuc   if (!II || !II->getName().equals(NS))
47f4a2713aSLionel Sambuc     return false;
48f4a2713aSLionel Sambuc   return isa<TranslationUnitDecl>(ND->getDeclContext());
49f4a2713aSLionel Sambuc }
50f4a2713aSLionel Sambuc 
IsStdString(QualType T)51f4a2713aSLionel Sambuc static bool IsStdString(QualType T) {
52f4a2713aSLionel Sambuc   if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
53f4a2713aSLionel Sambuc     T = QT->getNamedType();
54f4a2713aSLionel Sambuc 
55f4a2713aSLionel Sambuc   const TypedefType *TT = T->getAs<TypedefType>();
56f4a2713aSLionel Sambuc   if (!TT)
57f4a2713aSLionel Sambuc     return false;
58f4a2713aSLionel Sambuc 
59f4a2713aSLionel Sambuc   const TypedefNameDecl *TD = TT->getDecl();
60f4a2713aSLionel Sambuc 
61*0a6a1f1dSLionel Sambuc   if (!TD->isInStdNamespace())
62f4a2713aSLionel Sambuc     return false;
63f4a2713aSLionel Sambuc 
64f4a2713aSLionel Sambuc   return TD->getName() == "string";
65f4a2713aSLionel Sambuc }
66f4a2713aSLionel Sambuc 
IsClangType(const RecordDecl * RD)67f4a2713aSLionel Sambuc static bool IsClangType(const RecordDecl *RD) {
68f4a2713aSLionel Sambuc   return RD->getName() == "Type" && InNamespace(RD, "clang");
69f4a2713aSLionel Sambuc }
70f4a2713aSLionel Sambuc 
IsClangDecl(const RecordDecl * RD)71f4a2713aSLionel Sambuc static bool IsClangDecl(const RecordDecl *RD) {
72f4a2713aSLionel Sambuc   return RD->getName() == "Decl" && InNamespace(RD, "clang");
73f4a2713aSLionel Sambuc }
74f4a2713aSLionel Sambuc 
IsClangStmt(const RecordDecl * RD)75f4a2713aSLionel Sambuc static bool IsClangStmt(const RecordDecl *RD) {
76f4a2713aSLionel Sambuc   return RD->getName() == "Stmt" && InNamespace(RD, "clang");
77f4a2713aSLionel Sambuc }
78f4a2713aSLionel Sambuc 
IsClangAttr(const RecordDecl * RD)79f4a2713aSLionel Sambuc static bool IsClangAttr(const RecordDecl *RD) {
80f4a2713aSLionel Sambuc   return RD->getName() == "Attr" && InNamespace(RD, "clang");
81f4a2713aSLionel Sambuc }
82f4a2713aSLionel Sambuc 
IsStdVector(QualType T)83f4a2713aSLionel Sambuc static bool IsStdVector(QualType T) {
84f4a2713aSLionel Sambuc   const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
85f4a2713aSLionel Sambuc   if (!TS)
86f4a2713aSLionel Sambuc     return false;
87f4a2713aSLionel Sambuc 
88f4a2713aSLionel Sambuc   TemplateName TM = TS->getTemplateName();
89f4a2713aSLionel Sambuc   TemplateDecl *TD = TM.getAsTemplateDecl();
90f4a2713aSLionel Sambuc 
91f4a2713aSLionel Sambuc   if (!TD || !InNamespace(TD, "std"))
92f4a2713aSLionel Sambuc     return false;
93f4a2713aSLionel Sambuc 
94f4a2713aSLionel Sambuc   return TD->getName() == "vector";
95f4a2713aSLionel Sambuc }
96f4a2713aSLionel Sambuc 
IsSmallVector(QualType T)97f4a2713aSLionel Sambuc static bool IsSmallVector(QualType T) {
98f4a2713aSLionel Sambuc   const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
99f4a2713aSLionel Sambuc   if (!TS)
100f4a2713aSLionel Sambuc     return false;
101f4a2713aSLionel Sambuc 
102f4a2713aSLionel Sambuc   TemplateName TM = TS->getTemplateName();
103f4a2713aSLionel Sambuc   TemplateDecl *TD = TM.getAsTemplateDecl();
104f4a2713aSLionel Sambuc 
105f4a2713aSLionel Sambuc   if (!TD || !InNamespace(TD, "llvm"))
106f4a2713aSLionel Sambuc     return false;
107f4a2713aSLionel Sambuc 
108f4a2713aSLionel Sambuc   return TD->getName() == "SmallVector";
109f4a2713aSLionel Sambuc }
110f4a2713aSLionel Sambuc 
111f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
112f4a2713aSLionel Sambuc // CHECK: a StringRef should not be bound to a temporary std::string whose
113f4a2713aSLionel Sambuc // lifetime is shorter than the StringRef's.
114f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
115f4a2713aSLionel Sambuc 
116f4a2713aSLionel Sambuc namespace {
117f4a2713aSLionel Sambuc class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
118f4a2713aSLionel Sambuc   const Decl *DeclWithIssue;
119*0a6a1f1dSLionel Sambuc   BugReporter &BR;
120*0a6a1f1dSLionel Sambuc   const CheckerBase *Checker;
121*0a6a1f1dSLionel Sambuc 
122f4a2713aSLionel Sambuc public:
StringRefCheckerVisitor(const Decl * declWithIssue,BugReporter & br,const CheckerBase * checker)123*0a6a1f1dSLionel Sambuc   StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br,
124*0a6a1f1dSLionel Sambuc                           const CheckerBase *checker)
125*0a6a1f1dSLionel Sambuc       : DeclWithIssue(declWithIssue), BR(br), Checker(checker) {}
VisitChildren(Stmt * S)126f4a2713aSLionel Sambuc   void VisitChildren(Stmt *S) {
127f4a2713aSLionel Sambuc     for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
128f4a2713aSLionel Sambuc       I != E; ++I)
129f4a2713aSLionel Sambuc       if (Stmt *child = *I)
130f4a2713aSLionel Sambuc         Visit(child);
131f4a2713aSLionel Sambuc   }
VisitStmt(Stmt * S)132f4a2713aSLionel Sambuc   void VisitStmt(Stmt *S) { VisitChildren(S); }
133f4a2713aSLionel Sambuc   void VisitDeclStmt(DeclStmt *DS);
134f4a2713aSLionel Sambuc private:
135f4a2713aSLionel Sambuc   void VisitVarDecl(VarDecl *VD);
136f4a2713aSLionel Sambuc };
137f4a2713aSLionel Sambuc } // end anonymous namespace
138f4a2713aSLionel Sambuc 
CheckStringRefAssignedTemporary(const Decl * D,BugReporter & BR,const CheckerBase * Checker)139*0a6a1f1dSLionel Sambuc static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR,
140*0a6a1f1dSLionel Sambuc                                             const CheckerBase *Checker) {
141*0a6a1f1dSLionel Sambuc   StringRefCheckerVisitor walker(D, BR, Checker);
142f4a2713aSLionel Sambuc   walker.Visit(D->getBody());
143f4a2713aSLionel Sambuc }
144f4a2713aSLionel Sambuc 
VisitDeclStmt(DeclStmt * S)145f4a2713aSLionel Sambuc void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
146f4a2713aSLionel Sambuc   VisitChildren(S);
147f4a2713aSLionel Sambuc 
148*0a6a1f1dSLionel Sambuc   for (auto *I : S->decls())
149*0a6a1f1dSLionel Sambuc     if (VarDecl *VD = dyn_cast<VarDecl>(I))
150f4a2713aSLionel Sambuc       VisitVarDecl(VD);
151f4a2713aSLionel Sambuc }
152f4a2713aSLionel Sambuc 
VisitVarDecl(VarDecl * VD)153f4a2713aSLionel Sambuc void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
154f4a2713aSLionel Sambuc   Expr *Init = VD->getInit();
155f4a2713aSLionel Sambuc   if (!Init)
156f4a2713aSLionel Sambuc     return;
157f4a2713aSLionel Sambuc 
158f4a2713aSLionel Sambuc   // Pattern match for:
159f4a2713aSLionel Sambuc   // StringRef x = call() (where call returns std::string)
160f4a2713aSLionel Sambuc   if (!IsLLVMStringRef(VD->getType()))
161f4a2713aSLionel Sambuc     return;
162f4a2713aSLionel Sambuc   ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init);
163f4a2713aSLionel Sambuc   if (!Ex1)
164f4a2713aSLionel Sambuc     return;
165f4a2713aSLionel Sambuc   CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
166f4a2713aSLionel Sambuc   if (!Ex2 || Ex2->getNumArgs() != 1)
167f4a2713aSLionel Sambuc     return;
168f4a2713aSLionel Sambuc   ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
169f4a2713aSLionel Sambuc   if (!Ex3)
170f4a2713aSLionel Sambuc     return;
171f4a2713aSLionel Sambuc   CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
172f4a2713aSLionel Sambuc   if (!Ex4 || Ex4->getNumArgs() != 1)
173f4a2713aSLionel Sambuc     return;
174f4a2713aSLionel Sambuc   ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
175f4a2713aSLionel Sambuc   if (!Ex5)
176f4a2713aSLionel Sambuc     return;
177f4a2713aSLionel Sambuc   CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
178f4a2713aSLionel Sambuc   if (!Ex6 || !IsStdString(Ex6->getType()))
179f4a2713aSLionel Sambuc     return;
180f4a2713aSLionel Sambuc 
181f4a2713aSLionel Sambuc   // Okay, badness!  Report an error.
182f4a2713aSLionel Sambuc   const char *desc = "StringRef should not be bound to temporary "
183f4a2713aSLionel Sambuc                      "std::string that it outlives";
184f4a2713aSLionel Sambuc   PathDiagnosticLocation VDLoc =
185f4a2713aSLionel Sambuc     PathDiagnosticLocation::createBegin(VD, BR.getSourceManager());
186*0a6a1f1dSLionel Sambuc   BR.EmitBasicReport(DeclWithIssue, Checker, desc, "LLVM Conventions", desc,
187f4a2713aSLionel Sambuc                      VDLoc, Init->getSourceRange());
188f4a2713aSLionel Sambuc }
189f4a2713aSLionel Sambuc 
190f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
191f4a2713aSLionel Sambuc // CHECK: Clang AST nodes should not have fields that can allocate
192f4a2713aSLionel Sambuc //   memory.
193f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
194f4a2713aSLionel Sambuc 
AllocatesMemory(QualType T)195f4a2713aSLionel Sambuc static bool AllocatesMemory(QualType T) {
196f4a2713aSLionel Sambuc   return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
197f4a2713aSLionel Sambuc }
198f4a2713aSLionel Sambuc 
199f4a2713aSLionel Sambuc // This type checking could be sped up via dynamic programming.
IsPartOfAST(const CXXRecordDecl * R)200f4a2713aSLionel Sambuc static bool IsPartOfAST(const CXXRecordDecl *R) {
201f4a2713aSLionel Sambuc   if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
202f4a2713aSLionel Sambuc     return true;
203f4a2713aSLionel Sambuc 
204*0a6a1f1dSLionel Sambuc   for (const auto &BS : R->bases()) {
205f4a2713aSLionel Sambuc     QualType T = BS.getType();
206f4a2713aSLionel Sambuc     if (const RecordType *baseT = T->getAs<RecordType>()) {
207f4a2713aSLionel Sambuc       CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
208f4a2713aSLionel Sambuc       if (IsPartOfAST(baseD))
209f4a2713aSLionel Sambuc         return true;
210f4a2713aSLionel Sambuc     }
211f4a2713aSLionel Sambuc   }
212f4a2713aSLionel Sambuc 
213f4a2713aSLionel Sambuc   return false;
214f4a2713aSLionel Sambuc }
215f4a2713aSLionel Sambuc 
216f4a2713aSLionel Sambuc namespace {
217f4a2713aSLionel Sambuc class ASTFieldVisitor {
218f4a2713aSLionel Sambuc   SmallVector<FieldDecl*, 10> FieldChain;
219f4a2713aSLionel Sambuc   const CXXRecordDecl *Root;
220f4a2713aSLionel Sambuc   BugReporter &BR;
221*0a6a1f1dSLionel Sambuc   const CheckerBase *Checker;
222*0a6a1f1dSLionel Sambuc 
223f4a2713aSLionel Sambuc public:
ASTFieldVisitor(const CXXRecordDecl * root,BugReporter & br,const CheckerBase * checker)224*0a6a1f1dSLionel Sambuc   ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br,
225*0a6a1f1dSLionel Sambuc                   const CheckerBase *checker)
226*0a6a1f1dSLionel Sambuc       : Root(root), BR(br), Checker(checker) {}
227f4a2713aSLionel Sambuc 
228f4a2713aSLionel Sambuc   void Visit(FieldDecl *D);
229f4a2713aSLionel Sambuc   void ReportError(QualType T);
230f4a2713aSLionel Sambuc };
231f4a2713aSLionel Sambuc } // end anonymous namespace
232f4a2713aSLionel Sambuc 
CheckASTMemory(const CXXRecordDecl * R,BugReporter & BR,const CheckerBase * Checker)233*0a6a1f1dSLionel Sambuc static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR,
234*0a6a1f1dSLionel Sambuc                            const CheckerBase *Checker) {
235f4a2713aSLionel Sambuc   if (!IsPartOfAST(R))
236f4a2713aSLionel Sambuc     return;
237f4a2713aSLionel Sambuc 
238*0a6a1f1dSLionel Sambuc   for (auto *I : R->fields()) {
239*0a6a1f1dSLionel Sambuc     ASTFieldVisitor walker(R, BR, Checker);
240*0a6a1f1dSLionel Sambuc     walker.Visit(I);
241f4a2713aSLionel Sambuc   }
242f4a2713aSLionel Sambuc }
243f4a2713aSLionel Sambuc 
Visit(FieldDecl * D)244f4a2713aSLionel Sambuc void ASTFieldVisitor::Visit(FieldDecl *D) {
245f4a2713aSLionel Sambuc   FieldChain.push_back(D);
246f4a2713aSLionel Sambuc 
247f4a2713aSLionel Sambuc   QualType T = D->getType();
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc   if (AllocatesMemory(T))
250f4a2713aSLionel Sambuc     ReportError(T);
251f4a2713aSLionel Sambuc 
252f4a2713aSLionel Sambuc   if (const RecordType *RT = T->getAs<RecordType>()) {
253f4a2713aSLionel Sambuc     const RecordDecl *RD = RT->getDecl()->getDefinition();
254*0a6a1f1dSLionel Sambuc     for (auto *I : RD->fields())
255*0a6a1f1dSLionel Sambuc       Visit(I);
256f4a2713aSLionel Sambuc   }
257f4a2713aSLionel Sambuc 
258f4a2713aSLionel Sambuc   FieldChain.pop_back();
259f4a2713aSLionel Sambuc }
260f4a2713aSLionel Sambuc 
ReportError(QualType T)261f4a2713aSLionel Sambuc void ASTFieldVisitor::ReportError(QualType T) {
262f4a2713aSLionel Sambuc   SmallString<1024> buf;
263f4a2713aSLionel Sambuc   llvm::raw_svector_ostream os(buf);
264f4a2713aSLionel Sambuc 
265f4a2713aSLionel Sambuc   os << "AST class '" << Root->getName() << "' has a field '"
266f4a2713aSLionel Sambuc      << FieldChain.front()->getName() << "' that allocates heap memory";
267f4a2713aSLionel Sambuc   if (FieldChain.size() > 1) {
268f4a2713aSLionel Sambuc     os << " via the following chain: ";
269f4a2713aSLionel Sambuc     bool isFirst = true;
270f4a2713aSLionel Sambuc     for (SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
271f4a2713aSLionel Sambuc          E=FieldChain.end(); I!=E; ++I) {
272f4a2713aSLionel Sambuc       if (!isFirst)
273f4a2713aSLionel Sambuc         os << '.';
274f4a2713aSLionel Sambuc       else
275f4a2713aSLionel Sambuc         isFirst = false;
276f4a2713aSLionel Sambuc       os << (*I)->getName();
277f4a2713aSLionel Sambuc     }
278f4a2713aSLionel Sambuc   }
279f4a2713aSLionel Sambuc   os << " (type " << FieldChain.back()->getType().getAsString() << ")";
280f4a2713aSLionel Sambuc   os.flush();
281f4a2713aSLionel Sambuc 
282f4a2713aSLionel Sambuc   // Note that this will fire for every translation unit that uses this
283f4a2713aSLionel Sambuc   // class.  This is suboptimal, but at least scan-build will merge
284f4a2713aSLionel Sambuc   // duplicate HTML reports.  In the future we need a unified way of merging
285f4a2713aSLionel Sambuc   // duplicate reports across translation units.  For C++ classes we cannot
286f4a2713aSLionel Sambuc   // just report warnings when we see an out-of-line method definition for a
287f4a2713aSLionel Sambuc   // class, as that heuristic doesn't always work (the complete definition of
288f4a2713aSLionel Sambuc   // the class may be in the header file, for example).
289f4a2713aSLionel Sambuc   PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(
290f4a2713aSLionel Sambuc                                FieldChain.front(), BR.getSourceManager());
291*0a6a1f1dSLionel Sambuc   BR.EmitBasicReport(Root, Checker, "AST node allocates heap memory",
292*0a6a1f1dSLionel Sambuc                      "LLVM Conventions", os.str(), L);
293f4a2713aSLionel Sambuc }
294f4a2713aSLionel Sambuc 
295f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
296f4a2713aSLionel Sambuc // LLVMConventionsChecker
297f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
298f4a2713aSLionel Sambuc 
299f4a2713aSLionel Sambuc namespace {
300f4a2713aSLionel Sambuc class LLVMConventionsChecker : public Checker<
301f4a2713aSLionel Sambuc                                                 check::ASTDecl<CXXRecordDecl>,
302f4a2713aSLionel Sambuc                                                 check::ASTCodeBody > {
303f4a2713aSLionel Sambuc public:
checkASTDecl(const CXXRecordDecl * R,AnalysisManager & mgr,BugReporter & BR) const304f4a2713aSLionel Sambuc   void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
305f4a2713aSLionel Sambuc                     BugReporter &BR) const {
306f4a2713aSLionel Sambuc     if (R->isCompleteDefinition())
307*0a6a1f1dSLionel Sambuc       CheckASTMemory(R, BR, this);
308f4a2713aSLionel Sambuc   }
309f4a2713aSLionel Sambuc 
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const310f4a2713aSLionel Sambuc   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
311f4a2713aSLionel Sambuc                         BugReporter &BR) const {
312*0a6a1f1dSLionel Sambuc     CheckStringRefAssignedTemporary(D, BR, this);
313f4a2713aSLionel Sambuc   }
314f4a2713aSLionel Sambuc };
315f4a2713aSLionel Sambuc }
316f4a2713aSLionel Sambuc 
registerLLVMConventionsChecker(CheckerManager & mgr)317f4a2713aSLionel Sambuc void ento::registerLLVMConventionsChecker(CheckerManager &mgr) {
318f4a2713aSLionel Sambuc   mgr.registerChecker<LLVMConventionsChecker>();
319f4a2713aSLionel Sambuc }
320