CppEditor: Consider symbol occurrences in comments

... when renaming.
For local renaming, we consider only function parameters.

Task-number: QTCREATORBUG-12051
Change-Id: I7948d69f11b97663c9bd747ae6241a82dd9bdd82
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-08-23 17:26:02 +02:00
parent 164cb389dc
commit 0a058bb657
28 changed files with 525 additions and 86 deletions

View File

@@ -8,58 +8,35 @@
#include <cplusplus/Overview.h>
#include <utils/algorithm.h>
#include <utils/textutils.h>
#include <QRegularExpression>
#include <QStringList>
#include <QTextBlock>
#include <QTextDocument>
namespace CPlusPlus {
QList<Token> commentsForDeclaration(const Symbol *symbol, const Snapshot &snapshot,
const QTextDocument &textDoc)
static QString nameFromSymbol(const Symbol *symbol)
{
// Set up cpp document.
const Document::Ptr cppDoc = snapshot.preprocessedDocument(textDoc.toPlainText().toUtf8(),
symbol->filePath());
cppDoc->parse();
TranslationUnit * const tu = cppDoc->translationUnit();
if (!tu || !tu->isParsed())
const QStringList symbolParts = Overview().prettyName(symbol->name())
.split("::", Qt::SkipEmptyParts);
if (symbolParts.isEmpty())
return {};
return symbolParts.last();
}
// Find the symbol declaration's AST node.
// We stop at the last declaration node that precedes the symbol, except:
// - For parameter declarations, we just continue, because we are interested in the function.
// - If the declaration node is preceded directly by another one, we choose that one instead,
// because with nested declarations we want the outer one (e.g. templates).
int line, column;
tu->getTokenPosition(symbol->sourceLocation(), &line, &column);
const QList<AST *> astPath = ASTPath(cppDoc)(line, column);
if (astPath.isEmpty())
return {};
if (astPath.last()->firstToken() != symbol->sourceLocation())
return {};
const AST *declAst = nullptr;
bool needsSymbolReference = false;
bool isParameter = false;
for (auto it = std::next(std::rbegin(astPath)); it != std::rend(astPath); ++it) {
AST * const node = *it;
if (node->asParameterDeclaration()) {
needsSymbolReference = true;
isParameter = true;
continue;
}
if (node->asDeclaration()) {
declAst = node;
continue;
}
if (declAst)
break;
}
if (!declAst)
static QList<Token> commentsForDeclaration(
const AST *decl, const QString &symbolName, const QTextDocument &textDoc,
const Document::Ptr &cppDoc, bool isParameter)
{
if (symbolName.isEmpty())
return {};
// Get the list of all tokens (including comments) and find the declaration start token there.
const Token &declToken = tu->tokenAt(declAst->firstToken());
TranslationUnit * const tu = cppDoc->translationUnit();
QTC_ASSERT(tu && tu->isParsed(), return {});
const Token &declToken = tu->tokenAt(decl->firstToken());
std::vector<Token> allTokens = tu->allTokens();
QTC_ASSERT(!allTokens.empty(), return {});
int tokenPos = -1;
@@ -86,6 +63,7 @@ QList<Token> commentsForDeclaration(const Symbol *symbol, const Snapshot &snapsh
const auto blockForTokenEnd = [&](const Token &tok) {
return textDoc.findBlock(tu->getTokenEndPositionInDocument(tok, &textDoc));
};
bool needsSymbolReference = isParameter;
for (int i = tokenPos - 1; i >= 0; --i) {
const Token &tok = allTokens.at(i);
if (!tok.isComment())
@@ -127,7 +105,6 @@ QList<Token> commentsForDeclaration(const Symbol *symbol, const Snapshot &snapsh
return tokenList();
// b)
const QString symbolName = Overview().prettyName(symbol->name());
const Kind tokenKind = comments.first().token.kind();
const bool isDoxygenComment = tokenKind == T_DOXY_COMMENT || tokenKind == T_CPP_DOXY_COMMENT;
const QRegularExpression symbolRegExp(QString("%1\\b%2\\b").arg(
@@ -142,4 +119,57 @@ QList<Token> commentsForDeclaration(const Symbol *symbol, const Snapshot &snapsh
return {};
}
QList<Token> commentsForDeclaration(const Symbol *symbol, const QTextDocument &textDoc,
const Document::Ptr &cppDoc)
{
QTC_ASSERT(cppDoc->translationUnit() && cppDoc->translationUnit()->isParsed(), return {});
Utils::Text::Position pos;
cppDoc->translationUnit()->getTokenPosition(symbol->sourceLocation(), &pos.line, &pos.column);
--pos.column;
return commentsForDeclaration(nameFromSymbol(symbol), pos, textDoc, cppDoc);
}
QList<Token> commentsForDeclaration(const QString &symbolName, const Utils::Text::Position &pos,
const QTextDocument &textDoc, const Document::Ptr &cppDoc)
{
if (symbolName.isEmpty())
return {};
// Find the symbol declaration's AST node.
// We stop at the last declaration node that precedes the symbol, except:
// - For parameter declarations, we just continue, because we are interested in the function.
// - If the declaration node is preceded directly by another one, we choose that one instead,
// because with nested declarations we want the outer one (e.g. templates).
const QList<AST *> astPath = ASTPath(cppDoc)(pos.line, pos.column + 1);
if (astPath.isEmpty())
return {};
const AST *declAst = nullptr;
bool isParameter = false;
for (auto it = std::next(std::rbegin(astPath)); it != std::rend(astPath); ++it) {
AST * const node = *it;
if (node->asParameterDeclaration()) {
isParameter = true;
continue;
}
if (node->asDeclaration()) {
declAst = node;
continue;
}
if (declAst)
break;
}
if (!declAst)
return {};
return commentsForDeclaration(declAst, symbolName, textDoc, cppDoc, isParameter);
}
QList<Token> commentsForDeclaration(const Symbol *symbol, const AST *decl,
const QTextDocument &textDoc, const Document::Ptr &cppDoc)
{
return commentsForDeclaration(decl, nameFromSymbol(symbol), textDoc, cppDoc,
symbol->asArgument());
}
} // namespace CPlusPlus

View File

@@ -3,6 +3,7 @@
#pragma once
#include <cplusplus/CppDocument.h>
#include <cplusplus/Token.h>
#include <QList>
@@ -11,11 +12,24 @@ QT_BEGIN_NAMESPACE
class QTextDocument;
QT_END_NAMESPACE
namespace Utils { namespace Text { class Position; } }
namespace CPlusPlus {
class Snapshot;
class AST;
class Symbol;
QList<Token> CPLUSPLUS_EXPORT commentsForDeclaration(const Symbol *symbol,
const Snapshot &snapshot,
const QTextDocument &textDoc);
const QTextDocument &textDoc,
const Document::Ptr &cppDoc);
QList<Token> CPLUSPLUS_EXPORT commentsForDeclaration(const Symbol *symbol,
const AST *decl,
const QTextDocument &textDoc,
const Document::Ptr &cppDoc);
QList<Token> CPLUSPLUS_EXPORT commentsForDeclaration(const QString &symbolName,
const Utils::Text::Position &pos,
const QTextDocument &textDoc,
const Document::Ptr &cppDoc);
} // namespace CPlusPlus