1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef LO_CLANG_SHARED_PLUGINS
#include <cassert>
#include <stack>
#include <unordered_set>
#include "check.hxx"
#include "plugin.hxx"
#include "config_clang.h"
// Find matches of
//
// foo(s.getStr())
//
// (for the rtl string classes) that can be written as just
//
// foo(s)
//
// and warn about them, which prevents constructing unnecessary temporaries.
namespace
{
class UnnecessaryGetStr final : public loplugin::FilteringPlugin<UnnecessaryGetStr>
{
public:
explicit UnnecessaryGetStr(loplugin::InstantiationData const& data)
: FilteringPlugin(data)
{
}
bool VisitCallExpr(const CallExpr* callExpr)
{
if (ignoreLocation(callExpr))
return true;
const FunctionDecl* func = callExpr->getDirectCallee();
if (!func)
return true;
if (loplugin::DeclCheck(func)
.Function("createFromAscii")
.Class("OUString")
.Namespace("rtl")
.GlobalNamespace())
{
checkForGetStr(callExpr->getArg(0), "OUString::createFromAscii",
/*isOStringConstructor*/ false);
}
return true;
}
bool VisitCXXConstructExpr(const CXXConstructExpr* constructExpr)
{
if (ignoreLocation(constructExpr))
return true;
auto tc = loplugin::TypeCheck(constructExpr->getType());
if (tc.ClassOrStruct("basic_stringstream").StdNamespace())
{
// ignore the implicit-conversion nodes that are added here
if (constructExpr->getNumArgs() > 0)
nodesToIgnore.insert(constructExpr->getArg(0)->IgnoreImplicit());
}
else if (tc.ClassOrStruct("basic_string").StdNamespace())
{
if (constructExpr->getNumArgs() == 1 || constructExpr->getNumArgs() == 2)
{
if (nodesToIgnore.find(constructExpr) == nodesToIgnore.end())
checkForGetStr(constructExpr->getArg(0), "string constructor",
/*isOStringConstructor*/ false);
}
}
else if (tc.ClassOrStruct("basic_string_view").StdNamespace())
{
if (constructExpr->getNumArgs() == 1)
checkForGetStr(constructExpr->getArg(0), "string_view constructor",
/*isOStringConstructor*/ false);
}
else if (tc.Class("OString").Namespace("rtl").GlobalNamespace())
{
if (constructExpr->getNumArgs() == 1 || constructExpr->getNumArgs() == 2)
checkForGetStr(constructExpr->getArg(0), "OString constructor",
/*isOStringConstructor*/ true);
}
else if (tc.Class("OUString").Namespace("rtl").GlobalNamespace())
{
if (constructExpr->getNumArgs() == 2)
checkForGetStr(constructExpr->getArg(0), "OUString constructor",
/*isOStringConstructor*/ false);
}
return true;
}
bool preRun() override
{
if (!compiler.getLangOpts().CPlusPlus)
return false;
std::string fn(handler.getMainFileName());
loplugin::normalizeDotDotInFilePath(fn);
if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/qa/"))
return false;
return true;
}
private:
void checkForGetStr(const Expr* arg, const char* msg, bool isOStringConstructor)
{
auto e = dyn_cast<CXXMemberCallExpr>(arg->IgnoreImplicit());
if (!e)
return;
auto const t = e->getObjectType();
auto const tc2 = loplugin::TypeCheck(t);
if (tc2.Class("OString").Namespace("rtl").GlobalNamespace()
|| tc2.Class("OUString").Namespace("rtl").GlobalNamespace()
|| tc2.Class("OStringBuffer").Namespace("rtl").GlobalNamespace()
|| tc2.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()
|| tc2.ClassOrStruct("StringNumber").Namespace("rtl").GlobalNamespace())
{
if (loplugin::DeclCheck(e->getMethodDecl()).Function("getStr"))
{
StringRef fileName = getFilenameOfLocation(
compiler.getSourceManager().getSpellingLoc(e->getBeginLoc()));
if (!loplugin::hasPathnamePrefix(fileName, SRCDIR "/include/rtl/"))
report(DiagnosticsEngine::Warning,
"unnecessary call to 'getStr' when passing to %0", e->getExprLoc())
<< msg << e->getSourceRange();
}
}
// we do need to use c_str() when passing to an OString
else if (!isOStringConstructor && tc2.Class("basic_string").StdNamespace())
{
if (loplugin::DeclCheck(e->getMethodDecl()).Function("c_str"))
report(DiagnosticsEngine::Warning, "unnecessary call to 'c_str' when passing to %0",
e->getExprLoc())
<< msg << e->getSourceRange();
}
}
void run() override
{
if (preRun())
{
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
}
std::unordered_set<const Expr*> nodesToIgnore;
};
loplugin::Plugin::Registration<UnnecessaryGetStr> unnecessarygetstr("unnecessarygetstr");
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|