Warning, file /sdk/umbrello/lib/cppparser/macro.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2006 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #ifndef MACRO_H
0007 #define MACRO_H
0008 
0009 #include <qpair.h>
0010 #include <QStringList>
0011 #include <QString>
0012 #include <qdatastream.h>
0013 #include <qmap.h>
0014 #include <qdatetime.h>
0015 #include <map>
0016 #include <set>
0017 #include <hashedstring.h>
0018 #include <kdatastream.h>
0019 #include <codemodel.h>
0020 
0021 typedef signed char Q_INT8;
0022 
0023 //This files should be renamed to something like "helpers.h"
0024 
0025 /**
0026  * Encapsulates a problem in a piece of source code.
0027  */
0028 class Problem
0029 {
0030 public:
0031     enum {
0032         Level_Error = 0,   ///< Indicates an error that will prevent the code from compiling
0033         Level_Warning,   ///< Indicates a warning
0034         Level_Todo,   ///< Indicates there is still something left to do
0035         Level_Fixme ///< Indicates that something needs to be fixed
0036     };
0037 
0038 public:
0039     Problem() {}
0040     Problem(const Problem& source)
0041         : m_text(source.m_text), m_line(source.m_line),
0042           m_column(source.m_column), m_level(source.m_level), m_file(source.m_file) {}
0043     Problem(const QString& text, int line, int column, int level = Level_Error)
0044         : m_text(text), m_line(line), m_column(column), m_level(level) {}
0045 
0046     Problem(const Problem& source, bool /*threadSafeClone*/)
0047         : m_text(QString::fromUtf8(source.m_text.toUtf8().data())), m_line(source.m_line),
0048           m_column(source.m_column), m_level(source.m_level), m_file(QString::fromUtf8(source.m_file.toUtf8().data())) {}
0049 
0050     Problem& operator = (const Problem& source)
0051     {
0052         m_text = source.m_text;
0053         m_line = source.m_line;
0054         m_column = source.m_column;
0055         m_level = source.m_level;
0056         m_file = source.m_file;
0057         return (*this);
0058     }
0059 
0060     void setFileName(const QString& fileName)
0061     {
0062         m_file = fileName;
0063     }
0064 
0065     bool operator == (const Problem& p) const
0066     {
0067         return m_text == p.m_text && m_line == p.m_line && m_column == p.m_column && m_level == p.m_level && m_file == p.m_file;
0068     }
0069 
0070     /** Get the filename in which the problem was encountered */
0071     QString fileName() const
0072     {
0073         return m_file;
0074     }
0075 
0076     /** Get the text for the problem */
0077     QString text() const
0078     {
0079         return m_text;
0080     }
0081     /** Get the line number of the problem */
0082     int line() const
0083     {
0084         return m_line;
0085     }
0086     /** Get the column of the problem */
0087     int column() const
0088     {
0089         return m_column;
0090     }
0091     /**
0092      * Get the seriousness of the problem. There are four possibilities:
0093      * \li Error
0094      * \li Warning
0095      * \li Todo
0096      * \li Fixme
0097      */
0098     int level() const
0099     {
0100         return m_level;
0101     }
0102 
0103 private:
0104     QString m_text;
0105     int m_line;
0106     int m_column;
0107     int m_level;
0108     QString m_file;
0109 };
0110 
0111 
0112 /**
0113  * A datatype that represents a preprocessor macro.
0114  * Most of the functions in this class need to be inline, so we do not have to import cppparser to many modules. The other solution would be moving macro into interfaces.
0115  */
0116 class Macro
0117 {
0118 public:
0119     typedef QString Argument;
0120 
0121 public:
0122     explicit Macro(bool hasArguments = false)
0123         : m_idHashValid(false),
0124           m_valueHashValid(false),
0125           m_idHash(0),
0126           m_valueHash(0),
0127           m_line(0),
0128           m_column(0),
0129           m_hasArguments(hasArguments),
0130           m_isUndefMacro(false)
0131     {}
0132     Macro(const QString &n, const QString &b)
0133         : m_idHashValid(false),
0134           m_valueHashValid(false),
0135           m_idHash(0),
0136           m_valueHash(0),
0137           m_name(n),
0138           m_line(0),
0139           m_column(0),
0140           m_body(b),
0141           m_hasArguments(false),
0142           m_isUndefMacro(false)
0143     {}
0144 
0145     //Sorts the macros by their hash-value, then by their name.
0146     class NameArgCompare {
0147     public:
0148         bool operator () (const Macro& lhs, const Macro& rhs) const
0149         {
0150             size_t lhash = lhs.idHash();
0151             size_t rhash = rhs.idHash();
0152             if (lhash < rhash) return true;
0153             else if (lhash > rhash) return false;
0154 
0155             int df = lhs.m_name.compare(rhs.m_name);
0156             if (df < 0)
0157                 return true;
0158             if (df == 0) {
0159                 if (!lhs.m_hasArguments && rhs.m_hasArguments) {
0160                     return true;
0161                 } else if (lhs.m_hasArguments == rhs.m_hasArguments) {
0162                     return lhs.m_argumentList.count() < rhs.m_argumentList.count();
0163 
0164                 } else {
0165                     return false;
0166                 }
0167             }
0168             return false;
0169         }
0170     };
0171     class NameCompare {
0172     public:
0173         bool operator () (const Macro& lhs, const Macro& rhs) const
0174         {
0175             size_t lhash = lhs.idHash();
0176             size_t rhash = rhs.idHash();
0177             if (lhash < rhash) return true;
0178             else if (lhash > rhash) return false;
0179 
0180             int df = lhs.m_name.compare(rhs.m_name);
0181             return df < 0;
0182         }
0183     };
0184 
0185     class NameArgHash {
0186     public:
0187         size_t operator () (const Macro& macro) const
0188         {
0189             return macro.idHash();
0190         }
0191     };
0192 
0193     class NameArgEqual {
0194     public:
0195         bool operator () (const Macro& lhs, const Macro& rhs) const
0196         {
0197             int df = lhs.m_name.compare(rhs.m_name);
0198             if (df == 0) {
0199                 if (lhs.m_hasArguments != rhs.m_hasArguments) {
0200                     return false;
0201                 } else {
0202                     if (lhs.m_argumentList.count() != rhs.m_argumentList.count()) return false;
0203                     /*QStringList::const_iterator it2 = rhs.m_argumentList.begin();
0204                     for(QStringList::const_iterator it = lhs.m_argumentList.begin(); it != lhs.m_argumentList.end();) {
0205                         if(*it != *it2) return false;
0206 
0207                         ++it;
0208                         ++it2;
0209                     }*/
0210                     return true;
0211 
0212                 }
0213             }
0214             return false;
0215         }
0216     };
0217 
0218     Macro(const Macro& source)
0219         : m_idHashValid(source.m_idHashValid),
0220           m_valueHashValid(source.m_valueHashValid),
0221           m_idHash(source.m_idHash),
0222           m_valueHash(source.m_valueHash),
0223           m_name(source.m_name),
0224           m_fileName(source.m_fileName),
0225           m_line(source.m_line),
0226           m_column(source.m_column),
0227           m_body(source.m_body),
0228           m_hasArguments(source.m_hasArguments),
0229           m_argumentList(source.m_argumentList),
0230           m_isUndefMacro(source.m_isUndefMacro)
0231     {}
0232 
0233     Macro& operator = (const Macro& source)
0234     {
0235         m_idHashValid = source.m_idHashValid;
0236         m_valueHashValid = source.m_valueHashValid;
0237         m_idHash = source.m_idHash;
0238         m_valueHash = source.m_valueHash;
0239         m_name = source.m_name;
0240         m_fileName = source.m_fileName;
0241         m_line = source.m_line;
0242         m_column = source.m_column;
0243         m_body = source.m_body;
0244         m_hasArguments = source.m_hasArguments;
0245         m_argumentList = source.m_argumentList;
0246         m_isUndefMacro = source.m_isUndefMacro;
0247         return *this;
0248     }
0249 
0250     bool operator == (const Macro& source) const
0251     {
0252         if (!m_idHashValid || !m_valueHashValid) computeHash();
0253         if (!source.m_idHashValid || !source.m_valueHashValid) source.computeHash();
0254 
0255         if (m_idHash != source.m_idHash) return false;
0256         if (m_valueHash != source.m_valueHash) return false;
0257 
0258         return m_name == source.m_name &&
0259                m_fileName == source.m_fileName &&
0260                m_body == source.m_body &&
0261                m_hasArguments == source.m_hasArguments &&
0262                m_argumentList == source.m_argumentList && m_isUndefMacro == source.m_isUndefMacro;
0263     }
0264 
0265     void read(QDataStream& stream)
0266     {
0267         Q_INT8 i;
0268         stream >> i;
0269         m_idHashValid = i;
0270         stream >> i;
0271         m_valueHashValid = i;
0272         stream >> i;
0273         m_hasArguments = i;
0274 
0275         stream >> m_idHash;
0276         stream >> m_valueHash;
0277         stream >> m_name;
0278         stream >> m_line;
0279         stream >> m_column;
0280         stream >> m_body;
0281         stream >> m_fileName;
0282         stream >> m_argumentList;
0283     }
0284 
0285     void write(QDataStream& stream) const
0286     {
0287         Q_INT8 i;
0288         i = m_idHashValid;
0289         stream << i;
0290         i = m_valueHashValid;
0291         stream << i;
0292         i = m_hasArguments;
0293         stream << i;
0294 
0295         stream << m_idHash;
0296         stream << m_valueHash;
0297         stream << m_name;
0298         stream << m_line;
0299         stream << m_column;
0300         stream << m_body;
0301         stream << m_fileName;
0302         stream << m_argumentList;
0303     }
0304 
0305     /** Get the name for this macro */
0306     QString name() const
0307     {
0308         return m_name;
0309     }
0310     /** Set the name for this macro */
0311     void setName(const QString& name)
0312     {
0313         m_name = name;
0314         invalidateHash();
0315     }
0316 
0317     /** Get the file name that contains this macro */
0318     QString fileName() const
0319     {
0320         return m_fileName;
0321     }
0322     /** Set the file name that contains this macro */
0323     void setFileName(const QString& fileName)
0324     {
0325         m_fileName = fileName;
0326         invalidateHash();
0327     }
0328 
0329     /** Get the line the macro is defined on */
0330     int line() const
0331     {
0332         return m_line;
0333     }
0334     /** Set the line the macro is defined on */
0335     void setLine(int line)
0336     {
0337         m_line = line;
0338     }
0339 
0340     /** Get the column the macro starts at */
0341     int column() const
0342     {
0343         return m_column;
0344     }
0345     /** Set the column the macro starts at */
0346     void setColumn(int column)
0347     {
0348         m_column = column;
0349     }
0350 
0351     /** Get the body of the macro */
0352     QString body() const
0353     {
0354         return m_body;
0355     }
0356     /** Set the body of the macro */
0357     void setBody(const QString& body)
0358     {
0359         m_body = body;
0360         invalidateHash();
0361     }
0362 
0363     /** This is used so the lexer does not have to remove macros that should really stay(they are just temporarily shadowed by an isUndef-macro */
0364     bool isUndef() const
0365     {
0366         return m_isUndefMacro;
0367     };
0368 
0369     void setUndef()
0370     {
0371         m_isUndefMacro = true;
0372         invalidateHash();
0373     };
0374 
0375     /** Check whether the macro has arguments that are passed to it */
0376     bool hasArguments() const
0377     {
0378         return m_hasArguments;
0379     }
0380     void setHasArguments(bool hasArguments)
0381     {
0382         m_hasArguments = hasArguments;
0383         invalidateHash();
0384     }
0385     /** Get a list of arguments passed to this macro */
0386     QList<Argument> argumentList() const
0387     {
0388         return m_argumentList;
0389     }
0390 
0391     /** Clear the list of arguments this macro has */
0392     void clearArgumentList()
0393     {
0394         m_argumentList.clear();
0395         m_hasArguments = false;
0396         invalidateHash();
0397     }
0398     /** Add an argument to this macro */
0399     void addArgument(const Argument& argument)
0400     {
0401         m_argumentList << argument;
0402     }
0403     /** Add a list of arguments to this macro */
0404     void addArgumentList(const QList<Argument>& arguments)
0405     {
0406         m_argumentList += arguments;
0407         invalidateHash();
0408     }
0409 
0410     ///This hash respects macro-name and argument-count
0411     size_t idHash() const
0412     {
0413         if (!m_idHashValid) computeHash();
0414         return m_idHash;
0415     }
0416 
0417     ///This hash respects body and if it is an undef-macro
0418     size_t valueHash() const
0419     {
0420         if (!m_valueHashValid) computeHash();
0421         return m_valueHash;
0422     }
0423 
0424 private:
0425     inline void invalidateHash() const
0426     {
0427         m_idHashValid = m_valueHashValid = false;
0428     }
0429 
0430     void computeHash() const
0431     {
0432         m_idHash = 7 * (HashedString::hashString(m_name));
0433         int a = 1;
0434         //m_idHash += 31 * m_argumentList.count();
0435 
0436         m_valueHash = 27 * (HashedString::hashString(m_body) +  (m_isUndefMacro ? 1 : 0));
0437 
0438         for (QList<Argument>::const_iterator it = m_argumentList.begin(); it != m_argumentList.end(); ++it) {
0439             a *= 19;
0440             m_valueHash += a * HashedString::hashString(*it);
0441         }
0442         m_valueHashValid = true;
0443         m_idHashValid = true;
0444     }
0445 
0446     mutable bool m_idHashValid;
0447     mutable bool m_valueHashValid;
0448     mutable size_t m_idHash; //Hash that represents the ids of all macros
0449     mutable size_t m_valueHash; //Hash that represents the values of all macros
0450 
0451     QString m_name;
0452     QString m_fileName;
0453     int m_line;
0454     int m_column;
0455     QString m_body;
0456     bool m_hasArguments;
0457     QStringList m_argumentList; //While identification, only the count plays a role, not the values.
0458     bool m_isUndefMacro;
0459     friend class NameCompare;
0460     friend class NameArgEqual;
0461 };
0462 
0463 class MacroSet
0464 {
0465 public:
0466     //typedef __gnu_cxx::hash_set< Macro, Macro::NameArgHash, Macro::NameArgEqual > Macros;
0467     typedef std::set< Macro, Macro::NameCompare > Macros;
0468     MacroSet()
0469       : m_idHashValid(false),
0470         m_valueHashValid(false),
0471         m_idHash(0),
0472         m_valueHash(0)
0473     {
0474     }
0475 
0476     void addMacro(const Macro& macro);
0477 
0478     void read(QDataStream& stream)
0479     {
0480         //stream >> m_idHashValid >> m_idHash >> m_valueHashValid >> m_valueHash;
0481         m_idHashValid = false;
0482         m_valueHashValid = false;
0483         int cnt;
0484         stream >> cnt;
0485         m_usedMacros.clear();
0486         Macro m;
0487         for (int a = 0; a < cnt; a++) {
0488             m.read(stream);
0489             m_usedMacros.insert(m);
0490         }
0491     }
0492 
0493     void write(QDataStream& stream) const
0494     {
0495         //stream << m_idHashValid << m_idHash << m_valueHashValid << m_valueHash;
0496         stream << int(m_usedMacros.size());
0497         for (Macros::const_iterator it = m_usedMacros.begin(); it != m_usedMacros.end(); ++it) {
0498             (*it).write(stream);
0499         }
0500     }
0501 
0502     bool hasMacro(const QString& name) const;
0503     bool hasMacro(const HashedString& name) const;
0504     Macro macro(const QString& name) const;
0505 
0506     size_t idHash() const;
0507     size_t valueHash() const;
0508 
0509     const Macros& macros() const
0510     {
0511         return m_usedMacros;
0512     }
0513 
0514     void merge(const MacroSet& macros);
0515 private:
0516     void computeHash() const;
0517     Macros m_usedMacros;
0518     mutable bool m_idHashValid;
0519     mutable bool m_valueHashValid;
0520     mutable size_t m_idHash; //Hash that represents the ids of all macros
0521     mutable size_t m_valueHash; //Hash that represents the values of all macros
0522 
0523     friend class Driver;
0524 };
0525 
0526 #endif