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/.
14 // Find those calls of rtl::OUString::equalsIgnoreAsciiCaseAscii and
15 // rtl::OUString::equalsIgnoreAsciiCaseAsciiL that could be simplified to call
16 // rtl::OUString::equalsIgnoreAsciiCase instead:
20 class LiteralAlternative
:
21 public RecursiveASTVisitor
<LiteralAlternative
>, public loplugin::Plugin
24 explicit LiteralAlternative(CompilerInstance
& compiler
): Plugin(compiler
) {}
26 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
28 bool VisitCallExpr(const CallExpr
* expr
);
31 bool LiteralAlternative::VisitCallExpr(const CallExpr
* expr
) {
32 if (ignoreLocation(expr
)) {
35 FunctionDecl
const * fdecl
= expr
->getDirectCallee();
36 if (fdecl
== nullptr) {
39 std::string qname
{ fdecl
->getQualifiedNameAsString() };
40 if (qname
== "rtl::OUString::equalsIgnoreAsciiCaseAscii"
41 && fdecl
->getNumParams() == 1 && expr
->getNumArgs() == 1)
43 // equalsIgnoreAsciiCaseAscii("foo") -> equalsIngoreAsciiCase("foo"):
44 StringLiteral
const * lit
45 = dyn_cast
<StringLiteral
>(expr
->getArg(0)->IgnoreParenImpCasts());
48 DiagnosticsEngine::Warning
,
49 ("rewrite call of rtl::OUString::equalsIgnoreAsciiCaseAscii"
50 " with string literal argument as call of"
51 " rtl::OUString::equalsIgnoreAsciiCase"),
53 //TODO: a better loc (the "equalsIgnoreAsciiCaseAscii" part)?
57 if (qname
== "rtl::OUString::equalsIgnoreAsciiCaseAsciiL"
58 && fdecl
->getNumParams() == 2 && expr
->getNumArgs() == 2)
60 // equalsIgnoreAsciiCaseAsciiL("foo", 3) -> equalsIngoreAsciiCase("foo")
61 // especially also for
62 // equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("foo")), where
63 // RTL_CONSTASCII_STRINGPARAM expands to complicated expressions
64 // involving (&(X)[0] sub-expressions (and it might or might not be
65 // better to handle that at the level of non-expanded macros instead,
66 // but I have not found out how to do that yet anyway):
68 if (expr
->getArg(1)->isIntegerConstantExpr(res
, compiler
.getASTContext())) {
69 Expr
const * arg0
= expr
->getArg(0)->IgnoreParenImpCasts();
70 StringLiteral
const * lit
= dyn_cast
<StringLiteral
>(arg0
);
73 match
= res
== lit
->getLength();
75 UnaryOperator
const * op
= dyn_cast
<UnaryOperator
>(arg0
);
76 if (op
!= nullptr && op
->getOpcode() == UO_AddrOf
) {
77 ArraySubscriptExpr
const * subs
78 = dyn_cast
<ArraySubscriptExpr
>(
79 op
->getSubExpr()->IgnoreParenImpCasts());
80 if (subs
!= nullptr) {
81 lit
= dyn_cast
<StringLiteral
>(
82 subs
->getBase()->IgnoreParenImpCasts());
83 match
= lit
!= nullptr
84 && subs
->getIdx()->isIntegerConstantExpr(
85 res
, compiler
.getASTContext())
92 DiagnosticsEngine::Warning
,
94 " rtl::OUString::equalsIgnoreAsciiCaseAsciiL with string"
95 " literal and matching length arguments as call of"
96 " rtl::OUString::equalsIgnoreAsciiCase"),
98 //TODO: a better loc (the "equalsIgnoreAsciiCaseAsciiL"
107 loplugin::Plugin::Registration
< LiteralAlternative
> X("literalalternative");
111 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */