teach lolugin:stringconstant about calling constructors

so we can remove unnecessary calls to the OUString(literal) constructor
when calling constructors like this:
   Foo(OUString("xxx"), 1)

Change-Id: I1de60ef561437c86b27dc9cb095a5deb2e103b36
Reviewed-on: https://gerrit.libreoffice.org/33698
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin
2017-01-30 16:38:54 +02:00
parent e1e6cdbb1e
commit 1c3e84d819
267 changed files with 1122 additions and 1156 deletions

View File

@@ -152,6 +152,10 @@ private:
CallExpr const * expr, unsigned arg, FunctionDecl const * callee,
bool explicitFunctionalCastNotation);
void handleOUStringCtor(
Expr const * expr, Expr const * argExpr, FunctionDecl const * callee,
bool explicitFunctionalCastNotation);
void handleFunArgOstring(
CallExpr const * expr, unsigned arg, FunctionDecl const * callee);
@@ -1054,37 +1058,33 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
return true;
}
std::string file(compiler.getSourceManager().getFilename(
compiler.getSourceManager().getSpellingLoc(expr->getLocStart())));
if (file == SRCDIR "/sal/qa/rtl/oustringbuffer/test_oustringbuffer_tostring.cxx")
{
return true;
}
if (isInUnoIncludeFile(expr->getLocStart())) {
return true;
}
auto consDecl = expr->getConstructor();
for (unsigned i = 0; i != consDecl->getNumParams(); ++i) {
auto t = consDecl->getParamDecl(i)->getType();
if (loplugin::TypeCheck(t).NotSubstTemplateTypeParmType()
.LvalueReference().Const().NotSubstTemplateTypeParmType()
.Class("OUString").Namespace("rtl").GlobalNamespace())
{
auto argExpr = expr->getArg(i);
if (argExpr && i <= consDecl->getNumParams())
{
if (!hasOverloads(consDecl, expr->getNumArgs()))
{
handleOUStringCtor(expr, argExpr, consDecl, true);
}
}
}
}
// Now check for calls to one of our exception classes where an unnecessary OUString
// constructor is used for the first parameter.
if (isInUnoIncludeFile(expr->getConstructor()->getCanonicalDecl())) {
return true;
}
if (!expr->getConstructor()->getParent()->getName().endswith("Exception")) {
return true;
}
if (expr->getNumArgs() == 0) {
return true;
}
MaterializeTemporaryExpr const * subExpr1 = dyn_cast<MaterializeTemporaryExpr>(expr->getArg(0));
if (!subExpr1) {
return true;
}
if (!loplugin::TypeCheck(subExpr1->getType()).Class("OUString").Namespace("rtl").GlobalNamespace()) {
return true;
}
ImplicitCastExpr const * subExpr2 = dyn_cast<ImplicitCastExpr>(subExpr1->GetTemporaryExpr());
if (!subExpr2) {
return true;
}
CXXFunctionalCastExpr const * subExpr3 = dyn_cast<CXXFunctionalCastExpr>(subExpr2->getSubExpr());
if (!subExpr3) {
return true;
}
report(DiagnosticsEngine::Warning,
"no need to use an explicit OUString constructor here",
subExpr3->getLocStart())
<< subExpr3->getSourceRange();
return true;
}
@@ -1592,7 +1592,14 @@ void StringConstant::handleOUStringCtor(
CallExpr const * expr, unsigned arg, FunctionDecl const * callee,
bool explicitFunctionalCastNotation)
{
auto e0 = expr->getArg(arg)->IgnoreParenImpCasts();
handleOUStringCtor(expr, expr->getArg(arg), callee, explicitFunctionalCastNotation);
}
void StringConstant::handleOUStringCtor(
Expr const * expr, Expr const * argExpr, FunctionDecl const * callee,
bool explicitFunctionalCastNotation)
{
auto e0 = argExpr->IgnoreParenImpCasts();
auto e1 = dyn_cast<CXXFunctionalCastExpr>(e0);
if (e1 == nullptr) {
if (explicitFunctionalCastNotation) {

View File

@@ -14,6 +14,12 @@
#include "com/sun/star/uno/Reference.hxx"
#include "rtl/strbuf.hxx"
extern void foo(OUString const &); // expected-error {{extern prototype in main file without definition}}
struct Foo {
Foo(OUString const &, int) {}
};
int main() {
char const s1[] = "foo";
char const * const s2 = "foo";
@@ -47,6 +53,11 @@ int main() {
sb.insert(0, "foo", std::strlen("foo")); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert' [loplugin:stringconstant]}}
sb.insert(0, s1, 3/*std::strlen(s1)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert' [loplugin:stringconstant]}}
sb.insert(0, s2, 3/*std::strlen(s2)*/); // expected-error {{rewrite call of 'rtl::OStringBuffer::insert' with string constant and matching length arguments as call of 'rtl::OStringBuffer::insert', and turn the non-array string constant into an array [loplugin:stringconstant]}}
foo(OUString("xxx")); // expected-error {{in call of 'foo', replace 'OUString' constructed from a string literal directly with the string literal [loplugin:stringconstant}}
Foo aFoo(OUString("xxx"), 1); // expected-error {{in call of 'Foo::Foo', replace 'OUString' constructed from a string literal directly with the string literal}}
(void)aFoo;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */