1 | //===--- ProTypeStaticCastDowncastCheck.cpp - clang-tidy-------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "ProTypeStaticCastDowncastCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | |
13 | using namespace clang::ast_matchers; |
14 | |
15 | namespace clang::tidy::cppcoreguidelines { |
16 | |
17 | ProTypeStaticCastDowncastCheck::ProTypeStaticCastDowncastCheck( |
18 | StringRef Name, ClangTidyContext *Context) |
19 | : ClangTidyCheck(Name, Context), |
20 | StrictMode(Options.getLocalOrGlobal(LocalName: "StrictMode" , Default: true)) {} |
21 | |
22 | void ProTypeStaticCastDowncastCheck::storeOptions( |
23 | ClangTidyOptions::OptionMap &Opts) { |
24 | Options.store(Options&: Opts, LocalName: "StrictMode" , Value: StrictMode); |
25 | } |
26 | |
27 | void ProTypeStaticCastDowncastCheck::registerMatchers(MatchFinder *Finder) { |
28 | Finder->addMatcher( |
29 | NodeMatch: cxxStaticCastExpr(hasCastKind(Kind: CK_BaseToDerived)).bind(ID: "cast" ), Action: this); |
30 | } |
31 | |
32 | void ProTypeStaticCastDowncastCheck::check( |
33 | const MatchFinder::MatchResult &Result) { |
34 | const auto *MatchedCast = Result.Nodes.getNodeAs<CXXStaticCastExpr>(ID: "cast" ); |
35 | |
36 | QualType SourceType = MatchedCast->getSubExpr()->getType(); |
37 | const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl(); |
38 | if (!SourceDecl) // The cast is from object to reference |
39 | SourceDecl = SourceType->getAsCXXRecordDecl(); |
40 | if (!SourceDecl) |
41 | return; |
42 | |
43 | if (SourceDecl->isPolymorphic()) { |
44 | diag(MatchedCast->getOperatorLoc(), |
45 | "do not use static_cast to downcast from a base to a derived class; " |
46 | "use dynamic_cast instead" ) |
47 | << FixItHint::CreateReplacement(MatchedCast->getOperatorLoc(), |
48 | "dynamic_cast" ); |
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" ); |
57 | } |
58 | |
59 | } // namespace clang::tidy::cppcoreguidelines |
60 | |