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/.
15 // Find places where we are returning a pointer to something, where we can be returning a reference.
20 // X* getX() { return &x; }
23 // X& getX() { return x; }
28 public loplugin::FilteringPlugin
<ReturnByRef
>
31 explicit ReturnByRef(InstantiationData
const & data
): FilteringPlugin(data
) {}
33 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
35 bool VisitCXXMethodDecl(const CXXMethodDecl
* decl
);
37 std::string
getFilename(SourceLocation loc
);
40 bool ReturnByRef::VisitCXXMethodDecl(const CXXMethodDecl
* functionDecl
) {
41 if (ignoreLocation(functionDecl
)) {
44 if (functionDecl
->isVirtual()) {
47 if (!functionDecl
->isInstance()) {
50 if (!functionDecl
->hasBody()) {
53 // ignore stuff that forms part of the stable URE interface
54 if (isInUnoIncludeFile(functionDecl
)) {
57 QualType t1
{ functionDecl
->getReturnType() };
58 if (!t1
->isPointerType()) {
62 // operator vcl::Window *(){ return &m_rWindow; }
63 if (dyn_cast
< CXXConversionDecl
>( functionDecl
) != nullptr) {
67 std::string aFilename
= getFilename(functionDecl
->getCanonicalDecl()->getLocStart());
68 if (aFilename
== SRCDIR
"/include/o3tl/cow_wrapper.hxx")
72 if ( functionDecl
->getNameAsString() == "operator->") {
75 std::string aFunctionName
= functionDecl
->getQualifiedNameAsString();
76 if (aFunctionName
== "SbxValue::data") {
80 std::string aParentName = functionDecl->getParent()->getQualifiedNameAsString();
81 std::string fqn = aParentName + "::" + functionDecl->getNameAsString();
82 if (aFilename == "TextCharAttribList::GetAttrib") {
87 The AST here looks like:
93 const CompoundStmt
* compoundStmt
= dyn_cast
< CompoundStmt
>( functionDecl
->getBody() );
94 if (compoundStmt
== nullptr || compoundStmt
->body_begin() == compoundStmt
->body_end()) {
97 const ReturnStmt
* returnStmt
= dyn_cast
<ReturnStmt
>(*compoundStmt
->child_begin());
98 if (returnStmt
== nullptr) {
102 const Stmt
* nextStmt
= dyn_cast
<Expr
>(*returnStmt
->child_begin())->IgnoreParens();
103 const UnaryOperator
* unaryOperator
= dyn_cast
<UnaryOperator
>(nextStmt
);
104 if (unaryOperator
== nullptr || unaryOperator
->getOpcode() != UO_AddrOf
) {
109 DiagnosticsEngine::Warning
,
110 "rather return by reference ",
111 functionDecl
->getSourceRange().getBegin())
112 << functionDecl
->getSourceRange();
114 // display the location of the class member declaration so I don't have to search for it by hand
115 auto otherLoc
= functionDecl
->getCanonicalDecl()->getSourceRange().getBegin();
116 if (otherLoc
!= functionDecl
->getSourceRange().getBegin())
119 DiagnosticsEngine::Note
,
120 "rather return by reference",
121 functionDecl
->getCanonicalDecl()->getSourceRange().getBegin())
122 << functionDecl
->getCanonicalDecl()->getSourceRange();
128 std::string
ReturnByRef::getFilename(SourceLocation loc
)
130 SourceLocation spellingLocation
= compiler
.getSourceManager().getSpellingLoc(loc
);
131 return compiler
.getSourceManager().getFilename(spellingLocation
);
134 loplugin::Plugin::Registration
< ReturnByRef
> X("returnbyref");
138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */