blob: 17a17a8bbfe12fb88224d4e1cec7196f58e0d728 [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
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/StmtVisitor.h"
17#include "clang/Checker/Checkers/LocalCheckers.h"
18#include "clang/Checker/BugReporter/BugReporter.h"
19#include <string>
20#include <llvm/ADT/StringRef.h>
21
22using namespace clang;
23
24//===----------------------------------------------------------------------===//
Ted Kremenek55abf162010-02-14 19:08:36 +000025// Generic type checking routines.
26//===----------------------------------------------------------------------===//
27
28static bool IsStringRef(QualType T) {
29 const RecordType *RT = T->getAs<RecordType>();
30 if (!RT)
31 return false;
32
33 return llvm::StringRef(QualType(RT, 0).getAsString()) ==
34 "class llvm::StringRef";
35}
36
37static bool IsStdString(QualType T) {
38 if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
39 T = QT->getNamedType();
40
41 const TypedefType *TT = T->getAs<TypedefType>();
42 if (!TT)
43 return false;
44
Ted Kremenek676ca152010-02-14 19:09:05 +000045 const TypedefDecl *TD = TT->getDecl();
Ted Kremenek55abf162010-02-14 19:08:36 +000046 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(TD->getDeclContext());
47 if (!ND)
48 return false;
49 const IdentifierInfo *II = ND->getIdentifier();
50 if (!II || II->getName() != "std")
51 return false;
52
53 DeclarationName N = TD->getDeclName();
54 return llvm::StringRef(N.getAsString()) == "string";
55}
56
57//===----------------------------------------------------------------------===//
58// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
59// lifetime is shorter than the StringRef's.
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000060//===----------------------------------------------------------------------===//
61
62namespace {
63class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
64 BugReporter &BR;
65public:
66 StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
67 void VisitChildren(Stmt *S) {
68 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
69 I != E; ++I)
70 if (Stmt *child = *I)
71 Visit(child);
72 }
73 void VisitStmt(Stmt *S) { VisitChildren(S); }
74 void VisitDeclStmt(DeclStmt *DS);
75private:
76 void VisitVarDecl(VarDecl *VD);
Ted Kremenek005f09b2010-02-14 19:08:43 +000077 void CheckStringRefBoundtoTemporaryString(VarDecl *VD);
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000078};
79} // end anonymous namespace
80
81static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
82 StringRefCheckerVisitor walker(BR);
83 walker.Visit(D->getBody());
84}
85
86void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
Ted Kremenek005f09b2010-02-14 19:08:43 +000087 VisitChildren(S);
88
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000089 for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
90 if (VarDecl *VD = dyn_cast<VarDecl>(*I))
91 VisitVarDecl(VD);
92}
93
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000094void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
95 Expr *Init = VD->getInit();
96 if (!Init)
Ted Kremenek676ca152010-02-14 19:09:05 +000097 return;
Ted Kremenek55abf162010-02-14 19:08:36 +000098
Ted Kremenek6dd66ed2010-02-14 02:45:18 +000099 // Pattern match for:
100 // llvm::StringRef x = call() (where call returns std::string)
101 if (!IsStringRef(VD->getType()))
102 return;
103 CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
104 if (!Ex1)
105 return;
106 CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
107 if (!Ex2 || Ex2->getNumArgs() != 1)
108 return;
109 ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
110 if (!Ex3)
111 return;
112 CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
113 if (!Ex4 || Ex4->getNumArgs() != 1)
114 return;
115 ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
116 if (!Ex5)
117 return;
118 CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
119 if (!Ex6 || !IsStdString(Ex6->getType()))
120 return;
Ted Kremenek55abf162010-02-14 19:08:36 +0000121
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000122 // Okay, badness! Report an error.
123 BR.EmitBasicReport("StringRef should not be bound to temporary "
124 "std::string that it outlives", "LLVM Conventions",
125 VD->getLocStart(), Init->getSourceRange());
126}
127
128//===----------------------------------------------------------------------===//
129// Entry point for all checks.
130//===----------------------------------------------------------------------===//
131
Ted Kremenek676ca152010-02-14 19:09:05 +0000132static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
133 for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
134 I!=E ; ++I) {
135
136 Decl *D = *I;
137 if (D->getBody()) {
138 CheckStringRefAssignedTemporary(D, BR);
139 }
140
141 if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
142 ScanCodeDecls(DC_child, BR);
143 }
Ted Kremenek6dd66ed2010-02-14 02:45:18 +0000144}
Ted Kremenek676ca152010-02-14 19:09:05 +0000145
146void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
147 BugReporter &BR) {
148 ScanCodeDecls(&TU, BR);
149}
150