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/.
16 // Find non-const vars of 'char const *' type initialized with a const expr,
17 // that could likely be const (and will then probably trigger further
18 // loplugin:stringconstant findings).
22 // It looks like Clang wrongly implements DR 4
23 // (<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#4>) and treats
24 // a variable declared in an 'extern "..." {...}'-style linkage-specification as
25 // if it contained the 'extern' specifier:
26 bool hasExternalLinkage(VarDecl
const * decl
) {
27 if (decl
->getLinkageAndVisibility().getLinkage() != ExternalLinkage
) {
30 for (auto ctx
= decl
->getLexicalDeclContext();
31 ctx
->getDeclKind() != Decl::TranslationUnit
;
32 ctx
= ctx
->getLexicalParent())
34 if (auto ls
= dyn_cast
<LinkageSpecDecl
>(ctx
)) {
35 if (!ls
->hasBraces()) {
38 if (auto prev
= decl
->getPreviousDecl()) {
39 return hasExternalLinkage(prev
);
41 return !decl
->isInAnonymousNamespace();
48 public loplugin::FilteringPlugin
<ConstStringVar
>
51 explicit ConstStringVar(loplugin::InstantiationData
const & data
):
52 FilteringPlugin(data
) {}
55 if (compiler
.getLangOpts().CPlusPlus
) {
56 // clang::Expr::isCXX11ConstantExpr only works for C++
57 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
60 DiagnosticsEngine::Warning
,
61 "variable is only used as rvalue, should be const",
63 << v
->getSourceRange();
68 bool TraverseImplicitCastExpr(ImplicitCastExpr
* expr
) {
70 switch (expr
->getCastKind()) {
72 // OString CharPtrDetector ctor:
74 loplugin::TypeCheck(expr
->getType()).Const().Pointer().Const()
77 case CK_LValueToRValue
:
86 if (auto dr
= dyn_cast
<DeclRefExpr
>(
87 expr
->getSubExpr()->IgnoreParenImpCasts()))
89 if (auto vd
= dyn_cast
<VarDecl
>(dr
->getDecl())) {
90 if (vars_
.find(vd
->getCanonicalDecl()) != vars_
.end()) {
97 bool b
= RecursiveASTVisitor::TraverseImplicitCastExpr(expr
);
104 bool VisitVarDecl(VarDecl
const * decl
) {
105 if (ignoreLocation(decl
)) {
108 if (decl
!= decl
->getCanonicalDecl()) {
111 if (isa
<ParmVarDecl
>(decl
) || hasExternalLinkage(decl
)) {
114 if (!loplugin::TypeCheck(decl
->getType()).NonConstVolatile().Pointer()
119 auto init
= decl
->getAnyInitializer();
120 if (init
== nullptr) {
123 if (init
->isInstantiationDependent()) {
124 // avoid problems with isCXX11ConstantExpr in template code
128 if (!init
->isCXX11ConstantExpr(compiler
.getASTContext(), &v
)) {
135 bool VisitDeclRefExpr(DeclRefExpr
const * expr
) {
136 if (!casted_
.empty() && expr
== casted_
.top()) {
139 auto vd
= dyn_cast
<VarDecl
>(expr
->getDecl());
143 vars_
.erase(vd
->getCanonicalDecl());
148 std::set
<VarDecl
const *> vars_
;
149 std::stack
<DeclRefExpr
const *> casted_
;
152 loplugin::Plugin::Registration
<ConstStringVar
> X("conststringvar");
156 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */