Commit 805c3f7a authored by Sergey Kalinichev's avatar Sergey Kalinichev

Fix '.' to '->' member access replacement

Clang doesn't provide diagnostic for it. So let't try to
manually determine whether this is the case, this is not so hard
after all.

This also means that now we use clang_codeCompleteAt twice, but
it doesn't matter much here as the input is already invalid,
hence no completion items.

REVIEW: 125305
parent 194d8feb
......@@ -642,7 +642,7 @@ public slots:
auto cursor = activeView->cursorPosition();
QString oldAccess, newAccess;
if (type == DotToArrow) {
if (type == ArrowToDot) {
oldAccess = QStringLiteral("->");
newAccess = QStringLiteral(".");
} else {
......@@ -651,6 +651,14 @@ public slots:
}
auto oldRange = KTextEditor::Range(cursor - KTextEditor::Cursor(0, oldAccess.length()), cursor);
// This code needed for testReplaceMemberAccess test
// Maybe we should do a similar thing for '->' to '.' direction, but this is not so important
while (textDocument->text(oldRange) == QLatin1String(" ") && oldRange.start().column() >= 0) {
oldRange = KTextEditor::Range({oldRange.start().line(), oldRange.start().column() - 1},
{oldRange.end().line(), oldRange.end().column() - 1});
}
if (oldRange.start().column() >= 0 && textDocument->text(oldRange) == oldAccess) {
textDocument->replaceText(oldRange, newAccess);
}
......@@ -668,9 +676,10 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text
const QString& text,
const QString& followingText
)
: CodeCompletionContext(context, text, CursorInRevision::castFromSimpleCursor(position), 0)
: CodeCompletionContext(context, text + followingText, CursorInRevision::castFromSimpleCursor(position), 0)
, m_results(nullptr, clang_disposeCodeCompleteResults)
, m_parseSessionData(sessionData)
{
......@@ -704,9 +713,9 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
if (diagnosticType == ClangDiagnosticEvaluator::ReplaceWithArrowProblem || diagnosticType == ClangDiagnosticEvaluator::ReplaceWithDotProblem) {
MemberAccessReplacer::Type replacementType;
if (diagnosticType == ClangDiagnosticEvaluator::ReplaceWithDotProblem) {
replacementType = MemberAccessReplacer::DotToArrow;
} else {
replacementType = MemberAccessReplacer::ArrowToDot;
} else {
replacementType = MemberAccessReplacer::DotToArrow;
}
QMetaObject::invokeMethod(&s_memberAccessReplacer, "replaceCurrentAccess", Qt::QueuedConnection,
......@@ -723,6 +732,35 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
}
}
if (!m_results->NumResults) {
const auto trimmedText = text.trimmed();
if (trimmedText.endsWith(QLatin1Char('.'))) {
// TODO: This shouldn't be needed if Clang provided diagnostic.
// But it doesn't always do it, so let's try to manually determine whether '.' is used instead of '->'
m_text = trimmedText.left(trimmedText.size() - 1);
m_text += QStringLiteral("->");
CXUnsavedFile unsaved;
unsaved.Filename = file.constData();
const QByteArray content = m_text.toUtf8();
unsaved.Contents = content.constData();
unsaved.Length = content.size() + 1;
m_results.reset(clang_codeCompleteAt(session.unit(), file.constData(),
position.line() + 1, position.column() + 1,
&unsaved, 1,
clang_defaultCodeCompleteOptions()));
if (m_results && m_results->NumResults) {
QMetaObject::invokeMethod(&s_memberAccessReplacer, "replaceCurrentAccess", Qt::QueuedConnection,
Q_ARG(MemberAccessReplacer::Type, MemberAccessReplacer::DotToArrow));
}
m_valid = false;
return;
}
}
// check 'isValidPosition' after parsing the new content
auto clangFile = session.file(file);
if (!isValidPosition(session.unit(), clangFile)) {
......
......@@ -49,7 +49,8 @@ public:
const ParseSessionData::Ptr& sessionData,
const QUrl& url,
const KTextEditor::Cursor& position,
const QString& text);
const QString& text,
const QString& followingText = {});
~ClangCodeCompletionContext();
virtual QList<KDevelop::CompletionTreeItemPointer> completionItems(bool& abort, bool fullCompletion = true) override;
......
......@@ -71,7 +71,7 @@ QSharedPointer<CodeCompletionContext> createCompletionContext(const DUContextPoi
if (includePathCompletionRequired(text)) {
return QSharedPointer<IncludePathCompletionContext>::create(context, session, url, position, text);
} else {
return QSharedPointer<ClangCodeCompletionContext>::create(context, session, url, position, text + followingText);
return QSharedPointer<ClangCodeCompletionContext>::create(context, session, url, position, text, followingText);
}
}
......
......@@ -226,7 +226,7 @@ void executeMemberAccessReplacerTest(const QString& code, const CompletionItems&
lock.unlock();
auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), expectedCompletionItems.position, QString());
auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), expectedCompletionItems.position, code);
QApplication::processEvents();
document->close(KDevelop::IDocument::Silent);
......@@ -237,7 +237,6 @@ void executeMemberAccessReplacerTest(const QString& code, const CompletionItems&
auto tester = ClangCodeCompletionItemTester(QExplicitlySharedDataPointer<ClangCodeCompletionContext>(context));
tester.names.sort();
QEXPECT_FAIL("replace dot to arrow", "Clang doesn't provide the diagnostic when '.' used instead of '->'", Continue);
QCOMPARE(tester.names, expectedCompletionItems.completions);
}
......@@ -480,8 +479,8 @@ void TestCodeCompletion::testReplaceMemberAccess_data()
QTest::newRow("replace dot to arrow")
<< "struct Struct { void function(); };"
"int main() { Struct* s; \ns. "
<< CompletionItems{{1, 2}, {
"int main() { Struct* s; \ns. "
<< CompletionItems{{1, 3}, {
"function"
}};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment