File indexing completed on 2024-04-28 16:57:49

0001 /*
0002     This file is part of the clazy static checker.
0003 
0004     Copyright (C) 2016 Sergio Martins <smartins@kde.org>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 
0023 #ifndef CLAZY_STL_H
0024 #define CLAZY_STL_H
0025 
0026 #include <clang/AST/Stmt.h>
0027 
0028 #include <algorithm>
0029 #include <cctype>
0030 #include <sstream>
0031 
0032 namespace clazy {
0033 
0034 // Don't use .begin() or cend(), clang's ranges don't have them
0035 // Don't use .size(), clang's ranges doesn't have it
0036 
0037 template<typename C>
0038 bool contains(const C &container, const typename C::value_type &value)
0039 {
0040     return std::find(container.begin(), container.end(), value) != container.end();
0041 }
0042 
0043 inline bool contains(const std::string &haystack, const std::string &needle)
0044 {
0045     return haystack.find(needle) != std::string::npos;
0046 }
0047 
0048 template<typename C>
0049 typename C::iterator find(C &container, const typename C::value_type &value)
0050 {
0051     return std::find(container.begin(), container.end(), value);
0052 }
0053 
0054 template<typename C>
0055 typename C::const_iterator find(const C &container, const typename C::value_type &value)
0056 {
0057     return std::find(container.begin(), container.end(), value);
0058 }
0059 
0060 template<typename C, typename Pred>
0061 typename C::iterator find_if(C &container, Pred pred)
0062 {
0063     return std::find_if(container.begin(), container.end(), pred);
0064 }
0065 
0066 template<typename C, typename Pred>
0067 typename C::const_iterator find_if(const C &container, Pred pred)
0068 {
0069     return std::find_if(container.begin(), container.end(), pred);
0070 }
0071 
0072 template<typename Range, typename Pred>
0073 bool any_of(const Range &r, Pred pred)
0074 {
0075     return std::any_of(r.begin(), r.end(), pred);
0076 }
0077 
0078 template<typename Range, typename Pred>
0079 bool all_of(const Range &r, Pred pred)
0080 {
0081     return std::all_of(r.begin(), r.end(), pred);
0082 }
0083 
0084 template <typename Range>
0085 size_t count(const Range &r)
0086 {
0087     return std::distance(r.begin(), r.end());
0088 }
0089 
0090 template<typename SrcContainer, typename DstContainer>
0091 void append(const SrcContainer &src, DstContainer &dst)
0092 {
0093     dst.reserve(clazy::count(dst) + clazy::count(src));
0094     std::copy(src.begin(), src.end(), std::back_inserter(dst));
0095 }
0096 
0097 template<typename SrcContainer, typename DstContainer, typename Pred>
0098 void append_if(const SrcContainer &src, DstContainer &dst, Pred pred)
0099 {
0100     dst.reserve(clazy::count(dst) + clazy::count(src));
0101     std::copy_if(src.begin(), src.end(), std::back_inserter(dst), pred);
0102 }
0103 
0104 template <typename Range>
0105 bool isEmpty(const Range &r)
0106 {
0107     return r.begin() == r.end();
0108 }
0109 
0110 inline bool hasChildren(clang::Stmt *s)
0111 {
0112     return s && !clazy::isEmpty(s->children());
0113 }
0114 
0115 inline clang::Stmt* childAt(clang::Stmt *s, int index)
0116 {
0117     int count = s ? std::distance(s->child_begin(), s->child_end()) : 0;
0118     if (count > index) {
0119         auto it = s->child_begin();
0120         while (index > 0) {
0121             ++it;
0122             --index;
0123         }
0124         return *it;
0125     }
0126 
0127     return nullptr;
0128 }
0129 
0130 /**
0131  * Returns true if the string target starts with maybeBeginning
0132  */
0133 inline bool startsWith(const std::string &target, const std::string &maybeBeginning)
0134 {
0135     return target.compare(0, maybeBeginning.length(), maybeBeginning) == 0;
0136 }
0137 
0138 /**
0139  * Returns true if the string target starts with any of the strings in beginningCandidates
0140  */
0141 inline bool startsWithAny(const std::string &target, const std::vector<std::string> &beginningCandidates)
0142 {
0143     return clazy::any_of(beginningCandidates, [target](const std::string &maybeBeginning) {
0144             return clazy::startsWith(target, maybeBeginning);
0145         });
0146 }
0147 
0148 /**
0149  * Returns true if the target equals any of the candidate strings
0150  */
0151 inline bool equalsAny(const std::string &target, const std::vector<std::string> &candidates)
0152 {
0153     return clazy::any_of(candidates, [target](const std::string &candidate) {
0154             return candidate == target;
0155         });
0156 }
0157 
0158 /**
0159  * Returns true if the string target ends with maybeEnding
0160  */
0161 inline bool endsWith(const std::string &target, const std::string &maybeEnding)
0162 {
0163     return target.size() >= maybeEnding.size() &&
0164            target.compare(target.size() - maybeEnding.size(), maybeEnding.size(), maybeEnding) == 0;
0165 }
0166 
0167 /**
0168  * Returns true if the string target ends with any of the strings in endingCandidates
0169  */
0170 inline bool endsWithAny(const std::string &target, const std::vector<std::string> &endingCandidates)
0171 {
0172     return clazy::any_of(endingCandidates, [target](const std::string &maybeEnding) {
0173             return clazy::endsWith(target, maybeEnding);
0174         });
0175 }
0176 
0177 
0178 inline std::string toLower(const std::string &s)
0179 {
0180     std::string result(s.size(), 0);
0181     std::transform(s.begin(), s.end(), result.begin(), ::tolower);
0182     return result;
0183 }
0184 
0185 inline void rtrim(std::string &s)
0186 {
0187     while (!s.empty() && std::isspace(s.back()))
0188         s.pop_back();
0189 }
0190 
0191 inline std::vector<std::string> splitString(const std::string &str, char separator)
0192 {
0193     std::string token;
0194     std::vector<std::string> result;
0195     std::istringstream istream(str);
0196     while (std::getline(istream, token, separator)) {
0197         result.push_back(token);
0198     }
0199 
0200     return result;
0201 }
0202 
0203 inline std::vector<std::string> splitString(const char *str, char separator)
0204 {
0205     if (!str)
0206         return {};
0207 
0208     return clazy::splitString(std::string(str), separator);
0209 }
0210 
0211 template<typename Container, typename LessThan>
0212 void sort(Container &c, LessThan lessThan)
0213 {
0214     std::sort(c.begin(), c.end(), lessThan);
0215 }
0216 
0217 template<typename Container, typename LessThan>
0218 void sort_and_remove_dups(Container &c, LessThan lessThan)
0219 {
0220     std::sort(c.begin(), c.end(), lessThan);
0221     c.erase(std::unique(c.begin(), c.end()), c.end());
0222 }
0223 
0224 inline std::string unquoteString(const std::string &str)
0225 {
0226     // If first and last are ", return what's in between quotes:
0227     if (str.size() >= 3 && str[0] == '"' && str.at(str.size() - 1) == '"')
0228         return str.substr(1, str.size() - 2);
0229 
0230     return str;
0231 }
0232 
0233 }
0234 
0235 #endif