[clang-tidy] Add new check cppcoreguidelines-pro-bounds-array-to-pointer-decay

Summary:
This check flags all array to pointer decays.

Pointers should not be used as arrays. array_view is a bounds-checked,
safe alternative to using pointers to access arrays.

This rule is part of the "Bounds safety" profile of the C++ Core
Guidelines, see
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-bounds3-no-array-to-pointer-decay

Reviewers: alexfh, sbenza, bkramer, aaron.ballman

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D13640

git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@251358 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matthias Gehre 2015-10-26 21:56:02 +00:00
Родитель eaac82467f
Коммит 40fe18c79e
7 изменённых файлов: 149 добавлений и 0 удалений

Просмотреть файл

@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyCppCoreGuidelinesModule
CppCoreGuidelinesTidyModule.cpp
ProBoundsArrayToPointerDecayCheck.cpp
ProBoundsPointerArithmeticCheck.cpp
ProTypeConstCastCheck.cpp
ProTypeReinterpretCastCheck.cpp

Просмотреть файл

@ -11,6 +11,7 @@
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "../misc/AssignOperatorSignatureCheck.h"
#include "ProBoundsArrayToPointerDecayCheck.h"
#include "ProBoundsPointerArithmeticCheck.h"
#include "ProTypeConstCastCheck.h"
#include "ProTypeReinterpretCastCheck.h"
@ -26,6 +27,8 @@ namespace cppcoreguidelines {
class CppCoreGuidelinesModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<ProBoundsArrayToPointerDecayCheck>(
"cppcoreguidelines-pro-bounds-array-to-pointer-decay");
CheckFactories.registerCheck<ProBoundsPointerArithmeticCheck>(
"cppcoreguidelines-pro-bounds-pointer-arithmetic");
CheckFactories.registerCheck<ProTypeConstCastCheck>(

Просмотреть файл

@ -0,0 +1,60 @@
//===--- ProBoundsArrayToPointerDecayCheck.cpp - clang-tidy----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ProBoundsArrayToPointerDecayCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
AST_MATCHER_P(CXXForRangeStmt, hasRangeBeginEndStmt,
ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
const DeclStmt *const Stmt = Node.getBeginEndStmt();
return (Stmt != nullptr && InnerMatcher.matches(*Stmt, Finder, Builder));
}
AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt) {
return stmt(hasAncestor(cxxForRangeStmt(
hasRangeBeginEndStmt(hasDescendant(equalsNode(&Node))))))
.matches(Node, Finder, Builder);
}
void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;
// The only allowed array to pointer decay
// 1) just before array subscription
// 2) inside a range-for over an array
// 3) if it converts a string literal to a pointer
Finder->addMatcher(
implicitCastExpr(unless(hasParent(arraySubscriptExpr())),
unless(hasParent(explicitCastExpr())),
unless(isInsideOfRangeBeginEndStmt()),
unless(hasSourceExpression(stringLiteral())))
.bind("cast"),
this);
}
void ProBoundsArrayToPointerDecayCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *MatchedCast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast");
if (MatchedCast->getCastKind() != CK_ArrayToPointerDecay)
return;
diag(MatchedCast->getExprLoc(), "do not implicitly decay an array into a "
"pointer; consider using gsl::array_view or "
"an explicit cast instead");
}
} // namespace tidy
} // namespace clang

Просмотреть файл

@ -0,0 +1,34 @@
//===--- ProBoundsArrayToPointerDecayCheck.h - clang-tidy--------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H
#include "../ClangTidy.h"
namespace clang {
namespace tidy {
/// This check flags all array to pointer decays
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.html
class ProBoundsArrayToPointerDecayCheck : public ClangTidyCheck {
public:
ProBoundsArrayToPointerDecayCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H

Просмотреть файл

@ -0,0 +1,9 @@
cppcoreguidelines-pro-bounds-array-to-pointer-decay
===================================================
This check flags all array to pointer decays.
Pointers should not be used as arrays. array_view is a bounds-checked, safe alternative to using pointers to access arrays.
This rule is part of the "Bounds safety" profile of the C++ Core Guidelines, see
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-bounds3-no-array-to-pointer-decay

Просмотреть файл

@ -4,6 +4,7 @@ List of clang-tidy Checks
.. toctree::
cert-setlongjmp
cert-variadic-function-def
cppcoreguidelines-pro-bounds-array-to-pointer-decay
cppcoreguidelines-pro-bounds-pointer-arithmetic
cppcoreguidelines-pro-type-const-cast
cppcoreguidelines-pro-type-reinterpret-cast

Просмотреть файл

@ -0,0 +1,41 @@
// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t
#include <stddef.h>
namespace gsl {
template <class T>
class array_view {
public:
template <class U, size_t N>
array_view(U (&arr)[N]);
};
}
void pointerfun(int *p);
void arrayfun(int p[]);
void arrayviewfun(gsl::array_view<int> &p);
size_t s();
void f() {
int a[5];
pointerfun(a);
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]
pointerfun((int *)a); // OK, explicit cast
arrayfun(a);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not implicitly decay an array into a pointer
pointerfun(a + s() - 10); // Convert to &a[g() - 10];
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer
gsl::array_view<int> av(a);
arrayviewfun(av); // OK
int i = a[0]; // OK
pointerfun(&a[0]); // OK
for (auto &e : a) // OK, iteration internally decays array to pointer
e = 1;
}
const char *g() {
return "clang"; // OK, decay string literal to pointer
}