bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / returnbyref.cxx
blobb3044f37f9a58610d746380c6d67736b9d661f0e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <string>
11 #include <set>
13 #include "compat.hxx"
14 #include "plugin.hxx"
16 // Find places where we are returning a pointer to something, where we can be returning a reference.
17 // e.g.
18 // class A {
19 // struct X x;
20 // public:
21 // X* getX() { return &x; }
22 // }
23 // which can be:
24 // X& getX() { return x; }
26 namespace {
28 class ReturnByRef:
29 public RecursiveASTVisitor<ReturnByRef>, public loplugin::Plugin
31 public:
32 explicit ReturnByRef(InstantiationData const & data): Plugin(data) {}
34 virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
36 bool VisitCXXMethodDecl(const CXXMethodDecl * decl);
39 bool ReturnByRef::VisitCXXMethodDecl(const CXXMethodDecl * functionDecl) {
40 if (ignoreLocation(functionDecl)) {
41 return true;
43 if (functionDecl->isVirtual()) {
44 return true;
46 if (!functionDecl->isInstance()) {
47 return true;
49 if (!functionDecl->hasBody()) {
50 return true;
52 // ignore stuff that forms part of the stable URE interface
53 if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(
54 functionDecl->getCanonicalDecl()->getNameInfo().getLoc()))) {
55 return true;
57 QualType t1 { compat::getReturnType(*functionDecl) };
58 if (!t1->isPointerType()) {
59 return true;
61 // Ignore stuff like:
62 // operator vcl::Window *(){ return &m_rWindow; }
63 if (dyn_cast< CXXConversionDecl >( functionDecl ) != nullptr) {
64 return true;
68 The AST here looks like:
69 -CompoundStmt
70 `-ReturnStmt
71 `-UnaryOperator
72 `-MemberExpr
73 `-CXXThisExpr
76 const CompoundStmt* compoundStmt = dyn_cast< CompoundStmt >( functionDecl->getBody() );
77 if (compoundStmt == nullptr || compoundStmt->body_begin() == compoundStmt->body_end()) {
78 return true;
80 const ReturnStmt* returnStmt = dyn_cast<ReturnStmt>(*compoundStmt->child_begin());
81 if (returnStmt == nullptr) {
82 return true;
85 const Stmt* nextStmt = dyn_cast<Expr>(*returnStmt->child_begin())->IgnoreParens();
86 const UnaryOperator* unaryOperator = dyn_cast<UnaryOperator>(nextStmt);
87 if (unaryOperator == nullptr || unaryOperator->getOpcode() != UO_AddrOf) {
88 return true;
91 nextStmt = dyn_cast<Expr>(*unaryOperator->child_begin())->IgnoreParens();
92 const MemberExpr* memberExpr = dyn_cast<MemberExpr>(nextStmt);
93 if (memberExpr == nullptr) {
94 return true;
97 nextStmt = dyn_cast<Expr>(*memberExpr->child_begin())->IgnoreParens();
98 const CXXThisExpr* cXXThisExpr = dyn_cast<CXXThisExpr>(nextStmt);
99 if (cXXThisExpr == nullptr) {
100 return true;
103 report(
104 DiagnosticsEngine::Warning,
105 "rather return by reference",
106 functionDecl->getSourceRange().getBegin())
107 << functionDecl->getSourceRange();
108 // display the location of the class member declaration so I don't have to search for it by hand
109 report(
110 DiagnosticsEngine::Note,
111 "rather return by reference",
112 functionDecl->getCanonicalDecl()->getSourceRange().getBegin())
113 << functionDecl->getCanonicalDecl()->getSourceRange();
115 return true;
118 loplugin::Plugin::Registration< ReturnByRef > X("returnbyref");
122 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */