diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2023-07-21 22:42:35 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2023-07-31 23:24:52 +0200 |
commit | 5d80385fd167e5e88bb0ce959c78568d7d817842 (patch) | |
tree | bd71c541fc226f1b8a6986ba45148762f9e079ca /compilerplugins | |
parent | f0b8ad888aff453e1a765611dceb6bc1cf970780 (diff) |
loplugin:stringconstant: Catch some O[U]String::getStr anti-patterns
Change-Id: I36bc86fcffc3c10fe44e60d779c9aa48eeed00f2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154749
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/stringconstant.cxx | 43 | ||||
-rw-r--r-- | compilerplugins/clang/test/stringconstant.cxx | 13 |
2 files changed, 56 insertions, 0 deletions
diff --git a/compilerplugins/clang/stringconstant.cxx b/compilerplugins/clang/stringconstant.cxx index cf1eb6afedbf..c64c2c9d6589 100644 --- a/compilerplugins/clang/stringconstant.cxx +++ b/compilerplugins/clang/stringconstant.cxx @@ -191,6 +191,8 @@ public: bool VisitCallExpr(CallExpr const * expr); + bool VisitCXXMemberCallExpr(CXXMemberCallExpr const * expr); + bool VisitCXXConstructExpr(CXXConstructExpr const * expr); bool VisitReturnStmt(ReturnStmt const * stmt); @@ -856,6 +858,47 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) { return true; } +bool StringConstant::VisitCXXMemberCallExpr(CXXMemberCallExpr const * expr) { + if (ignoreLocation(expr)) { + return true; + } + FunctionDecl const * fdecl = expr->getDirectCallee(); + if (fdecl == nullptr) { + return true; + } + auto const c = loplugin::DeclCheck(fdecl).Function("getStr"); + if ((c.Class("OString").Namespace("rtl").GlobalNamespace() + || c.Class("OUString").Namespace("rtl").GlobalNamespace()) + && fdecl->getNumParams() == 0) + { + auto const e1 = expr->getImplicitObjectArgument()->IgnoreImplicit()->IgnoreParens(); + if (auto const e2 = dyn_cast<CXXTemporaryObjectExpr>(e1)) { + if (e2->getNumArgs() != 0) { + return true; + } + report( + DiagnosticsEngine::Warning, + "in call of '%0', replace default-constructed %1 directly with an empty %select{ordinary|UTF-16}2 string literal", + expr->getExprLoc()) + << fdecl->getQualifiedNameAsString() << e2->getType() << bool(loplugin::TypeCheck(e2->getType()).Class("OUString")) << expr->getSourceRange(); + return true; + } + if (auto const e2 = dyn_cast<CXXFunctionalCastExpr>(e1)) { + auto const e3 = dyn_cast<clang::StringLiteral>(e2->getSubExprAsWritten()->IgnoreParens()); + if (e3 == nullptr) { + return true; + } + report( + DiagnosticsEngine::Warning, + "in call of '%0', replace %1 constructed from a string literal directly with %select{the|a UTF-16}2 string literal", + expr->getExprLoc()) + << fdecl->getQualifiedNameAsString() << e2->getType() << (loplugin::TypeCheck(e2->getType()).Class("OUString") && !e3->isUTF16()) << expr->getSourceRange(); + return true; + } + } + return true; +} + bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) { if (ignoreLocation(expr)) { return true; diff --git a/compilerplugins/clang/test/stringconstant.cxx b/compilerplugins/clang/test/stringconstant.cxx index 02f83b531068..ada901b877ce 100644 --- a/compilerplugins/clang/test/stringconstant.cxx +++ b/compilerplugins/clang/test/stringconstant.cxx @@ -128,6 +128,19 @@ int main() { ub.append(static_cast<char const *>(sc2)); // at runtime: append "foo" ub.append(static_cast<char const *>(sc3)); // at runtime: assert ub.append(static_cast<char const *>(sc4)); // at runtime: UB + + // expected-error-re@+1 {{in call of 'rtl::OString::getStr', replace default-constructed '{{(rtl::)?}}OString' directly with an empty ordinary string literal}} + OString().getStr(); + // expected-error-re@+1 {{in call of 'rtl::OString::getStr', replace '{{(rtl::)?}}OString' constructed from a string literal directly with the string literal}} + OString("foo").getStr(); + // expected-error-re@+1 {{in call of 'rtl::OString::getStr', replace '{{(rtl::)?}}OString' constructed from a string literal directly with the string literal}} + (OString(("foo"))).getStr(); + // expected-error-re@+1 {{in call of 'rtl::OUString::getStr', replace default-constructed '{{(rtl::)?}}OUString' directly with an empty UTF-16 string literal}} + OUString().getStr(); + // expected-error-re@+1 {{in call of 'rtl::OUString::getStr', replace '{{(rtl::)?}}OUString' constructed from a string literal directly with a UTF-16 string literal}} + OUString("foo").getStr(); + // expected-error-re@+1 {{in call of 'rtl::OUString::getStr', replace '{{(rtl::)?}}OUString' constructed from a string literal directly with the string literal}} + OUString(u"foo").getStr(); } |