1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
10 #ifndef LO_CLANG_SHARED_PLUGINS
14 #include <unordered_set>
18 #include "config_clang.h"
24 // (for the rtl string classes) that can be written as just
28 // and warn about them, which prevents constructing unnecessary temporaries.
32 class UnnecessaryGetStr final
: public loplugin::FilteringPlugin
<UnnecessaryGetStr
>
35 explicit UnnecessaryGetStr(loplugin::InstantiationData
const& data
)
36 : FilteringPlugin(data
)
40 bool VisitCallExpr(const CallExpr
* callExpr
)
42 if (ignoreLocation(callExpr
))
44 const FunctionDecl
* func
= callExpr
->getDirectCallee();
47 if (loplugin::DeclCheck(func
)
48 .Function("createFromAscii")
53 checkForGetStr(callExpr
->getArg(0), "OUString::createFromAscii",
54 /*isOStringConstructor*/ false);
59 bool VisitCXXConstructExpr(const CXXConstructExpr
* constructExpr
)
61 if (ignoreLocation(constructExpr
))
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);
100 bool preRun() override
102 if (!compiler
.getLangOpts().CPlusPlus
)
104 std::string
fn(handler
.getMainFileName());
105 loplugin::normalizeDotDotInFilePath(fn
);
106 if (loplugin::hasPathnamePrefix(fn
, SRCDIR
"/sal/qa/"))
112 void checkForGetStr(const Expr
* arg
, const char* msg
, bool isOStringConstructor
)
114 auto e
= dyn_cast
<CXXMemberCallExpr
>(arg
->IgnoreImplicit());
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",
141 << msg
<< e
->getSourceRange();
148 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
152 std::unordered_set
<const Expr
*> nodesToIgnore
;
155 loplugin::Plugin::Registration
<UnnecessaryGetStr
> unnecessarygetstr("unnecessarygetstr");
160 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */