From a7d40f575463467698df76f041e558cb3bea7c85 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Thu, 12 Sep 2019 15:38:05 +0200 Subject: compiler check for rtl::OUStringConcat instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Something like auto str = "string" + OUString::number( 10 ); will not be OUString but actually rtl::OUStringConcat (which gets implicitly converted to OUString, but not with auto). Since those refer to temporaries from the expression, they should not outlive the expression. Change-Id: Ib4cde4b38befb3d49927d0cf01c52ebb2d36df89 Reviewed-on: https://gerrit.libreoffice.org/78830 Tested-by: Jenkins Reviewed-by: Luboš Luňák --- compilerplugins/clang/stringconcat.cxx | 162 --------------------- compilerplugins/clang/stringconcatauto.cxx | 112 ++++++++++++++ compilerplugins/clang/stringconcatliterals.cxx | 162 +++++++++++++++++++++ compilerplugins/clang/test/stringconcat.cxx | 65 --------- compilerplugins/clang/test/stringconcatauto.cxx | 57 ++++++++ .../clang/test/stringconcatliterals.cxx | 65 +++++++++ 6 files changed, 396 insertions(+), 227 deletions(-) delete mode 100644 compilerplugins/clang/stringconcat.cxx create mode 100644 compilerplugins/clang/stringconcatauto.cxx create mode 100644 compilerplugins/clang/stringconcatliterals.cxx delete mode 100644 compilerplugins/clang/test/stringconcat.cxx create mode 100644 compilerplugins/clang/test/stringconcatauto.cxx create mode 100644 compilerplugins/clang/test/stringconcatliterals.cxx (limited to 'compilerplugins/clang') diff --git a/compilerplugins/clang/stringconcat.cxx b/compilerplugins/clang/stringconcat.cxx deleted file mode 100644 index 8511f849d64f..000000000000 --- a/compilerplugins/clang/stringconcat.cxx +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * 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/. - */ - -#ifndef LO_CLANG_SHARED_PLUGINS - -#include "plugin.hxx" -#include "check.hxx" - -namespace { - -Expr const * stripCtor(Expr const * expr) { - auto e1 = expr; - if (auto const e = dyn_cast(e1)) { - e1 = e->getSubExpr()->IgnoreParenImpCasts(); - } - if (auto const e = dyn_cast(e1)) { - e1 = e->getSubExpr()->IgnoreParenImpCasts(); - } - auto const e2 = dyn_cast(e1); - if (e2 == nullptr) { - return expr; - } - auto qt = loplugin::DeclCheck(e2->getConstructor()); - if (qt.MemberFunction().Struct("OStringLiteral").Namespace("rtl").GlobalNamespace()) { - if (e2->getNumArgs() == 1) { - return e2->getArg(0)->IgnoreParenImpCasts(); - } - return expr; - } - if (!((qt.MemberFunction().Class("OString").Namespace("rtl") - .GlobalNamespace()) - || (qt.MemberFunction().Class("OUString").Namespace("rtl") - .GlobalNamespace()) - || qt.MemberFunction().Struct("OUStringLiteral").Namespace("rtl").GlobalNamespace())) - { - return expr; - } - if (e2->getNumArgs() != 2) { - return expr; - } - return e2->getArg(0)->IgnoreParenImpCasts(); -} - -class StringConcat: - public loplugin::FilteringPlugin -{ -public: - explicit StringConcat(loplugin::InstantiationData const & data): - FilteringPlugin(data) {} - - void run() override - { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } - - bool VisitCallExpr(CallExpr const * expr); - -private: - bool isStringLiteral(Expr const * expr); -}; - -bool StringConcat::VisitCallExpr(CallExpr const * expr) { - if (ignoreLocation(expr)) { - return true; - } - FunctionDecl const * fdecl = expr->getDirectCallee(); - if (fdecl == nullptr) { - return true; - } - OverloadedOperatorKind oo = fdecl->getOverloadedOperator(); - if ((oo != OverloadedOperatorKind::OO_Plus - && oo != OverloadedOperatorKind::OO_LessLess) - || fdecl->getNumParams() != 2 || expr->getNumArgs() != 2 - || !isStringLiteral(expr->getArg(1)->IgnoreParenImpCasts())) - { - return true; - } - SourceLocation leftLoc; - auto const leftExpr = expr->getArg(0)->IgnoreParenImpCasts(); - if (isStringLiteral(leftExpr)) { - leftLoc = compat::getBeginLoc(leftExpr); - } else { - CallExpr const * left = dyn_cast(leftExpr); - if (left == nullptr) { - return true; - } - FunctionDecl const * ldecl = left->getDirectCallee(); - if (ldecl == nullptr) { - return true; - } - OverloadedOperatorKind loo = ldecl->getOverloadedOperator(); - if ((loo != OverloadedOperatorKind::OO_Plus - && loo != OverloadedOperatorKind::OO_LessLess) - || ldecl->getNumParams() != 2 || left->getNumArgs() != 2 - || !isStringLiteral(left->getArg(1)->IgnoreParenImpCasts())) - { - return true; - } - leftLoc = compat::getBeginLoc(left->getArg(1)); - } - - // We add an extra " " in the TOOLS_WARN_EXCEPTION macro, which triggers this plugin - if (loplugin::isSamePathname( - compiler.getSourceManager().getFilename( - compiler.getSourceManager().getSpellingLoc( - compiler.getSourceManager().getImmediateMacroCallerLoc( - compiler.getSourceManager().getImmediateMacroCallerLoc( - compat::getBeginLoc(expr))))), - SRCDIR "/include/tools/diagnose_ex.h")) - return true; - - StringRef name { - getFileNameOfSpellingLoc( - compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))) }; - if (loplugin::isSamePathname( - name, SRCDIR "/sal/qa/rtl/oustringbuffer/test_oustringbuffer_assign.cxx") - || loplugin::isSamePathname( - name, SRCDIR "/sal/qa/rtl/strings/test_ostring_concat.cxx") - || loplugin::isSamePathname( - name, SRCDIR "/sal/qa/rtl/strings/test_oustring_concat.cxx")) - { - return true; - } - CXXOperatorCallExpr const * op = dyn_cast(expr); - report( - DiagnosticsEngine::Warning, - "replace '%0' between string literals with juxtaposition", - op == nullptr ? expr->getExprLoc() : op->getOperatorLoc()) - << (oo == OverloadedOperatorKind::OO_Plus ? "+" : "<<") - << SourceRange(leftLoc, compat::getEndLoc(expr->getArg(1))); - return true; -} - -bool StringConcat::isStringLiteral(Expr const * expr) { - expr = stripCtor(expr); - if (!isa(expr)) { - return false; - } - // OSL_THIS_FUNC may be defined as "" in include/osl/diagnose.h, so don't - // warn about expressions like 'SAL_INFO(..., OSL_THIS_FUNC << ":")' or - // 'OUString(OSL_THIS_FUNC) + ":"': - auto loc = compat::getBeginLoc(expr); - while (compiler.getSourceManager().isMacroArgExpansion(loc)) { - loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc); - } - return !compiler.getSourceManager().isMacroBodyExpansion(loc) - || (Lexer::getImmediateMacroName( - loc, compiler.getSourceManager(), compiler.getLangOpts()) - != "OSL_THIS_FUNC"); -} - -loplugin::Plugin::Registration stringconcat("stringconcat"); - -} // namespace - -#endif // LO_CLANG_SHARED_PLUGINS - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/stringconcatauto.cxx b/compilerplugins/clang/stringconcatauto.cxx new file mode 100644 index 000000000000..1437b7537323 --- /dev/null +++ b/compilerplugins/clang/stringconcatauto.cxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +/* +This is a compile check. + +Warns about 'auto' declarations becoming rtl::OUStringConcat, such as +auto str = "string" + OUString::number( 10 ); +The type of the expression is rtl::OUStringConcat and those refer to temporaries +and so their lifecycle should not extend the lifecycle of those temporaries. +*/ + +#ifndef LO_CLANG_SHARED_PLUGINS + +#include "plugin.hxx" +#include "check.hxx" + +#include + +namespace loplugin +{ + +class StringConcatAuto + : public FilteringPlugin< StringConcatAuto > + { + public: + StringConcatAuto( const InstantiationData& data ); + virtual void run() override; + bool shouldVisitTemplateInstantiations () const { return true; } + bool VisitVarDecl( const VarDecl* decl ); + bool VisitFunctionDecl( const FunctionDecl* decl ); + private: + enum class Check { Var, Return }; + bool checkDecl( const DeclaratorDecl* decl, const QualType type, const SourceRange& range, Check check ); + }; + +StringConcatAuto::StringConcatAuto( const InstantiationData& data ) + : FilteringPlugin( data ) + { + } + +void StringConcatAuto::run() + { + TraverseDecl( compiler.getASTContext().getTranslationUnitDecl()); + } + +bool StringConcatAuto::VisitVarDecl( const VarDecl* decl ) + { + return checkDecl( decl, decl->getType(), + decl->getTypeSourceInfo() + ? decl->getTypeSourceInfo()->getTypeLoc().getSourceRange() + : decl->getSourceRange(), + Check::Var ); + } + +bool StringConcatAuto::VisitFunctionDecl( const FunctionDecl* decl ) + { + return checkDecl( decl, decl->getReturnType(), decl->getReturnTypeSourceRange(), Check::Return ); + } + +bool StringConcatAuto::checkDecl( const DeclaratorDecl* decl, QualType type, const SourceRange& range, Check check ) + { + if( ignoreLocation( decl )) + return true; + if( isa< ParmVarDecl >( decl )) // parameters should be fine, temporaries should exist during the call + return true; + std::string fileName = getFileNameOfSpellingLoc( + compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(decl))); + loplugin::normalizeDotDotInFilePath(fileName); + if (fileName == SRCDIR "/include/rtl/string.hxx" + || fileName == SRCDIR "/include/rtl/ustring.hxx" + || fileName == SRCDIR "/include/rtl/strbuf.hxx" + || fileName == SRCDIR "/include/rtl/ustrbuf.hxx" + || fileName == SRCDIR "/include/rtl/stringconcat.hxx") + return true; + auto const tc = loplugin::TypeCheck( type.getNonReferenceType().getCanonicalType()); + const char* typeString = nullptr; + if( tc.Struct("OUStringConcat").Namespace("rtl").GlobalNamespace()) + typeString = "OUString"; + else if( tc.Struct("OStringConcat").Namespace("rtl").GlobalNamespace()) + typeString = "OString"; + else + return true; + report( DiagnosticsEngine::Warning, + check == Check::Var + ? "creating a variable of type %0 will make it reference temporaries" + : "returning a variable of type %0 will make it reference temporaries", + decl->getLocation()) + << type; + report( DiagnosticsEngine::Note, + "use %0 instead", + range.getBegin()) + << typeString + << FixItHint::CreateReplacement( range, typeString ); + return true; + } + +static Plugin::Registration< StringConcatAuto > stringconcatauto( "stringconcatauto" ); + +} // namespace + +#endif // LO_CLANG_SHARED_PLUGINS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/stringconcatliterals.cxx b/compilerplugins/clang/stringconcatliterals.cxx new file mode 100644 index 000000000000..f6008175f38d --- /dev/null +++ b/compilerplugins/clang/stringconcatliterals.cxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + */ + +#ifndef LO_CLANG_SHARED_PLUGINS + +#include "plugin.hxx" +#include "check.hxx" + +namespace { + +Expr const * stripCtor(Expr const * expr) { + auto e1 = expr; + if (auto const e = dyn_cast(e1)) { + e1 = e->getSubExpr()->IgnoreParenImpCasts(); + } + if (auto const e = dyn_cast(e1)) { + e1 = e->getSubExpr()->IgnoreParenImpCasts(); + } + auto const e2 = dyn_cast(e1); + if (e2 == nullptr) { + return expr; + } + auto qt = loplugin::DeclCheck(e2->getConstructor()); + if (qt.MemberFunction().Struct("OStringLiteral").Namespace("rtl").GlobalNamespace()) { + if (e2->getNumArgs() == 1) { + return e2->getArg(0)->IgnoreParenImpCasts(); + } + return expr; + } + if (!((qt.MemberFunction().Class("OString").Namespace("rtl") + .GlobalNamespace()) + || (qt.MemberFunction().Class("OUString").Namespace("rtl") + .GlobalNamespace()) + || qt.MemberFunction().Struct("OUStringLiteral").Namespace("rtl").GlobalNamespace())) + { + return expr; + } + if (e2->getNumArgs() != 2) { + return expr; + } + return e2->getArg(0)->IgnoreParenImpCasts(); +} + +class StringConcatLiterals: + public loplugin::FilteringPlugin +{ +public: + explicit StringConcatLiterals(loplugin::InstantiationData const & data): + FilteringPlugin(data) {} + + void run() override + { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } + + bool VisitCallExpr(CallExpr const * expr); + +private: + bool isStringLiteral(Expr const * expr); +}; + +bool StringConcatLiterals::VisitCallExpr(CallExpr const * expr) { + if (ignoreLocation(expr)) { + return true; + } + FunctionDecl const * fdecl = expr->getDirectCallee(); + if (fdecl == nullptr) { + return true; + } + OverloadedOperatorKind oo = fdecl->getOverloadedOperator(); + if ((oo != OverloadedOperatorKind::OO_Plus + && oo != OverloadedOperatorKind::OO_LessLess) + || fdecl->getNumParams() != 2 || expr->getNumArgs() != 2 + || !isStringLiteral(expr->getArg(1)->IgnoreParenImpCasts())) + { + return true; + } + SourceLocation leftLoc; + auto const leftExpr = expr->getArg(0)->IgnoreParenImpCasts(); + if (isStringLiteral(leftExpr)) { + leftLoc = compat::getBeginLoc(leftExpr); + } else { + CallExpr const * left = dyn_cast(leftExpr); + if (left == nullptr) { + return true; + } + FunctionDecl const * ldecl = left->getDirectCallee(); + if (ldecl == nullptr) { + return true; + } + OverloadedOperatorKind loo = ldecl->getOverloadedOperator(); + if ((loo != OverloadedOperatorKind::OO_Plus + && loo != OverloadedOperatorKind::OO_LessLess) + || ldecl->getNumParams() != 2 || left->getNumArgs() != 2 + || !isStringLiteral(left->getArg(1)->IgnoreParenImpCasts())) + { + return true; + } + leftLoc = compat::getBeginLoc(left->getArg(1)); + } + + // We add an extra " " in the TOOLS_WARN_EXCEPTION macro, which triggers this plugin + if (loplugin::isSamePathname( + compiler.getSourceManager().getFilename( + compiler.getSourceManager().getSpellingLoc( + compiler.getSourceManager().getImmediateMacroCallerLoc( + compiler.getSourceManager().getImmediateMacroCallerLoc( + compat::getBeginLoc(expr))))), + SRCDIR "/include/tools/diagnose_ex.h")) + return true; + + StringRef name { + getFileNameOfSpellingLoc( + compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))) }; + if (loplugin::isSamePathname( + name, SRCDIR "/sal/qa/rtl/oustringbuffer/test_oustringbuffer_assign.cxx") + || loplugin::isSamePathname( + name, SRCDIR "/sal/qa/rtl/strings/test_ostring_concat.cxx") + || loplugin::isSamePathname( + name, SRCDIR "/sal/qa/rtl/strings/test_oustring_concat.cxx")) + { + return true; + } + CXXOperatorCallExpr const * op = dyn_cast(expr); + report( + DiagnosticsEngine::Warning, + "replace '%0' between string literals with juxtaposition", + op == nullptr ? expr->getExprLoc() : op->getOperatorLoc()) + << (oo == OverloadedOperatorKind::OO_Plus ? "+" : "<<") + << SourceRange(leftLoc, compat::getEndLoc(expr->getArg(1))); + return true; +} + +bool StringConcatLiterals::isStringLiteral(Expr const * expr) { + expr = stripCtor(expr); + if (!isa(expr)) { + return false; + } + // OSL_THIS_FUNC may be defined as "" in include/osl/diagnose.h, so don't + // warn about expressions like 'SAL_INFO(..., OSL_THIS_FUNC << ":")' or + // 'OUString(OSL_THIS_FUNC) + ":"': + auto loc = compat::getBeginLoc(expr); + while (compiler.getSourceManager().isMacroArgExpansion(loc)) { + loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc); + } + return !compiler.getSourceManager().isMacroBodyExpansion(loc) + || (Lexer::getImmediateMacroName( + loc, compiler.getSourceManager(), compiler.getLangOpts()) + != "OSL_THIS_FUNC"); +} + +loplugin::Plugin::Registration stringconcatliterals("stringconcatliterals"); + +} // namespace + +#endif // LO_CLANG_SHARED_PLUGINS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/stringconcat.cxx b/compilerplugins/clang/test/stringconcat.cxx deleted file mode 100644 index e2d5a8ce20e3..000000000000 --- a/compilerplugins/clang/test/stringconcat.cxx +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- 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 - -#include - -#include -#include - -#define FOO "foo" - -void f(std::ostream& s1) -{ - static char const foo[] = "foo"; - s1 << "foo" - << "foo"; - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << FOO; - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << foo; - s1 << "foo" << OString("foo"); - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << OString(FOO); - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << OString(foo); - s1 << "foo" << OUString("foo"); - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << OUString(FOO); - // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} - s1 << "foo" << OUString(foo); - s1 << "foo" << OUStringLiteral("foo"); //TODO: warn too, OUStringLiteral wrapped in OUString - s1 << "foo" << OUStringLiteral(FOO); //TODO: warn too, OUStringLiteral wrapped in OUString - s1 << "foo" << OUStringLiteral(foo); - OString s2; - s2 = "foo" + OString("foo"); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s2 = "foo" + OString(FOO); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s2 = "foo" + OString(foo); - s2 = "foo" + OStringLiteral("foo"); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s2 = "foo" + OStringLiteral(FOO); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s2 = "foo" + OStringLiteral(foo); - OUString s3; - s3 = "foo" + OUString("foo"); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s3 = "foo" + OUString(FOO); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s3 = "foo" + OUString(foo); - s3 = "foo" + OUStringLiteral("foo"); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s3 = "foo" + OUStringLiteral(FOO); - // expected-error@-1 {{replace '+' between string literals with juxtaposition}} - s3 = "foo" + OUStringLiteral(foo); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/test/stringconcatauto.cxx b/compilerplugins/clang/test/stringconcatauto.cxx new file mode 100644 index 000000000000..777da46e84a4 --- /dev/null +++ b/compilerplugins/clang/test/stringconcatauto.cxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +#include + +void foo() +{ + auto str1 = "str1" + OUString::number( 10 ); + // expected-error-re@-1 {{creating a variable of type 'rtl::OUStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + OUString str2 = "str2" + OUString::number( 20 ) + "ing"; + const auto& str3 = "str3" + OUString::number( 30 ); + // expected-error-re@-1 {{creating a variable of type 'const rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + const auto str4 = "str4" + OString::number( 40 ); + // expected-error-re@-1 {{creating a variable of type 'const rtl::OStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OString instead}} + (void) str1; + (void) str2; + (void) str3; + (void) str4; +} + +struct A +{ + auto bar() + // expected-error-re@-1 {{returning a variable of type 'rtl::OStringConcat<{{.*}}>' will make it reference temporaries}} + // expected-note@-2 {{use OString instead}} + { + return "bar" + OString::number( 110 ); + } +}; + +template< typename T > +void fun( const T& par ) +// parameters are without warnings +{ + const T& var = par; + // expected-error-re@-1 {{creating a variable of type 'const rtl::OUStringConcat<{{.*}}> &' will make it reference temporaries}} + // expected-note@-2 {{use OUString instead}} + (void) var; +} + +void testfun() +{ + fun( "fun" + OUString::number( 200 )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/stringconcatliterals.cxx b/compilerplugins/clang/test/stringconcatliterals.cxx new file mode 100644 index 000000000000..e2d5a8ce20e3 --- /dev/null +++ b/compilerplugins/clang/test/stringconcatliterals.cxx @@ -0,0 +1,65 @@ +/* -*- 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 + +#include + +#include +#include + +#define FOO "foo" + +void f(std::ostream& s1) +{ + static char const foo[] = "foo"; + s1 << "foo" + << "foo"; + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << FOO; + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << foo; + s1 << "foo" << OString("foo"); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OString(FOO); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OString(foo); + s1 << "foo" << OUString("foo"); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OUString(FOO); + // expected-error@-1 {{replace '<<' between string literals with juxtaposition}} + s1 << "foo" << OUString(foo); + s1 << "foo" << OUStringLiteral("foo"); //TODO: warn too, OUStringLiteral wrapped in OUString + s1 << "foo" << OUStringLiteral(FOO); //TODO: warn too, OUStringLiteral wrapped in OUString + s1 << "foo" << OUStringLiteral(foo); + OString s2; + s2 = "foo" + OString("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OString(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OString(foo); + s2 = "foo" + OStringLiteral("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OStringLiteral(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s2 = "foo" + OStringLiteral(foo); + OUString s3; + s3 = "foo" + OUString("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUString(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUString(foo); + s3 = "foo" + OUStringLiteral("foo"); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUStringLiteral(FOO); + // expected-error@-1 {{replace '+' between string literals with juxtaposition}} + s3 = "foo" + OUStringLiteral(foo); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ -- cgit