1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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
23 // (for the rtl string classes) that can be written as just
29 class GetStr final
: public loplugin::FilteringPlugin
<GetStr
>
32 explicit GetStr(loplugin::InstantiationData
const& data
)
33 : FilteringPlugin(data
)
37 bool PreTraverseFunctionDecl(FunctionDecl
* decl
)
39 functions_
.push(decl
);
43 bool PostTraverseFunctionDecl(FunctionDecl
*, bool)
45 assert(!functions_
.empty());
50 bool TraverseFunctionDecl(FunctionDecl
* decl
)
53 if (PreTraverseFunctionDecl(decl
))
55 ret
= FilteringPlugin::TraverseFunctionDecl(decl
);
56 PostTraverseFunctionDecl(decl
, ret
);
61 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr
* expr
)
63 if (ignoreLocation(expr
))
67 if (expr
->getOperator() != OO_LessLess
)
71 assert(expr
->getNumArgs() == 2);
72 if (!loplugin::TypeCheck(expr
->getArg(0)->getType())
73 .ClassOrStruct("basic_ostream")
74 .StdNamespace()) //TODO: check template args
78 auto const arg1
= expr
->getArg(1);
79 auto const e
= dyn_cast
<CXXMemberCallExpr
>(arg1
->IgnoreParenImpCasts());
84 bool castToVoid
= false;
85 if (auto const ic
= dyn_cast
<ImplicitCastExpr
>(arg1
))
87 if (loplugin::TypeCheck(arg1
->getType()).Pointer().Void())
92 auto const t
= compat::getObjectType(e
);
93 auto const tc
= loplugin::TypeCheck(t
);
94 if (!(tc
.Class("OString").Namespace("rtl").GlobalNamespace()
95 || tc
.Class("OUString").Namespace("rtl").GlobalNamespace()
97 && (tc
.Class("OStringBuffer").Namespace("rtl").GlobalNamespace()
98 || tc
.Class("OUStringBuffer").Namespace("rtl").GlobalNamespace()))))
102 if (!loplugin::DeclCheck(e
->getMethodDecl()).Function("getStr"))
108 report(DiagnosticsEngine::Warning
,
109 ("suspicious use of 'getStr' on an object of type %0; the result is implicitly"
110 " cast to a void pointer in a call of 'operator <<'"),
112 << t
.getLocalUnqualifiedType() << expr
->getSourceRange();
115 if (!functions_
.empty())
117 // Filter out occurrences of `s << t.getStr()` in the implementation of
118 // `operator <<(std::basic_ostream<...> & s, T const & t)`:
119 auto const fd
= functions_
.top();
120 if (fd
->getOverloadedOperator() == OO_LessLess
)
122 assert(fd
->getNumParams() == 2);
123 if (loplugin::TypeCheck(fd
->getParamDecl(0)->getType())
126 .TemplateSpecializationClass()
127 .ClassOrStruct("basic_ostream")
128 .StdNamespace()) //TODO: check template args
131 = fd
->getParamDecl(1)->getType()->getAs
<LValueReferenceType
>())
133 auto const t3
= t2
->getPointeeType();
134 if (t3
.isConstQualified() && !t3
.isVolatileQualified()
135 && (t3
.getCanonicalType().getTypePtr()
136 == t
.getCanonicalType().getTypePtr()))
144 report(DiagnosticsEngine::Warning
,
145 ("directly use object of type %0 in a call of 'operator <<', instead of calling"
148 << t
.getLocalUnqualifiedType() << expr
->getSourceRange();
152 bool preRun() override
{ return compiler
.getLangOpts().CPlusPlus
; }
155 std::stack
<FunctionDecl
*> functions_
;
161 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
166 loplugin::Plugin::Registration
<GetStr
> getstr("getstr");
171 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */