1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
17 #include <clang/AST/CXXInheritance.h>
26 * which can be transformed to:
41 class RedundantPointerOps
:
42 public loplugin::FilteringPlugin
<RedundantPointerOps
>
45 explicit RedundantPointerOps(loplugin::InstantiationData
const & data
): FilteringPlugin(data
) {}
47 virtual void run() override
50 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
53 bool VisitFunctionDecl(FunctionDecl
const *);
54 bool VisitMemberExpr(MemberExpr
const *);
55 bool VisitUnaryOperator(UnaryOperator
const *);
58 bool RedundantPointerOps::VisitFunctionDecl(FunctionDecl
const * functionDecl
)
60 if (ignoreLocation(functionDecl
))
62 //functionDecl->dump();
66 bool RedundantPointerOps::VisitMemberExpr(MemberExpr
const * memberExpr
)
68 if (ignoreLocation(memberExpr
))
70 if (compat::getBeginLoc(memberExpr
).isMacroID())
72 auto base
= memberExpr
->getBase()->IgnoreParenImpCasts();
73 //parentStmt(parentStmt(memberExpr))->dump();
74 if (memberExpr
->isArrow())
76 if (auto unaryOp
= dyn_cast
<UnaryOperator
>(base
))
78 if (unaryOp
->getOpcode() == UO_AddrOf
)
80 DiagnosticsEngine::Warning
,
81 "'&' followed by '->' operating on %0, rather use '.'",
82 compat::getBeginLoc(memberExpr
))
83 << memberExpr
->getBase()->getType()->getPointeeType()
84 << memberExpr
->getSourceRange();
87 else if (auto operatorCallExpr
= dyn_cast
<CXXOperatorCallExpr
>(base
))
89 if (operatorCallExpr
->getOperator() == OO_Amp
)
91 DiagnosticsEngine::Warning
,
92 "'&' followed by '->' operating on %0, rather use '.'",
93 compat::getBeginLoc(memberExpr
))
94 << memberExpr
->getBase()->getType()->getPointeeType()
95 << memberExpr
->getSourceRange();
101 // if (auto unaryOp = dyn_cast<UnaryOperator>(base))
103 // if (unaryOp->getOpcode() == UO_Deref)
105 // DiagnosticsEngine::Warning, "'*' followed by '.', rather use '->'",
106 // memberExpr->getLocStart())
107 // << memberExpr->getSourceRange();
114 bool RedundantPointerOps::VisitUnaryOperator(UnaryOperator
const * unaryOperator
)
116 if (ignoreLocation(unaryOperator
))
118 if (compat::getBeginLoc(unaryOperator
).isMacroID())
120 if (unaryOperator
->getOpcode() != UO_Deref
)
122 auto subExpr
= unaryOperator
->getSubExpr()->IgnoreParenImpCasts();
123 auto innerOp
= dyn_cast
<UnaryOperator
>(subExpr
);
124 if (innerOp
&& innerOp
->getOpcode() == UO_AddrOf
)
126 DiagnosticsEngine::Warning
, "'&' followed by '*' operating on %0, rather use '.'",
127 compat::getBeginLoc(unaryOperator
))
128 << innerOp
->getSubExpr()->getType() << unaryOperator
->getSourceRange();
129 if (auto cxxMemberCallExpr
= dyn_cast
<CXXMemberCallExpr
>(subExpr
))
131 auto methodDecl
= cxxMemberCallExpr
->getMethodDecl();
132 if (methodDecl
->getIdentifier() && methodDecl
->getName() == "get")
134 auto const e
= cxxMemberCallExpr
->getImplicitObjectArgument();
135 // First check the object type as written, in case the get member function is
136 // declared at a base class of std::unique_ptr or std::shared_ptr:
137 auto const t
= e
->IgnoreImpCasts()->getType();
138 auto const tc1
= loplugin::TypeCheck(t
);
139 if (!(tc1
.ClassOrStruct("unique_ptr").StdNamespace()
140 || tc1
.ClassOrStruct("shared_ptr").StdNamespace()))
142 // Then check the object type coerced to the type of the get member function, in
143 // case the type-as-written is derived from one of these types (tools::SvRef is
144 // final, but the rest are not; but note that this will fail when the type-as-
145 // written is derived from std::unique_ptr or std::shared_ptr for which the get
146 // member function is declared at a base class):
147 auto const tc2
= loplugin::TypeCheck(e
->getType());
148 if (!((tc2
.ClassOrStruct("unique_ptr").StdNamespace()
149 || tc2
.ClassOrStruct("shared_ptr").StdNamespace()
150 || (tc2
.Class("Reference").Namespace("uno").Namespace("star")
151 .Namespace("sun").Namespace("com").GlobalNamespace())
152 || tc2
.Class("Reference").Namespace("rtl").GlobalNamespace()
153 || tc2
.Class("SvRef").Namespace("tools").GlobalNamespace())))
159 DiagnosticsEngine::Warning
,
160 "'*' followed by '.get()' operating on %0, just use '*'",
161 compat::getBeginLoc(unaryOperator
))
162 << t
.getLocalUnqualifiedType() << unaryOperator
->getSourceRange();
169 loplugin::Plugin::Registration
< RedundantPointerOps
> redundantpointerops("redundantpointerops");
173 #endif // LO_CLANG_SHARED_PLUGINS
175 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */