xref: /llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp (revision af07d7ba883b6e4921820d88b6679f294a0b9fa5)
1 //===--- ProTypeConstCastCheck.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 "ProTypeConstCastCheck.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 
hasConstQualifier(QualType Type)17 static bool hasConstQualifier(QualType Type) {
18   const QualType PtrType = Type->getPointeeType();
19   if (!PtrType.isNull())
20     return hasConstQualifier(PtrType);
21 
22   return Type.isConstQualified();
23 }
24 
hasVolatileQualifier(QualType Type)25 static bool hasVolatileQualifier(QualType Type) {
26   const QualType PtrType = Type->getPointeeType();
27   if (!PtrType.isNull())
28     return hasVolatileQualifier(PtrType);
29   return Type.isVolatileQualified();
30 }
31 
ProTypeConstCastCheck(StringRef Name,ClangTidyContext * Context)32 ProTypeConstCastCheck::ProTypeConstCastCheck(StringRef Name,
33                                              ClangTidyContext *Context)
34     : ClangTidyCheck(Name, Context),
35       StrictMode(Options.getLocalOrGlobal("StrictMode", false)) {}
36 
storeOptions(ClangTidyOptions::OptionMap & Opts)37 void ProTypeConstCastCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
38   Options.store(Opts, "StrictMode", StrictMode);
39 }
40 
registerMatchers(MatchFinder * Finder)41 void ProTypeConstCastCheck::registerMatchers(MatchFinder *Finder) {
42   Finder->addMatcher(cxxConstCastExpr().bind("cast"), this);
43 }
44 
check(const MatchFinder::MatchResult & Result)45 void ProTypeConstCastCheck::check(const MatchFinder::MatchResult &Result) {
46   const auto *MatchedCast = Result.Nodes.getNodeAs<CXXConstCastExpr>("cast");
47   if (StrictMode) {
48     diag(MatchedCast->getOperatorLoc(), "do not use const_cast");
49     return;
50   }
51 
52   const QualType TargetType = MatchedCast->getType().getCanonicalType();
53   const QualType SourceType =
54       MatchedCast->getSubExpr()->getType().getCanonicalType();
55 
56   const bool RemovingConst =
57       hasConstQualifier(SourceType) && !hasConstQualifier(TargetType);
58   const bool RemovingVolatile =
59       hasVolatileQualifier(SourceType) && !hasVolatileQualifier(TargetType);
60 
61   if (!RemovingConst && !RemovingVolatile) {
62     // Cast is doing nothing.
63     return;
64   }
65 
66   diag(MatchedCast->getOperatorLoc(),
67        "do not use const_cast to remove%select{| const}0%select{| "
68        "and}2%select{| volatile}1 qualifier")
69       << RemovingConst << RemovingVolatile
70       << (RemovingConst && RemovingVolatile);
71 }
72 
73 } // namespace clang::tidy::cppcoreguidelines
74