[clang-tools-extra] r252425 - [clang-tidy] add new check cppcoreguidelines-pro-type-cstyle-cast

Matthias Gehre via cfe-commits cfe-commits at lists.llvm.org
Sun Nov 8 13:10:39 PST 2015


Author: mgehre
Date: Sun Nov  8 15:10:39 2015
New Revision: 252425

URL: http://llvm.org/viewvc/llvm-project?rev=252425&view=rev
Log:
[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

Added:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst
    clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt?rev=252425&r1=252424&r2=252425&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt Sun Nov  8 15:10:39 2015
@@ -5,6 +5,7 @@ add_clang_library(clangTidyCppCoreGuidel
   ProBoundsArrayToPointerDecayCheck.cpp
   ProBoundsPointerArithmeticCheck.cpp
   ProTypeConstCastCheck.cpp
+  ProTypeCstyleCastCheck.cpp
   ProTypeReinterpretCastCheck.cpp
   ProTypeStaticCastDowncastCheck.cpp
   ProTypeUnionAccessCheck.cpp

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp?rev=252425&r1=252424&r2=252425&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp Sun Nov  8 15:10:39 2015
@@ -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>(

Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp?rev=252425&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp Sun Nov  8 15:10:39 2015
@@ -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

Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h?rev=252425&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h Sun Nov  8 15:10:39 2015
@@ -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

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst?rev=252425&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst Sun Nov  8 15:10:39 2015
@@ -0,0 +1,15 @@
+cppcoreguidelines-pro-type-cstyle-cast
+======================================
+
+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.

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=252425&r1=252424&r2=252425&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Sun Nov  8 15:10:39 2015
@@ -7,6 +7,7 @@ List of clang-tidy Checks
    cppcoreguidelines-pro-bounds-array-to-pointer-decay
    cppcoreguidelines-pro-bounds-pointer-arithmetic
    cppcoreguidelines-pro-type-const-cast
+   cppcoreguidelines-pro-type-cstyle-cast
    cppcoreguidelines-pro-type-reinterpret-cast
    cppcoreguidelines-pro-type-static-cast-downcast
    cppcoreguidelines-pro-type-union-access

Added: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp?rev=252425&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp Sun Nov  8 15:10:39 2015
@@ -0,0 +1,141 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-cstyle-cast %t
+
+void reinterpretcast() {
+  int i = 0;
+  void *j;
+  j = (int*)j;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
+}
+
+void constcast() {
+  int* i;
+  const int* j;
+  i = (int*)j;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to cast away constness
+  j = (const int*)i; // OK, const added
+  (void)j; // OK, not a const_cast
+}
+
+void const_and_reinterpret() {
+  int* i;
+  const void* j;
+  i = (int*)j;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types
+}
+
+class Base {
+};
+
+class Derived : public Base {
+};
+
+class Base2 {
+};
+
+class MultiDerived : public Base, public Base2 {
+};
+
+class PolymorphicBase {
+public:
+  virtual ~PolymorphicBase();
+};
+
+class PolymorphicDerived : public PolymorphicBase {
+};
+
+class PolymorphicMultiDerived : public Base, public PolymorphicBase {
+};
+
+void pointers() {
+
+  auto P0 = (Derived*)new Base();
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+  const Base* B0;
+  auto PC0 = (const Derived*)(B0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+  auto P1 = (Base*)new Derived(); // OK, upcast to a public base
+  auto P2 = (Base*)new MultiDerived(); // OK, upcast to a public base
+  auto P3 = (Base2*)new MultiDerived(); // OK, upcast to a public base
+}
+
+void pointers_polymorphic() {
+
+  auto PP0 = (PolymorphicDerived*)new PolymorphicBase();
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
+
+  const PolymorphicBase* B0;
+  auto PPC0 = (const PolymorphicDerived*)B0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
+
+
+  auto B1 = (PolymorphicBase*)new PolymorphicDerived(); // OK, upcast to a public base
+  auto B2 = (PolymorphicBase*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+  auto B3 = (Base*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+}
+
+void arrays() {
+  Base ArrayOfBase[10];
+  auto A0 = (Derived*)ArrayOfBase;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+}
+
+void arrays_polymorphic() {
+  PolymorphicBase ArrayOfPolymorphicBase[10];
+  auto AP0 = (PolymorphicDerived*)ArrayOfPolymorphicBase;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+}
+
+void references() {
+  Base B0;
+  auto R0 = (Derived&)B0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+  Base& RefToBase = B0;
+  auto R1 = (Derived&)RefToBase;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+  const Base& ConstRefToBase = B0;
+  auto RC1 = (const Derived&)ConstRefToBase;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+
+  Derived RD1;
+  auto R2 = (Base&)RD1; // OK, upcast to a public base
+}
+
+void references_polymorphic() {
+  PolymorphicBase B0;
+  auto RP0 = (PolymorphicDerived&)B0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
+
+  PolymorphicBase& RefToPolymorphicBase = B0;
+  auto RP1 = (PolymorphicDerived&)RefToPolymorphicBase;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+
+  const PolymorphicBase& ConstRefToPolymorphicBase = B0;
+  auto RPC2 = (const PolymorphicDerived&)(ConstRefToPolymorphicBase);
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+  // CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+
+  PolymorphicDerived d1;
+  auto RP2 = (PolymorphicBase&)d1; // OK, upcast to a public base
+}
+
+template<class B, class D>
+void templ() {
+  auto B0 = (B*)new D();
+}
+
+void templ_bad_call() {
+  templ<Derived, Base>(); //FIXME: this should trigger a warning
+}
+
+void templ_good_call() {
+  templ<Base, Derived>(); // OK, upcast to a public base
+}




More information about the cfe-commits mailing list