cURL: follow redirects
[LibreOffice.git] / compilerplugins / clang / store / returnbyref.cxx
blobaacfd7d833cff61428f599b6f5a0658870566a65
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);
37 private:
38 std::string getFilename(SourceLocation loc);
41 bool ReturnByRef::VisitCXXMethodDecl(const CXXMethodDecl * functionDecl) {
42 if (ignoreLocation(functionDecl)) {
43 return true;
45 if (functionDecl->isVirtual()) {
46 return true;
48 if (!functionDecl->isInstance()) {
49 return true;
51 if (!functionDecl->hasBody()) {
52 return true;
54 // ignore stuff that forms part of the stable URE interface
55 if (isInUnoIncludeFile(functionDecl)) {
56 return true;
58 QualType t1 { compat::getReturnType(*functionDecl) };
59 if (!t1->isPointerType()) {
60 return true;
62 // Ignore stuff like:
63 // operator vcl::Window *(){ return &m_rWindow; }
64 if (dyn_cast< CXXConversionDecl >( functionDecl ) != nullptr) {
65 return true;
68 std::string aFilename = getFilename(functionDecl->getCanonicalDecl()->getLocStart());
69 if (aFilename == SRCDIR "/include/o3tl/cow_wrapper.hxx")
71 return true;
73 if ( functionDecl->getNameAsString() == "operator->") {
74 return true;
77 std::string aParentName = functionDecl->getParent()->getQualifiedNameAsString();
78 std::string fqn = aParentName + "::" + functionDecl->getNameAsString();
79 if (aFilename == "TextCharAttribList::GetAttrib") {
80 return true;
81 }*/
84 The AST here looks like:
85 -CompoundStmt
86 `-ReturnStmt
87 `-UnaryOperator
90 const CompoundStmt* compoundStmt = dyn_cast< CompoundStmt >( functionDecl->getBody() );
91 if (compoundStmt == nullptr || compoundStmt->body_begin() == compoundStmt->body_end()) {
92 return true;
94 const ReturnStmt* returnStmt = dyn_cast<ReturnStmt>(*compoundStmt->child_begin());
95 if (returnStmt == nullptr) {
96 return true;
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) {
102 return true;
104 nextStmt->dump();
105 report(
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())
115 report(
116 DiagnosticsEngine::Note,
117 "rather return by reference",
118 functionDecl->getCanonicalDecl()->getSourceRange().getBegin())
119 << functionDecl->getCanonicalDecl()->getSourceRange();
122 return true;
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: */