diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp index 5344d465ad1fa..2a89de27760fe 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp @@ -14,17 +14,24 @@ using namespace clang::ast_matchers; namespace clang::tidy::cppcoreguidelines { +ProTypeStaticCastDowncastCheck::ProTypeStaticCastDowncastCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StrictMode(Options.getLocalOrGlobal("StrictMode", true)) {} + +void ProTypeStaticCastDowncastCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "StrictMode", StrictMode); +} + void ProTypeStaticCastDowncastCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxStaticCastExpr(unless(isInTemplateInstantiation())).bind("cast"), - this); + cxxStaticCastExpr(hasCastKind(CK_BaseToDerived)).bind("cast"), this); } void ProTypeStaticCastDowncastCheck::check( const MatchFinder::MatchResult &Result) { const auto *MatchedCast = Result.Nodes.getNodeAs("cast"); - if (MatchedCast->getCastKind() != CK_BaseToDerived) - return; QualType SourceType = MatchedCast->getSubExpr()->getType(); const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl(); @@ -33,15 +40,20 @@ void ProTypeStaticCastDowncastCheck::check( if (!SourceDecl) return; - if (SourceDecl->isPolymorphic()) + if (SourceDecl->isPolymorphic()) { diag(MatchedCast->getOperatorLoc(), "do not use static_cast to downcast from a base to a derived class; " "use dynamic_cast instead") << FixItHint::CreateReplacement(MatchedCast->getOperatorLoc(), "dynamic_cast"); - else - diag(MatchedCast->getOperatorLoc(), - "do not use static_cast to downcast from a base to a derived class"); + return; + } + + if (!StrictMode) + return; + + diag(MatchedCast->getOperatorLoc(), + "do not use static_cast to downcast from a base to a derived class"); } } // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h index 33ec8a071c108..b9e78a82a39f2 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h @@ -20,13 +20,19 @@ namespace clang::tidy::cppcoreguidelines { /// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.html class ProTypeStaticCastDowncastCheck : public ClangTidyCheck { public: - ProTypeStaticCastDowncastCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + ProTypeStaticCastDowncastCheck(StringRef Name, ClangTidyContext *Context); bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool StrictMode; }; } // namespace clang::tidy::cppcoreguidelines diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index c93775beb8aea..8e4288399a769 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -269,6 +269,11 @@ Changes in existing checks ` check to ignore dependent delegate constructors. +- Improved :doc:`cppcoreguidelines-pro-type-static-cast-downcast + ` check to + disregard casts on non-polymorphic types when the `StrictMode` option is set + to `false`. + - Improved :doc:`cppcoreguidelines-pro-type-vararg ` check to ignore false-positives in unevaluated context (e.g., ``decltype``, ``sizeof``, ...). diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.rst index bcb353301f028..333e6db2aacec 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.rst @@ -14,3 +14,11 @@ unrelated type ``Z``. This rule is part of the `Type safety (Type.2) `_ profile from the C++ Core Guidelines. + +Options +------- + +.. option:: StrictMode + + When set to `false`, no warnings are emitted for casts on non-polymorphic + types. Default is `true`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp index 7a6c027ec479b..11179b7d2d19b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp @@ -1,4 +1,5 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-static-cast-downcast %t +// RUN: %check_clang_tidy -check-suffixes=NSTRICT,STRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t +// RUN: %check_clang_tidy -check-suffix=NSTRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t -- -config="{CheckOptions: {StrictMode: false}}" class Base { }; @@ -26,11 +27,11 @@ class PolymorphicMultiDerived : public Base, public PolymorphicBase { void pointers() { auto P0 = static_cast(new Base()); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] const Base* B0; auto PC0 = static_cast(B0); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] auto P1 = static_cast(new Derived()); // OK, upcast to a public base auto P2 = static_cast(new MultiDerived()); // OK, upcast to a public base @@ -40,13 +41,13 @@ void pointers() { void pointers_polymorphic() { auto PP0 = static_cast(new PolymorphicBase()); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] - // CHECK-FIXES: auto PP0 = dynamic_cast(new PolymorphicBase()); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-FIXES-NSTRICT: auto PP0 = dynamic_cast(new PolymorphicBase()); const PolymorphicBase* B0; auto PPC0 = static_cast(B0); - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] - // CHECK-FIXES: auto PPC0 = dynamic_cast(B0); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-FIXES-NSTRICT: auto PPC0 = dynamic_cast(B0); auto B1 = static_cast(new PolymorphicDerived()); // OK, upcast to a public base @@ -57,27 +58,27 @@ void pointers_polymorphic() { void arrays() { Base ArrayOfBase[10]; auto A0 = static_cast(ArrayOfBase); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] } void arrays_polymorphic() { PolymorphicBase ArrayOfPolymorphicBase[10]; auto AP0 = static_cast(ArrayOfPolymorphicBase); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead - // CHECK-FIXES: auto AP0 = dynamic_cast(ArrayOfPolymorphicBase); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead + // CHECK-FIXES-NSTRICT: auto AP0 = dynamic_cast(ArrayOfPolymorphicBase); } void references() { Base B0; auto R0 = static_cast(B0); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] Base& RefToBase = B0; auto R1 = static_cast(RefToBase); - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] const Base& ConstRefToBase = B0; auto RC1 = static_cast(ConstRefToBase); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast] Derived RD1; @@ -87,18 +88,18 @@ void references() { void references_polymorphic() { PolymorphicBase B0; auto RP0 = static_cast(B0); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead - // CHECK-FIXES: auto RP0 = dynamic_cast(B0); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead + // CHECK-FIXES-NSTRICT: auto RP0 = dynamic_cast(B0); PolymorphicBase& RefToPolymorphicBase = B0; auto RP1 = static_cast(RefToPolymorphicBase); - // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] - // CHECK-FIXES: auto RP1 = dynamic_cast(RefToPolymorphicBase); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-FIXES-NSTRICT: auto RP1 = dynamic_cast(RefToPolymorphicBase); const PolymorphicBase& ConstRefToPolymorphicBase = B0; auto RPC2 = static_cast(ConstRefToPolymorphicBase); - // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] - // CHECK-FIXES: auto RPC2 = dynamic_cast(ConstRefToPolymorphicBase); + // CHECK-MESSAGES-NSTRICT: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast] + // CHECK-FIXES-NSTRICT: auto RPC2 = dynamic_cast(ConstRefToPolymorphicBase); PolymorphicDerived d1; auto RP2 = static_cast(d1); // OK, upcast to a public base