diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /compilerplugins/clang/stringconcatliterals.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | compilerplugins/clang/stringconcatliterals.cxx | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/compilerplugins/clang/stringconcatliterals.cxx b/compilerplugins/clang/stringconcatliterals.cxx new file mode 100644 index 000000000..0f26f4f55 --- /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<CXXFunctionalCastExpr>(e1)) { + e1 = e->getSubExpr()->IgnoreParenImpCasts(); + } + if (auto const e = dyn_cast<CXXBindTemporaryExpr>(e1)) { + e1 = e->getSubExpr()->IgnoreParenImpCasts(); + } + auto const e2 = dyn_cast<CXXConstructExpr>(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<StringConcatLiterals> +{ +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<CallExpr>(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( + getFilenameOfLocation( + compiler.getSourceManager().getSpellingLoc( + compiler.getSourceManager().getImmediateMacroCallerLoc( + compiler.getSourceManager().getImmediateMacroCallerLoc( + compat::getBeginLoc(expr))))), + SRCDIR "/include/tools/diagnose_ex.h")) + return true; + + StringRef name { + getFilenameOfLocation( + 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<CXXOperatorCallExpr>(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<clang::StringLiteral>(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("stringconcatliterals"); + +} // namespace + +#endif // LO_CLANG_SHARED_PLUGINS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |