diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2021-02-01 15:44:56 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2021-02-12 14:16:14 +0000 |
commit | 8dc4cb17c1708a39b4f513f0faa9f374ff9af067 (patch) | |
tree | f7ce087c5a26959cd79ff06766906df4feb866b9 /src/plugins/cpptools/cpptoolsreuse.cpp | |
parent | 29f1aca1c8e39f6edeaa27cc546eaa49e6459819 (diff) | |
download | qt-creator-8dc4cb17c1708a39b4f513f0faa9f374ff9af067.tar.gz |
Designer: Re-use CppTools functionality
... for slot insertion logic.
Fixes: QTCREATORBUG-8220
Change-Id: I3516a62d62174b64d557c82ce38a9cc334790efc
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/cpptools/cpptoolsreuse.cpp')
-rw-r--r-- | src/plugins/cpptools/cpptoolsreuse.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/plugins/cpptools/cpptoolsreuse.cpp b/src/plugins/cpptools/cpptoolsreuse.cpp index 9267a8171c..b618fea8a7 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -26,6 +26,7 @@ #include "cpptoolsreuse.h" #include "cppcodemodelsettings.h" +#include "cpprefactoringchanges.h" #include "cpptoolsconstants.h" #include "cpptoolsplugin.h" @@ -384,4 +385,191 @@ ClangDiagnosticConfigsModel diagnosticConfigsModel() return diagnosticConfigsModel(CppTools::codeModelSettings()->clangCustomDiagnosticConfigs()); } +NSVisitor::NSVisitor(const CppRefactoringFile *file, const QStringList &namespaces, int symbolPos) + : ASTVisitor(file->cppDocument()->translationUnit()), + m_file(file), + m_remainingNamespaces(namespaces), + m_symbolPos(symbolPos) +{} + +bool CppTools::NSVisitor::preVisit(AST *ast) +{ + if (!m_firstToken) + m_firstToken = ast; + if (m_file->startOf(ast) >= m_symbolPos) + m_done = true; + return !m_done; +} + +bool NSVisitor::visit(NamespaceAST *ns) +{ + if (!m_firstNamespace) + m_firstNamespace = ns; + if (m_remainingNamespaces.isEmpty()) { + m_done = true; + return false; + } + + QString name; + const Identifier * const id = translationUnit()->identifier(ns->identifier_token); + if (id) + name = QString::fromUtf8(id->chars(), id->size()); + if (name != m_remainingNamespaces.first()) + return false; + + if (!ns->linkage_body) { + m_done = true; + return false; + } + + m_enclosingNamespace = ns; + m_remainingNamespaces.removeFirst(); + return !m_remainingNamespaces.isEmpty(); +} + +void NSVisitor::postVisit(AST *ast) +{ + if (ast == m_enclosingNamespace) + m_done = true; +} + +/** + * @brief The NSCheckerVisitor class checks which namespaces are missing for a given list + * of enclosing namespaces at a given position + */ +NSCheckerVisitor::NSCheckerVisitor(const CppRefactoringFile *file, const QStringList &namespaces, + int symbolPos) + : ASTVisitor(file->cppDocument()->translationUnit()) + , m_file(file) + , m_remainingNamespaces(namespaces) + , m_symbolPos(symbolPos) +{} + +bool NSCheckerVisitor::preVisit(AST *ast) +{ + if (m_file->startOf(ast) >= m_symbolPos) + m_done = true; + return !m_done; +} + +void NSCheckerVisitor::postVisit(AST *ast) +{ + if (!m_done && m_file->endOf(ast) > m_symbolPos) + m_done = true; +} + +bool NSCheckerVisitor::visit(NamespaceAST *ns) +{ + if (m_remainingNamespaces.isEmpty()) + return false; + + QString name = getName(ns); + if (name != m_remainingNamespaces.first()) + return false; + + m_enteredNamespaces.push_back(ns); + m_remainingNamespaces.removeFirst(); + // if we reached the searched namespace we don't have to search deeper + return !m_remainingNamespaces.isEmpty(); +} + +bool NSCheckerVisitor::visit(UsingDirectiveAST *usingNS) +{ + // example: we search foo::bar and get 'using namespace foo;using namespace foo::bar;' + const QString fullName = Overview{}.prettyName(usingNS->name->name); + const QStringList namespaces = fullName.split("::"); + if (namespaces.length() > m_remainingNamespaces.length()) + return false; + + // from other using namespace statements + const auto curList = m_usingsPerNamespace.find(currentNamespace()); + const bool isCurListValid = curList != m_usingsPerNamespace.end(); + + const bool startEqual = std::equal(namespaces.cbegin(), + namespaces.cend(), + m_remainingNamespaces.cbegin()); + if (startEqual) { + if (isCurListValid) { + if (namespaces.length() > curList->second.length()) { + // eg. we already have 'using namespace foo;' and + // now get 'using namespace foo::bar;' + curList->second = namespaces; + } + // the other case: first 'using namespace foo::bar;' and now 'using namespace foo;' + } else + m_usingsPerNamespace.emplace(currentNamespace(), namespaces); + } else if (isCurListValid) { + // ex: we have already 'using namespace foo;' and get 'using namespace bar;' now + QStringList newlist = curList->second; + newlist.append(namespaces); + if (newlist.length() <= m_remainingNamespaces.length()) { + const bool startEqual = std::equal(newlist.cbegin(), + newlist.cend(), + m_remainingNamespaces.cbegin()); + if (startEqual) + curList->second.append(namespaces); + } + } + return false; +} + +void NSCheckerVisitor::endVisit(NamespaceAST *ns) +{ + // if the symbolPos was in the namespace and the + // namespace has no children, m_done should be true + postVisit(ns); + if (!m_done && currentNamespace() == ns) { + // we were not succesfull in this namespace, so undo all changes + m_remainingNamespaces.push_front(getName(currentNamespace())); + m_usingsPerNamespace.erase(currentNamespace()); + m_enteredNamespaces.pop_back(); + } +} + +void NSCheckerVisitor::endVisit(TranslationUnitAST *) +{ + // the last node, create the final result + // we must handle like the following: We search for foo::bar and have: + // using namespace foo::bar; + // namespace foo { + // // cursor/symbolPos here + // } + if (m_remainingNamespaces.empty()) { + // we are already finished + return; + } + // find the longest combination of normal namespaces + using statements + int longestNamespaceList = 0; + int enteredNamespaceCount = 0; + // check 'using namespace ...;' statements in the global scope + const auto namespaces = m_usingsPerNamespace.find(nullptr); + if (namespaces != m_usingsPerNamespace.end()) + longestNamespaceList = namespaces->second.length(); + + for (auto ns : m_enteredNamespaces) { + ++enteredNamespaceCount; + const auto namespaces = m_usingsPerNamespace.find(ns); + int newListLength = enteredNamespaceCount; + if (namespaces != m_usingsPerNamespace.end()) + newListLength += namespaces->second.length(); + longestNamespaceList = std::max(newListLength, longestNamespaceList); + } + m_remainingNamespaces.erase(m_remainingNamespaces.begin(), + m_remainingNamespaces.begin() + longestNamespaceList + - m_enteredNamespaces.size()); +} + +QString NSCheckerVisitor::getName(NamespaceAST *ns) +{ + const Identifier *const id = translationUnit()->identifier(ns->identifier_token); + if (id) + return QString::fromUtf8(id->chars(), id->size()); + return {}; +} + +NamespaceAST *NSCheckerVisitor::currentNamespace() +{ + return m_enteredNamespaces.empty() ? nullptr : m_enteredNamespaces.back(); +} + } // CppTools |