Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++ #ifndef CPP_H
++ #define CPP_H
++
++ #include <translator.h>
++ #include <QtCore/QSet>
++ #include <QtCore/QStack>
++
++ QT_BEGIN_NAMESPACE
++
++ struct HashString
++ {
++ HashString() : m_hash(0x80000000) {}
++ explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {}
++ void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; }
++ const QString &value() const { return m_str; }
++ bool operator==(const HashString &other) const { return m_str == other.m_str; }
++ QString m_str;
++
++ mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid)
++ };
++
++ QDebug operator<<(QDebug debug, const HashString &s);
++ size_t qHash(const HashString &str, size_t seed = 0);
++
++ struct HashStringList {
++ explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hash(0x80000000) {}
++ const QList<HashString> &value() const { return m_list; }
++ bool operator==(const HashStringList &other) const { return m_list == other.m_list; }
++
++ QList<HashString> m_list;
++ mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid)
++ };
++
++ QDebug operator<<(QDebug debug, const HashStringList &lst);
++ size_t qHash(const HashStringList &list, size_t seed = 0);
++
++ typedef QList<HashString> NamespaceList;
++
++ struct Namespace {
++
++ Namespace() : classDef(this) { }
++ ~Namespace()
++ {
++ qDeleteAll(children);
++ }
++
++ Namespace *parent = nullptr;
++ QHash<HashString, Namespace *> children;
++ QHash<HashString, NamespaceList> aliases;
++ QList<HashStringList> usings;
++
++ // Class declarations set no flags and create no namespaces, so they are ignored.
++ // Class definitions may appear multiple times - but only because we are trying to
++ // "compile" all sources irrespective of build configuration.
++ // Nested classes may be forward-declared inside a definition, and defined in another file.
++ // The latter will detach the class' child list, so clones need a backlink to the original
++ // definition (either one in case of multiple definitions).
++ // Namespaces can have tr() functions as well, so we need to track parent definitions for
++ // them as well. The complication is that we may have to deal with a forrest instead of
++ // a tree - in that case the parent will be arbitrary. However, it seem likely that
++ // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central
++ // header or only locally in a file.
++ Namespace *classDef;
++
++ QString trQualification;
++
++ bool hasTrFunctions = false;
++ bool complained = false; // ... that tr functions are missing.
++ bool isClass = false; // True if this represents a class, false for namespace
++ };
++
++ struct ParseResults {
++ int fileId;
++ Namespace rootNamespace;
++ QSet<const ParseResults *> includes;
++ };
++
++ struct IncludeCycle {
++ QSet<QString> fileNames;
++ QSet<const ParseResults *> results;
++ };
++
++ struct CppParserState
++ {
++ NamespaceList namespaces;
++ QStack<qsizetype> namespaceDepths;
++ NamespaceList functionContext;
++ QString functionContextUnresolved;
++ QString pendingContext;
++
++ bool operator==(const CppParserState &other) const
++ {
++ return namespaces == other.namespaces
++ && namespaceDepths == other.namespaceDepths
++ && functionContext == other.functionContext
++ && functionContextUnresolved == other.functionContextUnresolved
++ && pendingContext == other.pendingContext;
++ }
++ };
++
++ size_t qHash(const CppParserState &s, size_t seed);
++
++ struct ResultsCacheKey
++ {
++ const QString cleanFile;
++ const CppParserState parserState;
++
++ ResultsCacheKey(const QString &filePath)
++ : cleanFile(filePath)
++ {
++ }
++
++ ResultsCacheKey(const QString &filePath, const CppParserState &state)
++ : cleanFile(filePath),
++ parserState(state)
++ {
++ }
++
++ bool operator==(const ResultsCacheKey &other) const
++ {
++ return cleanFile == other.cleanFile
++ && parserState == other.parserState;
++ }
++ };
++
++ size_t qHash(const ResultsCacheKey &key, size_t seed);
++
++ typedef QHash<ResultsCacheKey, IncludeCycle *> IncludeCycleHash;
++ typedef QHash<QString, const Translator *> TranslatorHash;
++
++ class CppFiles {
++ public:
++ static QSet<const ParseResults *> getResults(const ResultsCacheKey &key);
++ static void setResults(const ResultsCacheKey &key, const ParseResults *results);
++ static const Translator *getTranslator(const QString &cleanFile);
++ static void setTranslator(const QString &cleanFile, const Translator *results);
++ static bool isBlacklisted(const QString &cleanFile);
++ static void setBlacklisted(const QString &cleanFile);
++ static void addIncludeCycle(const QSet<QString> &fileNames, const CppParserState &parserState);
++
++ private:
++ static IncludeCycleHash &includeCycles();
++ static TranslatorHash &translatedFiles();
++ static QSet<QString> &blacklistedFiles();
++ };
++
++ QT_END_NAMESPACE
++
++ #endif // CPP_H