1 //=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This defines LLVMConventionsChecker, a bunch of small little checks
11 // for checking specific coding conventions in the LLVM/Clang codebase.
13 //===----------------------------------------------------------------------===//
15 #include "clang/AST/DeclTemplate.h"
16 #include "clang/AST/StmtVisitor.h"
17 #include "clang/GR/Checkers/LocalCheckers.h"
18 #include "clang/GR/BugReporter/BugReporter.h"
20 #include "llvm/ADT/StringRef.h"
22 using namespace clang
;
24 //===----------------------------------------------------------------------===//
25 // Generic type checking routines.
26 //===----------------------------------------------------------------------===//
28 static bool IsLLVMStringRef(QualType T
) {
29 const RecordType
*RT
= T
->getAs
<RecordType
>();
33 return llvm::StringRef(QualType(RT
, 0).getAsString()) ==
34 "class llvm::StringRef";
37 /// Check whether the declaration is semantically inside the top-level
38 /// namespace named by ns.
39 static bool InNamespace(const Decl
*D
, llvm::StringRef NS
) {
40 const DeclContext
*DC
= D
->getDeclContext();
41 const NamespaceDecl
*ND
= dyn_cast
<NamespaceDecl
>(D
->getDeclContext());
44 const IdentifierInfo
*II
= ND
->getIdentifier();
45 if (!II
|| !II
->getName().equals(NS
))
47 DC
= ND
->getDeclContext();
48 return isa
<TranslationUnitDecl
>(DC
);
51 static bool IsStdString(QualType T
) {
52 if (const ElaboratedType
*QT
= T
->getAs
<ElaboratedType
>())
53 T
= QT
->getNamedType();
55 const TypedefType
*TT
= T
->getAs
<TypedefType
>();
59 const TypedefDecl
*TD
= TT
->getDecl();
61 if (!InNamespace(TD
, "std"))
64 return TD
->getName() == "string";
67 static bool IsClangType(const RecordDecl
*RD
) {
68 return RD
->getName() == "Type" && InNamespace(RD
, "clang");
71 static bool IsClangDecl(const RecordDecl
*RD
) {
72 return RD
->getName() == "Decl" && InNamespace(RD
, "clang");
75 static bool IsClangStmt(const RecordDecl
*RD
) {
76 return RD
->getName() == "Stmt" && InNamespace(RD
, "clang");
79 static bool IsClangAttr(const RecordDecl
*RD
) {
80 return RD
->getName() == "Attr" && InNamespace(RD
, "clang");
83 static bool IsStdVector(QualType T
) {
84 const TemplateSpecializationType
*TS
= T
->getAs
<TemplateSpecializationType
>();
88 TemplateName TM
= TS
->getTemplateName();
89 TemplateDecl
*TD
= TM
.getAsTemplateDecl();
91 if (!TD
|| !InNamespace(TD
, "std"))
94 return TD
->getName() == "vector";
97 static bool IsSmallVector(QualType T
) {
98 const TemplateSpecializationType
*TS
= T
->getAs
<TemplateSpecializationType
>();
102 TemplateName TM
= TS
->getTemplateName();
103 TemplateDecl
*TD
= TM
.getAsTemplateDecl();
105 if (!TD
|| !InNamespace(TD
, "llvm"))
108 return TD
->getName() == "SmallVector";
111 //===----------------------------------------------------------------------===//
112 // CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
113 // lifetime is shorter than the StringRef's.
114 //===----------------------------------------------------------------------===//
117 class StringRefCheckerVisitor
: public StmtVisitor
<StringRefCheckerVisitor
> {
120 StringRefCheckerVisitor(BugReporter
&br
) : BR(br
) {}
121 void VisitChildren(Stmt
*S
) {
122 for (Stmt::child_iterator I
= S
->child_begin(), E
= S
->child_end() ;
124 if (Stmt
*child
= *I
)
127 void VisitStmt(Stmt
*S
) { VisitChildren(S
); }
128 void VisitDeclStmt(DeclStmt
*DS
);
130 void VisitVarDecl(VarDecl
*VD
);
132 } // end anonymous namespace
134 static void CheckStringRefAssignedTemporary(const Decl
*D
, BugReporter
&BR
) {
135 StringRefCheckerVisitor
walker(BR
);
136 walker
.Visit(D
->getBody());
139 void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt
*S
) {
142 for (DeclStmt::decl_iterator I
= S
->decl_begin(), E
= S
->decl_end();I
!=E
; ++I
)
143 if (VarDecl
*VD
= dyn_cast
<VarDecl
>(*I
))
147 void StringRefCheckerVisitor::VisitVarDecl(VarDecl
*VD
) {
148 Expr
*Init
= VD
->getInit();
152 // Pattern match for:
153 // llvm::StringRef x = call() (where call returns std::string)
154 if (!IsLLVMStringRef(VD
->getType()))
156 ExprWithCleanups
*Ex1
= dyn_cast
<ExprWithCleanups
>(Init
);
159 CXXConstructExpr
*Ex2
= dyn_cast
<CXXConstructExpr
>(Ex1
->getSubExpr());
160 if (!Ex2
|| Ex2
->getNumArgs() != 1)
162 ImplicitCastExpr
*Ex3
= dyn_cast
<ImplicitCastExpr
>(Ex2
->getArg(0));
165 CXXConstructExpr
*Ex4
= dyn_cast
<CXXConstructExpr
>(Ex3
->getSubExpr());
166 if (!Ex4
|| Ex4
->getNumArgs() != 1)
168 ImplicitCastExpr
*Ex5
= dyn_cast
<ImplicitCastExpr
>(Ex4
->getArg(0));
171 CXXBindTemporaryExpr
*Ex6
= dyn_cast
<CXXBindTemporaryExpr
>(Ex5
->getSubExpr());
172 if (!Ex6
|| !IsStdString(Ex6
->getType()))
175 // Okay, badness! Report an error.
176 const char *desc
= "StringRef should not be bound to temporary "
177 "std::string that it outlives";
179 BR
.EmitBasicReport(desc
, "LLVM Conventions", desc
,
180 VD
->getLocStart(), Init
->getSourceRange());
183 //===----------------------------------------------------------------------===//
184 // CHECK: Clang AST nodes should not have fields that can allocate
186 //===----------------------------------------------------------------------===//
188 static bool AllocatesMemory(QualType T
) {
189 return IsStdVector(T
) || IsStdString(T
) || IsSmallVector(T
);
192 // This type checking could be sped up via dynamic programming.
193 static bool IsPartOfAST(const CXXRecordDecl
*R
) {
194 if (IsClangStmt(R
) || IsClangType(R
) || IsClangDecl(R
) || IsClangAttr(R
))
197 for (CXXRecordDecl::base_class_const_iterator I
= R
->bases_begin(),
198 E
= R
->bases_end(); I
!=E
; ++I
) {
199 CXXBaseSpecifier BS
= *I
;
200 QualType T
= BS
.getType();
201 if (const RecordType
*baseT
= T
->getAs
<RecordType
>()) {
202 CXXRecordDecl
*baseD
= cast
<CXXRecordDecl
>(baseT
->getDecl());
203 if (IsPartOfAST(baseD
))
212 class ASTFieldVisitor
{
213 llvm::SmallVector
<FieldDecl
*, 10> FieldChain
;
217 ASTFieldVisitor(CXXRecordDecl
*root
, BugReporter
&br
)
218 : Root(root
), BR(br
) {}
220 void Visit(FieldDecl
*D
);
221 void ReportError(QualType T
);
223 } // end anonymous namespace
225 static void CheckASTMemory(CXXRecordDecl
*R
, BugReporter
&BR
) {
229 for (RecordDecl::field_iterator I
= R
->field_begin(), E
= R
->field_end();
231 ASTFieldVisitor
walker(R
, BR
);
236 void ASTFieldVisitor::Visit(FieldDecl
*D
) {
237 FieldChain
.push_back(D
);
239 QualType T
= D
->getType();
241 if (AllocatesMemory(T
))
244 if (const RecordType
*RT
= T
->getAs
<RecordType
>()) {
245 const RecordDecl
*RD
= RT
->getDecl()->getDefinition();
246 for (RecordDecl::field_iterator I
= RD
->field_begin(), E
= RD
->field_end();
251 FieldChain
.pop_back();
254 void ASTFieldVisitor::ReportError(QualType T
) {
255 llvm::SmallString
<1024> buf
;
256 llvm::raw_svector_ostream
os(buf
);
258 os
<< "AST class '" << Root
->getName() << "' has a field '"
259 << FieldChain
.front()->getName() << "' that allocates heap memory";
260 if (FieldChain
.size() > 1) {
261 os
<< " via the following chain: ";
263 for (llvm::SmallVectorImpl
<FieldDecl
*>::iterator I
=FieldChain
.begin(),
264 E
=FieldChain
.end(); I
!=E
; ++I
) {
269 os
<< (*I
)->getName();
272 os
<< " (type " << FieldChain
.back()->getType().getAsString() << ")";
275 // Note that this will fire for every translation unit that uses this
276 // class. This is suboptimal, but at least scan-build will merge
277 // duplicate HTML reports. In the future we need a unified way of merging
278 // duplicate reports across translation units. For C++ classes we cannot
279 // just report warnings when we see an out-of-line method definition for a
280 // class, as that heuristic doesn't always work (the complete definition of
281 // the class may be in the header file, for example).
282 BR
.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
283 os
.str(), FieldChain
.front()->getLocStart());
286 //===----------------------------------------------------------------------===//
287 // Entry point for all checks.
288 //===----------------------------------------------------------------------===//
290 static void ScanCodeDecls(DeclContext
*DC
, BugReporter
&BR
) {
291 for (DeclContext::decl_iterator I
=DC
->decls_begin(), E
=DC
->decls_end();
297 CheckStringRefAssignedTemporary(D
, BR
);
299 if (CXXRecordDecl
*R
= dyn_cast
<CXXRecordDecl
>(D
))
300 if (R
->isDefinition())
301 CheckASTMemory(R
, BR
);
303 if (DeclContext
*DC_child
= dyn_cast
<DeclContext
>(D
))
304 ScanCodeDecls(DC_child
, BR
);
308 void clang::CheckLLVMConventions(TranslationUnitDecl
&TU
,
310 ScanCodeDecls(&TU
, BR
);