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/.
19 Comments from Bjoern Michaelsen:
21 Killing the 1-argument vector fill constructor:
23 std::vector< basebmp::Color > aDevPal(2);
25 in general is probably a Good Thing(tm). It can just be too misleading.
26 Requiring at least the explicit two-value fill constructor for the rare cases where
27 someone wants a filled vector isn't too much to ask and less prone to
30 std::vector< basebmp::Color > aDevPal(2, basebmp::Color(0,0,0));
32 Although that _still_ might be misleading[1], so turning all those into the
33 somewhat longer, but more explicit:
35 std::vector< basebmp::Color > aDevPal;
37 aDevPal.push_back(...);
40 > So I suppose the check would be for a size reservation on a vector
41 > followed by push_back - rather than some array indexing - does that make
42 > sense ? or did I go crazy ;-)
44 Yes, in general you want neither of the above forms. Preferably instead of
47 std::vector< basebmp::Color > aDevPal(2);
48 aDevPal[0] = basebmp::Color( 0, 0, 0 );
49 aDevPal[1] = basebmp::Color( 0xff, 0xff, 0xff );
51 you would -- if possible -- simply:
53 std::vector< basebmp::Color > aDevPal{
54 basebmp::Color( 0, 0, 0 ),
55 basebmp::Color( 0xff, 0xff, 0xff ) };
57 and only for complex cases, where you do not have the elements statically
58 available, something like:
60 std::vector< foo > vFoos;
61 vFoos.reserve(vInput.size());
62 std::transform(std::back_inserter(vFoos),
65 [] (decltype(vInput)::value_type aInputValue) { return do_something(aInputValue); });
68 https://skyfromme.wordpress.com/2015/03/02/50-ways-to-fill-your-vector/
69 https://skyfromme.wordpress.com/2015/03/12/following-the-white-rabbit/
70 (tl;dr: Use initializer lists to fill vectors when possible).
76 [1] Well, except that:
77 std::vector<int>(3, 0)
78 is doing something different from:
79 std::vector<int>{3, 0}
80 just to make things more interesting. But hey, that's C++ for you.
81 But that wart exists for the 1-arg ctor too -- yet another reason to kill that.
88 public loplugin::FilteringPlugin
<BadVectorInit
>
91 explicit BadVectorInit(InstantiationData
const & data
): FilteringPlugin(data
) {}
93 virtual void run() override
95 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
98 bool VisitCXXConstructExpr(const CXXConstructExpr
* );
99 bool TraverseFunctionDecl(FunctionDecl
* );
100 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr
* );
102 StringRef
getFilename(SourceLocation loc
);
103 std::set
<const VarDecl
*> suspectSet
;
106 bool BadVectorInit::TraverseFunctionDecl(FunctionDecl
* decl
)
108 bool ret
= RecursiveASTVisitor::TraverseFunctionDecl(decl
);
113 StringRef
BadVectorInit::getFilename(SourceLocation loc
)
115 SourceLocation spellingLocation
= compiler
.getSourceManager().getSpellingLoc(loc
);
116 StringRef name
{ compiler
.getSourceManager().getFilename(spellingLocation
) };
120 bool BadVectorInit::VisitCXXMemberCallExpr(const CXXMemberCallExpr
* expr
)
122 if (suspectSet
.empty() || ignoreLocation( expr
))
125 // need to exclude some false positives
126 StringRef aFileName
= getFilename(expr
->getLocStart());
127 if (aFileName
== SRCDIR
"/framework/source/services/autorecovery.cxx"
128 || aFileName
== SRCDIR
"/vcl/source/opengl/OpenGLHelper.cxx"
129 || aFileName
== SRCDIR
"/vcl/source/gdi/gdimtf.cxx"
135 const FunctionDecl
* functionDecl
= expr
->getDirectCallee();
138 if (functionDecl
->getNameAsString().find("push_back") == string::npos
)
140 const DeclRefExpr
* declExpr
= dyn_cast
<DeclRefExpr
>(expr
->getImplicitObjectArgument());
143 const VarDecl
* varDecl
= dyn_cast
<VarDecl
>(declExpr
->getDecl());
146 varDecl
= varDecl
->getCanonicalDecl();
147 if (suspectSet
.find(varDecl
) == suspectSet
.end())
150 DiagnosticsEngine::Warning
,
151 "calling push_back after using sized constructor",
153 << expr
->getSourceRange();
155 DiagnosticsEngine::Note
,
157 varDecl
->getLocStart())
158 << varDecl
->getSourceRange();
163 bool BadVectorInit::VisitCXXConstructExpr(const CXXConstructExpr
* expr
)
165 if (ignoreLocation( expr
))
168 const CXXConstructorDecl
*consDecl
= expr
->getConstructor();
169 consDecl
= consDecl
->getCanonicalDecl();
171 // The default constructor can potentially have a parameter, e.g.
172 // in glibcxx-debug the default constructor is:
173 // explicit vector(const _Allocator& __a = _Allocator())
174 if (consDecl
->param_size() == 0 || consDecl
->isDefaultConstructor())
177 std::string aParentName
= consDecl
->getParent()->getQualifiedNameAsString();
178 if (aParentName
.find("vector") == string::npos
&& aParentName
.find("deque") == string::npos
)
181 // ignore the copy/move constructors, and those taking an initializer_list
183 if (consDecl
->isCopyConstructor() || consDecl
->isMoveConstructor())
185 const ParmVarDecl
* pParam
= consDecl
->getParamDecl(0);
186 std::string aParam1
= pParam
->getOriginalType().getAsString();
187 if (aParam1
.find("initializer_list") != string::npos
188 || aParam1
.find("iterator") != string::npos
)
191 // found a call to the 1-arg vector constructor, now look for the VarDecl it belongs to
193 const Stmt
* parent
= expr
;
195 parent
= parentStmt(parent
);
197 if (isa
<DeclStmt
>(parent
))
199 const DeclStmt
* declStmt
= dyn_cast
<DeclStmt
>(parent
);
200 const Decl
* decl
= declStmt
->getSingleDecl();
201 if (decl
&& isa
<VarDecl
>(decl
))
202 suspectSet
.insert(dyn_cast
<VarDecl
>(decl
)->getCanonicalDecl());
210 loplugin::Plugin::Registration
< BadVectorInit
> X("badvectorinit", true);
214 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */