blob: 242f4de2b6817a560b9b73f42fc48e94cc8879b1 [file] [log] [blame]
Ted Kremenek6dd66ed2010-02-14 02:45:18 +00001//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This defines LLVMConventionsChecker, a bunch of small little checks
11// for checking specific coding conventions in the LLVM/Clang codebase.
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremeneka6b87932010-02-14 19:09:13 +000015#include "clang/AST/DeclTemplate.h"
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000016#include "clang/AST/StmtVisitor.h"
17#include "clang/Checker/Checkers/LocalCheckers.h"
18#include "clang/Checker/BugReporter/BugReporter.h"
19#include <string>
Ted Kremeneka6b87932010-02-14 19:09:13 +000020#include "llvm/ADT/StringRef.h"
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000021
22using namespace clang;
23
24//===----------------------------------------------------------------------===//
Ted Kremenek55abf162010-02-14 19:08:36 +000025// Generic type checking routines.
26//===----------------------------------------------------------------------===//
27
Ted Kremeneka6b87932010-02-14 19:09:13 +000028static bool IsLLVMStringRef(QualType T) {
Ted Kremenek55abf162010-02-14 19:08:36 +000029 const RecordType *RT = T->getAs<RecordType>();
30 if (!RT)
31 return false;
32
33 return llvm::StringRef(QualType(RT, 0).getAsString()) ==
Ted Kremeneka6b87932010-02-14 19:09:13 +000034 "class llvm::StringRef";
35}
36
37static bool InStdNamespace(const Decl *D) {
38 const DeclContext *DC = D->getDeclContext();
39 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
40 if (!ND)
41 return false;
42 const IdentifierInfo *II = ND->getIdentifier();
43 if (!II || II->getName() != "std")
44 return false;
45 DC = ND->getDeclContext();
46 return isa<TranslationUnitDecl>(DC);
Ted Kremenek55abf162010-02-14 19:08:36 +000047}
48
49static bool IsStdString(QualType T) {
50 if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
51 T = QT->getNamedType();
52
53 const TypedefType *TT = T->getAs<TypedefType>();
54 if (!TT)
55 return false;
56
Ted Kremenek676ca152010-02-14 19:09:05 +000057 const TypedefDecl *TD = TT->getDecl();
Ted Kremeneka6b87932010-02-14 19:09:13 +000058
59 if (!InStdNamespace(TD))
60 return false;
61
62 return TD->getName() == "string";
63}
64
65static bool InClangNamespace(const Decl *D) {
66 const DeclContext *DC = D->getDeclContext();
67 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
Ted Kremenek55abf162010-02-14 19:08:36 +000068 if (!ND)
69 return false;
70 const IdentifierInfo *II = ND->getIdentifier();
Ted Kremeneka6b87932010-02-14 19:09:13 +000071 if (!II || II->getName() != "clang")
72 return false;
73 DC = ND->getDeclContext();
74 return isa<TranslationUnitDecl>(DC);
75}
76
77static bool InLLVMNamespace(const Decl *D) {
78 const DeclContext *DC = D->getDeclContext();
79 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
80 if (!ND)
81 return false;
82 const IdentifierInfo *II = ND->getIdentifier();
83 if (!II || II->getName() != "llvm")
84 return false;
85 DC = ND->getDeclContext();
86 return isa<TranslationUnitDecl>(DC);
87}
88
89static bool IsClangType(const RecordDecl *RD) {
90 return RD->getName() == "Type" && InClangNamespace(RD);
91}
92
93static bool IsClangDecl(const RecordDecl *RD) {
94 return RD->getName() == "Decl" && InClangNamespace(RD);
95}
96
97static bool IsClangStmt(const RecordDecl *RD) {
98 return RD->getName() == "Stmt" && InClangNamespace(RD);
99}
100
101static bool IsStdVector(QualType T) {
102 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
103 if (!TS)
Ted Kremenek55abf162010-02-14 19:08:36 +0000104 return false;
105
Ted Kremeneka6b87932010-02-14 19:09:13 +0000106 TemplateName TM = TS->getTemplateName();
107 TemplateDecl *TD = TM.getAsTemplateDecl();
108
109 if (!TD || !InStdNamespace(TD))
110 return false;
111
112 return TD->getName() == "vector";
113}
114
115static bool IsSmallVector(QualType T) {
116 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
117 if (!TS)
118 return false;
119
120 TemplateName TM = TS->getTemplateName();
121 TemplateDecl *TD = TM.getAsTemplateDecl();
122
123 if (!TD || !InLLVMNamespace(TD))
124 return false;
125
126 return TD->getName() == "SmallVector";
Ted Kremenek55abf162010-02-14 19:08:36 +0000127}
128
129//===----------------------------------------------------------------------===//
130// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
131// lifetime is shorter than the StringRef's.
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000132//===----------------------------------------------------------------------===//
133
134namespace {
135class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
136 BugReporter &BR;
137public:
138 StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
139 void VisitChildren(Stmt *S) {
140 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
141 I != E; ++I)
142 if (Stmt *child = *I)
143 Visit(child);
144 }
145 void VisitStmt(Stmt *S) { VisitChildren(S); }
146 void VisitDeclStmt(DeclStmt *DS);
147private:
148 void VisitVarDecl(VarDecl *VD);
Ted Kremenek005f09b2010-02-14 19:08:43 +0000149 void CheckStringRefBoundtoTemporaryString(VarDecl *VD);
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000150};
151} // end anonymous namespace
152
153static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
154 StringRefCheckerVisitor walker(BR);
155 walker.Visit(D->getBody());
156}
157
158void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
Ted Kremenek005f09b2010-02-14 19:08:43 +0000159 VisitChildren(S);
160
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000161 for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
162 if (VarDecl *VD = dyn_cast<VarDecl>(*I))
163 VisitVarDecl(VD);
164}
165
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000166void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
167 Expr *Init = VD->getInit();
168 if (!Init)
Ted Kremenek676ca152010-02-14 19:09:05 +0000169 return;
Ted Kremenek55abf162010-02-14 19:08:36 +0000170
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000171 // Pattern match for:
172 // llvm::StringRef x = call() (where call returns std::string)
Ted Kremeneka6b87932010-02-14 19:09:13 +0000173 if (!IsLLVMStringRef(VD->getType()))
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000174 return;
175 CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
176 if (!Ex1)
177 return;
178 CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
179 if (!Ex2 || Ex2->getNumArgs() != 1)
180 return;
181 ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
182 if (!Ex3)
183 return;
184 CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
185 if (!Ex4 || Ex4->getNumArgs() != 1)
186 return;
187 ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
188 if (!Ex5)
189 return;
190 CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
191 if (!Ex6 || !IsStdString(Ex6->getType()))
192 return;
Ted Kremenek55abf162010-02-14 19:08:36 +0000193
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000194 // Okay, badness! Report an error.
Ted Kremeneka6b87932010-02-14 19:09:13 +0000195 const char *desc = "StringRef should not be bound to temporary "
196 "std::string that it outlives";
197
198 BR.EmitBasicReport(desc, "LLVM Conventions", desc,
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000199 VD->getLocStart(), Init->getSourceRange());
200}
201
202//===----------------------------------------------------------------------===//
Ted Kremeneka6b87932010-02-14 19:09:13 +0000203// CHECK: Clang AST nodes should not have fields that can allocate
204// memory.
205//===----------------------------------------------------------------------===//
206
207static bool AllocatesMemory(QualType T) {
208 return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
209}
210
211// This type checking could be sped up via dynamic programming.
212static bool IsPartOfAST(const CXXRecordDecl *R) {
213 if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R))
214 return true;
215
216 for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
217 E = R->bases_end(); I!=E; ++I) {
218 CXXBaseSpecifier BS = *I;
219 QualType T = BS.getType();
220 if (const RecordType *baseT = T->getAs<RecordType>()) {
221 CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
222 if (IsPartOfAST(baseD))
223 return true;
224 }
225 }
226
227 return false;
228}
229
230namespace {
231class ASTFieldVisitor {
232 llvm::SmallVector<FieldDecl*, 10> FieldChain;
233 CXXRecordDecl *Root;
234 BugReporter &BR;
235public:
236 ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
237 : Root(root), BR(br) {}
238
239 void Visit(FieldDecl *D);
240 void ReportError(QualType T);
241};
242} // end anonymous namespace
243
244static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
245 if (!IsPartOfAST(R))
246 return;
247
248 for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
249 I != E; ++I) {
250 ASTFieldVisitor walker(R, BR);
251 walker.Visit(*I);
252 }
253}
254
255void ASTFieldVisitor::Visit(FieldDecl *D) {
256 FieldChain.push_back(D);
257
258 QualType T = D->getType();
259
260 if (AllocatesMemory(T))
261 ReportError(T);
262
263 if (const RecordType *RT = T->getAs<RecordType>()) {
264 const RecordDecl *RD = RT->getDecl()->getDefinition();
265 for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
266 I != E; ++I)
267 Visit(*I);
268 }
269
270 FieldChain.pop_back();
271}
272
273void ASTFieldVisitor::ReportError(QualType T) {
274 llvm::SmallString<1024> buf;
275 llvm::raw_svector_ostream os(buf);
276
277 os << "AST class '" << Root->getName() << "' has a field '"
278 << FieldChain.front()->getName() << "' that allocates heap memory";
279 if (FieldChain.size() > 1) {
280 os << " via the following chain: ";
281 bool isFirst = true;
282 for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
283 E=FieldChain.end(); I!=E; ++I) {
284 if (!isFirst)
285 os << '.';
286 else
287 isFirst = false;
288 os << (*I)->getName();
289 }
290 }
291 os << " (type " << FieldChain.back()->getType().getAsString() << ")";
292 os.flush();
293
294 // Note that this will fire for every translation unit that uses this
295 // class. This is suboptimal, but at least scan-build will merge
296 // duplicate HTML reports. In the future we need a unified way of merging
297 // duplicate reports across translation units. For C++ classes we cannot
298 // just report warnings when we see an out-of-line method definition for a
299 // class, as that heuristic doesn't always work (the complete definition of
300 // the class may be in the header file, for example).
301 BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
302 os.str(), FieldChain.front()->getLocStart());
303}
304
305//===----------------------------------------------------------------------===//
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000306// Entry point for all checks.
307//===----------------------------------------------------------------------===//
308
Ted Kremenek676ca152010-02-14 19:09:05 +0000309static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
310 for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
311 I!=E ; ++I) {
312
313 Decl *D = *I;
Ted Kremeneka6b87932010-02-14 19:09:13 +0000314
315 if (D->getBody())
Ted Kremenek676ca152010-02-14 19:09:05 +0000316 CheckStringRefAssignedTemporary(D, BR);
Ted Kremeneka6b87932010-02-14 19:09:13 +0000317
318 if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
319 if (R->isDefinition())
320 CheckASTMemory(R, BR);
Ted Kremenek676ca152010-02-14 19:09:05 +0000321
322 if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
323 ScanCodeDecls(DC_child, BR);
324 }
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000325}
Ted Kremenek676ca152010-02-14 19:09:05 +0000326
327void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
328 BugReporter &BR) {
329 ScanCodeDecls(&TU, BR);
330}
331