File indexing completed on 2024-05-19 04:39:55

0001 /*
0002     SPDX-FileCopyrightText: 2012 Miha Čančula <miha@noughmad.eu>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kdevfilters.h"
0008 
0009 #include <language/duchain/persistentsymboltable.h>
0010 #include <language/duchain/types/structuretype.h>
0011 #include <language/duchain/duchainlock.h>
0012 #include <language/duchain/duchain.h>
0013 #include <language/duchain/declaration.h>
0014 
0015 using namespace KDevelop;
0016 
0017 static
0018 QString safeString(const QVariant& variant)
0019 {
0020     if (variant.canConvert<Grantlee::SafeString>())
0021     {
0022         return variant.value<Grantlee::SafeString>().get();
0023     }
0024     else
0025     {
0026         return variant.toString();
0027     }
0028 }
0029 
0030 QStringList words(const QVariant& input)
0031 {
0032     QString string = safeString(input);
0033     if (string == string.toLower() && !string.contains(QLatin1Char('_'))) {
0034         return QStringList(string);
0035     }
0036 
0037     if (string.contains(QLatin1Char('_'))) {
0038         return string.toLower().split(QLatin1Char('_'));
0039     }
0040 
0041     int n = string.size();
0042     QStringList ret;
0043     int last = 0;
0044     for (int i = 1; i < n; ++i)
0045     {
0046         if (string[i].isUpper())
0047         {
0048             ret << string.mid(last, i-last).toLower();
0049             last = i;
0050         }
0051     }
0052     ret << string.mid(last).toLower();
0053     return ret;
0054 }
0055 
0056 QVariant CamelCaseFilter::doFilter(const QVariant& input, const QVariant& /*argument*/,
0057                                    bool /*autoescape*/) const
0058 {
0059     QString ret;
0060     const auto words = ::words(input);
0061     for (const QString& word : words) {
0062         QString w = word;
0063         w[0] = w[0].toUpper();
0064         ret += w;
0065     }
0066     return Grantlee::SafeString(ret);
0067 }
0068 
0069 QVariant LowerCamelCaseFilter::doFilter(const QVariant& input, const QVariant& /*argument*/,
0070                                         bool /*autoescape*/) const
0071 {
0072     QString ret;
0073     const auto words = ::words(input);
0074     for (const QString& word :  words) {
0075         QString w = word;
0076         w[0] = w[0].toUpper();
0077         ret += w;
0078     }
0079     if (!ret.isEmpty())
0080     {
0081         ret[0] = ret[0].toUpper();
0082     }
0083     return Grantlee::SafeString(ret);
0084 }
0085 
0086 QVariant UnderscoreFilter::doFilter(const QVariant& input, const QVariant& /*argument*/,
0087                                     bool /*autoescape*/) const
0088 {
0089     QString ret = words(input).join(QLatin1Char('_'));
0090     return Grantlee::SafeString(ret);
0091 }
0092 
0093 QVariant UpperFirstFilter::doFilter(const QVariant& input, const QVariant& /*argument*/,
0094                                     bool /*autoescape*/) const
0095 {
0096     QString in = safeString(input);
0097     if (!in.isEmpty())
0098     {
0099         in[0] = in[0].toUpper();
0100     }
0101     return Grantlee::SafeString(in);
0102 }
0103 
0104 
0105 QVariant SplitLinesFilter::doFilter(const QVariant& input, const QVariant& argument,
0106                                     bool /*autoescape*/) const
0107 {
0108     QStringList retLines;
0109     QString start = safeString(argument);
0110     const QString inputString = safeString(input);
0111     const auto lines = inputString.splitRef(QLatin1Char('\n'), Qt::KeepEmptyParts);
0112     retLines.reserve(lines.size());
0113     for (const auto& line : lines) {
0114         retLines << start + line;
0115     }
0116     return Grantlee::SafeString(retLines.join(QLatin1Char('\n')));
0117 }
0118 
0119 QVariant ArgumentTypeFilter::doFilter (const QVariant& input, const QVariant& /*argument*/,
0120                                        bool /*autoescape*/) const
0121 {
0122     auto type = safeString(input);
0123 
0124     auto visit = [&type](const IndexedDeclaration& indexedDeclaration) {
0125         auto declaration = indexedDeclaration.declaration();
0126         if (!declaration || declaration->isForwardDeclaration()) {
0127             return PersistentSymbolTable::VisitorState::Continue;
0128         }
0129 
0130         // Check if it's a class/struct/etc
0131         if (declaration->type<StructureType>()) {
0132             type = QLatin1String("const %1&").arg(type);
0133             return PersistentSymbolTable::VisitorState::Break;
0134         }
0135 
0136         return PersistentSymbolTable::VisitorState::Continue;
0137     };
0138 
0139     DUChainReadLocker locker(DUChain::lock());
0140     PersistentSymbolTable::self().visitDeclarations(IndexedQualifiedIdentifier(QualifiedIdentifier(type)), visit);
0141 
0142     return Grantlee::SafeString(type);
0143 }
0144 
0145 KDevFilters::KDevFilters(QObject* parent, const QVariantList &)
0146 : QObject(parent)
0147 {
0148 }
0149 
0150 KDevFilters::~KDevFilters()
0151 {
0152 
0153 }
0154 
0155 QHash< QString, Grantlee::Filter* > KDevFilters::filters(const QString& name)
0156 {
0157     Q_UNUSED(name);
0158     QHash< QString, Grantlee::Filter* > filters;
0159 
0160     filters[QStringLiteral("camel_case")] = new CamelCaseFilter();
0161     filters[QStringLiteral("camel_case_lower")] = new LowerCamelCaseFilter();
0162     filters[QStringLiteral("underscores")] = new UnderscoreFilter();
0163     filters[QStringLiteral("lines_prepend")] = new SplitLinesFilter();
0164     filters[QStringLiteral("upper_first")] = new UpperFirstFilter();
0165     filters[QStringLiteral("arg_type")] = new ArgumentTypeFilter();
0166 
0167     return filters;
0168 }
0169 
0170 #include "moc_kdevfilters.cpp"