/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "clangeditordocumentprocessor.h" #include "clangfollowsymbol.h" #include #include #include #include #include namespace ClangCodeModel { namespace Internal { // Returns invalid Mark if it is not found at (line, column) static bool findMark(const QVector &marks, uint line, uint column, ClangBackEnd::TokenInfoContainer &mark) { mark = Utils::findOrDefault(marks, [line, column](const ClangBackEnd::TokenInfoContainer &curMark) { if (curMark.line() != line) return false; if (curMark.column() == column) return true; if (curMark.column() < column && curMark.column() + curMark.length() > column) return true; return false; }); if (mark.isInvalid()) return false; return true; } static int getMarkPos(QTextCursor cursor, const ClangBackEnd::TokenInfoContainer &mark) { cursor.setPosition(0); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, mark.line() - 1); cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, mark.column() - 1); return cursor.position(); } static Utils::Link linkAtCursor(QTextCursor cursor, const QString &filePath, uint line, uint column, ClangEditorDocumentProcessor *processor) { using Link = Utils::Link; const QVector &marks = processor->tokenInfos(); ClangBackEnd::TokenInfoContainer mark; if (!findMark(marks, line, column, mark)) return Link(); cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); const QString tokenStr = cursor.selectedText(); Link token(filePath, mark.line(), mark.column()); token.linkTextStart = getMarkPos(cursor, mark); token.linkTextEnd = token.linkTextStart + mark.length(); if (mark.extraInfo().includeDirectivePath) { if (tokenStr != "include" && tokenStr != "#" && tokenStr != "<") return token; return Link(); } if (mark.extraInfo().identifier || tokenStr == "operator") return token; return Link(); } Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data, bool resolveTarget, const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Document::Ptr &documentFromSemanticInfo, CppTools::SymbolFinder *symbolFinder, bool inNextSplit) { int lineNumber = 0, positionInBlock = 0; QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); Utils::Text::convertPosition(cursor.document(), cursor.position(), &lineNumber, &positionInBlock); const uint line = lineNumber; const uint column = positionInBlock + 1; ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get( data.filePath().toString()); if (!processor) return Link(); if (!resolveTarget) return linkAtCursor(cursor, data.filePath().toString(), line, column, processor); QFuture info = processor->requestFollowSymbol(static_cast(line), static_cast(column)); if (info.isCanceled()) return Link(); while (!info.isFinished()) { if (info.isCanceled()) return Link(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } CppTools::SymbolInfo result = info.result(); // We did not fail but the result is empty if (result.fileName.isEmpty()) { const CppTools::RefactoringEngineInterface &refactoringEngine = *CppTools::CppModelManager::instance(); return refactoringEngine.globalFollowSymbol(data, snapshot, documentFromSemanticInfo, symbolFinder, inNextSplit); } return Link(result.fileName, result.startLine, result.startColumn - 1); } } // namespace Internal } // namespace ClangCodeModel