Clang: send function name position for completion

... to reuse this position in backend (instead of
searching the function start again)

Change-Id: I02818dce4fc37ed6e7ecfb533191dbfe60610204
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2017-08-10 10:24:54 +02:00
parent cffcba67bf
commit d809e3fb8f
7 changed files with 78 additions and 25 deletions

View File

@@ -933,9 +933,12 @@ void IpcCommunicator::completeCode(ClangCompletionAssistProcessor *assistProcess
const QString &filePath, const QString &filePath,
quint32 line, quint32 line,
quint32 column, quint32 column,
const QString &projectFilePath) const QString &projectFilePath,
qint32 funcNameStartLine,
qint32 funcNameStartColumn)
{ {
const CompleteCodeMessage message(filePath, line, column, projectFilePath); const CompleteCodeMessage message(filePath, line, column, projectFilePath, funcNameStartLine,
funcNameStartColumn);
m_ipcSender->completeCode(message); m_ipcSender->completeCode(message);
m_ipcReceiver.addExpectedCodeCompletedMessage(message.ticketNumber(), assistProcessor); m_ipcReceiver.addExpectedCodeCompletedMessage(message.ticketNumber(), assistProcessor);
} }

View File

@@ -174,7 +174,9 @@ public:
void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath, void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath,
quint32 line, quint32 line,
quint32 column, quint32 column,
const QString &projectFilePath); const QString &projectFilePath,
qint32 funcNameStartLine = -1,
qint32 funcNameStartColumn = -1);
void registerProjectsParts(const QVector<CppTools::ProjectPart::Ptr> projectParts); void registerProjectsParts(const QVector<CppTools::ProjectPart::Ptr> projectParts);

View File

@@ -253,7 +253,8 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
} }
case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: { case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: {
m_sentRequestType = FunctionHintCompletion; m_sentRequestType = FunctionHintCompletion;
const bool requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray()); const bool requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(),
analyzer.functionNameStart());
setPerformWasApplicable(requestSent); setPerformWasApplicable(requestSent);
break; break;
} }
@@ -548,14 +549,26 @@ void setLastCompletionPosition(const QString &filePath,
} }
bool ClangCompletionAssistProcessor::sendCompletionRequest(int position, ClangCompletionAssistProcessor::Position
const QByteArray &customFileContent) ClangCompletionAssistProcessor::extractLineColumn(int position)
{ {
int line, column; if (position < 0)
TextEditor::Convenience::convertPosition(m_interface->textDocument(), position, &line, &column); return {-1, -1};
int line = -1, column = -1;
TextEditor::Convenience::convertPosition(m_interface->textDocument(),
position,
&line,
&column);
const QTextBlock block = m_interface->textDocument()->findBlock(position); const QTextBlock block = m_interface->textDocument()->findBlock(position);
column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column) + 1; column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column) + 1;
return {line, column};
}
bool ClangCompletionAssistProcessor::sendCompletionRequest(int position,
const QByteArray &customFileContent,
int functionNameStartPosition)
{
const QString filePath = m_interface->fileName(); const QString filePath = m_interface->fileName();
auto &ipcCommunicator = m_interface->ipcCommunicator(); auto &ipcCommunicator = m_interface->ipcCommunicator();
@@ -567,8 +580,12 @@ bool ClangCompletionAssistProcessor::sendCompletionRequest(int position,
setLastDocumentRevision(filePath); setLastDocumentRevision(filePath);
} }
const Position cursorPosition = extractLineColumn(position);
const Position functionNameStart = extractLineColumn(functionNameStartPosition);
const QString projectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath); const QString projectPartId = CppTools::CppToolsBridge::projectPartIdForFile(filePath);
ipcCommunicator.completeCode(this, filePath, uint(line), uint(column), projectPartId); ipcCommunicator.completeCode(this, filePath, uint(cursorPosition.line),
uint(cursorPosition.column), projectPartId,
functionNameStart.line, functionNameStart.column);
setLastCompletionPosition(filePath, position); setLastCompletionPosition(filePath, position);
return true; return true;
} }

View File

@@ -82,9 +82,14 @@ private:
UnsavedFileContentInfo unsavedFileContent(const QByteArray &customFileContent) const; UnsavedFileContentInfo unsavedFileContent(const QByteArray &customFileContent) const;
void sendFileContent(const QByteArray &customFileContent); void sendFileContent(const QByteArray &customFileContent);
bool sendCompletionRequest(int position, const QByteArray &customFileContent); bool sendCompletionRequest(int position,
const QByteArray &customFileContent,
int functionNameStartPosition = -1);
private: private:
struct Position { int line; int column; };
Position extractLineColumn(int position);
QScopedPointer<const ClangCompletionAssistInterface> m_interface; QScopedPointer<const ClangCompletionAssistInterface> m_interface;
unsigned m_completionOperator; unsigned m_completionOperator;
enum CompletionRequestType { NormalCompletion, FunctionHintCompletion } m_sentRequestType; enum CompletionRequestType { NormalCompletion, FunctionHintCompletion } m_sentRequestType;

View File

@@ -91,7 +91,7 @@ void ClangCompletionContextAnalyzer::analyze()
} }
} }
bool ClangCompletionContextAnalyzer::looksLikeAFunctionCall(int endOfOperator) const int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const
{ {
int index = ActivationSequenceContextProcessor::skipPrecedingWhitespace(m_interface, int index = ActivationSequenceContextProcessor::skipPrecedingWhitespace(m_interface,
endOfOperator); endOfOperator);
@@ -104,22 +104,24 @@ bool ClangCompletionContextAnalyzer::looksLikeAFunctionCall(int endOfOperator) c
const int functionNameStart = ActivationSequenceContextProcessor::findStartOfName(m_interface, const int functionNameStart = ActivationSequenceContextProcessor::findStartOfName(m_interface,
index); index);
if (functionNameStart == -1) if (functionNameStart == -1)
return false; return -1;
QTextCursor functionNameSelector(m_interface->textDocument()); QTextCursor functionNameSelector(m_interface->textDocument());
functionNameSelector.setPosition(functionNameStart); functionNameSelector.setPosition(functionNameStart);
functionNameSelector.setPosition(index, QTextCursor::KeepAnchor); functionNameSelector.setPosition(index, QTextCursor::KeepAnchor);
const QString functionName = functionNameSelector.selectedText().trimmed(); const QString functionName = functionNameSelector.selectedText().trimmed();
return !functionName.isEmpty(); return functionName.isEmpty() ? -1 : functionNameStart;
} }
void ClangCompletionContextAnalyzer::setActionAndClangPosition(CompletionAction action, void ClangCompletionContextAnalyzer::setActionAndClangPosition(CompletionAction action,
int position) int position,
int functionNameStart)
{ {
QTC_CHECK(position >= -1); QTC_CHECK(position >= -1);
m_completionAction = action; m_completionAction = action;
m_positionForClang = position; m_positionForClang = position;
m_functionNameStart = functionNameStart;
} }
void void
@@ -157,18 +159,22 @@ void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPositio
// No function completion if cursor is not after '(' or ',' // No function completion if cursor is not after '(' or ','
m_positionForProposal = afterOperatorPosition; m_positionForProposal = afterOperatorPosition;
setActionAndClangPosition(PassThroughToLibClang, afterOperatorPosition); setActionAndClangPosition(PassThroughToLibClang, afterOperatorPosition);
} else if (looksLikeAFunctionCall(afterOperatorPosition)) { } else {
const int functionNameStart = startOfFunctionCall(afterOperatorPosition);
if (functionNameStart >= 0) {
// Always pass the position right after '(' to libclang because // Always pass the position right after '(' to libclang because
// positions after the comma might be problematic if a preceding // positions after the comma might be problematic if a preceding
// argument is invalid code. // argument is invalid code.
setActionAndClangPosition(PassThroughToLibClangAfterLeftParen, setActionAndClangPosition(PassThroughToLibClangAfterLeftParen,
m_positionForProposal); m_positionForProposal,
functionNameStart);
} else { // e.g. "(" without any function name in front } else { // e.g. "(" without any function name in front
m_positionForProposal = afterOperatorPosition; m_positionForProposal = afterOperatorPosition;
setActionAndClangPosition(PassThroughToLibClang, afterOperatorPosition); setActionAndClangPosition(PassThroughToLibClang, afterOperatorPosition);
} }
} }
} }
}
bool ClangCompletionContextAnalyzer::handleNonFunctionCall(int position) bool ClangCompletionContextAnalyzer::handleNonFunctionCall(int position)
{ {

View File

@@ -56,14 +56,17 @@ public:
unsigned completionOperator() const { return m_completionOperator; } unsigned completionOperator() const { return m_completionOperator; }
int positionForProposal() const { return m_positionForProposal; } int positionForProposal() const { return m_positionForProposal; }
int positionForClang() const { return m_positionForClang; } int positionForClang() const { return m_positionForClang; }
int functionNameStart() const { return m_functionNameStart; }
int positionEndOfExpression() const { return m_positionEndOfExpression; } int positionEndOfExpression() const { return m_positionEndOfExpression; }
private: private:
ClangCompletionContextAnalyzer(); ClangCompletionContextAnalyzer();
bool looksLikeAFunctionCall(int endOfExpression) const; int startOfFunctionCall(int endOfExpression) const;
void setActionAndClangPosition(CompletionAction action, int position); void setActionAndClangPosition(CompletionAction action,
int position,
int functionNameStart = -1);
void setAction(CompletionAction action); void setAction(CompletionAction action);
bool handleNonFunctionCall(int position); bool handleNonFunctionCall(int position);
@@ -79,6 +82,7 @@ private:
CPlusPlus::Kind m_completionOperator = CPlusPlus::T_EOF_SYMBOL; CPlusPlus::Kind m_completionOperator = CPlusPlus::T_EOF_SYMBOL;
int m_positionForProposal = -1; int m_positionForProposal = -1;
int m_positionForClang = -1; int m_positionForClang = -1;
int m_functionNameStart = -1;
int m_positionEndOfExpression = -1; int m_positionEndOfExpression = -1;
}; };

View File

@@ -497,4 +497,20 @@ TEST_F(ClangCompletionContextAnalyzer, TemplatedFunctionSecondArgument)
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText)); ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText));
} }
TEST_F(ClangCompletionContextAnalyzer, FunctionNameStartPosition)
{
auto analyzer = runAnalyzer(" f<Bar>(1, @");
int functionNameStartPosition = analyzer.functionNameStart();
ASSERT_THAT(functionNameStartPosition, 1);
}
TEST_F(ClangCompletionContextAnalyzer, QualifiedFunctionNameStartPosition)
{
auto analyzer = runAnalyzer(" Namespace::f<Bar>(1, @");
int functionNameStartPosition = analyzer.functionNameStart();
ASSERT_THAT(functionNameStartPosition, 1);
}
} }