blob: 14f0fc1280dfcdd259d78596d21b879ce5c98c1e [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
Ted Kremenek1ed482b2010-02-14 22:58:16 +0000101static bool isClangAttr(const RecordDecl *RD) {
102 return RD->getName() == "Attr" && InClangNamespace(RD);
103}
104
Ted Kremeneka6b87932010-02-14 19:09:13 +0000105static bool IsStdVector(QualType T) {
106 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
107 if (!TS)
Ted Kremenek55abf162010-02-14 19:08:36 +0000108 return false;
109
Ted Kremeneka6b87932010-02-14 19:09:13 +0000110 TemplateName TM = TS->getTemplateName();
111 TemplateDecl *TD = TM.getAsTemplateDecl();
112
113 if (!TD || !InStdNamespace(TD))
114 return false;
115
116 return TD->getName() == "vector";
117}
118
119static bool IsSmallVector(QualType T) {
120 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
121 if (!TS)
122 return false;
123
124 TemplateName TM = TS->getTemplateName();
125 TemplateDecl *TD = TM.getAsTemplateDecl();
126
127 if (!TD || !InLLVMNamespace(TD))
128 return false;
129
130 return TD->getName() == "SmallVector";
Ted Kremenek55abf162010-02-14 19:08:36 +0000131}
132
133//===----------------------------------------------------------------------===//
134// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
135// lifetime is shorter than the StringRef's.
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000136//===----------------------------------------------------------------------===//
137
138namespace {
139class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
140 BugReporter &BR;
141public:
142 StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
143 void VisitChildren(Stmt *S) {
144 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
145 I != E; ++I)
146 if (Stmt *child = *I)
147 Visit(child);
148 }
149 void VisitStmt(Stmt *S) { VisitChildren(S); }
150 void VisitDeclStmt(DeclStmt *DS);
151private:
152 void VisitVarDecl(VarDecl *VD);
Ted Kremenek005f09b2010-02-14 19:08:43 +0000153 void CheckStringRefBoundtoTemporaryString(VarDecl *VD);
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000154};
155} // end anonymous namespace
156
157static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
158 StringRefCheckerVisitor walker(BR);
159 walker.Visit(D->getBody());
160}
161
162void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
Ted Kremenek005f09b2010-02-14 19:08:43 +0000163 VisitChildren(S);
164
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000165 for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
166 if (VarDecl *VD = dyn_cast<VarDecl>(*I))
167 VisitVarDecl(VD);
168}
169
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000170void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
171 Expr *Init = VD->getInit();
172 if (!Init)
Ted Kremenek676ca152010-02-14 19:09:05 +0000173 return;
Ted Kremenek55abf162010-02-14 19:08:36 +0000174
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000175 // Pattern match for:
176 // llvm::StringRef x = call() (where call returns std::string)
Ted Kremeneka6b87932010-02-14 19:09:13 +0000177 if (!IsLLVMStringRef(VD->getType()))
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000178 return;
179 CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
180 if (!Ex1)
181 return;
182 CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
183 if (!Ex2 || Ex2->getNumArgs() != 1)
184 return;
185 ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
186 if (!Ex3)
187 return;
188 CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
189 if (!Ex4 || Ex4->getNumArgs() != 1)
190 return;
191 ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
192 if (!Ex5)
193 return;
194 CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
195 if (!Ex6 || !IsStdString(Ex6->getType()))
196 return;
Ted Kremenek55abf162010-02-14 19:08:36 +0000197
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000198 // Okay, badness! Report an error.
Ted Kremeneka6b87932010-02-14 19:09:13 +0000199 const char *desc = "StringRef should not be bound to temporary "
200 "std::string that it outlives";
201
202 BR.EmitBasicReport(desc, "LLVM Conventions", desc,
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000203 VD->getLocStart(), Init->getSourceRange());
204}
205
206//===----------------------------------------------------------------------===//
Ted Kremeneka6b87932010-02-14 19:09:13 +0000207// CHECK: Clang AST nodes should not have fields that can allocate
208// memory.
209//===----------------------------------------------------------------------===//
210
211static bool AllocatesMemory(QualType T) {
212 return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
213}
214
215// This type checking could be sped up via dynamic programming.
216static bool IsPartOfAST(const CXXRecordDecl *R) {
Ted Kremenek1ed482b2010-02-14 22:58:16 +0000217 if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || isClangAttr(R))
Ted Kremeneka6b87932010-02-14 19:09:13 +0000218 return true;
219
220 for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
221 E = R->bases_end(); I!=E; ++I) {
222 CXXBaseSpecifier BS = *I;
223 QualType T = BS.getType();
224 if (const RecordType *baseT = T->getAs<RecordType>()) {
225 CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
226 if (IsPartOfAST(baseD))
227 return true;
228 }
229 }
230
231 return false;
232}
233
234namespace {
235class ASTFieldVisitor {
236 llvm::SmallVector<FieldDecl*, 10> FieldChain;
237 CXXRecordDecl *Root;
238 BugReporter &BR;
239public:
240 ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
241 : Root(root), BR(br) {}
242
243 void Visit(FieldDecl *D);
244 void ReportError(QualType T);
245};
246} // end anonymous namespace
247
248static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
249 if (!IsPartOfAST(R))
250 return;
251
252 for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
253 I != E; ++I) {
254 ASTFieldVisitor walker(R, BR);
255 walker.Visit(*I);
256 }
257}
258
259void ASTFieldVisitor::Visit(FieldDecl *D) {
260 FieldChain.push_back(D);
261
262 QualType T = D->getType();
263
264 if (AllocatesMemory(T))
265 ReportError(T);
266
267 if (const RecordType *RT = T->getAs<RecordType>()) {
268 const RecordDecl *RD = RT->getDecl()->getDefinition();
269 for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
270 I != E; ++I)
271 Visit(*I);
272 }
273
274 FieldChain.pop_back();
275}
276
277void ASTFieldVisitor::ReportError(QualType T) {
278 llvm::SmallString<1024> buf;
279 llvm::raw_svector_ostream os(buf);
280
281 os << "AST class '" << Root->getName() << "' has a field '"
282 << FieldChain.front()->getName() << "' that allocates heap memory";
283 if (FieldChain.size() > 1) {
284 os << " via the following chain: ";
285 bool isFirst = true;
286 for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
287 E=FieldChain.end(); I!=E; ++I) {
288 if (!isFirst)
289 os << '.';
290 else
291 isFirst = false;
292 os << (*I)->getName();
293 }
294 }
295 os << " (type " << FieldChain.back()->getType().getAsString() << ")";
296 os.flush();
297
298 // Note that this will fire for every translation unit that uses this
299 // class. This is suboptimal, but at least scan-build will merge
300 // duplicate HTML reports. In the future we need a unified way of merging
301 // duplicate reports across translation units. For C++ classes we cannot
302 // just report warnings when we see an out-of-line method definition for a
303 // class, as that heuristic doesn't always work (the complete definition of
304 // the class may be in the header file, for example).
305 BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
306 os.str(), FieldChain.front()->getLocStart());
307}
308
309//===----------------------------------------------------------------------===//
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000310// Entry point for all checks.
311//===----------------------------------------------------------------------===//
312
Ted Kremenek676ca152010-02-14 19:09:05 +0000313static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
314 for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
315 I!=E ; ++I) {
316
317 Decl *D = *I;
Ted Kremeneka6b87932010-02-14 19:09:13 +0000318
319 if (D->getBody())
Ted Kremenek676ca152010-02-14 19:09:05 +0000320 CheckStringRefAssignedTemporary(D, BR);
Ted Kremeneka6b87932010-02-14 19:09:13 +0000321
322 if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
323 if (R->isDefinition())
324 CheckASTMemory(R, BR);
Ted Kremenek676ca152010-02-14 19:09:05 +0000325
326 if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
327 ScanCodeDecls(DC_child, BR);
328 }
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000329}
Ted Kremenek676ca152010-02-14 19:09:05 +0000330
331void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
332 BugReporter &BR) {
333 ScanCodeDecls(&TU, BR);
334}
335