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/.
16 // Find places where we are returning a pointer to something, where we can be returning a reference.
21 // X* getX() { return &x; }
24 // X& getX() { return x; }
29 public RecursiveASTVisitor
<ReturnByRef
>, public loplugin::Plugin
32 explicit ReturnByRef(InstantiationData
const & data
): Plugin(data
) {}
34 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
36 bool VisitCXXMethodDecl(const CXXMethodDecl
* decl
);
38 std::string
getFilename(SourceLocation loc
);
41 bool ReturnByRef::VisitCXXMethodDecl(const CXXMethodDecl
* functionDecl
) {
42 if (ignoreLocation(functionDecl
)) {
45 if (functionDecl
->isVirtual()) {
48 if (!functionDecl
->isInstance()) {
51 if (!functionDecl
->hasBody()) {
54 // ignore stuff that forms part of the stable URE interface
55 if (isInUnoIncludeFile(functionDecl
)) {
58 QualType t1
{ compat::getReturnType(*functionDecl
) };
59 if (!t1
->isPointerType()) {
63 // operator vcl::Window *(){ return &m_rWindow; }
64 if (dyn_cast
< CXXConversionDecl
>( functionDecl
) != nullptr) {
68 std::string aFilename
= getFilename(functionDecl
->getCanonicalDecl()->getLocStart());
69 if (aFilename
== SRCDIR
"/include/o3tl/cow_wrapper.hxx")
73 if ( functionDecl
->getNameAsString() == "operator->") {
77 std::string aParentName = functionDecl->getParent()->getQualifiedNameAsString();
78 std::string fqn = aParentName + "::" + functionDecl->getNameAsString();
79 if (aFilename == "TextCharAttribList::GetAttrib") {
84 The AST here looks like:
90 const CompoundStmt
* compoundStmt
= dyn_cast
< CompoundStmt
>( functionDecl
->getBody() );
91 if (compoundStmt
== nullptr || compoundStmt
->body_begin() == compoundStmt
->body_end()) {
94 const ReturnStmt
* returnStmt
= dyn_cast
<ReturnStmt
>(*compoundStmt
->child_begin());
95 if (returnStmt
== nullptr) {
99 const Stmt
* nextStmt
= dyn_cast
<Expr
>(*returnStmt
->child_begin())->IgnoreParens();
100 const UnaryOperator
* unaryOperator
= dyn_cast
<UnaryOperator
>(nextStmt
);
101 if (unaryOperator
== nullptr || unaryOperator
->getOpcode() != UO_AddrOf
) {
106 DiagnosticsEngine::Warning
,
107 "rather return by reference ",
108 functionDecl
->getSourceRange().getBegin())
109 << functionDecl
->getSourceRange();
111 // display the location of the class member declaration so I don't have to search for it by hand
112 auto otherLoc
= functionDecl
->getCanonicalDecl()->getSourceRange().getBegin();
113 if (otherLoc
!= functionDecl
->getSourceRange().getBegin())
116 DiagnosticsEngine::Note
,
117 "rather return by reference",
118 functionDecl
->getCanonicalDecl()->getSourceRange().getBegin())
119 << functionDecl
->getCanonicalDecl()->getSourceRange();
125 std::string
ReturnByRef::getFilename(SourceLocation loc
)
127 SourceLocation spellingLocation
= compiler
.getSourceManager().getSpellingLoc(loc
);
128 return compiler
.getSourceManager().getFilename(spellingLocation
);
131 loplugin::Plugin::Registration
< ReturnByRef
> X("returnbyref");
135 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */