clang-tools  14.0.0git
ProTypeCstyleCastCheck.cpp
Go to the documentation of this file.
1 //===--- ProTypeCstyleCastCheck.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 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace cppcoreguidelines {
19 
20 static bool needsConstCast(QualType SourceType, QualType DestType) {
21  SourceType = SourceType.getNonReferenceType();
22  DestType = DestType.getNonReferenceType();
23  while (SourceType->isPointerType() && DestType->isPointerType()) {
24  SourceType = SourceType->getPointeeType();
25  DestType = DestType->getPointeeType();
26  if (SourceType.isConstQualified() && !DestType.isConstQualified())
27  return true;
28  }
29  return false;
30 }
31 
32 void ProTypeCstyleCastCheck::registerMatchers(MatchFinder *Finder) {
33  Finder->addMatcher(
34  cStyleCastExpr(unless(isInTemplateInstantiation())).bind("cast"), this);
35 }
36 
37 void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
38  const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
39 
40  if (MatchedCast->getCastKind() == CK_BitCast ||
41  MatchedCast->getCastKind() == CK_LValueBitCast ||
42  MatchedCast->getCastKind() == CK_IntegralToPointer ||
43  MatchedCast->getCastKind() == CK_PointerToIntegral ||
44  MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) {
45  diag(MatchedCast->getBeginLoc(),
46  "do not use C-style cast to convert between unrelated types");
47  return;
48  }
49 
50  QualType SourceType = MatchedCast->getSubExpr()->getType();
51 
52  if (MatchedCast->getCastKind() == CK_BaseToDerived) {
53  const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
54  if (!SourceDecl) // The cast is from object to reference.
55  SourceDecl = SourceType->getAsCXXRecordDecl();
56  if (!SourceDecl)
57  return;
58 
59  if (SourceDecl->isPolymorphic()) {
60  // Leave type spelling exactly as it was (unlike
61  // getTypeAsWritten().getAsString() which would spell enum types 'enum
62  // X').
63  StringRef DestTypeString = Lexer::getSourceText(
64  CharSourceRange::getTokenRange(
65  MatchedCast->getLParenLoc().getLocWithOffset(1),
66  MatchedCast->getRParenLoc().getLocWithOffset(-1)),
67  *Result.SourceManager, getLangOpts());
68 
69  auto DiagBuilder = diag(
70  MatchedCast->getBeginLoc(),
71  "do not use C-style cast to downcast from a base to a derived class; "
72  "use dynamic_cast instead");
73 
74  const Expr *SubExpr =
75  MatchedCast->getSubExprAsWritten()->IgnoreImpCasts();
76  std::string CastText = ("dynamic_cast<" + DestTypeString + ">").str();
77  if (!isa<ParenExpr>(SubExpr)) {
78  CastText.push_back('(');
79  DiagBuilder << FixItHint::CreateInsertion(
80  Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0,
81  *Result.SourceManager, getLangOpts()),
82  ")");
83  }
84  auto ParenRange = CharSourceRange::getTokenRange(
85  MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc());
86  DiagBuilder << FixItHint::CreateReplacement(ParenRange, CastText);
87  } else {
88  diag(
89  MatchedCast->getBeginLoc(),
90  "do not use C-style cast to downcast from a base to a derived class");
91  }
92  return;
93  }
94 
95  if (MatchedCast->getCastKind() == CK_NoOp &&
96  needsConstCast(SourceType, MatchedCast->getType())) {
97  diag(MatchedCast->getBeginLoc(),
98  "do not use C-style cast to cast away constness");
99  }
100 }
101 
102 } // namespace cppcoreguidelines
103 } // namespace tidy
104 } // namespace clang
clang::tidy::cppcoreguidelines::getSourceText
static std::string getSourceText(const CXXDestructorDecl &Destructor)
Definition: VirtualClassDestructorCheck.cpp:109
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::clangd::check
bool check(llvm::StringRef File, llvm::function_ref< bool(const Position &)> ShouldCheckLine, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts, bool EnableCodeCompletion)
Definition: Check.cpp:253
ProTypeCstyleCastCheck.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::cppcoreguidelines::needsConstCast
static bool needsConstCast(QualType SourceType, QualType DestType)
Definition: ProTypeCstyleCastCheck.cpp:20