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