// 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)) returntrue; const FunctionDecl* func = callExpr->getDirectCallee(); if (!func) returntrue; if (loplugin::DeclCheck(func)
.Function("createFromAscii")
.Class("OUString")
.Namespace("rtl")
.GlobalNamespace())
{
checkForGetStr(callExpr->getArg(0), "OUString::createFromAscii", /*isOStringConstructor*/ false);
} returntrue;
}
bool VisitCXXConstructExpr(const CXXConstructExpr* constructExpr)
{ if (ignoreLocation(constructExpr)) returntrue; 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());
} elseif (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);
}
} elseif (tc.ClassOrStruct("basic_string_view").StdNamespace())
{ if (constructExpr->getNumArgs() == 1)
checkForGetStr(constructExpr->getArg(0), "string_view constructor", /*isOStringConstructor*/ false);
} elseif (tc.Class("OString").Namespace("rtl").GlobalNamespace())
{ if (constructExpr->getNumArgs() == 1 || constructExpr->getNumArgs() == 2)
checkForGetStr(constructExpr->getArg(0), "OString constructor", /*isOStringConstructor*/ true);
} elseif (tc.Class("OUString").Namespace("rtl").GlobalNamespace())
{ if (constructExpr->getNumArgs() == 2)
checkForGetStr(constructExpr->getArg(0), "OUString constructor", /*isOStringConstructor*/ false);
} returntrue;
}
bool preRun() override
{ if (!compiler.getLangOpts().CPlusPlus) returnfalse;
std::string fn(handler.getMainFileName());
loplugin::normalizeDotDotInFilePath(fn); if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/qa/")) returnfalse; returntrue;
}
private: void checkForGetStr(const Expr* arg, constchar* msg, bool isOStringConstructor)
{ auto e = dyn_cast<CXXMemberCallExpr>(arg->IgnoreImplicit()); if (!e) return; autoconst t = e->getObjectType(); autoconst 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 elseif (!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());
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.