clang-tools 20.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
14using namespace clang::ast_matchers;
15
17
18static bool needsConstCast(QualType SourceType, QualType DestType) {
19 SourceType = SourceType.getNonReferenceType();
20 DestType = DestType.getNonReferenceType();
21 while (SourceType->isPointerType() && DestType->isPointerType()) {
22 SourceType = SourceType->getPointeeType();
23 DestType = DestType->getPointeeType();
24 if (SourceType.isConstQualified() && !DestType.isConstQualified())
25 return true;
26 }
27 return false;
28}
29
31 Finder->addMatcher(
32 cStyleCastExpr(unless(isInTemplateInstantiation())).bind("cast"), this);
33}
34
35void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
36 const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
37
38 if (MatchedCast->getCastKind() == CK_BitCast ||
39 MatchedCast->getCastKind() == CK_LValueBitCast ||
40 MatchedCast->getCastKind() == CK_IntegralToPointer ||
41 MatchedCast->getCastKind() == CK_PointerToIntegral ||
42 MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) {
43 diag(MatchedCast->getBeginLoc(),
44 "do not use C-style cast to convert between unrelated types");
45 return;
46 }
47
48 QualType SourceType = MatchedCast->getSubExpr()->getType();
49
50 if (MatchedCast->getCastKind() == CK_BaseToDerived) {
51 const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
52 if (!SourceDecl) // The cast is from object to reference.
53 SourceDecl = SourceType->getAsCXXRecordDecl();
54 if (!SourceDecl)
55 return;
56
57 if (SourceDecl->isPolymorphic()) {
58 // Leave type spelling exactly as it was (unlike
59 // getTypeAsWritten().getAsString() which would spell enum types 'enum
60 // X').
61 StringRef DestTypeString = Lexer::getSourceText(
62 CharSourceRange::getTokenRange(
63 MatchedCast->getLParenLoc().getLocWithOffset(1),
64 MatchedCast->getRParenLoc().getLocWithOffset(-1)),
65 *Result.SourceManager, getLangOpts());
66
67 auto DiagBuilder = diag(
68 MatchedCast->getBeginLoc(),
69 "do not use C-style cast to downcast from a base to a derived class; "
70 "use dynamic_cast instead");
71
72 const Expr *SubExpr =
73 MatchedCast->getSubExprAsWritten()->IgnoreImpCasts();
74 std::string CastText = ("dynamic_cast<" + DestTypeString + ">").str();
75 if (!isa<ParenExpr>(SubExpr)) {
76 CastText.push_back('(');
77 DiagBuilder << FixItHint::CreateInsertion(
78 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0,
79 *Result.SourceManager, getLangOpts()),
80 ")");
81 }
82 auto ParenRange = CharSourceRange::getTokenRange(
83 MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc());
84 DiagBuilder << FixItHint::CreateReplacement(ParenRange, CastText);
85 } else {
86 diag(
87 MatchedCast->getBeginLoc(),
88 "do not use C-style cast to downcast from a base to a derived class");
89 }
90 return;
91 }
92
93 if (MatchedCast->getCastKind() == CK_NoOp &&
94 needsConstCast(SourceType, MatchedCast->getType())) {
95 diag(MatchedCast->getBeginLoc(),
96 "do not use C-style cast to cast away constness");
97 }
98}
99
100} // namespace clang::tidy::cppcoreguidelines
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static bool needsConstCast(QualType SourceType, QualType DestType)