Skip to content

Commit c02b2ab

Browse files
authored
[clang-tidy] Add StrictMode to cppcoreguidelines-pro-type-static-cast-downcast (#69529)
Add StrictMode option that controls behavior whatever warnings are emitted for casts on non-polymorphic types. Fixes: #69414
1 parent 15254eb commit c02b2ab

File tree

5 files changed

+61
-29
lines changed

5 files changed

+61
-29
lines changed

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,24 @@ using namespace clang::ast_matchers;
1414

1515
namespace clang::tidy::cppcoreguidelines {
1616

17+
ProTypeStaticCastDowncastCheck::ProTypeStaticCastDowncastCheck(
18+
StringRef Name, ClangTidyContext *Context)
19+
: ClangTidyCheck(Name, Context),
20+
StrictMode(Options.getLocalOrGlobal("StrictMode", true)) {}
21+
22+
void ProTypeStaticCastDowncastCheck::storeOptions(
23+
ClangTidyOptions::OptionMap &Opts) {
24+
Options.store(Opts, "StrictMode", StrictMode);
25+
}
26+
1727
void ProTypeStaticCastDowncastCheck::registerMatchers(MatchFinder *Finder) {
1828
Finder->addMatcher(
19-
cxxStaticCastExpr(unless(isInTemplateInstantiation())).bind("cast"),
20-
this);
29+
cxxStaticCastExpr(hasCastKind(CK_BaseToDerived)).bind("cast"), this);
2130
}
2231

2332
void ProTypeStaticCastDowncastCheck::check(
2433
const MatchFinder::MatchResult &Result) {
2534
const auto *MatchedCast = Result.Nodes.getNodeAs<CXXStaticCastExpr>("cast");
26-
if (MatchedCast->getCastKind() != CK_BaseToDerived)
27-
return;
2835

2936
QualType SourceType = MatchedCast->getSubExpr()->getType();
3037
const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
@@ -33,15 +40,20 @@ void ProTypeStaticCastDowncastCheck::check(
3340
if (!SourceDecl)
3441
return;
3542

36-
if (SourceDecl->isPolymorphic())
43+
if (SourceDecl->isPolymorphic()) {
3744
diag(MatchedCast->getOperatorLoc(),
3845
"do not use static_cast to downcast from a base to a derived class; "
3946
"use dynamic_cast instead")
4047
<< FixItHint::CreateReplacement(MatchedCast->getOperatorLoc(),
4148
"dynamic_cast");
42-
else
43-
diag(MatchedCast->getOperatorLoc(),
44-
"do not use static_cast to downcast from a base to a derived class");
49+
return;
50+
}
51+
52+
if (!StrictMode)
53+
return;
54+
55+
diag(MatchedCast->getOperatorLoc(),
56+
"do not use static_cast to downcast from a base to a derived class");
4557
}
4658

4759
} // namespace clang::tidy::cppcoreguidelines

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ namespace clang::tidy::cppcoreguidelines {
2020
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.html
2121
class ProTypeStaticCastDowncastCheck : public ClangTidyCheck {
2222
public:
23-
ProTypeStaticCastDowncastCheck(StringRef Name, ClangTidyContext *Context)
24-
: ClangTidyCheck(Name, Context) {}
23+
ProTypeStaticCastDowncastCheck(StringRef Name, ClangTidyContext *Context);
2524
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
2625
return LangOpts.CPlusPlus;
2726
}
2827
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
2928
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
29+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
30+
std::optional<TraversalKind> getCheckTraversalKind() const override {
31+
return TK_IgnoreUnlessSpelledInSource;
32+
}
33+
34+
private:
35+
const bool StrictMode;
3036
};
3137

3238
} // namespace clang::tidy::cppcoreguidelines

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ Changes in existing checks
269269
<clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check to ignore
270270
dependent delegate constructors.
271271

272+
- Improved :doc:`cppcoreguidelines-pro-type-static-cast-downcast
273+
<clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast>` check to
274+
disregard casts on non-polymorphic types when the `StrictMode` option is set
275+
to `false`.
276+
272277
- Improved :doc:`cppcoreguidelines-pro-type-vararg
273278
<clang-tidy/checks/cppcoreguidelines/pro-type-vararg>` check to ignore
274279
false-positives in unevaluated context (e.g., ``decltype``, ``sizeof``, ...).

clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/pro-type-static-cast-downcast.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ unrelated type ``Z``.
1414
This rule is part of the `Type safety (Type.2)
1515
<https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Pro-type-downcast>`_
1616
profile from the C++ Core Guidelines.
17+
18+
Options
19+
-------
20+
21+
.. option:: StrictMode
22+
23+
When set to `false`, no warnings are emitted for casts on non-polymorphic
24+
types. Default is `true`.

clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-static-cast-downcast.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-static-cast-downcast %t
1+
// RUN: %check_clang_tidy -check-suffixes=NSTRICT,STRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t
2+
// RUN: %check_clang_tidy -check-suffix=NSTRICT %s cppcoreguidelines-pro-type-static-cast-downcast %t -- -config="{CheckOptions: {StrictMode: false}}"
23

34
class Base {
45
};
@@ -26,11 +27,11 @@ class PolymorphicMultiDerived : public Base, public PolymorphicBase {
2627
void pointers() {
2728

2829
auto P0 = static_cast<Derived*>(new Base());
29-
// 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]
30+
// 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]
3031

3132
const Base* B0;
3233
auto PC0 = static_cast<const Derived*>(B0);
33-
// 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]
34+
// 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]
3435

3536
auto P1 = static_cast<Base*>(new Derived()); // OK, upcast to a public base
3637
auto P2 = static_cast<Base*>(new MultiDerived()); // OK, upcast to a public base
@@ -40,13 +41,13 @@ void pointers() {
4041
void pointers_polymorphic() {
4142

4243
auto PP0 = static_cast<PolymorphicDerived*>(new PolymorphicBase());
43-
// 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]
44-
// CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
44+
// 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]
45+
// CHECK-FIXES-NSTRICT: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
4546

4647
const PolymorphicBase* B0;
4748
auto PPC0 = static_cast<const PolymorphicDerived*>(B0);
48-
// 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]
49-
// CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
49+
// 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]
50+
// CHECK-FIXES-NSTRICT: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
5051

5152

5253
auto B1 = static_cast<PolymorphicBase*>(new PolymorphicDerived()); // OK, upcast to a public base
@@ -57,27 +58,27 @@ void pointers_polymorphic() {
5758
void arrays() {
5859
Base ArrayOfBase[10];
5960
auto A0 = static_cast<Derived*>(ArrayOfBase);
60-
// 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]
61+
// 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]
6162
}
6263

6364
void arrays_polymorphic() {
6465
PolymorphicBase ArrayOfPolymorphicBase[10];
6566
auto AP0 = static_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
66-
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
67-
// CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
67+
// 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
68+
// CHECK-FIXES-NSTRICT: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
6869
}
6970

7071
void references() {
7172
Base B0;
7273
auto R0 = static_cast<Derived&>(B0);
73-
// 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]
74+
// 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]
7475
Base& RefToBase = B0;
7576
auto R1 = static_cast<Derived&>(RefToBase);
76-
// 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]
77+
// 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]
7778

7879
const Base& ConstRefToBase = B0;
7980
auto RC1 = static_cast<const Derived&>(ConstRefToBase);
80-
// 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]
81+
// 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]
8182

8283

8384
Derived RD1;
@@ -87,18 +88,18 @@ void references() {
8788
void references_polymorphic() {
8889
PolymorphicBase B0;
8990
auto RP0 = static_cast<PolymorphicDerived&>(B0);
90-
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
91-
// CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
91+
// 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
92+
// CHECK-FIXES-NSTRICT: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
9293

9394
PolymorphicBase& RefToPolymorphicBase = B0;
9495
auto RP1 = static_cast<PolymorphicDerived&>(RefToPolymorphicBase);
95-
// 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]
96-
// CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
96+
// 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]
97+
// CHECK-FIXES-NSTRICT: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
9798

9899
const PolymorphicBase& ConstRefToPolymorphicBase = B0;
99100
auto RPC2 = static_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
100-
// 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]
101-
// CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
101+
// 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]
102+
// CHECK-FIXES-NSTRICT: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
102103

103104
PolymorphicDerived d1;
104105
auto RP2 = static_cast<PolymorphicBase&>(d1); // OK, upcast to a public base

0 commit comments

Comments
 (0)