ClangCodeModel: Another clangd cursor adjustment

This time for the case where we are after the last character of a
function call argument.

Fixes: QTCREATORBUG-26638
Change-Id: I634fa91e87103a7ae82e3a43246dfbc7069dbbdc
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Christian Kandeler
2021-12-07 11:40:13 +01:00
parent ca9742e2a1
commit 92e3eb722a

View File

@@ -2385,36 +2385,60 @@ QTextCursor ClangdClient::Private::adjustedCursor(const QTextCursor &cursor,
if (!cppDoc)
return cursor;
const QList<AST *> builtinAstPath = ASTPath(cppDoc)(cursor);
for (auto it = builtinAstPath.rbegin(); it != builtinAstPath.rend(); ++it) {
const MemberAccessAST * const memberAccess = (*it)->asMemberAccess();
if (!memberAccess)
continue;
const TranslationUnit * const tu = cppDoc->translationUnit();
switch (tu->tokenAt(memberAccess->access_token).kind()) {
case T_DOT:
break;
case T_ARROW: {
const Utils::optional<AstNode> clangdAst = astCache.get(doc);
if (!clangdAst)
return cursor;
const QList<AstNode> clangdAstPath = getAstPath(*clangdAst, Range(cursor));
for (auto it = clangdAstPath.rbegin(); it != clangdAstPath.rend(); ++it) {
if (it->detailIs("operator->") && it->arcanaContains("CXXMethod"))
return cursor;
}
break;
}
default:
return cursor;
}
int dotLine, dotColumn;
tu->getTokenPosition(memberAccess->access_token, &dotLine, &dotColumn);
const int dotPos = Utils::Text::positionInText(doc->document(), dotLine, dotColumn);
if (dotPos != cursor.position())
return cursor;
const TranslationUnit * const tu = cppDoc->translationUnit();
const auto posForToken = [doc, tu](int tok) {
int line, column;
tu->getTokenPosition(tok, &line, &column);
return Utils::Text::positionInText(doc->document(), line, column);
};
const auto leftMovedCursor = [cursor] {
QTextCursor c = cursor;
c.setPosition(cursor.position() - 1);
return c;
};
for (auto it = builtinAstPath.rbegin(); it != builtinAstPath.rend(); ++it) {
// s|.x or s|->x
if (const MemberAccessAST * const memberAccess = (*it)->asMemberAccess()) {
switch (tu->tokenAt(memberAccess->access_token).kind()) {
case T_DOT:
break;
case T_ARROW: {
const Utils::optional<AstNode> clangdAst = astCache.get(doc);
if (!clangdAst)
return cursor;
const QList<AstNode> clangdAstPath = getAstPath(*clangdAst, Range(cursor));
for (auto it = clangdAstPath.rbegin(); it != clangdAstPath.rend(); ++it) {
if (it->detailIs("operator->") && it->arcanaContains("CXXMethod"))
return cursor;
}
break;
}
default:
return cursor;
}
if (posForToken(memberAccess->access_token) != cursor.position())
return cursor;
return leftMovedCursor();
}
// f(arg1|, arg2)
if (const CallAST *const callAst = (*it)->asCall()) {
const int tok = builtinAstPath.last()->lastToken();
if (posForToken(tok) != cursor.position())
return cursor;
if (tok == callAst->rparen_token)
return leftMovedCursor();
if (tu->tokenKind(tok) != T_COMMA)
return cursor;
// Guard against edge case of overloaded comma operator.
for (auto list = callAst->expression_list; list; list = list->next) {
if (list->value->lastToken() == tok)
return leftMovedCursor();
}
return cursor;
}
}
return cursor;
}