diff options
author | Matthias Gehre <M.Gehre@gmx.de> | 2015-11-08 21:10:39 +0000 |
---|---|---|
committer | Matthias Gehre <M.Gehre@gmx.de> | 2015-11-08 21:10:39 +0000 |
commit | eeb71758cc32933863a8f165c1a63c517fd9283a (patch) | |
tree | 470284cd44e5ecce4db918dd097e91ccb265cc19 /clang-tools-extra/clang-tidy/cppcoreguidelines | |
parent | f85ad0411f1dcec5a1da1958c2663a50e8c2748b (diff) | |
download | bcm5719-llvm-eeb71758cc32933863a8f165c1a63c517fd9283a.tar.gz bcm5719-llvm-eeb71758cc32933863a8f165c1a63c517fd9283a.zip |
[clang-tidy] add new check cppcoreguidelines-pro-type-cstyle-cast
Summary:
This check flags all use of c-style casts that perform a static_cast
downcast, const_cast, or reinterpret_cast.
Use of these casts can violate type safety and cause the program to
access a
variable that is actually of type X to be accessed as if it were of an
unrelated type Z. Note that a C-style (T)expression cast means to
perform
the first of the following that is possible: a const_cast, a
static_cast, a
static_cast followed by a const_cast, a reinterpret_cast, or a
reinterpret_cast followed by a const_cast. This rule bans (T)expression
only when used to perform an unsafe cast.
This rule is part of the "Type safety" profile of the C++ Core
Guidelines, see
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-type4-dont-use-c-style-texpression-casts-that-would-perform-a-static_cast-downcast-const_cast-or-reinterpret_cast.
Reviewers: alexfh, sbenza, bkramer, aaron.ballman
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D14096
llvm-svn: 252425
Diffstat (limited to 'clang-tools-extra/clang-tidy/cppcoreguidelines')
4 files changed, 145 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt index 506a90741ba..3bf729cbd10 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule ProBoundsArrayToPointerDecayCheck.cpp ProBoundsPointerArithmeticCheck.cpp ProTypeConstCastCheck.cpp + ProTypeCstyleCastCheck.cpp ProTypeReinterpretCastCheck.cpp ProTypeStaticCastDowncastCheck.cpp ProTypeUnionAccessCheck.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index d77954b51a1..1ef55da14ab 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -14,6 +14,7 @@ #include "ProBoundsArrayToPointerDecayCheck.h" #include "ProBoundsPointerArithmeticCheck.h" #include "ProTypeConstCastCheck.h" +#include "ProTypeCstyleCastCheck.h" #include "ProTypeReinterpretCastCheck.h" #include "ProTypeStaticCastDowncastCheck.h" #include "ProTypeUnionAccessCheck.h" @@ -33,6 +34,8 @@ public: "cppcoreguidelines-pro-bounds-pointer-arithmetic"); CheckFactories.registerCheck<ProTypeConstCastCheck>( "cppcoreguidelines-pro-type-const-cast"); + CheckFactories.registerCheck<ProTypeCstyleCastCheck>( + "cppcoreguidelines-pro-type-cstyle-cast"); CheckFactories.registerCheck<ProTypeReinterpretCastCheck>( "cppcoreguidelines-pro-type-reinterpret-cast"); CheckFactories.registerCheck<ProTypeStaticCastDowncastCheck>( diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp new file mode 100644 index 00000000000..542dd854c43 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp @@ -0,0 +1,107 @@ +//===--- ProTypeCstyleCastCheck.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 "ProTypeCstyleCastCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +static bool needsConstCast(QualType SourceType, QualType DestType) { + SourceType = SourceType.getNonReferenceType(); + DestType = DestType.getNonReferenceType(); + while (SourceType->isPointerType() && DestType->isPointerType()) { + SourceType = SourceType->getPointeeType(); + DestType = DestType->getPointeeType(); + if (SourceType.isConstQualified() && !DestType.isConstQualified()) + return true; + } + return false; +} + +void ProTypeCstyleCastCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus) + return; + + Finder->addMatcher( + cStyleCastExpr(unless(isInTemplateInstantiation())).bind("cast"), this); +} + +void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>("cast"); + + if (MatchedCast->getCastKind() == CK_BitCast || + MatchedCast->getCastKind() == CK_LValueBitCast || + MatchedCast->getCastKind() == CK_IntegralToPointer || + MatchedCast->getCastKind() == CK_PointerToIntegral || + MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) { + diag(MatchedCast->getLocStart(), + "do not use C-style cast to convert between unrelated types"); + return; + } + + QualType SourceType = MatchedCast->getSubExpr()->getType(); + + if (MatchedCast->getCastKind() == CK_BaseToDerived) { + const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl(); + if (!SourceDecl) // The cast is from object to reference. + SourceDecl = SourceType->getAsCXXRecordDecl(); + if (!SourceDecl) + return; + + if (SourceDecl->isPolymorphic()) { + // Leave type spelling exactly as it was (unlike + // getTypeAsWritten().getAsString() which would spell enum types 'enum + // X'). + StringRef DestTypeString = Lexer::getSourceText( + CharSourceRange::getTokenRange( + MatchedCast->getLParenLoc().getLocWithOffset(1), + MatchedCast->getRParenLoc().getLocWithOffset(-1)), + *Result.SourceManager, Result.Context->getLangOpts()); + + auto diag_builder = diag( + MatchedCast->getLocStart(), + "do not use C-style cast to downcast from a base to a derived class; " + "use dynamic_cast instead"); + + const Expr *SubExpr = + MatchedCast->getSubExprAsWritten()->IgnoreImpCasts(); + std::string CastText = ("dynamic_cast<" + DestTypeString + ">").str(); + if (!isa<ParenExpr>(SubExpr)) { + CastText.push_back('('); + diag_builder << FixItHint::CreateInsertion( + Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, + *Result.SourceManager, + Result.Context->getLangOpts()), + ")"); + } + auto ParenRange = CharSourceRange::getTokenRange( + MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc()); + diag_builder << FixItHint::CreateReplacement(ParenRange, CastText); + } else { + diag( + MatchedCast->getLocStart(), + "do not use C-style cast to downcast from a base to a derived class"); + } + return; + } + + if (MatchedCast->getCastKind() == CK_NoOp && + needsConstCast(SourceType, MatchedCast->getType())) { + diag(MatchedCast->getLocStart(), + "do not use C-style cast to cast away constness"); + } +} + +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h new file mode 100644 index 00000000000..f85be87d93b --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h @@ -0,0 +1,34 @@ +//===--- ProTypeCstyleCastCheck.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_TYPE_CSTYLE_CAST_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CSTYLE_CAST_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { + +/// This check flags all use of C-style casts that perform a static_cast +/// downcast, const_cast, or reinterpret_cast. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.html +class ProTypeCstyleCastCheck : public ClangTidyCheck { +public: + ProTypeCstyleCastCheck(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_TYPE_CSTYLE_CAST_H |