summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2023-07-21 22:42:35 +0200
committerStephan Bergmann <sbergman@redhat.com>2023-07-31 23:24:52 +0200
commit5d80385fd167e5e88bb0ce959c78568d7d817842 (patch)
treebd71c541fc226f1b8a6986ba45148762f9e079ca /compilerplugins
parentf0b8ad888aff453e1a765611dceb6bc1cf970780 (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.cxx43
-rw-r--r--compilerplugins/clang/test/stringconstant.cxx13
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();
}