10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/ParentMapContext.h"
12 #include "clang/AST/RecursiveASTVisitor.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Lex/Lexer.h"
20 namespace readability {
22 AST_MATCHER(CXXMethodDecl, isStatic) {
return Node.isStatic(); }
24 AST_MATCHER(CXXMethodDecl, hasTrivialBody) {
return Node.hasTrivialBody(); }
27 return Node.hasAnyDependentBases();
31 return Node.getTemplatedKind() != FunctionDecl::TK_NonTemplate;
35 return Node.isDependentContext();
38 AST_MATCHER(CXXMethodDecl, isInsideMacroDefinition) {
39 const ASTContext &Ctxt = Finder->getASTContext();
40 return clang::Lexer::makeFileCharRange(
41 clang::CharSourceRange::getCharRange(
42 Node.getTypeSourceInfo()->getTypeLoc().getSourceRange()),
43 Ctxt.getSourceManager(), Ctxt.getLangOpts())
48 ast_matchers::internal::Matcher<CXXMethodDecl>, InnerMatcher) {
49 return InnerMatcher.matches(*Node.getCanonicalDecl(), Finder,
Builder);
61 template <
class T>
const T *getParent(
const Expr *
E) {
62 DynTypedNodeList Parents = Ctxt.getParents(*
E);
63 if (Parents.size() != 1)
66 return Parents.begin()->get<T>();
69 const Expr *getParentExprIgnoreParens(
const Expr *
E) {
70 const Expr *
Parent = getParent<Expr>(
E);
71 while (isa_and_nonnull<ParenExpr>(
Parent))
102 if (Cast->getCastKind() != CK_NoOp)
106 QualType QT = Cast->getType();
107 if (QT->isPointerType())
108 QT = QT->getPointeeType();
110 if (!QT.isConstQualified())
113 const auto *
Parent = getParent<Stmt>(Cast);
117 if (isa<ReturnStmt>(
Parent))
120 if (isa<CallExpr>(
Parent))
124 if (
const auto *Member = dyn_cast<MemberExpr>(
Parent))
125 return visitUser(Member,
true);
132 bool visitUser(
const MemberExpr *Member,
bool OnConstObject) {
133 if (Member->isBoundMemberFunction(Ctxt)) {
134 if (!OnConstObject || Member->getFoundDecl().getAccess() != AS_public) {
150 const auto *
Parent = getParentExprIgnoreParens(Member);
152 if (
const auto *Cast = dyn_cast_or_null<ImplicitCastExpr>(
Parent)) {
157 if (Member->getFoundDecl().getAccess() != AS_public &&
158 !Cast->getType()->isBuiltinType())
161 if (Cast->getCastKind() == CK_LValueToRValue)
164 if (Cast->getCastKind() == CK_NoOp && Cast->getType().isConstQualified())
168 if (
const auto *
M = dyn_cast_or_null<MemberExpr>(
Parent))
169 return visitUser(
M,
false);
177 const auto *
Parent = getParentExprIgnoreParens(
E);
180 if (
const auto *UnOp = dyn_cast_or_null<UnaryOperator>(
Parent)) {
181 if (UnOp->getOpcode() == UO_Deref) {
182 Parent = getParentExprIgnoreParens(UnOp);
191 if (
const auto *Cast = dyn_cast_or_null<ImplicitCastExpr>(
Parent)) {
199 }
else if (
const auto *Member = dyn_cast_or_null<MemberExpr>(
Parent)) {
200 if (visitUser(Member,
false))
214 UsageOfThis.TraverseStmt(
const_cast<Stmt *
>(Node.getBody()));
219 void MakeMemberFunctionConstCheck::registerMatchers(MatchFinder *Finder) {
224 isDefinition(), isUserProvided(),
226 isExpansionInSystemHeader(), isVirtual(), isConst(),
227 isStatic(), hasTrivialBody(), cxxConstructorDecl(),
228 cxxDestructorDecl(), isTemplate(), isDependentContext(),
229 ofClass(anyOf(isLambda(),
230 hasAnyDependentBases())
234 isInsideMacroDefinition(),
235 hasCanonicalDecl(isInsideMacroDefinition()))),
242 TypeSourceInfo *TSI =
M->getTypeSourceInfo();
246 FunctionTypeLoc FTL =
247 TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
251 return FTL.getRParenLoc().getLocWithOffset(1);
255 const MatchFinder::MatchResult &Result) {
256 const auto *Definition = Result.Nodes.getNodeAs<CXXMethodDecl>(
"x");
258 const auto *Declaration = Definition->getCanonicalDecl();
260 auto Diag = diag(Definition->getLocation(),
"method %0 can be made const")
264 if (Declaration != Definition) {