forked from qt-creator/qt-creator
		
	Allows to follow outside of current TU. Change-Id: Ieea2fd72bfdf6d60a988b40efcf2f41c5a71d045 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
		
			
				
	
	
		
			146 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/****************************************************************************
 | 
						|
**
 | 
						|
** 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 <cpptools/cppmodelmanager.h>
 | 
						|
#include <texteditor/texteditor.h>
 | 
						|
 | 
						|
#include <clangsupport/tokeninfocontainer.h>
 | 
						|
 | 
						|
#include <utils/textutils.h>
 | 
						|
#include <utils/algorithm.h>
 | 
						|
 | 
						|
namespace ClangCodeModel {
 | 
						|
namespace Internal {
 | 
						|
 | 
						|
// Returns invalid Mark if it is not found at (line, column)
 | 
						|
static bool findMark(const QVector<ClangBackEnd::TokenInfoContainer> &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<ClangBackEnd::TokenInfoContainer> &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.isIncludeDirectivePath()) {
 | 
						|
        if (tokenStr != "include" && tokenStr != "#" && tokenStr != "<")
 | 
						|
            return token;
 | 
						|
        return Link();
 | 
						|
    }
 | 
						|
    if (mark.isIdentifier() || 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<CppTools::SymbolInfo> info
 | 
						|
            = processor->requestFollowSymbol(static_cast<int>(line),
 | 
						|
                                             static_cast<int>(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
 |