Clang: Fix determining current parameter

...for emphasis in the function signature tooltip when doing function
completion.

Braces, brackets and less/greater were not considered so that arguments
containing initializer lists, lambda captures or templates could lead to
the emphasis of no or the wrong parameter:

  void foo(VariantType t1, VariantType t2);

  void g(int x, int y)
  {
      foo({1,2, // Ops, no parameter emphasized
      foo({1,2}, // Ops, no parameter emphasized

      foo([x, y](){}, // Ops, no parameter emphasized

      foo(Bar<int, // Ops, second parameter emphasized
      foo(Bar<int, int>, // Ops, no parameter emphasized
  }

Change-Id: I2515fcbd892850b608bd90b35dd348ae522144b2
Reviewed-by: Marco Bubke <marco.bubke@theqtcompany.com>
This commit is contained in:
Nikolai Kosjar
2015-12-09 18:23:31 +01:00
parent c0e1b1581b
commit f25b9cab14
2 changed files with 43 additions and 18 deletions

View File

@@ -41,7 +41,7 @@ using namespace CPlusPlus;
ClangFunctionHintModel::ClangFunctionHintModel(const ClangBackEnd::CodeCompletions &functionSymbols) ClangFunctionHintModel::ClangFunctionHintModel(const ClangBackEnd::CodeCompletions &functionSymbols)
: m_functionSymbols(functionSymbols) : m_functionSymbols(functionSymbols)
, m_currentArg(-1) , m_currentArgument(-1)
{ {
} }
@@ -58,34 +58,59 @@ QString ClangFunctionHintModel::text(int index) const
{ {
const ClangBackEnd::CodeCompletionChunks chunks = m_functionSymbols.at(index).chunks(); const ClangBackEnd::CodeCompletionChunks chunks = m_functionSymbols.at(index).chunks();
const QString signatureWithEmphasizedCurrentParameter const QString signatureWithEmphasizedCurrentParameter
= CompletionChunksToTextConverter::convertToFunctionSignature(chunks, m_currentArg + 1); = CompletionChunksToTextConverter::convertToFunctionSignature(chunks, m_currentArgument + 1);
return signatureWithEmphasizedCurrentParameter; return signatureWithEmphasizedCurrentParameter;
} }
int ClangFunctionHintModel::activeArgument(const QString &prefix) const int ClangFunctionHintModel::activeArgument(const QString &prefix) const
{ {
int argnr = 0; int activeArgumentNumber = 0;
int parcount = 0;
int unbalancedParens = 0; // expressions
int unbalancedBraces = 0; // initializer lists
int unbalancedBrackets = 0; // lambda-capture
int unbalancedLessGreater = 0; // template arguments
SimpleLexer tokenize; SimpleLexer tokenize;
Tokens tokens = tokenize(prefix); const Tokens tokens = tokenize(prefix);
for (int i = 0; i < tokens.count(); ++i) { for (const Token &token : tokens) {
const Token &tk = tokens.at(i); if (token.is(T_LPAREN)) {
if (tk.is(T_LPAREN)) ++unbalancedParens;
++parcount; } else if (token.is(T_RPAREN)) {
else if (tk.is(T_RPAREN)) --unbalancedParens;
--parcount; } else if (token.is(T_LBRACE)) {
else if (! parcount && tk.is(T_COMMA)) ++unbalancedBraces;
++argnr; } else if (token.is(T_RBRACE)) {
--unbalancedBraces;
} else if (token.is(T_LBRACKET)) {
++unbalancedBrackets;
} else if (token.is(T_RBRACKET)) {
--unbalancedBrackets;
} else if (token.is(T_LESS)) {
++unbalancedLessGreater;
} else if (token.is(T_GREATER)) {
--unbalancedLessGreater;
} else if (!unbalancedParens
&& !unbalancedBraces
&& !unbalancedBrackets
&& !unbalancedLessGreater
&& token.is(T_COMMA)) {
++activeArgumentNumber;
}
} }
if (parcount < 0) if (unbalancedParens < 0
|| unbalancedBraces < 0
|| unbalancedBrackets < 0
|| unbalancedLessGreater < 0) {
return -1; return -1;
}
if (argnr != m_currentArg) if (activeArgumentNumber != m_currentArgument)
m_currentArg = argnr; m_currentArgument = activeArgumentNumber;
return argnr; return activeArgumentNumber;
} }
} // namespace Internal } // namespace Internal

View File

@@ -50,7 +50,7 @@ public:
private: private:
ClangBackEnd::CodeCompletions m_functionSymbols; ClangBackEnd::CodeCompletions m_functionSymbols;
mutable int m_currentArg; mutable int m_currentArgument;
}; };
} // namespace Internal } // namespace Internal