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);
62 DynTypedNodeList Parents = Ctxt.getParents(*
E);
63 if (Parents.size() != 1)
66 return Parents.begin()->get<T>();
95 if (Cast->getCastKind() != CK_NoOp)
99 QualType QT = Cast->getType();
100 if (QT->isPointerType())
101 QT = QT->getPointeeType();
103 if (!QT.isConstQualified())
106 const auto *
Parent = getParent<Stmt>(Cast);
110 if (isa<ReturnStmt>(
Parent))
113 if (isa<CallExpr>(
Parent))
117 if (
const auto *Member = dyn_cast<MemberExpr>(
Parent))
118 return VisitUser(Member,
true);
125 bool VisitUser(
const MemberExpr *Member,
bool OnConstObject) {
126 if (Member->isBoundMemberFunction(Ctxt)) {
127 if (!OnConstObject || Member->getFoundDecl().getAccess() != AS_public) {
143 const auto *
Parent = getParent<Expr>(Member);
145 if (
const auto *Cast = dyn_cast_or_null<ImplicitCastExpr>(
Parent)) {
150 if (Member->getFoundDecl().getAccess() != AS_public &&
151 !Cast->getType()->isBuiltinType())
154 if (Cast->getCastKind() == CK_LValueToRValue)
157 if (Cast->getCastKind() == CK_NoOp && Cast->getType().isConstQualified())
161 if (
const auto *M = dyn_cast_or_null<MemberExpr>(
Parent))
162 return VisitUser(M,
false);
170 const auto *
Parent = getParent<Expr>(
E);
173 if (
const auto *UnOp = dyn_cast_or_null<UnaryOperator>(
Parent)) {
174 if (UnOp->getOpcode() == UO_Deref) {
175 Parent = getParent<Expr>(UnOp);
184 if (
const auto *Cast = dyn_cast_or_null<ImplicitCastExpr>(
Parent)) {
192 }
else if (
const auto *Member = dyn_cast_or_null<MemberExpr>(
Parent)) {
193 if (VisitUser(Member,
false))
207 UsageOfThis.TraverseStmt(const_cast<Stmt *>(Node.getBody()));
212 void MakeMemberFunctionConstCheck::registerMatchers(MatchFinder *Finder) {
215 ast_type_traits::TK_AsIs,
217 isDefinition(), isUserProvided(),
219 isExpansionInSystemHeader(), isVirtual(), isConst(),
220 isStatic(), hasTrivialBody(), cxxConstructorDecl(),
221 cxxDestructorDecl(), isTemplate(), isDependentContext(),
222 ofClass(anyOf(isLambda(),
223 hasAnyDependentBases())
227 isInsideMacroDefinition(),
228 hasCanonicalDecl(isInsideMacroDefinition()))),
235 TypeSourceInfo *TSI = M->getTypeSourceInfo();
239 FunctionTypeLoc FTL =
240 TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
244 return FTL.getRParenLoc().getLocWithOffset(1);
247 void MakeMemberFunctionConstCheck::check(
248 const MatchFinder::MatchResult &Result) {
249 const auto *Definition = Result.Nodes.getNodeAs<CXXMethodDecl>(
"x");
251 auto Declaration = Definition->getCanonicalDecl();
253 auto Diag = diag(Definition->getLocation(),
"method %0 can be made const")
257 if (Declaration != Definition) {