blob: 82f6d2c7bde8a26ee7df92978688e63c8d6c3639 [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//===----------------------------------------------------------------------===//
25// Check if an llvm::StringRef is bound to temporary std::string whose lifetime
26// is shorter than the StringRef's.
27//===----------------------------------------------------------------------===//
28
29namespace {
30class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
31 BugReporter &BR;
32public:
33 StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
34 void VisitChildren(Stmt *S) {
35 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
36 I != E; ++I)
37 if (Stmt *child = *I)
38 Visit(child);
39 }
40 void VisitStmt(Stmt *S) { VisitChildren(S); }
41 void VisitDeclStmt(DeclStmt *DS);
42private:
43 void VisitVarDecl(VarDecl *VD);
44};
45} // end anonymous namespace
46
47static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
48 StringRefCheckerVisitor walker(BR);
49 walker.Visit(D->getBody());
50}
51
52void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
53 for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
54 if (VarDecl *VD = dyn_cast<VarDecl>(*I))
55 VisitVarDecl(VD);
56}
57
58static bool IsStringRef(QualType T) {
59 const RecordType *RT = T->getAs<RecordType>();
60 if (!RT)
61 return false;
62
63 return llvm::StringRef(QualType(RT, 0).getAsString()) ==
64 "class llvm::StringRef";
65}
66
67static bool IsStdString(QualType T) {
68 if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>())
69 T = QT->getNamedType();
70
71 const TypedefType *TT = T->getAs<TypedefType>();
72 if (!TT)
73 return false;
74
75 const TypedefDecl *TD = TT->getDecl();
76 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(TD->getDeclContext());
77 if (!ND)
78 return false;
79 const IdentifierInfo *II = ND->getIdentifier();
80 if (!II || II->getName() != "std")
81 return false;
82
83 DeclarationName N = TD->getDeclName();
84 return llvm::StringRef(N.getAsString()) == "string";
85}
86
87void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
88 Expr *Init = VD->getInit();
89 if (!Init)
90 return;
91
92 // Pattern match for:
93 // llvm::StringRef x = call() (where call returns std::string)
94 if (!IsStringRef(VD->getType()))
95 return;
96 CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init);
97 if (!Ex1)
98 return;
99 CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
100 if (!Ex2 || Ex2->getNumArgs() != 1)
101 return;
102 ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
103 if (!Ex3)
104 return;
105 CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
106 if (!Ex4 || Ex4->getNumArgs() != 1)
107 return;
108 ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
109 if (!Ex5)
110 return;
111 CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
112 if (!Ex6 || !IsStdString(Ex6->getType()))
113 return;
114
115 // Okay, badness! Report an error.
116 BR.EmitBasicReport("StringRef should not be bound to temporary "
117 "std::string that it outlives", "LLVM Conventions",
118 VD->getLocStart(), Init->getSourceRange());
119}
120
121//===----------------------------------------------------------------------===//
122// Entry point for all checks.
123//===----------------------------------------------------------------------===//
124
125void clang::CheckLLVMConventions(const Decl *D, BugReporter &BR) {
126 CheckStringRefAssignedTemporary(D, BR);
127}