summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp312
1 files changed, 0 insertions, 312 deletions
diff --git a/contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp b/contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp
deleted file mode 100644
index 2f87da1..0000000
--- a/contrib/llvm/tools/clang/lib/Checker/LLVMConventionsChecker.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-//=== 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/DeclTemplate.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;
-
-//===----------------------------------------------------------------------===//
-// Generic type checking routines.
-//===----------------------------------------------------------------------===//
-
-static bool IsLLVMStringRef(QualType T) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
-
- return llvm::StringRef(QualType(RT, 0).getAsString()) ==
- "class llvm::StringRef";
-}
-
-/// Check whether the declaration is semantically inside the top-level
-/// namespace named by ns.
-static bool InNamespace(const Decl *D, llvm::StringRef NS) {
- const DeclContext *DC = D->getDeclContext();
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
- if (!ND)
- return false;
- const IdentifierInfo *II = ND->getIdentifier();
- if (!II || !II->getName().equals(NS))
- return false;
- DC = ND->getDeclContext();
- return isa<TranslationUnitDecl>(DC);
-}
-
-static bool IsStdString(QualType T) {
- if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
- T = QT->getNamedType();
-
- const TypedefType *TT = T->getAs<TypedefType>();
- if (!TT)
- return false;
-
- const TypedefDecl *TD = TT->getDecl();
-
- if (!InNamespace(TD, "std"))
- return false;
-
- return TD->getName() == "string";
-}
-
-static bool IsClangType(const RecordDecl *RD) {
- return RD->getName() == "Type" && InNamespace(RD, "clang");
-}
-
-static bool IsClangDecl(const RecordDecl *RD) {
- return RD->getName() == "Decl" && InNamespace(RD, "clang");
-}
-
-static bool IsClangStmt(const RecordDecl *RD) {
- return RD->getName() == "Stmt" && InNamespace(RD, "clang");
-}
-
-static bool IsClangAttr(const RecordDecl *RD) {
- return RD->getName() == "Attr" && InNamespace(RD, "clang");
-}
-
-static bool IsStdVector(QualType T) {
- const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
- if (!TS)
- return false;
-
- TemplateName TM = TS->getTemplateName();
- TemplateDecl *TD = TM.getAsTemplateDecl();
-
- if (!TD || !InNamespace(TD, "std"))
- return false;
-
- return TD->getName() == "vector";
-}
-
-static bool IsSmallVector(QualType T) {
- const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
- if (!TS)
- return false;
-
- TemplateName TM = TS->getTemplateName();
- TemplateDecl *TD = TM.getAsTemplateDecl();
-
- if (!TD || !InNamespace(TD, "llvm"))
- return false;
-
- return TD->getName() == "SmallVector";
-}
-
-//===----------------------------------------------------------------------===//
-// CHECK: a llvm::StringRef should not be bound to a 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) {
- VisitChildren(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);
-}
-
-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 (!IsLLVMStringRef(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.
- const char *desc = "StringRef should not be bound to temporary "
- "std::string that it outlives";
-
- BR.EmitBasicReport(desc, "LLVM Conventions", desc,
- VD->getLocStart(), Init->getSourceRange());
-}
-
-//===----------------------------------------------------------------------===//
-// CHECK: Clang AST nodes should not have fields that can allocate
-// memory.
-//===----------------------------------------------------------------------===//
-
-static bool AllocatesMemory(QualType T) {
- return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
-}
-
-// This type checking could be sped up via dynamic programming.
-static bool IsPartOfAST(const CXXRecordDecl *R) {
- if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
- return true;
-
- for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
- E = R->bases_end(); I!=E; ++I) {
- CXXBaseSpecifier BS = *I;
- QualType T = BS.getType();
- if (const RecordType *baseT = T->getAs<RecordType>()) {
- CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
- if (IsPartOfAST(baseD))
- return true;
- }
- }
-
- return false;
-}
-
-namespace {
-class ASTFieldVisitor {
- llvm::SmallVector<FieldDecl*, 10> FieldChain;
- CXXRecordDecl *Root;
- BugReporter &BR;
-public:
- ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
- : Root(root), BR(br) {}
-
- void Visit(FieldDecl *D);
- void ReportError(QualType T);
-};
-} // end anonymous namespace
-
-static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
- if (!IsPartOfAST(R))
- return;
-
- for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
- I != E; ++I) {
- ASTFieldVisitor walker(R, BR);
- walker.Visit(*I);
- }
-}
-
-void ASTFieldVisitor::Visit(FieldDecl *D) {
- FieldChain.push_back(D);
-
- QualType T = D->getType();
-
- if (AllocatesMemory(T))
- ReportError(T);
-
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl()->getDefinition();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I)
- Visit(*I);
- }
-
- FieldChain.pop_back();
-}
-
-void ASTFieldVisitor::ReportError(QualType T) {
- llvm::SmallString<1024> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << "AST class '" << Root->getName() << "' has a field '"
- << FieldChain.front()->getName() << "' that allocates heap memory";
- if (FieldChain.size() > 1) {
- os << " via the following chain: ";
- bool isFirst = true;
- for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
- E=FieldChain.end(); I!=E; ++I) {
- if (!isFirst)
- os << '.';
- else
- isFirst = false;
- os << (*I)->getName();
- }
- }
- os << " (type " << FieldChain.back()->getType().getAsString() << ")";
- os.flush();
-
- // Note that this will fire for every translation unit that uses this
- // class. This is suboptimal, but at least scan-build will merge
- // duplicate HTML reports. In the future we need a unified way of merging
- // duplicate reports across translation units. For C++ classes we cannot
- // just report warnings when we see an out-of-line method definition for a
- // class, as that heuristic doesn't always work (the complete definition of
- // the class may be in the header file, for example).
- BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
- os.str(), FieldChain.front()->getLocStart());
-}
-
-//===----------------------------------------------------------------------===//
-// Entry point for all checks.
-//===----------------------------------------------------------------------===//
-
-static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
- for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
- I!=E ; ++I) {
-
- Decl *D = *I;
-
- if (D->hasBody())
- CheckStringRefAssignedTemporary(D, BR);
-
- if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
- if (R->isDefinition())
- CheckASTMemory(R, BR);
-
- if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
- ScanCodeDecls(DC_child, BR);
- }
-}
-
-void clang::CheckLLVMConventions(TranslationUnitDecl &TU,
- BugReporter &BR) {
- ScanCodeDecls(&TU, BR);
-}
-
OpenPOWER on IntegriCloud