summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2023-03-14 08:50:39 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2023-04-06 13:51:06 +0200
commitbd17c9c9495f555ea27f7debfabeb2407ac2b9b6 (patch)
tree354bb11636e1b14cc29d061ddaa8be95ba09bb4c /compilerplugins
parentd5673ec3f8b17d57857c75916186c681d66cf243 (diff)
loplugin:stringadd also check O[U]StringBuffers
For similar code sequences that can be improved. Also move containsComment from collapseif plugin code to plugin.cxx so we can use it from stringadd. Change-Id: Ie07d9aedf2c31cb0b2080e1b8584294d7046a8e1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149217 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/collapseif.cxx24
-rw-r--r--compilerplugins/clang/plugin.cxx26
-rw-r--r--compilerplugins/clang/plugin.hxx2
-rw-r--r--compilerplugins/clang/stringadd.cxx93
-rw-r--r--compilerplugins/clang/test/stringadd.cxx104
5 files changed, 179 insertions, 70 deletions
diff --git a/compilerplugins/clang/collapseif.cxx b/compilerplugins/clang/collapseif.cxx
index c50bf3352440..aecf10f5e0e9 100644
--- a/compilerplugins/clang/collapseif.cxx
+++ b/compilerplugins/clang/collapseif.cxx
@@ -38,7 +38,6 @@ public:
private:
int getNoCharsInSourceCodeOfExpr(IfStmt const*);
- bool containsComment(Stmt const* stmt);
};
bool CollapseIf::VisitIfStmt(IfStmt const* ifStmt)
@@ -73,7 +72,7 @@ bool CollapseIf::VisitIfStmt(IfStmt const* ifStmt)
// Sometimes there is a comment between the first and second if, so
// merging them would make the comment more awkward to write.
- if (containsComment(ifStmt))
+ if (containsComment(ifStmt->getSourceRange()))
return true;
report(DiagnosticsEngine::Warning, "nested if should be collapsed into one statement %0 %1",
@@ -101,27 +100,6 @@ int CollapseIf::getNoCharsInSourceCodeOfExpr(IfStmt const* ifStmt)
return count;
}
-bool CollapseIf::containsComment(Stmt const* stmt)
-{
- SourceManager& SM = compiler.getSourceManager();
- auto range = stmt->getSourceRange();
- SourceLocation startLoc = range.getBegin();
- SourceLocation endLoc = range.getEnd();
- char const* p1 = SM.getCharacterData(startLoc);
- char const* p2 = SM.getCharacterData(endLoc);
- p2 += Lexer::MeasureTokenLength(endLoc, SM, compiler.getLangOpts());
-
- // check for comments
- constexpr char const comment1[] = "/*";
- constexpr char const comment2[] = "//";
- if (std::search(p1, p2, comment1, comment1 + strlen(comment1)) != p2)
- return true;
- if (std::search(p1, p2, comment2, comment2 + strlen(comment2)) != p2)
- return true;
-
- return false;
-}
-
/** Off by default because some places are a judgement call if it should be collapsed or not. */
loplugin::Plugin::Registration<CollapseIf> X("collapseif", false);
}
diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index 727eda589548..94c5809ab730 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -543,6 +543,32 @@ bool Plugin::containsPreprocessingConditionalInclusion(SourceRange range)
return false;
}
+bool Plugin::containsComment(SourceRange range)
+{
+ SourceManager& SM = compiler.getSourceManager();
+ SourceLocation startLoc = range.getBegin();
+ SourceLocation endLoc = range.getEnd();
+ char const* p1 = SM.getCharacterData(startLoc);
+ char const* p2 = SM.getCharacterData(endLoc);
+ p2 += Lexer::MeasureTokenLength(endLoc, SM, compiler.getLangOpts());
+
+ // when doing 'make solenv.check' we don't want the special comments in the
+ // unit test files to trigger this check
+ constexpr char const comment0[] = "// expected-error";
+ if (std::search(p1, p2, comment0, comment0 + strlen(comment0)) != p2)
+ return false;
+
+ // check for comments
+ constexpr char const comment1[] = "/*";
+ constexpr char const comment2[] = "//";
+ if (std::search(p1, p2, comment1, comment1 + strlen(comment1)) != p2)
+ return true;
+ if (std::search(p1, p2, comment2, comment2 + strlen(comment2)) != p2)
+ return true;
+
+ return false;
+}
+
Plugin::IdenticalDefaultArgumentsResult Plugin::checkIdenticalDefaultArguments(
Expr const * argument1, Expr const * argument2)
{
diff --git a/compilerplugins/clang/plugin.hxx b/compilerplugins/clang/plugin.hxx
index cd272dc520f8..7980e79f7b45 100644
--- a/compilerplugins/clang/plugin.hxx
+++ b/compilerplugins/clang/plugin.hxx
@@ -102,6 +102,8 @@ protected:
bool containsPreprocessingConditionalInclusion(SourceRange range);
+ bool containsComment(SourceRange range);
+
enum class IdenticalDefaultArgumentsResult { No, Yes, Maybe };
IdenticalDefaultArgumentsResult checkIdenticalDefaultArguments(
Expr const * argument1, Expr const * argument2);
diff --git a/compilerplugins/clang/stringadd.cxx b/compilerplugins/clang/stringadd.cxx
index 1bf414e6d261..bf00ef2dc1d9 100644
--- a/compilerplugins/clang/stringadd.cxx
+++ b/compilerplugins/clang/stringadd.cxx
@@ -21,7 +21,7 @@
#include "clang/AST/StmtVisitor.h"
/**
- Look for repeated addition to OUString/OString.
+ Look for repeated addition to OUString/OString/OUStringBuffer/OStringBuffer.
Eg.
OUString x = "xxx";
@@ -61,6 +61,9 @@ public:
// TODO the += depends on the result of the preceding assign, so can't merge
if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
return false;
+ // TODO this file has a boatload of buffer appends' and I don't feel like fixing them all now
+ if (fn == SRCDIR "/vcl/source/gdi/pdfwriter_impl.cxx")
+ return false;
return true;
}
@@ -143,12 +146,26 @@ StringAdd::VarDeclAndSummands StringAdd::findAssignOrAdd(Stmt const* stmt)
{
auto tc = loplugin::TypeCheck(varDeclLHS->getType());
if (!tc.Class("OUString").Namespace("rtl").GlobalNamespace()
- && !tc.Class("OString").Namespace("rtl").GlobalNamespace())
+ && !tc.Class("OString").Namespace("rtl").GlobalNamespace()
+ && !tc.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()
+ && !tc.Class("OStringBuffer").Namespace("rtl").GlobalNamespace())
return {};
if (varDeclLHS->getStorageDuration() == SD_Static)
return {};
if (!varDeclLHS->hasInit())
return {};
+ if (tc.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()
+ || tc.Class("OStringBuffer").Namespace("rtl").GlobalNamespace())
+ {
+ // ignore the constructor that gives the buffer a default size
+ if (auto cxxConstructor = dyn_cast<CXXConstructExpr>(varDeclLHS->getInit()))
+ if (auto constructorDecl = cxxConstructor->getConstructor())
+ if (constructorDecl->getNumParams() == 1
+ && loplugin::TypeCheck(constructorDecl->getParamDecl(0)->getType())
+ .Typedef("sal_Int32")
+ .GlobalNamespace())
+ return {};
+ }
return { varDeclLHS, (isCompileTimeConstant(varDeclLHS->getInit())
? Summands::OnlyCompileTimeConstants
: (isSideEffectFree(varDeclLHS->getInit())
@@ -171,6 +188,24 @@ StringAdd::VarDeclAndSummands StringAdd::findAssignOrAdd(Stmt const* stmt)
: (isSideEffectFree(rhs) ? Summands::OnlySideEffectFree
: Summands::SideEffect)) };
}
+ if (auto memberCall = dyn_cast<CXXMemberCallExpr>(stmt))
+ if (auto cxxMethodDecl = dyn_cast_or_null<CXXMethodDecl>(memberCall->getDirectCallee()))
+ if (cxxMethodDecl->getIdentifier() && cxxMethodDecl->getName() == "append")
+ if (auto declRefExprLHS
+ = dyn_cast<DeclRefExpr>(ignore(memberCall->getImplicitObjectArgument())))
+ if (auto varDeclLHS = dyn_cast<VarDecl>(declRefExprLHS->getDecl()))
+ {
+ auto tc = loplugin::TypeCheck(varDeclLHS->getType());
+ if (!tc.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()
+ && !tc.Class("OStringBuffer").Namespace("rtl").GlobalNamespace())
+ return {};
+ auto rhs = memberCall->getArg(0);
+ return { varDeclLHS,
+ (isCompileTimeConstant(rhs)
+ ? Summands::OnlyCompileTimeConstants
+ : (isSideEffectFree(rhs) ? Summands::OnlySideEffectFree
+ : Summands::SideEffect)) };
+ }
return {};
}
@@ -182,20 +217,41 @@ bool StringAdd::checkForCompoundAssign(Stmt const* stmt1, Stmt const* stmt2,
stmt2 = exprCleanup->getSubExpr();
if (auto switchCase = dyn_cast<SwitchCase>(stmt2))
stmt2 = switchCase->getSubStmt();
- auto operatorCall = dyn_cast<CXXOperatorCallExpr>(stmt2);
- if (!operatorCall)
- return false;
- if (operatorCall->getOperator() != OO_PlusEqual)
- return false;
- auto declRefExprLHS = dyn_cast<DeclRefExpr>(ignore(operatorCall->getArg(0)));
+
+ const DeclRefExpr* declRefExprLHS;
+ const Expr* rhs;
+ auto tc = loplugin::TypeCheck(varDecl.varDecl->getType());
+ if (tc.Class("OString") || tc.Class("OUString"))
+ {
+ auto operatorCall = dyn_cast<CXXOperatorCallExpr>(stmt2);
+ if (!operatorCall)
+ return false;
+ if (operatorCall->getOperator() != OO_PlusEqual)
+ return false;
+ declRefExprLHS = dyn_cast<DeclRefExpr>(ignore(operatorCall->getArg(0)));
+ rhs = operatorCall->getArg(1);
+ }
+ else
+ {
+ // OUStringBuffer, OStringBuffer
+ auto memberCall = dyn_cast<CXXMemberCallExpr>(stmt2);
+ if (!memberCall)
+ return false;
+ auto cxxMethodDecl = dyn_cast_or_null<CXXMethodDecl>(memberCall->getDirectCallee());
+ if (!cxxMethodDecl)
+ return false;
+ if (!cxxMethodDecl->getIdentifier() || cxxMethodDecl->getName() != "append")
+ return false;
+ declRefExprLHS = dyn_cast<DeclRefExpr>(ignore(memberCall->getImplicitObjectArgument()));
+ rhs = memberCall->getArg(0);
+ }
if (!declRefExprLHS)
return false;
if (declRefExprLHS->getDecl() != varDecl.varDecl)
return false;
// if either side is a compile-time-constant, then we don't care about
// side-effects
- auto rhs = operatorCall->getArg(1);
- auto const ctcRhs = isCompileTimeConstant(rhs);
+ bool const ctcRhs = isCompileTimeConstant(rhs);
if (!ctcRhs)
{
auto const sefRhs = isSideEffectFree(rhs);
@@ -207,16 +263,23 @@ bool StringAdd::checkForCompoundAssign(Stmt const* stmt1, Stmt const* stmt2,
return true;
}
}
+ SourceRange mergeRange(stmt1->getSourceRange().getBegin(), stmt2->getSourceRange().getEnd());
// if we cross a #ifdef boundary
- if (containsPreprocessingConditionalInclusion(
- SourceRange(stmt1->getSourceRange().getBegin(), stmt2->getSourceRange().getEnd())))
+ if (containsPreprocessingConditionalInclusion(mergeRange))
{
varDecl.summands
= ctcRhs ? Summands::OnlyCompileTimeConstants
: isSideEffectFree(rhs) ? Summands::OnlySideEffectFree : Summands::SideEffect;
return true;
}
- report(DiagnosticsEngine::Warning, "simplify by merging with the preceding assignment",
+ // If there is a comment between two calls, rather don't suggest merge
+ // IMO, code clarity trumps efficiency (as far as plugin warnings go, anyway).
+ if (containsComment(mergeRange))
+ return true;
+ // I don't think the OUStringAppend functionality can handle this efficiently
+ if (isa<ConditionalOperator>(ignore(rhs)))
+ return false;
+ report(DiagnosticsEngine::Warning, "simplify by merging with the preceding assign/append",
stmt2->getBeginLoc())
<< stmt2->getSourceRange();
return true;
@@ -419,7 +482,9 @@ bool StringAdd::isSideEffectFree(Expr const* expr)
if (auto constructExpr = dyn_cast<CXXConstructExpr>(expr))
{
auto dc = loplugin::DeclCheck(constructExpr->getConstructor());
- if (dc.MemberFunction().Class("OUString") || dc.MemberFunction().Class("OString"))
+ if (dc.MemberFunction().Class("OUString") || dc.MemberFunction().Class("OString")
+ || dc.MemberFunction().Class("OUStringBuffer")
+ || dc.MemberFunction().Class("OStringBuffer"))
if (constructExpr->getNumArgs() == 0 || isSideEffectFree(constructExpr->getArg(0)))
return true;
// Expr::HasSideEffects does not like stuff that passes through OUStringLiteral
diff --git a/compilerplugins/clang/test/stringadd.cxx b/compilerplugins/clang/test/stringadd.cxx
index 6381d47f8baf..3ac2bb60ebe8 100644
--- a/compilerplugins/clang/test/stringadd.cxx
+++ b/compilerplugins/clang/test/stringadd.cxx
@@ -27,48 +27,48 @@ static const char XXX2[] = "xxx";
void f1(OUString s1, int i, OString o)
{
OUString s2 = s1;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += s1;
s2 = s1 + "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += s1;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += OUString::number(i);
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += XXX1;
// expected-error-re@+2 {{rather use O[U]String::Concat than constructing '{{(rtl::)?}}OUStringLiteral<4>'{{( \(aka 'rtl::OUStringLiteral<4>'\))?}} from 'const char16_t{{ ?}}[4]' on LHS of + (where RHS is of type 'const char{{ ?}}[4]') [loplugin:stringadd]}}
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += OUStringLiteral(XXX1u) + XXX2;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += OStringToOUString(o, RTL_TEXTENCODING_UTF8);
}
void f2(OString s1, int i, OUString u)
{
OString s2 = s1;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += s1;
s2 = s1 + "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += s1;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += OString::number(i);
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += OUStringToOString(u, RTL_TEXTENCODING_ASCII_US);
}
void f3(OUString aStr, int nFirstContent)
{
OUString aFirstStr = aStr.copy(0, nFirstContent);
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
aFirstStr += "...";
}
OUString side_effect();
@@ -76,15 +76,15 @@ void f4(int i)
{
OUString s1;
OUString s2("xxx");
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += "xxx";
++i;
// any other kind of statement breaks the chain (at least for now)
s2 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s2 += side_effect();
s1 += "yyy";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s1 += "yyy";
}
}
@@ -94,13 +94,13 @@ namespace test2
void f(OUString s3)
{
s3 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s3 += "xxx";
}
void g(OString s3)
{
s3 += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s3 += "xxx";
}
}
@@ -114,28 +114,28 @@ struct Bar
void f(Bar b1, Bar& b2, Bar* b3)
{
OUString s3 = "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s3 += b1.m_field;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s3 += b2.m_field;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s3 += b3->m_field;
}
OUString side_effect();
void f2(OUString s)
{
OUString sRet = "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += side_effect();
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += "xxx";
sRet += side_effect();
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += "xxx";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += "xxx";
sRet += s;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += "xxx";
}
}
@@ -151,7 +151,7 @@ void f()
sRet += ";";
#endif
sRet += " ";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sRet += side_effect();
}
}
@@ -172,9 +172,9 @@ namespace test6
void f(OUString sComma, OUString maExtension, int mnDocumentIconID)
{
OUString sValue;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sValue += sComma + sComma + maExtension + sComma;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sValue += OUString::number(mnDocumentIconID) + sComma;
}
struct Foo
@@ -188,7 +188,7 @@ void g(int x, const Foo& aValidation)
{
case 1:
sCondition += "cell-content-is-in-list(";
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
sCondition += aValidation.sFormula1 + ")";
}
}
@@ -251,7 +251,7 @@ C getC();
void f1(C c)
{
OString s;
- // expected-error@+1 {{simplify by merging with the preceding assignment [loplugin:stringadd]}}
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
s += c.constStringFunction(c.constIntFunction());
s += c.constStringFunction(c.nonConstIntFunction());
s += c.nonConstStringFunction();
@@ -259,4 +259,42 @@ void f1(C c)
}
}
+namespace test11
+{
+void f1()
+{
+ OUStringBuffer aFirstStr1("aaa");
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
+ aFirstStr1.append("...");
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
+ aFirstStr1.append("...");
+}
+}
+
+namespace test12
+{
+void f1(int j)
+{
+ OUStringBuffer aFirstStr1(12);
+ // no warning expected
+ aFirstStr1.append("...");
+ // expected-error@+1 {{simplify by merging with the preceding assign/append [loplugin:stringadd]}}
+ aFirstStr1.append("...");
+ // no warning expected
+ aFirstStr1.append(((j + 1) % 15) ? " " : "\n");
+}
+}
+
+namespace test13
+{
+void f1()
+{
+ OUStringBuffer aFirstStr1(12);
+ // no warning expected
+ aFirstStr1.append("...");
+ // because we have a comment between them
+ aFirstStr1.append("...");
+}
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */