Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule CppCoreGuidelinesTidyModule.cpp + ProBoundsArrayToPointerDecayCheck.cpp ProBoundsPointerArithmeticCheck.cpp ProTypeConstCastCheck.cpp ProTypeReinterpretCastCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.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 @@ class CppCoreGuidelinesModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "cppcoreguidelines-pro-bounds-array-to-pointer-decay"); CheckFactories.registerCheck( "cppcoreguidelines-pro-bounds-pointer-arithmetic"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h @@ -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 + Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp @@ -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, 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("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 Index: clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst @@ -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 Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -4,6 +4,7 @@ .. 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 Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp @@ -0,0 +1,41 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t +#include + +namespace gsl { +template +class array_view { +public: + template + array_view(U (&arr)[N]); +}; +} + +void pointerfun(int *p); +void arrayfun(int p[]); +void arrayviewfun(gsl::array_view &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 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 +}