forked from qt-creator/qt-creator
CppEditor: Generalize CppUseSelectionsUpdater
Let CppUseSelectionsUpdater delegate the work to *EditorDocumentProcessor so that the clang code model can also provide results. Change-Id: I6872afbfeea1a5c4a64fdf19fcb1992f134dde08 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "baseeditordocumentparser.h"
|
||||
#include "cppcursorinfo.h"
|
||||
#include "cppsemanticinfo.h"
|
||||
#include "cpptools_global.h"
|
||||
|
||||
@@ -72,6 +73,8 @@ public:
|
||||
|
||||
virtual void setParserConfig(const BaseEditorDocumentParser::Configuration config);
|
||||
|
||||
virtual QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms) = 0;
|
||||
|
||||
public:
|
||||
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
|
||||
|
||||
|
||||
360
src/plugins/cpptools/builtincursorinfo.cpp
Normal file
360
src/plugins/cpptools/builtincursorinfo.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "builtincursorinfo.h"
|
||||
|
||||
#include "cppcanonicalsymbol.h"
|
||||
#include "cppcursorinfo.h"
|
||||
#include "cpplocalsymbols.h"
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppsemanticinfo.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
|
||||
#include <texteditor/convenience.h>
|
||||
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <cplusplus/Macro.h>
|
||||
#include <cplusplus/TranslationUnit.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QTextBlock>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
using SemanticUses = QList<CppTools::SemanticInfo::Use>;
|
||||
|
||||
namespace CppTools {
|
||||
namespace Internal {
|
||||
namespace {
|
||||
|
||||
CursorInfo::Range toRange(const SemanticInfo::Use &use)
|
||||
{
|
||||
return CursorInfo::Range(use.line, use.column, use.length);
|
||||
}
|
||||
|
||||
CursorInfo::Range toRange(int tokenIndex, TranslationUnit *translationUnit)
|
||||
{
|
||||
unsigned line, column;
|
||||
translationUnit->getTokenPosition(static_cast<unsigned>(tokenIndex), &line, &column);
|
||||
if (column)
|
||||
--column; // adjust the column position.
|
||||
|
||||
return CursorInfo::Range(
|
||||
line,
|
||||
column +1,
|
||||
translationUnit->tokenAt(static_cast<unsigned>(tokenIndex)).utf16chars());
|
||||
}
|
||||
|
||||
CursorInfo::Range toRange(const QTextCursor &textCursor,
|
||||
unsigned utf16offset,
|
||||
unsigned length)
|
||||
{
|
||||
QTextCursor cursor(textCursor.document());
|
||||
cursor.setPosition(static_cast<int>(utf16offset));
|
||||
const QTextBlock textBlock = cursor.block();
|
||||
|
||||
return CursorInfo::Range(
|
||||
static_cast<unsigned>(textBlock.blockNumber() + 1),
|
||||
static_cast<unsigned>(cursor.position() - textBlock.position() + 1),
|
||||
length);
|
||||
}
|
||||
|
||||
CursorInfo::Ranges toRanges(const SemanticUses &uses)
|
||||
{
|
||||
CursorInfo::Ranges ranges;
|
||||
ranges.reserve(uses.size());
|
||||
|
||||
for (const SemanticInfo::Use &use : uses)
|
||||
ranges.append(toRange(use));
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
CursorInfo::Ranges toRanges(const QList<int> tokenIndices, TranslationUnit *translationUnit)
|
||||
{
|
||||
CursorInfo::Ranges ranges;
|
||||
ranges.reserve(tokenIndices.size());
|
||||
|
||||
for (int reference : tokenIndices)
|
||||
ranges.append(toRange(reference, translationUnit));
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
class FunctionDefinitionUnderCursor: protected ASTVisitor
|
||||
{
|
||||
unsigned _line = 0;
|
||||
unsigned _column = 0;
|
||||
DeclarationAST *_functionDefinition = nullptr;
|
||||
|
||||
public:
|
||||
FunctionDefinitionUnderCursor(TranslationUnit *translationUnit)
|
||||
: ASTVisitor(translationUnit)
|
||||
{ }
|
||||
|
||||
DeclarationAST *operator()(AST *ast, unsigned line, unsigned column)
|
||||
{
|
||||
_functionDefinition = nullptr;
|
||||
_line = line;
|
||||
_column = column;
|
||||
accept(ast);
|
||||
return _functionDefinition;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool preVisit(AST *ast)
|
||||
{
|
||||
if (_functionDefinition)
|
||||
return false;
|
||||
|
||||
if (FunctionDefinitionAST *def = ast->asFunctionDefinition())
|
||||
return checkDeclaration(def);
|
||||
|
||||
if (ObjCMethodDeclarationAST *method = ast->asObjCMethodDeclaration()) {
|
||||
if (method->function_body)
|
||||
return checkDeclaration(method);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool checkDeclaration(DeclarationAST *ast)
|
||||
{
|
||||
unsigned startLine, startColumn;
|
||||
unsigned endLine, endColumn;
|
||||
getTokenStartPosition(ast->firstToken(), &startLine, &startColumn);
|
||||
getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn);
|
||||
|
||||
if (_line > startLine || (_line == startLine && _column >= startColumn)) {
|
||||
if (_line < endLine || (_line == endLine && _column < endColumn)) {
|
||||
_functionDefinition = ast;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class FindUses
|
||||
{
|
||||
public:
|
||||
static CursorInfo find(const QTextCursor &textCursor,
|
||||
const Document::Ptr document,
|
||||
const Snapshot &snapshot)
|
||||
{
|
||||
const FindUses findUses(textCursor, document, snapshot);
|
||||
return findUses.doFind();
|
||||
}
|
||||
|
||||
private:
|
||||
FindUses(const QTextCursor &textCursor, const Document::Ptr document, const Snapshot &snapshot)
|
||||
: document(document), snapshot(snapshot)
|
||||
{
|
||||
TextEditor::Convenience::convertPosition(textCursor.document(), textCursor.position(),
|
||||
&line, &column);
|
||||
CanonicalSymbol canonicalSymbol(document, snapshot);
|
||||
scope = canonicalSymbol.getScopeAndExpression(textCursor, &expression);
|
||||
}
|
||||
|
||||
CursorInfo doFind() const
|
||||
{
|
||||
CursorInfo result;
|
||||
|
||||
const CppTools::SemanticInfo::LocalUseMap localUses = findLocalUses();
|
||||
result.localUses = localUses;
|
||||
splitLocalUses(localUses, &result.useRanges, &result.unusedVariablesRanges);
|
||||
|
||||
if (!result.useRanges.isEmpty()) {
|
||||
result.areUseRangesForLocalVariable = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.useRanges = findReferences();
|
||||
result.areUseRangesForLocalVariable = false;
|
||||
return result; // OK, result.unusedVariablesRanges will be passed on
|
||||
}
|
||||
|
||||
CppTools::SemanticInfo::LocalUseMap findLocalUses() const
|
||||
{
|
||||
AST *ast = document->translationUnit()->ast();
|
||||
FunctionDefinitionUnderCursor functionDefinitionUnderCursor(document->translationUnit());
|
||||
DeclarationAST *declaration = functionDefinitionUnderCursor(ast,
|
||||
static_cast<unsigned>(line),
|
||||
static_cast<unsigned>(column));
|
||||
return CppTools::LocalSymbols(document, declaration).uses;
|
||||
}
|
||||
|
||||
void splitLocalUses(const CppTools::SemanticInfo::LocalUseMap &uses,
|
||||
CursorInfo::Ranges *rangesForLocalVariableUnderCursor,
|
||||
CursorInfo::Ranges *rangesForLocalUnusedVariables) const
|
||||
{
|
||||
QTC_ASSERT(rangesForLocalVariableUnderCursor, return);
|
||||
QTC_ASSERT(rangesForLocalUnusedVariables, return);
|
||||
|
||||
LookupContext context(document, snapshot);
|
||||
|
||||
CppTools::SemanticInfo::LocalUseIterator it(uses);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
const SemanticUses &uses = it.value();
|
||||
|
||||
bool good = false;
|
||||
foreach (const CppTools::SemanticInfo::Use &use, uses) {
|
||||
unsigned l = static_cast<unsigned>(line);
|
||||
// convertCursorPosition() returns a 0-based column number.
|
||||
unsigned c = static_cast<unsigned>(column + 1);
|
||||
if (l == use.line && c >= use.column && c <= (use.column + use.length)) {
|
||||
good = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uses.size() == 1) {
|
||||
if (!CppTools::isOwnershipRAIIType(it.key(), context))
|
||||
rangesForLocalUnusedVariables->append(toRanges(uses)); // unused declaration
|
||||
} else if (good && rangesForLocalVariableUnderCursor->isEmpty()) {
|
||||
rangesForLocalVariableUnderCursor->append(toRanges(uses));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CursorInfo::Ranges findReferences() const
|
||||
{
|
||||
CursorInfo::Ranges result;
|
||||
if (!scope || expression.isEmpty())
|
||||
return result;
|
||||
|
||||
TypeOfExpression typeOfExpression;
|
||||
Snapshot theSnapshot = snapshot;
|
||||
theSnapshot.insert(document);
|
||||
typeOfExpression.init(document, theSnapshot);
|
||||
typeOfExpression.setExpandTemplates(true);
|
||||
|
||||
if (Symbol *s = CanonicalSymbol::canonicalSymbol(scope, expression, typeOfExpression)) {
|
||||
CppTools::CppModelManager *mmi = CppTools::CppModelManager::instance();
|
||||
const QList<int> tokenIndices = mmi->references(s, typeOfExpression.context());
|
||||
result = toRanges(tokenIndices, document->translationUnit());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
// Shared
|
||||
Document::Ptr document;
|
||||
|
||||
// For local use calculation
|
||||
int line;
|
||||
int column;
|
||||
|
||||
// For references calculation
|
||||
Scope *scope;
|
||||
QString expression;
|
||||
Snapshot snapshot;
|
||||
};
|
||||
|
||||
bool isSemanticInfoValidExceptLocalUses(const SemanticInfo &semanticInfo, int revision)
|
||||
{
|
||||
return semanticInfo.doc
|
||||
&& semanticInfo.revision == static_cast<unsigned>(revision)
|
||||
&& !semanticInfo.snapshot.isEmpty();
|
||||
}
|
||||
|
||||
bool isMacroUseOf(const Document::MacroUse &marcoUse, const Macro ¯o)
|
||||
{
|
||||
const Macro &candidate = marcoUse.macro();
|
||||
|
||||
return candidate.line() == macro.line()
|
||||
&& candidate.utf16CharOffset() == macro.utf16CharOffset()
|
||||
&& candidate.length() == macro.length()
|
||||
&& candidate.fileName() == macro.fileName();
|
||||
}
|
||||
|
||||
bool handleMacroCase(const Document::Ptr document,
|
||||
const QTextCursor &textCursor,
|
||||
CursorInfo::Ranges *ranges)
|
||||
{
|
||||
QTC_ASSERT(ranges, return false);
|
||||
|
||||
const Macro *macro = CppTools::findCanonicalMacro(textCursor, document);
|
||||
if (!macro)
|
||||
return false;
|
||||
|
||||
const unsigned length = static_cast<unsigned>(macro->nameToQString().size());
|
||||
|
||||
// Macro definition
|
||||
if (macro->fileName() == document->fileName())
|
||||
ranges->append(toRange(textCursor, macro->utf16CharOffset(), length));
|
||||
|
||||
// Other macro uses
|
||||
foreach (const Document::MacroUse &use, document->macroUses()) {
|
||||
if (isMacroUseOf(use, *macro))
|
||||
ranges->append(toRange(textCursor, use.utf16charsBegin(), length));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
QFuture<CursorInfo> BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoParams)
|
||||
{
|
||||
QFuture<CursorInfo> nothing;
|
||||
|
||||
const SemanticInfo semanticInfo = cursorInfoParams.semanticInfo;
|
||||
const int currentDocumentRevision = cursorInfoParams.textCursor.document()->revision();
|
||||
if (!isSemanticInfoValidExceptLocalUses(semanticInfo, currentDocumentRevision))
|
||||
return nothing;
|
||||
|
||||
const Document::Ptr document = semanticInfo.doc;
|
||||
const Snapshot snapshot = semanticInfo.snapshot;
|
||||
if (!document)
|
||||
return nothing;
|
||||
|
||||
QTC_ASSERT(document->translationUnit(), return nothing);
|
||||
QTC_ASSERT(document->translationUnit()->ast(), return nothing);
|
||||
QTC_ASSERT(!snapshot.isEmpty(), return nothing);
|
||||
|
||||
CursorInfo::Ranges ranges;
|
||||
if (handleMacroCase(document, cursorInfoParams.textCursor, &ranges)) {
|
||||
CursorInfo result;
|
||||
result.useRanges = ranges;
|
||||
result.areUseRangesForLocalVariable = false;
|
||||
|
||||
QFutureInterface<CursorInfo> fi;
|
||||
fi.reportResult(result);
|
||||
fi.reportFinished();
|
||||
|
||||
return fi.future();
|
||||
}
|
||||
|
||||
return Utils::runAsync(&FindUses::find, cursorInfoParams.textCursor, document, snapshot);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CppTools
|
||||
42
src/plugins/cpptools/builtincursorinfo.h
Normal file
42
src/plugins/cpptools/builtincursorinfo.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cppcursorinfo.h"
|
||||
|
||||
#include <QFuture>
|
||||
|
||||
namespace CppTools {
|
||||
namespace Internal {
|
||||
|
||||
class BuiltinCursorInfo
|
||||
{
|
||||
public:
|
||||
static QFuture<CursorInfo> run(const CursorInfoParams ¶ms);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CppTools
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "builtineditordocumentprocessor.h"
|
||||
|
||||
#include "builtincursorinfo.h"
|
||||
#include "cppchecksymbols.h"
|
||||
#include "cppcodemodelsettings.h"
|
||||
#include "cppmodelmanager.h"
|
||||
@@ -253,6 +254,12 @@ bool BuiltinEditorDocumentProcessor::isParserRunning() const
|
||||
return m_parserFuture.isRunning();
|
||||
}
|
||||
|
||||
QFuture<CursorInfo>
|
||||
BuiltinEditorDocumentProcessor::cursorInfo(const CursorInfoParams ¶ms)
|
||||
{
|
||||
return Internal::BuiltinCursorInfo::run(params);
|
||||
}
|
||||
|
||||
void BuiltinEditorDocumentProcessor::onParserFinished(CPlusPlus::Document::Ptr document,
|
||||
CPlusPlus::Snapshot snapshot)
|
||||
{
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
CPlusPlus::Snapshot snapshot() override;
|
||||
bool isParserRunning() const override;
|
||||
|
||||
QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms) override;
|
||||
|
||||
private:
|
||||
void onParserFinished(CPlusPlus::Document::Ptr document, CPlusPlus::Snapshot snapshot);
|
||||
void onSemanticInfoUpdated(const CppTools::SemanticInfo semanticInfo);
|
||||
|
||||
69
src/plugins/cpptools/cppcursorinfo.h
Normal file
69
src/plugins/cpptools/cppcursorinfo.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpptools_global.h"
|
||||
|
||||
#include "cppsemanticinfo.h"
|
||||
|
||||
#include <QTextCursor>
|
||||
#include <QVector>
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
class CPPTOOLS_EXPORT CursorInfoParams
|
||||
{
|
||||
public:
|
||||
CppTools::SemanticInfo semanticInfo;
|
||||
QTextCursor textCursor;
|
||||
};
|
||||
|
||||
class CPPTOOLS_EXPORT CursorInfo
|
||||
{
|
||||
public:
|
||||
struct Range {
|
||||
Range() = default;
|
||||
Range(unsigned line, unsigned column, unsigned length)
|
||||
: line(line)
|
||||
, column(column)
|
||||
, length(length)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned line = 0; // 1-based
|
||||
unsigned column = 0; // 1-based
|
||||
unsigned length = 0;
|
||||
};
|
||||
using Ranges = QVector<Range>;
|
||||
|
||||
Ranges useRanges;
|
||||
bool areUseRangesForLocalVariable = false;
|
||||
|
||||
Ranges unusedVariablesRanges;
|
||||
SemanticInfo::LocalUseMap localUses;
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
@@ -6,6 +6,7 @@ HEADERS += \
|
||||
abstracteditorsupport.h \
|
||||
baseeditordocumentparser.h \
|
||||
baseeditordocumentprocessor.h \
|
||||
builtincursorinfo.h \
|
||||
builtineditordocumentparser.h \
|
||||
builtineditordocumentprocessor.h \
|
||||
builtinindexingsupport.h \
|
||||
@@ -26,6 +27,7 @@ HEADERS += \
|
||||
cppcompletionassist.h \
|
||||
cppcompletionassistprocessor.h \
|
||||
cppcompletionassistprovider.h \
|
||||
cppcursorinfo.h \
|
||||
cppcurrentdocumentfilter.h \
|
||||
cppeditoroutline.h \
|
||||
cppdoxygen.h \
|
||||
@@ -90,6 +92,7 @@ SOURCES += \
|
||||
abstracteditorsupport.cpp \
|
||||
baseeditordocumentparser.cpp \
|
||||
baseeditordocumentprocessor.cpp \
|
||||
builtincursorinfo.cpp \
|
||||
builtineditordocumentparser.cpp \
|
||||
builtineditordocumentprocessor.cpp \
|
||||
builtinindexingsupport.cpp \
|
||||
|
||||
@@ -40,6 +40,8 @@ Project {
|
||||
"builtineditordocumentprocessor.h",
|
||||
"builtinindexingsupport.cpp",
|
||||
"builtinindexingsupport.h",
|
||||
"builtincursorinfo.cpp",
|
||||
"builtincursorinfo.h",
|
||||
"clangcompileroptionsbuilder.cpp",
|
||||
"clangcompileroptionsbuilder.h",
|
||||
"clangdiagnosticconfig.cpp",
|
||||
@@ -81,6 +83,7 @@ Project {
|
||||
"cppcompletionassistprocessor.h",
|
||||
"cppcompletionassistprovider.cpp",
|
||||
"cppcompletionassistprovider.h",
|
||||
"cppcursorinfo.h",
|
||||
"cppcurrentdocumentfilter.cpp",
|
||||
"cppcurrentdocumentfilter.h",
|
||||
"cppdoxygen.cpp",
|
||||
|
||||
Reference in New Issue
Block a user