update credits
[LibreOffice.git] / compilerplugins / clang / unnecessarygetstr.cxx
blob589ab405f786a22d77985ace527ceef8ebd4099e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 #ifndef LO_CLANG_SHARED_PLUGINS
12 #include <cassert>
13 #include <stack>
14 #include <unordered_set>
16 #include "check.hxx"
17 #include "plugin.hxx"
18 #include "config_clang.h"
20 // Find matches of
22 // foo(s.getStr())
24 // (for the rtl string classes) that can be written as just
26 // foo(s)
28 // and warn about them, which prevents constructing unnecessary temporaries.
30 namespace
32 class UnnecessaryGetStr final : public loplugin::FilteringPlugin<UnnecessaryGetStr>
34 public:
35 explicit UnnecessaryGetStr(loplugin::InstantiationData const& data)
36 : FilteringPlugin(data)
40 bool VisitCallExpr(const CallExpr* callExpr)
42 if (ignoreLocation(callExpr))
43 return true;
44 const FunctionDecl* func = callExpr->getDirectCallee();
45 if (!func)
46 return true;
47 if (loplugin::DeclCheck(func)
48 .Function("createFromAscii")
49 .Class("OUString")
50 .Namespace("rtl")
51 .GlobalNamespace())
53 checkForGetStr(callExpr->getArg(0), "OUString::createFromAscii",
54 /*isOStringConstructor*/ false);
56 return true;
59 bool VisitCXXConstructExpr(const CXXConstructExpr* constructExpr)
61 if (ignoreLocation(constructExpr))
62 return true;
63 auto tc = loplugin::TypeCheck(constructExpr->getType());
64 if (tc.ClassOrStruct("basic_stringstream").StdNamespace())
66 // ignore the implicit-conversion nodes that are added here
67 if (constructExpr->getNumArgs() > 0)
68 nodesToIgnore.insert(constructExpr->getArg(0)->IgnoreImplicit());
70 else if (tc.ClassOrStruct("basic_string").StdNamespace())
72 if (constructExpr->getNumArgs() == 1 || constructExpr->getNumArgs() == 2)
74 if (nodesToIgnore.find(constructExpr) == nodesToIgnore.end())
75 checkForGetStr(constructExpr->getArg(0), "string constructor",
76 /*isOStringConstructor*/ false);
79 else if (tc.ClassOrStruct("basic_string_view").StdNamespace())
81 if (constructExpr->getNumArgs() == 1)
82 checkForGetStr(constructExpr->getArg(0), "string_view constructor",
83 /*isOStringConstructor*/ false);
85 else if (tc.Class("OString").Namespace("rtl").GlobalNamespace())
87 if (constructExpr->getNumArgs() == 1 || constructExpr->getNumArgs() == 2)
88 checkForGetStr(constructExpr->getArg(0), "OString constructor",
89 /*isOStringConstructor*/ true);
91 else if (tc.Class("OUString").Namespace("rtl").GlobalNamespace())
93 if (constructExpr->getNumArgs() == 2)
94 checkForGetStr(constructExpr->getArg(0), "OUString constructor",
95 /*isOStringConstructor*/ false);
97 return true;
100 bool preRun() override
102 if (!compiler.getLangOpts().CPlusPlus)
103 return false;
104 std::string fn(handler.getMainFileName());
105 loplugin::normalizeDotDotInFilePath(fn);
106 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/qa/"))
107 return false;
108 return true;
111 private:
112 void checkForGetStr(const Expr* arg, const char* msg, bool isOStringConstructor)
114 auto e = dyn_cast<CXXMemberCallExpr>(arg->IgnoreImplicit());
115 if (!e)
116 return;
117 auto const t = e->getObjectType();
118 auto const tc2 = loplugin::TypeCheck(t);
119 if (tc2.Class("OString").Namespace("rtl").GlobalNamespace()
120 || tc2.Class("OUString").Namespace("rtl").GlobalNamespace()
121 || tc2.Class("OStringBuffer").Namespace("rtl").GlobalNamespace()
122 || tc2.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()
123 || tc2.ClassOrStruct("StringNumber").Namespace("rtl").GlobalNamespace())
125 if (loplugin::DeclCheck(e->getMethodDecl()).Function("getStr"))
127 StringRef fileName = getFilenameOfLocation(
128 compiler.getSourceManager().getSpellingLoc(e->getBeginLoc()));
129 if (!loplugin::hasPathnamePrefix(fileName, SRCDIR "/include/rtl/"))
130 report(DiagnosticsEngine::Warning,
131 "unnecessary call to 'getStr' when passing to %0", e->getExprLoc())
132 << msg << e->getSourceRange();
135 // we do need to use c_str() when passing to an OString
136 else if (!isOStringConstructor && tc2.Class("basic_string").StdNamespace())
138 if (loplugin::DeclCheck(e->getMethodDecl()).Function("c_str"))
139 report(DiagnosticsEngine::Warning, "unnecessary call to 'c_str' when passing to %0",
140 e->getExprLoc())
141 << msg << e->getSourceRange();
144 void run() override
146 if (preRun())
148 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
152 std::unordered_set<const Expr*> nodesToIgnore;
155 loplugin::Plugin::Registration<UnnecessaryGetStr> unnecessarygetstr("unnecessarygetstr");
158 #endif
160 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */