[Libreoffice-commits] core.git: compilerplugins/clang sc/source solenv/CompilerTest_compilerplugins_clang.mk

Stephan Bergmann sbergman at redhat.com
Wed Jan 25 06:58:42 UTC 2017


 compilerplugins/clang/stringconstant.cxx      |  366 ++++++++++++++++----------
 compilerplugins/clang/test/stringconstant.cxx |   52 +++
 sc/source/core/tool/interpr2.cxx              |    4 
 solenv/CompilerTest_compilerplugins_clang.mk  |    1 
 4 files changed, 288 insertions(+), 135 deletions(-)

New commits:
commit 236f69e710b1ce00a68d25c26da82724c658b0d4
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Wed Jan 25 07:58:10 2017 +0100

    Minor loplugin:stringconstant improvements
    
    Change-Id: I0b39526c0f0854ddbb29e77ece303cf2bdd842c4

diff --git a/compilerplugins/clang/stringconstant.cxx b/compilerplugins/clang/stringconstant.cxx
index 34a5421..464fe06 100644
--- a/compilerplugins/clang/stringconstant.cxx
+++ b/compilerplugins/clang/stringconstant.cxx
@@ -75,6 +75,24 @@ bool hasOverloads(FunctionDecl const * decl, unsigned arguments) {
     return false;
 }
 
+CXXConstructExpr const * lookForCXXConstructExpr(Expr const * expr) {
+    if (auto e = dyn_cast<MaterializeTemporaryExpr>(expr)) {
+        expr = e->GetTemporaryExpr();
+    }
+    if (auto e = dyn_cast<CXXFunctionalCastExpr>(expr)) {
+        expr = e->getSubExpr();
+    }
+    if (auto e = dyn_cast<CXXBindTemporaryExpr>(expr)) {
+        expr = e->getSubExpr();
+    }
+    return dyn_cast<CXXConstructExpr>(expr);
+}
+
+char const * adviseNonArray(bool nonArray) {
+    return nonArray
+        ? ", and turn the non-array string constant into an array" : "";
+}
+
 class StringConstant:
     public RecursiveASTVisitor<StringConstant>, public loplugin::RewritePlugin
 {
@@ -113,7 +131,7 @@ private:
 
     void reportChange(
         Expr const * expr, ChangeKind kind, std::string const & original,
-        std::string const & replacement, PassThrough pass,
+        std::string const & replacement, PassThrough pass, bool nonArray,
         char const * rewriteFrom, char const * rewriteTo);
 
     void checkEmpty(
@@ -134,6 +152,9 @@ private:
         CallExpr const * expr, unsigned arg, FunctionDecl const * callee,
         bool explicitFunctionalCastNotation);
 
+    void handleFunArgOstring(
+        CallExpr const * expr, unsigned arg, FunctionDecl const * callee);
+
     std::stack<Expr const *> calls_;
 };
 
@@ -490,7 +511,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
         if (non) {
             report(
                 DiagnosticsEngine::Warning,
-                ("call of %0 with string constant argument containging"
+                ("call of '%0' with string constant argument containging"
                  " non-ASCII characters"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
@@ -498,16 +519,16 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
         if (emb) {
             report(
                 DiagnosticsEngine::Warning,
-                ("call of %0 with string constant argument containging embedded"
-                 " NULs"),
+                ("call of '%0' with string constant argument containging"
+                 " embedded NULs"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
         }
         if (n == 0) {
             report(
                 DiagnosticsEngine::Warning,
-                ("rewrite call of %0  with empty string constant argument as"
-                 " call of rtl::OUString::isEmpty"),
+                ("rewrite call of '%0' with empty string constant argument as"
+                 " call of 'rtl::OUString::isEmpty'"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
             return true;
@@ -531,7 +552,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (non) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("call of %0 with string constant argument containging"
+                    ("call of '%0' with string constant argument containging"
                      " non-ASCII characters"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
@@ -540,7 +561,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (emb) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("call of %0 with string constant argument containging"
+                    ("call of '%0' with string constant argument containging"
                      " embedded NULs"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
@@ -549,8 +570,8 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (n == 0) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("rewrite call of %0 with empty string constant argument as"
-                     " call of rtl::OUString::isEmpty"),
+                    ("rewrite call of '%0' with empty string constant argument"
+                     " as call of 'rtl::OUString::isEmpty'"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
                     << expr->getSourceRange();
@@ -576,7 +597,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (non) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("call of %0 with string constant argument containging"
+                    ("call of '%0' with string constant argument containging"
                      " non-ASCII characters"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
@@ -585,7 +606,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (emb) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("call of %0 with string constant argument containging"
+                    ("call of '%0' with string constant argument containging"
                      " embedded NULs"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
@@ -594,8 +615,8 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
             if (n == 0) {
                 report(
                     DiagnosticsEngine::Warning,
-                    ("rewrite call of %0 with empty string constant argument as"
-                     " call of !rtl::OUString::isEmpty"),
+                    ("rewrite call of '%0' with empty string constant argument"
+                     " as call of '!rtl::OUString::isEmpty'"),
                     expr->getExprLoc())
                     << fdecl->getQualifiedNameAsString()
                     << expr->getSourceRange();
@@ -620,7 +641,7 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
         if (non) {
             report(
                 DiagnosticsEngine::Warning,
-                ("call of %0 with string constant argument containging"
+                ("call of '%0' with string constant argument containging"
                  " non-ASCII characters"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
@@ -628,16 +649,16 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
         if (emb) {
             report(
                 DiagnosticsEngine::Warning,
-                ("call of %0 with string constant argument containging embedded"
-                 " NULs"),
+                ("call of '%0' with string constant argument containging"
+                 " embedded NULs"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
         }
         if (n == 0) {
             report(
                 DiagnosticsEngine::Warning,
-                ("rewrite call of %0 with empty string constant argument as"
-                 " call of rtl::OUString::clear"),
+                ("rewrite call of '%0' with empty string constant argument as"
+                 " call of 'rtl::OUString::clear'"),
                 expr->getExprLoc())
                 << fdecl->getQualifiedNameAsString() << expr->getSourceRange();
             return true;
@@ -669,47 +690,8 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
     {
         switch (fdecl->getNumParams()) {
         case 1:
-            {
-                // char const * const s = "foo"; b.append(s) ->
-                // char const s[] = "foo"; b.append(s):
-                unsigned n;
-                bool nonArray;
-                bool non;
-                bool emb;
-                bool trm;
-                if (!isStringConstant(
-                        expr->getArg(0)->IgnoreParenImpCasts(), &n, &nonArray,
-                        &non, &emb, &trm))
-                {
-                    return true;
-                }
-                if (non || emb) {
-                    return true;
-                }
-                if (!trm) {
-                    report(
-                        DiagnosticsEngine::Warning,
-                        ("call of %0 with string constant argument lacking a"
-                         " terminating NUL"),
-                        getMemberLocation(expr))
-                        << fdecl->getQualifiedNameAsString()
-                        << expr->getSourceRange();
-                    return true;
-                }
-                std::string repl;
-                checkEmpty(expr, fdecl, TreatEmpty::Error, n, &repl);
-                if (nonArray) {
-                    report(
-                        DiagnosticsEngine::Warning,
-                        ("in call of %0 with non-array string constant"
-                         " argument, change that argument into an array"),
-                        getMemberLocation(expr))
-                        << fdecl->getQualifiedNameAsString()
-                        << expr->getSourceRange();
-                    return true;
-                }
-                return true;
-            }
+            handleFunArgOstring(expr, 0, fdecl);
+            break;
         case 2:
             {
                 // b.append("foo", 3) -> b.append("foo"):
@@ -725,11 +707,32 @@ bool StringConstant::VisitCallExpr(CallExpr const * expr) {
                 handleCharLen(
                     expr, 0, 1, fdecl, "rtl::OStringBuffer::append",
                     TreatEmpty::Error);
-                return true;
             }
+            break;
         default:
-            return true;
+            break;
         }
+        return true;
+    }
+    if (dc.Function("insert").Class("OStringBuffer").Namespace("rtl")
+        .GlobalNamespace())
+    {
+        switch (fdecl->getNumParams()) {
+        case 2:
+            handleFunArgOstring(expr, 1, fdecl);
+            break;
+        case 3:
+            {
+                // b.insert(i, "foo", 3) -> b.insert(i, "foo"):
+                handleCharLen(
+                    expr, 1, 2, fdecl, "rtl::OStringBuffer::insert",
+                    TreatEmpty::Error);
+                break;
+            }
+        default:
+            break;
+        }
+        return true;
     }
     return true;
 }
@@ -903,9 +906,9 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                             {
                                 report(
                                     DiagnosticsEngine::Warning,
-                                    ("rewrite call of %0 with construction of"
+                                    ("rewrite call of '%0' with construction of"
                                      " %1 with empty string constant argument"
-                                     " as call of rtl::OUString::isEmpty"),
+                                     " as call of 'rtl::OUString::isEmpty'"),
                                     getMemberLocation(call))
                                     << fdecl->getQualifiedNameAsString()
                                     << classdecl << call->getSourceRange();
@@ -916,9 +919,9 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                             {
                                 report(
                                     DiagnosticsEngine::Warning,
-                                    ("rewrite call of %0 with construction of"
+                                    ("rewrite call of '%0' with construction of"
                                      " %1 with empty string constant argument"
-                                     " as call of !rtl::OUString::isEmpty"),
+                                     " as call of '!rtl::OUString::isEmpty'"),
                                     getMemberLocation(call))
                                     << fdecl->getQualifiedNameAsString()
                                     << classdecl << call->getSourceRange();
@@ -931,8 +934,9 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                             {
                                 report(
                                     DiagnosticsEngine::Warning,
-                                    ("call of %0 with suspicous construction of"
-                                     " %1 with empty string constant argument"),
+                                    ("call of '%0' with suspicous construction"
+                                     " of %1 with empty string constant"
+                                     " argument"),
                                     getMemberLocation(call))
                                     << fdecl->getQualifiedNameAsString()
                                     << classdecl << call->getSourceRange();
@@ -943,9 +947,9 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                             {
                                 report(
                                     DiagnosticsEngine::Warning,
-                                    ("rewrite call of %0 with construction of"
+                                    ("rewrite call of '%0' with construction of"
                                      " %1 with empty string constant argument"
-                                     " as call of rtl::OUString::clear"),
+                                     " as call of 'rtl::OUString::clear'"),
                                     getMemberLocation(call))
                                     << fdecl->getQualifiedNameAsString()
                                     << classdecl << call->getSourceRange();
@@ -958,13 +962,12 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                             {
                                 report(
                                     DiagnosticsEngine::Warning,
-                                    (("rewrite call of %0 with construction of"
-                                      " %1 with ")
-                                     + describeChangeKind(kind)
-                                     + " as operator =="),
+                                    ("rewrite call of '%0' with construction of"
+                                     " %1 with %2 as 'operator =='"),
                                     getMemberLocation(call))
                                     << fdecl->getQualifiedNameAsString()
-                                    << classdecl << call->getSourceRange();
+                                    << classdecl << describeChangeKind(kind)
+                                    << call->getSourceRange();
                                 return true;
                             }
                             if ((dc.Operator(OO_Plus).Namespace("rtl")
@@ -1013,22 +1016,20 @@ bool StringConstant::VisitCXXConstructExpr(CXXConstructExpr const * expr) {
                                 if (kind == ChangeKind::SingleChar) {
                                     report(
                                         DiagnosticsEngine::Warning,
-                                        ("rewrite construction of %0 with "
-                                         + describeChangeKind(kind)
-                                         + (" in call of %1 as construction of"
-                                            " OUStringLiteral1")),
+                                        ("rewrite construction of %0 with %1 in"
+                                         " call of '%2' as construction of"
+                                         " 'OUStringLiteral1'"),
                                         getMemberLocation(expr))
-                                        << classdecl
+                                        << classdecl << describeChangeKind(kind)
                                         << fdecl->getQualifiedNameAsString()
                                         << expr->getSourceRange();
                                 } else {
                                     report(
                                         DiagnosticsEngine::Warning,
-                                        ("elide construction of %0 with "
-                                         + describeChangeKind(kind)
-                                         + " in call of %1"),
+                                        ("elide construction of %0 with %1 in"
+                                         " call of '%2'"),
                                         getMemberLocation(expr))
-                                        << classdecl
+                                        << classdecl << describeChangeKind(kind)
                                         << fdecl->getQualifiedNameAsString()
                                         << expr->getSourceRange();
                                 }
@@ -1220,8 +1221,8 @@ bool StringConstant::isZero(Expr const * expr) {
 
 void StringConstant::reportChange(
     Expr const * expr, ChangeKind kind, std::string const & original,
-    std::string const & replacement, PassThrough pass, char const * rewriteFrom,
-    char const * rewriteTo)
+    std::string const & replacement, PassThrough pass, bool nonArray,
+    char const * rewriteFrom, char const * rewriteTo)
 {
     assert((rewriteFrom == nullptr) == (rewriteTo == nullptr));
     if (pass != PassThrough::No && !calls_.empty()) {
@@ -1259,11 +1260,11 @@ void StringConstant::reportChange(
                         {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("rewrite call of %0 with call of " + original
-                                 + (" with empty string constant argument as"
-                                    " call of rtl::OUString::isEmpty")),
+                                ("rewrite call of '%0' with call of %1 with"
+                                 " empty string constant argument as call of"
+                                 " 'rtl::OUString::isEmpty'"),
                                 getMemberLocation(call))
-                                << fdecl->getQualifiedNameAsString()
+                                << fdecl->getQualifiedNameAsString() << original
                                 << call->getSourceRange();
                             return;
                         }
@@ -1272,11 +1273,11 @@ void StringConstant::reportChange(
                         {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("rewrite call of %0 with call of " + original
-                                 + (" with empty string constant argument as"
-                                    " call of !rtl::OUString::isEmpty")),
+                                ("rewrite call of '%0' with call of %1 with"
+                                 " empty string constant argument as call of"
+                                 " '!rtl::OUString::isEmpty'"),
                                 getMemberLocation(call))
-                                << fdecl->getQualifiedNameAsString()
+                                << fdecl->getQualifiedNameAsString() << original
                                 << call->getSourceRange();
                             return;
                         }
@@ -1287,10 +1288,10 @@ void StringConstant::reportChange(
                         {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("call of %0 with suspicous call of " + original
-                                 + " with empty string constant argument"),
+                                ("call of '%0' with suspicous call of %1 with"
+                                 " empty string constant argument"),
                                 getMemberLocation(call))
-                                << fdecl->getQualifiedNameAsString()
+                                << fdecl->getQualifiedNameAsString() << original
                                 << call->getSourceRange();
                             return;
                         }
@@ -1299,11 +1300,11 @@ void StringConstant::reportChange(
                         {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("rewrite call of %0 with call of " + original
-                                 + (" with empty string constant argument as"
-                                    " call of rtl::OUString::call")),
+                                ("rewrite call of '%0' with call of %1 with"
+                                 " empty string constant argument as call of"
+                                 " rtl::OUString::call"),
                                 getMemberLocation(call))
-                                << fdecl->getQualifiedNameAsString()
+                                << fdecl->getQualifiedNameAsString() << original
                                 << call->getSourceRange();
                             return;
                         }
@@ -1326,20 +1327,19 @@ void StringConstant::reportChange(
                         {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("elide call of " + original + " with "
-                                 + describeChangeKind(kind) + " in call of %0"),
+                                "elide call of %0 with %1 in call of '%2'",
                                 getMemberLocation(expr))
+                                << original << describeChangeKind(kind)
                                 << fdecl->getQualifiedNameAsString()
                                 << expr->getSourceRange();
                             return;
                         }
                         report(
                             DiagnosticsEngine::Warning,
-                            ("rewrite call of " + original + " with "
-                             + describeChangeKind(kind)
-                             + (" in call of %0 as (implicit) construction of"
-                                " rtl::OUString")),
+                            ("rewrite call of %0 with %1 in call of '%2' as"
+                             " (implicit) construction of 'OUString'"),
                             getMemberLocation(expr))
+                            << original << describeChangeKind(kind)
                             << fdecl->getQualifiedNameAsString()
                             << expr->getSourceRange();
                         return;
@@ -1356,23 +1356,21 @@ void StringConstant::reportChange(
                         if (pass == PassThrough::EmptyConstantString) {
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("rewrite construction of %0 with call of "
-                                 + original
-                                 + (" with empty string constant argument as"
-                                    " default construction of %0")),
+                                ("rewrite construction of %0 with call of %1"
+                                 " with empty string constant argument as"
+                                 " default construction of %0"),
                                 getMemberLocation(call))
-                                << classdecl->getQualifiedNameAsString()
+                                << classdecl << original
                                 << call->getSourceRange();
                         } else {
                             assert(pass == PassThrough::NonEmptyConstantString);
                             report(
                                 DiagnosticsEngine::Warning,
-                                ("elide call of " + original + " with "
-                                 + describeChangeKind(kind)
-                                 + " in construction of %0"),
+                                ("elide call of %0 with %1 in construction of"
+                                 " %2"),
                                 getMemberLocation(expr))
-                                << classdecl->getQualifiedNameAsString()
-                                << expr->getSourceRange();
+                                << original << describeChangeKind(kind)
+                                << classdecl << expr->getSourceRange();
                         }
                         return;
                     }
@@ -1382,7 +1380,7 @@ void StringConstant::reportChange(
             }
         }
     }
-    if (rewriter != nullptr && rewriteFrom != nullptr) {
+    if (rewriter != nullptr && !nonArray && rewriteFrom != nullptr) {
         SourceLocation loc = getMemberLocation(expr);
         while (compiler.getSourceManager().isMacroArgExpansion(loc)) {
             loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc);
@@ -1401,10 +1399,10 @@ void StringConstant::reportChange(
     }
     report(
         DiagnosticsEngine::Warning,
-        ("rewrite call of " + original + " with " + describeChangeKind(kind)
-         + " as call of " + replacement),
+        "rewrite call of '%0' with %1 as call of '%2'%3",
         getMemberLocation(expr))
-        << expr->getSourceRange();
+        << original << describeChangeKind(kind) << replacement
+        << adviseNonArray(nonArray) << expr->getSourceRange();
 }
 
 void StringConstant::checkEmpty(
@@ -1423,7 +1421,7 @@ void StringConstant::checkEmpty(
         case TreatEmpty::Error:
             report(
                 DiagnosticsEngine::Warning,
-                "call of %0 with suspicous empty string constant argument",
+                "call of '%0' with suspicous empty string constant argument",
                 getMemberLocation(expr))
                 << callee->getQualifiedNameAsString() << expr->getSourceRange();
             break;
@@ -1450,7 +1448,7 @@ void StringConstant::handleChar(
     if (non) {
         report(
             DiagnosticsEngine::Warning,
-            ("call of %0 with string constant argument containging non-ASCII"
+            ("call of '%0' with string constant argument containging non-ASCII"
              " characters"),
             getMemberLocation(expr))
             << callee->getQualifiedNameAsString() << expr->getSourceRange();
@@ -1459,7 +1457,7 @@ void StringConstant::handleChar(
     if (emb) {
         report(
             DiagnosticsEngine::Warning,
-            ("call of %0 with string constant argument containging embedded"
+            ("call of '%0' with string constant argument containging embedded"
              " NULs"),
             getMemberLocation(expr))
             << callee->getQualifiedNameAsString() << expr->getSourceRange();
@@ -1468,7 +1466,7 @@ void StringConstant::handleChar(
     if (!trm) {
         report(
             DiagnosticsEngine::Warning,
-            ("call of %0 with string constant argument lacking a terminating"
+            ("call of '%0' with string constant argument lacking a terminating"
              " NUL"),
             getMemberLocation(expr))
             << callee->getQualifiedNameAsString() << expr->getSourceRange();
@@ -1483,7 +1481,7 @@ void StringConstant::handleChar(
             ? PassThrough::EmptyConstantString
             : PassThrough::NonEmptyConstantString)
          : PassThrough::No),
-        rewriteFrom, rewriteTo);
+        nonArray, rewriteFrom, rewriteTo);
 }
 
 void StringConstant::handleCharLen(
@@ -1543,7 +1541,7 @@ void StringConstant::handleCharLen(
     if (non) {
         report(
             DiagnosticsEngine::Warning,
-            ("call of %0 with string constant argument containging non-ASCII"
+            ("call of '%0' with string constant argument containging non-ASCII"
              " characters"),
             getMemberLocation(expr))
             << callee->getQualifiedNameAsString() << expr->getSourceRange();
@@ -1555,7 +1553,7 @@ void StringConstant::handleCharLen(
     checkEmpty(expr, callee, treatEmpty, n, &repl);
     reportChange(
         expr, ChangeKind::CharLen, callee->getQualifiedNameAsString(), repl,
-        PassThrough::No, nullptr, nullptr);
+        PassThrough::No, nonArray, nullptr, nullptr);
 }
 
 void StringConstant::handleOUStringCtor(
@@ -1588,8 +1586,8 @@ void StringConstant::handleOUStringCtor(
     if (e3->getNumArgs() == 0) {
         report(
             DiagnosticsEngine::Warning,
-            ("in call of %0, replace default-constructed OUString with an empty"
-             " string literal"),
+            ("in call of '%0', replace default-constructed 'OUString' with an"
+             " empty string literal"),
             e3->getExprLoc())
             << callee->getQualifiedNameAsString() << expr->getSourceRange();
         return;
@@ -1605,8 +1603,8 @@ void StringConstant::handleOUStringCtor(
         if (!explicitFunctionalCastNotation) {
             report(
                 DiagnosticsEngine::Warning,
-                ("in call of %0, replace OUString constructed from a"
-                 " sal_Unicode with an OUStringLiteral1"),
+                ("in call of '%0', replace 'OUString' constructed from a"
+                 " 'sal_Unicode' with an 'OUStringLiteral1'"),
                 e3->getExprLoc())
                 << callee->getQualifiedNameAsString() << expr->getSourceRange();
         }
@@ -1695,12 +1693,114 @@ void StringConstant::handleOUStringCtor(
     }
     report(
         DiagnosticsEngine::Warning,
-        ("in call of %0, replace OUString constructed from a string literal"
+        ("in call of '%0', replace 'OUString' constructed from a string literal"
          " directly with the string literal"),
         e3->getExprLoc())
         << callee->getQualifiedNameAsString() << expr->getSourceRange();
 }
 
+void StringConstant::handleFunArgOstring(
+    CallExpr const * expr, unsigned arg, FunctionDecl const * callee)
+{
+    auto argExpr = expr->getArg(arg)->IgnoreParenImpCasts();
+    unsigned n;
+    bool nonArray;
+    bool non;
+    bool emb;
+    bool trm;
+    if (isStringConstant(argExpr, &n, &nonArray, &non, &emb, &trm)) {
+        if (non || emb) {
+            return;
+        }
+        if (!trm) {
+            report(
+                DiagnosticsEngine::Warning,
+                ("call of '%0' with string constant argument lacking a"
+                 " terminating NUL"),
+                getMemberLocation(expr))
+                << callee->getQualifiedNameAsString() << expr->getSourceRange();
+            return;
+        }
+        std::string repl;
+        checkEmpty(expr, callee, TreatEmpty::Error, n, &repl);
+        if (nonArray) {
+            report(
+                DiagnosticsEngine::Warning,
+                ("in call of '%0' with non-array string constant argument,"
+                 " turn the non-array string constant into an array"),
+                getMemberLocation(expr))
+                << callee->getQualifiedNameAsString() << expr->getSourceRange();
+        }
+    } else if (auto cexpr = lookForCXXConstructExpr(argExpr)) {
+        auto classdecl = cexpr->getConstructor()->getParent();
+        if (loplugin::DeclCheck(classdecl).Class("OString").Namespace("rtl")
+            .GlobalNamespace())
+        {
+            switch (cexpr->getConstructor()->getNumParams()) {
+            case 0:
+                report(
+                    DiagnosticsEngine::Warning,
+                    ("in call of '%0', replace empty %1 constructor with empty"
+                     " string literal"),
+                    cexpr->getLocation())
+                    << callee->getQualifiedNameAsString() << classdecl
+                    << expr->getSourceRange();
+                break;
+            case 2:
+                if (isStringConstant(
+                        cexpr->getArg(0)->IgnoreParenImpCasts(), &n, &nonArray,
+                        &non, &emb, &trm))
+                {
+                    APSInt res;
+                    if (cexpr->getArg(1)->EvaluateAsInt(
+                            res, compiler.getASTContext()))
+                    {
+                        if (res == n && !emb && trm) {
+                            report(
+                                DiagnosticsEngine::Warning,
+                                ("in call of '%0', elide explicit %1"
+                                 " constructor%2"),
+                                cexpr->getLocation())
+                                << callee->getQualifiedNameAsString()
+                                << classdecl << adviseNonArray(nonArray)
+                                << expr->getSourceRange();
+                        }
+                    } else {
+                        if (emb) {
+                            report(
+                                DiagnosticsEngine::Warning,
+                                ("call of %0 constructor with string constant"
+                                 " argument containing embedded NULs"),
+                                cexpr->getLocation())
+                                << classdecl << cexpr->getSourceRange();
+                            return;
+                        }
+                        if (!trm) {
+                            report(
+                                DiagnosticsEngine::Warning,
+                                ("call of %0 constructor with string constant"
+                                 " argument lacking a terminating NUL"),
+                                cexpr->getLocation())
+                                << classdecl << cexpr->getSourceRange();
+                            return;
+                        }
+                        report(
+                            DiagnosticsEngine::Warning,
+                            "in call of '%0', elide explicit %1 constructor%2",
+                            cexpr->getLocation())
+                            << callee->getQualifiedNameAsString() << classdecl
+                            << adviseNonArray(nonArray)
+                            << expr->getSourceRange();
+                    }
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
 loplugin::Plugin::Registration< StringConstant > X("stringconstant", true);
 
 }
diff --git a/compilerplugins/clang/test/stringconstant.cxx b/compilerplugins/clang/test/stringconstant.cxx
new file mode 100644
index 0000000..259b506
--- /dev/null
+++ b/compilerplugins/clang/test/stringconstant.cxx
@@ -0,0 +1,52 @@
+/* -*- 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/.
+ */
+
+#include "sal/config.h"
+
+#include <cstring>
+
+#include "com/sun/star/uno/Reference.hxx"
+#include "rtl/strbuf.hxx"
+
+int main() {
+    char const s1[] = "foo";
+    char const * const s2 = "foo";
+
+    OStringBuffer sb;
+
+    sb.append(OString()); // expected-error {{in call of 'rtl::OStringBuffer::append', replace empty 'OString' constructor with empty string literal [loplugin:stringconstant]}}
+    sb.append(OString("foo")); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.append(OString(s1)); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.append(OString(s2)); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}}
+    sb.append(OString("foo", std::strlen("foo"))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.append(OString(s1, std::strlen(s1))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.append(OString(s2, std::strlen(s2))); // expected-error {{in call of 'rtl::OStringBuffer::append', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}}
+    sb.append("foo");
+    sb.append(s1);
+    sb.append(s2); // expected-error {{in call of 'rtl::OStringBuffer::append' with non-array string constant argument, turn the non-array string constant into an array [loplugin:stringconstant]}}
+    sb.append("foo", std::strlen("foo")); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append' [loplugin:stringconstant]}}
+    sb.append(s1, std::strlen(s1)); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append' [loplugin:stringconstant]}}
+    sb.append(s2, std::strlen(s2)); // expected-error {{rewrite call of 'rtl::OStringBuffer::append' with string constant and matching length arguments as call of 'rtl::OStringBuffer::append', and turn the non-array string constant into an array [loplugin:stringconstant]}}
+
+    sb.insert(0, OString()); // expected-error {{in call of 'rtl::OStringBuffer::insert', replace empty 'OString' constructor with empty string literal [loplugin:stringconstant]}}
+    sb.insert(0, OString("foo")); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.insert(0, OString(s1)); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.insert(0, OString(s2)); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}}
+    sb.insert(0, OString("foo", std::strlen("foo"))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.insert(0, OString(s1, std::strlen(s1))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor [loplugin:stringconstant]}}
+    sb.insert(0, OString(s2, std::strlen(s2))); // expected-error {{in call of 'rtl::OStringBuffer::insert', elide explicit 'OString' constructor, and turn the non-array string constant into an array [loplugin:stringconstant]}}
+    sb.insert(0, "foo");
+    sb.insert(0, s1);
+    sb.insert(0, s2); // expected-error {{in call of 'rtl::OStringBuffer::insert' with non-array string constant argument, turn the non-array string constant into an array [loplugin:stringconstant]}}
+    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, 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, 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]}}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index 59e87b7..469ea71 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -3482,7 +3482,7 @@ void ScInterpreter::ScBahtText()
                 lclAppendBlock( aBlock, nBlock );
             // add leading "million", if there will come more blocks
             if( fBaht > 0.0 )
-                aBlock.insert( 0, OString(UTF8_TH_1E6 ) );
+                aBlock.insert( 0, UTF8_TH_1E6 );
 
             aText.insert(0, aBlock.makeStringAndClear());
         }
@@ -3502,7 +3502,7 @@ void ScInterpreter::ScBahtText()
 
         // add the minus sign
         if( bMinus )
-            aText.insert( 0, OString( UTF8_TH_MINUS ) );
+            aText.insert( 0, UTF8_TH_MINUS );
 
         PushString( OStringToOUString(aText.makeStringAndClear(), RTL_TEXTENCODING_UTF8) );
     }
diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk
index f01f8e3..7840b1e 100644
--- a/solenv/CompilerTest_compilerplugins_clang.mk
+++ b/solenv/CompilerTest_compilerplugins_clang.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \
     compilerplugins/clang/test/oslendian-2 \
     compilerplugins/clang/test/oslendian-3 \
     compilerplugins/clang/test/salbool \
+    compilerplugins/clang/test/stringconstant \
     compilerplugins/clang/test/unnecessaryoverride-dtor \
     compilerplugins/clang/test/vclwidgets \
 ))


More information about the Libreoffice-commits mailing list