diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-02-14 02:45:18 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-02-14 02:45:18 +0000 |
commit | 6dd66ed959b7f60749dd0040507b3f304183a1b6 (patch) | |
tree | 74e46fdabb8c12291a174290b04e2c511323c98f /lib/Checker/LLVMConventionsChecker.cpp | |
parent | 280cfd70c7a536311656fbd2082cb54d59cf3a2e (diff) |
Add new static analyzer for checking LLVM coding conventions: -analyzer-check-llvm-conventions
Currently these checks are intended to be largely syntactical, but may get more
sophisticated over time.
As an initial foray into this brave new world, emit a static analyzer warning
when binding a temporary 'std::string' to an 'llvm::StringRef' where the
lifetime of the 'std::string' does not outlive the 'llvm::StringRef'.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96147 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/LLVMConventionsChecker.cpp')
-rw-r--r-- | lib/Checker/LLVMConventionsChecker.cpp | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp new file mode 100644 index 0000000000..82f6d2c7bd --- /dev/null +++ b/lib/Checker/LLVMConventionsChecker.cpp @@ -0,0 +1,127 @@ +//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines LLVMConventionsChecker, a bunch of small little checks +// for checking specific coding conventions in the LLVM/Clang codebase. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include <string> +#include <llvm/ADT/StringRef.h> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Check if an llvm::StringRef is bound to temporary std::string whose lifetime +// is shorter than the StringRef's. +//===----------------------------------------------------------------------===// + +namespace { +class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> { + BugReporter &BR; +public: + StringRefCheckerVisitor(BugReporter &br) : BR(br) {} + void VisitChildren(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; + I != E; ++I) + if (Stmt *child = *I) + Visit(child); + } + void VisitStmt(Stmt *S) { VisitChildren(S); } + void VisitDeclStmt(DeclStmt *DS); +private: + void VisitVarDecl(VarDecl *VD); +}; +} // end anonymous namespace + +static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) { + StringRefCheckerVisitor walker(BR); + walker.Visit(D->getBody()); +} + +void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) { + for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I) + if (VarDecl *VD = dyn_cast<VarDecl>(*I)) + VisitVarDecl(VD); +} + +static bool IsStringRef(QualType T) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + return llvm::StringRef(QualType(RT, 0).getAsString()) == + "class llvm::StringRef"; +} + +static bool IsStdString(QualType T) { + if (const QualifiedNameType *QT = T->getAs<QualifiedNameType>()) + T = QT->getNamedType(); + + const TypedefType *TT = T->getAs<TypedefType>(); + if (!TT) + return false; + + const TypedefDecl *TD = TT->getDecl(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(TD->getDeclContext()); + if (!ND) + return false; + const IdentifierInfo *II = ND->getIdentifier(); + if (!II || II->getName() != "std") + return false; + + DeclarationName N = TD->getDeclName(); + return llvm::StringRef(N.getAsString()) == "string"; +} + +void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { + Expr *Init = VD->getInit(); + if (!Init) + return; + + // Pattern match for: + // llvm::StringRef x = call() (where call returns std::string) + if (!IsStringRef(VD->getType())) + return; + CXXExprWithTemporaries *Ex1 = dyn_cast<CXXExprWithTemporaries>(Init); + if (!Ex1) + return; + CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr()); + if (!Ex2 || Ex2->getNumArgs() != 1) + return; + ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0)); + if (!Ex3) + return; + CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr()); + if (!Ex4 || Ex4->getNumArgs() != 1) + return; + ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0)); + if (!Ex5) + return; + CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr()); + if (!Ex6 || !IsStdString(Ex6->getType())) + return; + + // Okay, badness! Report an error. + BR.EmitBasicReport("StringRef should not be bound to temporary " + "std::string that it outlives", "LLVM Conventions", + VD->getLocStart(), Init->getSourceRange()); +} + +//===----------------------------------------------------------------------===// +// Entry point for all checks. +//===----------------------------------------------------------------------===// + +void clang::CheckLLVMConventions(const Decl *D, BugReporter &BR) { + CheckStringRefAssignedTemporary(D, BR); +} |