forked from qt-creator/qt-creator
CppEditor: Fix looking up containing function for search result
- Move look-up to CplusPlus::FindUsages, where we are guaranteed that
we actually have the document source.
- Use the same straightforward algorithm as with clangd.
- Undo the changes to CppDocument::functionAt(), which broke
the autotest.
Amends 6f7e7980d2
.
Change-Id: I008d05ba41a3b63b71e3131d7021e0d4e7d0641f
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -96,86 +96,6 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainingFunctionAt: protected SymbolVisitor
|
|
||||||
{
|
|
||||||
TranslationUnit *translationUnit;
|
|
||||||
Symbol *root;
|
|
||||||
int line;
|
|
||||||
int column;
|
|
||||||
Symbol *functionSymbol;
|
|
||||||
bool foundFunction;
|
|
||||||
bool foundBlock;
|
|
||||||
|
|
||||||
bool scopeContains(Scope* scope, int line, int column){
|
|
||||||
if (!scope)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int scopeStartLine{-1}, scopeStartColumn{-1}, scopeEndLine{-1}, scopeEndColumn{-1};
|
|
||||||
translationUnit->getPosition(scope->startOffset(), &scopeStartLine, &scopeStartColumn);
|
|
||||||
translationUnit->getPosition(scope->endOffset(), &scopeEndLine, &scopeEndColumn);
|
|
||||||
|
|
||||||
if (line < scopeStartLine || line > scopeEndLine)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (line > scopeStartLine && line < scopeEndLine)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (scopeStartLine == line && column >= scopeStartColumn)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (scopeEndLine == line && column <= scopeEndColumn)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ContainingFunctionAt(TranslationUnit *unit, Symbol *root)
|
|
||||||
: translationUnit(unit), root(root), line(0), column(0), functionSymbol(nullptr)
|
|
||||||
, foundFunction(false), foundBlock(false) {}
|
|
||||||
|
|
||||||
Symbol *operator()(int line, int column)
|
|
||||||
{
|
|
||||||
this->line = line;
|
|
||||||
this->column = column;
|
|
||||||
this->functionSymbol = nullptr;
|
|
||||||
accept(root);
|
|
||||||
|
|
||||||
return foundBlock ? functionSymbol : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool preVisit(Symbol *s) final
|
|
||||||
{
|
|
||||||
if (foundBlock)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (foundFunction) {
|
|
||||||
auto block = s->asBlock();
|
|
||||||
if (!block)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (scopeContains(block->asScope(), line, column)) {
|
|
||||||
foundBlock = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto asFunction = s->asFunction();
|
|
||||||
if (asFunction) {
|
|
||||||
if (s->line() < line || (s->line() == line && s->column() <= column)) {
|
|
||||||
foundFunction = scopeContains(s->asScope(), line, column);
|
|
||||||
if (foundFunction)
|
|
||||||
functionSymbol = asFunction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FindScopeAt: protected SymbolVisitor
|
class FindScopeAt: protected SymbolVisitor
|
||||||
{
|
{
|
||||||
TranslationUnit *_unit;
|
TranslationUnit *_unit;
|
||||||
@@ -592,11 +512,19 @@ QString Document::functionAt(int line, int column, int *lineOpeningDeclaratorPar
|
|||||||
if (line < 1 || column < 1)
|
if (line < 1 || column < 1)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
Symbol *symbol = ContainingFunctionAt{translationUnit(), globalNamespace()}(line, column);
|
Symbol *symbol = lastVisibleSymbolAt(line, column);
|
||||||
if (!symbol)
|
if (!symbol)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
|
// Find the enclosing function scope (which might be several levels up, or we might be standing
|
||||||
|
// on it)
|
||||||
Scope *scope = symbol->asScope();
|
Scope *scope = symbol->asScope();
|
||||||
|
if (!scope)
|
||||||
|
scope = symbol->enclosingScope();
|
||||||
|
|
||||||
|
while (scope && !scope->isFunction() )
|
||||||
|
scope = scope->enclosingScope();
|
||||||
|
|
||||||
if (!scope)
|
if (!scope)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
|
@@ -142,11 +142,30 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &cand
|
|||||||
const int len = tk.utf16chars();
|
const int len = tk.utf16chars();
|
||||||
|
|
||||||
const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText,
|
const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText,
|
||||||
getType(line, col, tokenIndex), line, col - 1, len);
|
getContainingFunction(line, col), getType(line, col, tokenIndex),
|
||||||
|
line, col - 1, len);
|
||||||
_usages.append(u);
|
_usages.append(u);
|
||||||
_references.append(tokenIndex);
|
_references.append(tokenIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString FindUsages::getContainingFunction(int line, int column)
|
||||||
|
{
|
||||||
|
const QList<AST *> astPath = ASTPath(_doc)(line, column);
|
||||||
|
bool hasBlock = false;
|
||||||
|
for (auto it = astPath.crbegin(); it != astPath.crend(); ++it) {
|
||||||
|
if (!hasBlock && (*it)->asCompoundStatement())
|
||||||
|
hasBlock = true;
|
||||||
|
if (const auto func = (*it)->asFunctionDefinition()) {
|
||||||
|
if (!hasBlock)
|
||||||
|
return {};
|
||||||
|
if (!func->symbol)
|
||||||
|
return {};
|
||||||
|
return Overview().prettyName(func->symbol->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
class FindUsages::GetUsageType
|
class FindUsages::GetUsageType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@@ -42,11 +42,14 @@ public:
|
|||||||
enum class Type { Declaration, Initialization, Read, Write, WritableRef, Other };
|
enum class Type { Declaration, Initialization, Read, Write, WritableRef, Other };
|
||||||
|
|
||||||
Usage() = default;
|
Usage() = default;
|
||||||
Usage(const Utils::FilePath &path, const QString &lineText, Type t, int line, int col, int len)
|
Usage(const Utils::FilePath &path, const QString &lineText, const QString &func, Type t,
|
||||||
: path(path), lineText(lineText), type(t), line(line), col(col), len(len) {}
|
int line, int col, int len)
|
||||||
|
: path(path), lineText(lineText), containingFunction(func), type(t),
|
||||||
|
line(line), col(col), len(len) {}
|
||||||
|
|
||||||
Utils::FilePath path;
|
Utils::FilePath path;
|
||||||
QString lineText;
|
QString lineText;
|
||||||
|
QString containingFunction;
|
||||||
Type type = Type::Other;
|
Type type = Type::Other;
|
||||||
int line = 0;
|
int line = 0;
|
||||||
int col = 0;
|
int col = 0;
|
||||||
@@ -75,6 +78,7 @@ protected:
|
|||||||
void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr);
|
void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr);
|
||||||
void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates);
|
void reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates);
|
||||||
Usage::Type getType(int line, int column, int tokenIndex);
|
Usage::Type getType(int line, int column, int tokenIndex);
|
||||||
|
QString getContainingFunction(int line, int column);
|
||||||
|
|
||||||
bool checkCandidates(const QList<LookupItem> &candidates) const;
|
bool checkCandidates(const QList<LookupItem> &candidates) const;
|
||||||
void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr);
|
void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr);
|
||||||
|
@@ -632,25 +632,6 @@ CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParamete
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::optional<QString> getContainingFunctionName(const Utils::FilePath &fileName,
|
|
||||||
int line,
|
|
||||||
int column)
|
|
||||||
{
|
|
||||||
const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot();
|
|
||||||
auto document = snapshot.document(fileName);
|
|
||||||
|
|
||||||
// context properties need lookup inside function scope, and thus require a full check
|
|
||||||
CPlusPlus::Document::Ptr localDoc = document;
|
|
||||||
if (document->checkMode() != CPlusPlus::Document::FullCheck) {
|
|
||||||
localDoc = snapshot.documentFromSource(document->utf8Source(), document->fileName());
|
|
||||||
localDoc->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto funcName = localDoc->functionAt(line, column);
|
|
||||||
|
|
||||||
return funcName.size() ? Utils::make_optional(funcName) : Utils::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void displayResults(SearchResult *search,
|
static void displayResults(SearchResult *search,
|
||||||
QFutureWatcher<CPlusPlus::Usage> *watcher,
|
QFutureWatcher<CPlusPlus::Usage> *watcher,
|
||||||
int first,
|
int first,
|
||||||
@@ -665,24 +646,11 @@ static void displayResults(SearchResult *search,
|
|||||||
item.setMainRange(result.line, result.col, result.len);
|
item.setMainRange(result.line, result.col, result.len);
|
||||||
item.setLineText(result.lineText);
|
item.setLineText(result.lineText);
|
||||||
item.setUserData(int(result.type));
|
item.setUserData(int(result.type));
|
||||||
|
item.setContainingFunctionName(result.containingFunction);
|
||||||
item.setStyle(colorStyleForUsageType(result.type));
|
item.setStyle(colorStyleForUsageType(result.type));
|
||||||
item.setUseTextEditorFont(true);
|
item.setUseTextEditorFont(true);
|
||||||
if (search->supportsReplace())
|
if (search->supportsReplace())
|
||||||
item.setSelectForReplacement(SessionManager::projectForFile(result.path));
|
item.setSelectForReplacement(SessionManager::projectForFile(result.path));
|
||||||
|
|
||||||
// In case we're looking for a function, we need to look at the symbol near the end. This
|
|
||||||
// is needed to avoid following corner-cases:
|
|
||||||
// 1) if we're looking at the beginning of the function declaration, we can get the
|
|
||||||
// declaration of the previous function
|
|
||||||
// 2) if we're looking somewhere at the middle of the function declaration, we can still
|
|
||||||
// get the declaration of the previous function if the cursor is located at the
|
|
||||||
// namespace declaration, i.e. CppReference>|<s::findUsages
|
|
||||||
|
|
||||||
const auto containingFunctionName = getContainingFunctionName(result.path,
|
|
||||||
result.line,
|
|
||||||
(result.col + result.len) - 1);
|
|
||||||
|
|
||||||
item.setContainingFunctionName(containingFunctionName);
|
|
||||||
search->addResult(item);
|
search->addResult(item);
|
||||||
|
|
||||||
if (parameters.prettySymbolName.isEmpty())
|
if (parameters.prettySymbolName.isEmpty())
|
||||||
@@ -777,7 +745,7 @@ restart_search:
|
|||||||
if (macro.name() == useMacro.name()) {
|
if (macro.name() == useMacro.name()) {
|
||||||
unsigned column;
|
unsigned column;
|
||||||
const QString &lineSource = matchingLine(use.bytesBegin(), source, &column);
|
const QString &lineSource = matchingLine(use.bytesBegin(), source, &column);
|
||||||
usages.append(CPlusPlus::Usage(fileName, lineSource,
|
usages.append(CPlusPlus::Usage(fileName, lineSource, {},
|
||||||
CPlusPlus::Usage::Type::Other, use.beginLine(),
|
CPlusPlus::Usage::Type::Other, use.beginLine(),
|
||||||
column, useMacro.nameToQString().size()));
|
column, useMacro.nameToQString().size()));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user