1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #ifndef LO_CLANG_SHARED_PLUGINS
17 Expr
const * stripCtor(Expr
const * expr
) {
19 if (auto const e
= dyn_cast
<CXXFunctionalCastExpr
>(e1
)) {
20 e1
= e
->getSubExpr()->IgnoreParenImpCasts();
22 if (auto const e
= dyn_cast
<CXXBindTemporaryExpr
>(e1
)) {
23 e1
= e
->getSubExpr()->IgnoreParenImpCasts();
25 auto const e2
= dyn_cast
<CXXConstructExpr
>(e1
);
29 auto qt
= loplugin::DeclCheck(e2
->getConstructor());
30 if (qt
.MemberFunction().Struct("OStringLiteral").Namespace("rtl").GlobalNamespace()) {
31 if (e2
->getNumArgs() == 1) {
32 return e2
->getArg(0)->IgnoreParenImpCasts();
36 if (!((qt
.MemberFunction().Class("OString").Namespace("rtl")
38 || (qt
.MemberFunction().Class("OUString").Namespace("rtl")
40 || qt
.MemberFunction().Struct("OUStringLiteral").Namespace("rtl").GlobalNamespace()))
44 if (e2
->getNumArgs() != 2) {
47 return e2
->getArg(0)->IgnoreParenImpCasts();
50 class StringConcatLiterals
:
51 public loplugin::FilteringPlugin
<StringConcatLiterals
>
54 explicit StringConcatLiterals(loplugin::InstantiationData
const & data
):
55 FilteringPlugin(data
) {}
58 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
60 bool VisitCallExpr(CallExpr
const * expr
);
63 bool isStringLiteral(Expr
const * expr
);
66 bool StringConcatLiterals::VisitCallExpr(CallExpr
const * expr
) {
67 if (ignoreLocation(expr
)) {
70 FunctionDecl
const * fdecl
= expr
->getDirectCallee();
71 if (fdecl
== nullptr) {
74 OverloadedOperatorKind oo
= fdecl
->getOverloadedOperator();
75 if ((oo
!= OverloadedOperatorKind::OO_Plus
76 && oo
!= OverloadedOperatorKind::OO_LessLess
)
77 || fdecl
->getNumParams() != 2 || expr
->getNumArgs() != 2
78 || !isStringLiteral(expr
->getArg(1)->IgnoreParenImpCasts()))
82 SourceLocation leftLoc
;
83 auto const leftExpr
= expr
->getArg(0)->IgnoreParenImpCasts();
84 if (isStringLiteral(leftExpr
)) {
85 leftLoc
= compat::getBeginLoc(leftExpr
);
87 CallExpr
const * left
= dyn_cast
<CallExpr
>(leftExpr
);
88 if (left
== nullptr) {
91 FunctionDecl
const * ldecl
= left
->getDirectCallee();
92 if (ldecl
== nullptr) {
95 OverloadedOperatorKind loo
= ldecl
->getOverloadedOperator();
96 if ((loo
!= OverloadedOperatorKind::OO_Plus
97 && loo
!= OverloadedOperatorKind::OO_LessLess
)
98 || ldecl
->getNumParams() != 2 || left
->getNumArgs() != 2
99 || !isStringLiteral(left
->getArg(1)->IgnoreParenImpCasts()))
103 leftLoc
= compat::getBeginLoc(left
->getArg(1));
106 // We add an extra " " in the TOOLS_WARN_EXCEPTION macro, which triggers this plugin
107 if (loplugin::isSamePathname(
108 getFilenameOfLocation(
109 compiler
.getSourceManager().getSpellingLoc(
110 compiler
.getSourceManager().getImmediateMacroCallerLoc(
111 compiler
.getSourceManager().getImmediateMacroCallerLoc(
112 compat::getBeginLoc(expr
))))),
113 SRCDIR
"/include/tools/diagnose_ex.h"))
117 getFilenameOfLocation(
118 compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr
))) };
119 if (loplugin::isSamePathname(
120 name
, SRCDIR
"/sal/qa/rtl/oustringbuffer/test_oustringbuffer_assign.cxx")
121 || loplugin::isSamePathname(
122 name
, SRCDIR
"/sal/qa/rtl/strings/test_ostring_concat.cxx")
123 || loplugin::isSamePathname(
124 name
, SRCDIR
"/sal/qa/rtl/strings/test_oustring_concat.cxx"))
128 CXXOperatorCallExpr
const * op
= dyn_cast
<CXXOperatorCallExpr
>(expr
);
130 DiagnosticsEngine::Warning
,
131 "replace '%0' between string literals with juxtaposition",
132 op
== nullptr ? expr
->getExprLoc() : op
->getOperatorLoc())
133 << (oo
== OverloadedOperatorKind::OO_Plus
? "+" : "<<")
134 << SourceRange(leftLoc
, compat::getEndLoc(expr
->getArg(1)));
138 bool StringConcatLiterals::isStringLiteral(Expr
const * expr
) {
139 expr
= stripCtor(expr
);
140 if (!isa
<clang::StringLiteral
>(expr
)) {
143 // OSL_THIS_FUNC may be defined as "" in include/osl/diagnose.h, so don't
144 // warn about expressions like 'SAL_INFO(..., OSL_THIS_FUNC << ":")' or
145 // 'OUString(OSL_THIS_FUNC) + ":"':
146 auto loc
= compat::getBeginLoc(expr
);
147 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
148 loc
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
150 return !compiler
.getSourceManager().isMacroBodyExpansion(loc
)
151 || (Lexer::getImmediateMacroName(
152 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
156 loplugin::Plugin::Registration
<StringConcatLiterals
> stringconcatliterals("stringconcatliterals");
160 #endif // LO_CLANG_SHARED_PLUGINS
162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */