forked from qt-creator/qt-creator
CppTools: Fix completing qt5 style signals/slots in connect()
* Fix qualifying the member function, take namespace into account * Fallback to usual completion if we cannot provide anything * Ensure that the completion is not triggered outside connect() calls * Change to a two step process: 1. connect(obj, & // offer class name completion 2. connect(obj, &N::Foo:: // offer signal completions ...same for the 4th. argument. Change-Id: Ifa4c74cde1b96ec7c544daaeefc47c4efdd8294a Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
f3a2795c3b
commit
21e9893b4b
@@ -2174,6 +2174,8 @@ void CppToolsPlugin::test_completion_data()
|
|||||||
"#define slots\n"
|
"#define slots\n"
|
||||||
"#define Q_OBJECT virtual const QMetaObject *metaObject() const;"
|
"#define Q_OBJECT virtual const QMetaObject *metaObject() const;"
|
||||||
"\n"
|
"\n"
|
||||||
|
"namespace N {\n"
|
||||||
|
"\n"
|
||||||
"class Base : public QObject\n"
|
"class Base : public QObject\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" Q_OBJECT\n"
|
" Q_OBJECT\n"
|
||||||
@@ -2204,9 +2206,11 @@ void CppToolsPlugin::test_completion_data()
|
|||||||
" void derivedSlot2(int newValue);\n"
|
" void derivedSlot2(int newValue);\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"} // namespace N\n"
|
||||||
|
"\n"
|
||||||
"void client()\n"
|
"void client()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" Derived *myObject = new Derived;\n"
|
" N::Derived *myObject = new N::Derived;\n"
|
||||||
" @\n"
|
" @\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
@@ -2227,33 +2231,60 @@ void CppToolsPlugin::test_completion_data()
|
|||||||
<< QLatin1String("derivedSlot1()")
|
<< QLatin1String("derivedSlot1()")
|
||||||
<< QLatin1String("derivedSlot2(int)"));
|
<< QLatin1String("derivedSlot2(int)"));
|
||||||
|
|
||||||
QTest::newRow("Qt5 signal")
|
QTest::newRow("Qt5 signals: complete class after & at 2nd connect arg")
|
||||||
<< commonSignalSlotCompletionTestCode
|
<< commonSignalSlotCompletionTestCode
|
||||||
<< _("connect(myObject, &") << (QStringList()
|
<< _("connect(myObject, &") << (QStringList()
|
||||||
<< QLatin1String("Base::baseSignal1")
|
<< QLatin1String("N::Derived"));
|
||||||
<< QLatin1String("Base::baseSignal2")
|
|
||||||
<< QLatin1String("Base::hiddenSignal")
|
|
||||||
<< QLatin1String("Derived::derivedSignal1")
|
|
||||||
<< QLatin1String("Derived::derivedSignal2")
|
|
||||||
<< QLatin1String("Derived::hiddenSignal")); // OK, hidden signal
|
|
||||||
|
|
||||||
QTest::newRow("Qt5 slot")
|
QTest::newRow("Qt5 signals: complete class after & at 4th connect arg")
|
||||||
<< commonSignalSlotCompletionTestCode
|
<< commonSignalSlotCompletionTestCode
|
||||||
<< _("connect(myObject, &MyObject::timeout, myObject, &") << (QStringList()
|
<< _("connect(myObject, &MyObject::timeout, myObject, &") << (QStringList()
|
||||||
<< QLatin1String("Base::baseSignal1")
|
<< QLatin1String("N::Derived"));
|
||||||
<< QLatin1String("Base::baseSignal2")
|
|
||||||
<< QLatin1String("Base::baseSlot1")
|
QTest::newRow("Qt5 signals: complete signals")
|
||||||
<< QLatin1String("Base::baseSlot2")
|
<< commonSignalSlotCompletionTestCode
|
||||||
<< QLatin1String("Base::baseFunction")
|
<< _("connect(myObject, &N::Derived::") << (QStringList()
|
||||||
<< QLatin1String("Base::hiddenFunction")
|
<< QLatin1String("baseSignal1")
|
||||||
<< QLatin1String("Base::hiddenSignal")
|
<< QLatin1String("baseSignal2")
|
||||||
<< QLatin1String("Derived::derivedFunction")
|
<< QLatin1String("hiddenSignal")
|
||||||
<< QLatin1String("Derived::derivedSignal1")
|
<< QLatin1String("derivedSignal1")
|
||||||
<< QLatin1String("Derived::derivedSignal2")
|
<< QLatin1String("derivedSignal2"));
|
||||||
<< QLatin1String("Derived::derivedSlot1")
|
|
||||||
<< QLatin1String("Derived::derivedSlot2")
|
QTest::newRow("Qt5 slots")
|
||||||
<< QLatin1String("Derived::hiddenFunction")
|
<< commonSignalSlotCompletionTestCode
|
||||||
<< QLatin1String("Derived::hiddenSignal"));
|
<< _("connect(myObject, &N::Derived, myObject, &N::Derived::") << (QStringList()
|
||||||
|
<< QLatin1String("baseFunction")
|
||||||
|
<< QLatin1String("baseSignal1")
|
||||||
|
<< QLatin1String("baseSignal2")
|
||||||
|
<< QLatin1String("baseSlot1")
|
||||||
|
<< QLatin1String("baseSlot2")
|
||||||
|
<< QLatin1String("derivedFunction")
|
||||||
|
<< QLatin1String("derivedSignal1")
|
||||||
|
<< QLatin1String("derivedSignal2")
|
||||||
|
<< QLatin1String("derivedSlot1")
|
||||||
|
<< QLatin1String("derivedSlot2")
|
||||||
|
<< QLatin1String("hiddenFunction")
|
||||||
|
<< QLatin1String("hiddenSignal"));
|
||||||
|
|
||||||
|
QTest::newRow("Qt5 signals: no class name completion if not after 'connect(' 1")
|
||||||
|
<< commonSignalSlotCompletionTestCode
|
||||||
|
<< _("foo(myObject, &") << (QStringList());
|
||||||
|
|
||||||
|
QTest::newRow("Qt5 signals/slots: no class name completion if not after 'connect(' 2")
|
||||||
|
<< commonSignalSlotCompletionTestCode
|
||||||
|
<< _("&") << (QStringList());
|
||||||
|
|
||||||
|
QTest::newRow("Qt5 signals: fallback to scope completion")
|
||||||
|
<< commonSignalSlotCompletionTestCode
|
||||||
|
<< _("connect(myObject, &N::") << (QStringList()
|
||||||
|
<< QLatin1String("Base")
|
||||||
|
<< QLatin1String("Derived"));
|
||||||
|
|
||||||
|
QTest::newRow("Qt5 slots: fallback to scope completion")
|
||||||
|
<< commonSignalSlotCompletionTestCode
|
||||||
|
<< _("connect(myObject, &N::Derived, myObject, &N::") << (QStringList()
|
||||||
|
<< QLatin1String("Base")
|
||||||
|
<< QLatin1String("Derived"));
|
||||||
|
|
||||||
QTest::newRow("signals_hide_QPrivateSignal") << _(
|
QTest::newRow("signals_hide_QPrivateSignal") << _(
|
||||||
"#define SIGNAL(a) #a\n"
|
"#define SIGNAL(a) #a\n"
|
||||||
|
@@ -615,15 +615,186 @@ QString createQt4SignalOrSlot(CPlusPlus::Function *function, const Overview &ove
|
|||||||
return QString::fromUtf8(normalized, normalized.size());
|
return QString::fromUtf8(normalized, normalized.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString createQt5SignalOrSlot(CPlusPlus::Function *function, Class *klass)
|
QString createQt5SignalOrSlot(CPlusPlus::Function *function, const Overview &overview)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += Overview().prettyName(klass->name());
|
text += overview.prettyName(function->name());
|
||||||
text += QLatin1String("::");
|
|
||||||
text += Overview().prettyName(function->name());
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class BackwardsEater
|
||||||
|
\brief Checks strings and expressions before given position.
|
||||||
|
|
||||||
|
Similar to BackwardsScanner, but also can handle expressions. Ignores whitespace.
|
||||||
|
*/
|
||||||
|
class BackwardsEater
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BackwardsEater(const CppCompletionAssistInterface *assistInterface, int position)
|
||||||
|
: m_position(position)
|
||||||
|
, m_assistInterface(assistInterface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPositionValid() const
|
||||||
|
{
|
||||||
|
return m_position >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eatConnectOpenParenthesis()
|
||||||
|
{
|
||||||
|
return eatString(QLatin1String("(")) && eatString(QLatin1String("connect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eatExpressionCommaAmpersand()
|
||||||
|
{
|
||||||
|
return eatString(QLatin1String("&")) && eatString(QLatin1String(",")) && eatExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eatConnectOpenParenthesisExpressionCommaAmpersandExpressionComma()
|
||||||
|
{
|
||||||
|
return eatString(QLatin1String(","))
|
||||||
|
&& eatExpression()
|
||||||
|
&& eatExpressionCommaAmpersand()
|
||||||
|
&& eatConnectOpenParenthesis();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool eatExpression()
|
||||||
|
{
|
||||||
|
if (!isPositionValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
maybeEatWhitespace();
|
||||||
|
|
||||||
|
QTextCursor cursor(m_assistInterface->textDocument());
|
||||||
|
cursor.setPosition(m_position + 1);
|
||||||
|
ExpressionUnderCursor expressionUnderCursor;
|
||||||
|
const QString expression = expressionUnderCursor(cursor);
|
||||||
|
if (expression.isEmpty())
|
||||||
|
return false;
|
||||||
|
m_position = m_position - expression.length();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eatString(const QString &string)
|
||||||
|
{
|
||||||
|
if (!isPositionValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (string.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
maybeEatWhitespace();
|
||||||
|
|
||||||
|
const int stringLength = string.length();
|
||||||
|
const int stringStart = m_position - (stringLength - 1);
|
||||||
|
|
||||||
|
if (stringStart < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_assistInterface->textAt(stringStart, stringLength) == string) {
|
||||||
|
m_position = stringStart - 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybeEatWhitespace()
|
||||||
|
{
|
||||||
|
while (isPositionValid() && m_assistInterface->characterAt(m_position).isSpace())
|
||||||
|
--m_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_position;
|
||||||
|
const CppCompletionAssistInterface * const m_assistInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool canCompleteConnectSignalAt2ndArgument(const CppCompletionAssistInterface *assistInterface,
|
||||||
|
int startOfExpression)
|
||||||
|
{
|
||||||
|
BackwardsEater eater(assistInterface, startOfExpression);
|
||||||
|
|
||||||
|
return eater.isPositionValid()
|
||||||
|
&& eater.eatExpressionCommaAmpersand()
|
||||||
|
&& eater.eatConnectOpenParenthesis();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canCompleteConnectSignalAt4thArgument(const CppCompletionAssistInterface *assistInterface,
|
||||||
|
int startPosition)
|
||||||
|
{
|
||||||
|
BackwardsEater eater(assistInterface, startPosition);
|
||||||
|
|
||||||
|
return eater.isPositionValid()
|
||||||
|
&& eater.eatExpressionCommaAmpersand()
|
||||||
|
&& eater.eatConnectOpenParenthesisExpressionCommaAmpersandExpressionComma();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canCompleteClassNameAt2ndOr4thConnectArgument(
|
||||||
|
const CppCompletionAssistInterface *assistInterface,
|
||||||
|
int startPosition)
|
||||||
|
{
|
||||||
|
BackwardsEater eater(assistInterface, startPosition);
|
||||||
|
|
||||||
|
if (!eater.isPositionValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return eater.eatConnectOpenParenthesis()
|
||||||
|
|| eater.eatConnectOpenParenthesisExpressionCommaAmpersandExpressionComma();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassOrNamespace *classOrNamespaceFromLookupItem(const LookupItem &lookupItem,
|
||||||
|
const LookupContext &context)
|
||||||
|
{
|
||||||
|
const Name *name = 0;
|
||||||
|
|
||||||
|
if (Symbol *d = lookupItem.declaration()) {
|
||||||
|
if (Class *k = d->asClass())
|
||||||
|
name = k->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
FullySpecifiedType type = lookupItem.type().simplified();
|
||||||
|
|
||||||
|
if (PointerType *pointerType = type->asPointerType())
|
||||||
|
type = pointerType->elementType().simplified();
|
||||||
|
else
|
||||||
|
return 0; // not a pointer or a reference to a pointer.
|
||||||
|
|
||||||
|
NamedType *namedType = type->asNamedType();
|
||||||
|
if (!namedType) // not a class name.
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
name = namedType->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
return name ? context.lookupType(name, lookupItem.scope()) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class *classFromLookupItem(const LookupItem &lookupItem, const LookupContext &context)
|
||||||
|
{
|
||||||
|
ClassOrNamespace *b = classOrNamespaceFromLookupItem(lookupItem, context);
|
||||||
|
if (!b)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
foreach (Symbol *s, b->symbols()) {
|
||||||
|
if (Class *klass = s->asClass())
|
||||||
|
return klass;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Name *minimalName(Symbol *symbol, Scope *targetScope, const LookupContext &context)
|
||||||
|
{
|
||||||
|
ClassOrNamespace *target = context.lookupType(targetScope);
|
||||||
|
if (!target)
|
||||||
|
target = context.globalNamespace();
|
||||||
|
return context.minimalName(symbol, target, context.bindings()->control().data());
|
||||||
|
}
|
||||||
|
|
||||||
} // Anonymous
|
} // Anonymous
|
||||||
|
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
@@ -807,10 +978,8 @@ int InternalCppCompletionAssistProcessor::startOfOperator(int pos,
|
|||||||
|
|
||||||
if (*kind == T_AMPER && tokenIdx > 0) {
|
if (*kind == T_AMPER && tokenIdx > 0) {
|
||||||
const Token &previousToken = tokens.at(tokenIdx - 1);
|
const Token &previousToken = tokens.at(tokenIdx - 1);
|
||||||
if (previousToken.kind() == T_COMMA) {
|
if (previousToken.kind() == T_COMMA)
|
||||||
start = pos - (tk.utf16charOffset - previousToken.utf16charOffset) - 1;
|
start = pos - (tk.utf16charOffset - previousToken.utf16charOffset) - 1;
|
||||||
QTC_CHECK(m_interface->characterAt(start) == QLatin1Char(','));
|
|
||||||
}
|
|
||||||
} else if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
|
} else if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
|
||||||
*kind = T_EOF_SYMBOL;
|
*kind = T_EOF_SYMBOL;
|
||||||
start = pos;
|
start = pos;
|
||||||
@@ -895,18 +1064,6 @@ int InternalCppCompletionAssistProcessor::findStartOfName(int pos) const
|
|||||||
return pos + 1;
|
return pos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isPrecededByConnectAndOpenParenthesis(
|
|
||||||
const CppCompletionAssistInterface *assistInterface,
|
|
||||||
int startOfExpression)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(startOfExpression >= 0, return false);
|
|
||||||
|
|
||||||
int beforeExpression = startOfExpression;
|
|
||||||
while (beforeExpression > 0 && assistInterface->characterAt(--beforeExpression).isSpace()) ;
|
|
||||||
const int pos = beforeExpression - 7;
|
|
||||||
return pos >= 0 && assistInterface->textAt(pos, 7) == QLatin1String("connect");
|
|
||||||
}
|
|
||||||
|
|
||||||
int InternalCppCompletionAssistProcessor::startCompletionHelper()
|
int InternalCppCompletionAssistProcessor::startCompletionHelper()
|
||||||
{
|
{
|
||||||
if (m_languageFeatures.objCEnabled) {
|
if (m_languageFeatures.objCEnabled) {
|
||||||
@@ -978,10 +1135,21 @@ int InternalCppCompletionAssistProcessor::startCompletionHelper()
|
|||||||
startOfExpression = endOfExpression - expression.length();
|
startOfExpression = endOfExpression - expression.length();
|
||||||
|
|
||||||
if (m_model->m_completionOperator == T_AMPER) {
|
if (m_model->m_completionOperator == T_AMPER) {
|
||||||
m_model->m_completionOperator
|
// We expect 'expression' to be either "sender" or "receiver" in
|
||||||
= isPrecededByConnectAndOpenParenthesis(m_interface.data(), startOfExpression)
|
// "connect(sender, &" or
|
||||||
? CompleteQt5SignalTrigger
|
// "connect(otherSender, &Foo::signal1, receiver, &"
|
||||||
: CompleteQtSlotTrigger;
|
const int beforeExpression = startOfExpression - 1;
|
||||||
|
if (canCompleteClassNameAt2ndOr4thConnectArgument(m_interface.data(), beforeExpression))
|
||||||
|
m_model->m_completionOperator = CompleteQt5SignalOrSlotClassNameTrigger;
|
||||||
|
} else if (m_model->m_completionOperator == T_COLON_COLON) {
|
||||||
|
// We expect 'expression' to be "Foo" in
|
||||||
|
// "connect(sender, &Foo::" or
|
||||||
|
// "connect(sender, &Bar::signal1, receiver, &Foo::"
|
||||||
|
const int beforeExpression = startOfExpression - 1;
|
||||||
|
if (canCompleteConnectSignalAt2ndArgument(m_interface.data(), beforeExpression))
|
||||||
|
m_model->m_completionOperator = CompleteQt5SignalTrigger;
|
||||||
|
else if (canCompleteConnectSignalAt4thArgument(m_interface.data(), beforeExpression))
|
||||||
|
m_model->m_completionOperator = CompleteQt5SlotTrigger;
|
||||||
} else if (m_model->m_completionOperator == T_LPAREN) {
|
} else if (m_model->m_completionOperator == T_LPAREN) {
|
||||||
if (expression.endsWith(QLatin1String("SIGNAL"))) {
|
if (expression.endsWith(QLatin1String("SIGNAL"))) {
|
||||||
m_model->m_completionOperator = T_SIGNAL;
|
m_model->m_completionOperator = T_SIGNAL;
|
||||||
@@ -1249,10 +1417,7 @@ int InternalCppCompletionAssistProcessor::startCompletionInternal(const QString
|
|||||||
if (expression.isEmpty()) {
|
if (expression.isEmpty()) {
|
||||||
if (m_model->m_completionOperator == T_EOF_SYMBOL || m_model->m_completionOperator == T_COLON_COLON) {
|
if (m_model->m_completionOperator == T_EOF_SYMBOL || m_model->m_completionOperator == T_COLON_COLON) {
|
||||||
(void) (*m_model->m_typeOfExpression)(expression.toUtf8(), scope);
|
(void) (*m_model->m_typeOfExpression)(expression.toUtf8(), scope);
|
||||||
globalCompletion(scope);
|
return globalCompletion(scope) ? m_startPosition : -1;
|
||||||
if (m_completions.isEmpty())
|
|
||||||
return -1;
|
|
||||||
return m_startPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_model->m_completionOperator == T_SIGNAL || m_model->m_completionOperator == T_SLOT) {
|
if (m_model->m_completionOperator == T_SIGNAL || m_model->m_completionOperator == T_SLOT) {
|
||||||
@@ -1304,10 +1469,12 @@ int InternalCppCompletionAssistProcessor::startCompletionInternal(const QString
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
} else {
|
} else if (m_model->m_completionOperator == CompleteQt5SignalOrSlotClassNameTrigger) {
|
||||||
// nothing to do.
|
// Fallback to global completion if we could not lookup sender/receiver object.
|
||||||
return -1;
|
return globalCompletion(scope) ? m_startPosition : -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1; // nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1338,13 +1505,20 @@ int InternalCppCompletionAssistProcessor::startCompletionInternal(const QString
|
|||||||
return m_startPosition;
|
return m_startPosition;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CompleteQt5SignalTrigger:
|
case CompleteQt5SignalOrSlotClassNameTrigger:
|
||||||
if (completeQtMethod(results, CompleteQt5Signals))
|
if (completeQtMethodClassName(results, scope) || globalCompletion(scope))
|
||||||
return m_startPosition;
|
return m_startPosition;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CompleteQtSlotTrigger:
|
case CompleteQt5SignalTrigger:
|
||||||
if (completeQtMethod(results, CompleteQt5Slots))
|
// Fallback to scope completion if "X::" is a namespace and not a class.
|
||||||
|
if (completeQtMethod(results, CompleteQt5Signals) || completeScope(results))
|
||||||
|
return m_startPosition;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CompleteQt5SlotTrigger:
|
||||||
|
// Fallback to scope completion if "X::" is a namespace and not a class.
|
||||||
|
if (completeQtMethod(results, CompleteQt5Slots) || completeScope(results))
|
||||||
return m_startPosition;
|
return m_startPosition;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1356,13 +1530,13 @@ int InternalCppCompletionAssistProcessor::startCompletionInternal(const QString
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope)
|
bool InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope)
|
||||||
{
|
{
|
||||||
const LookupContext &context = m_model->m_typeOfExpression->context();
|
const LookupContext &context = m_model->m_typeOfExpression->context();
|
||||||
|
|
||||||
if (m_model->m_completionOperator == T_COLON_COLON) {
|
if (m_model->m_completionOperator == T_COLON_COLON) {
|
||||||
completeNamespace(context.globalNamespace());
|
completeNamespace(context.globalNamespace());
|
||||||
return;
|
return !m_completions.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ClassOrNamespace *> usingBindings;
|
QList<ClassOrNamespace *> usingBindings;
|
||||||
@@ -1431,6 +1605,7 @@ void InternalCppCompletionAssistProcessor::globalCompletion(Scope *currentScope)
|
|||||||
addMacros(CppModelManager::configurationFileName(), context.snapshot());
|
addMacros(CppModelManager::configurationFileName(), context.snapshot());
|
||||||
addMacros(context.thisDocument()->fileName(), context.snapshot());
|
addMacros(context.thisDocument()->fileName(), context.snapshot());
|
||||||
addSnippets();
|
addSnippets();
|
||||||
|
return !m_completions.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InternalCppCompletionAssistProcessor::completeMember(const QList<LookupItem> &baseResults)
|
bool InternalCppCompletionAssistProcessor::completeMember(const QList<LookupItem> &baseResults)
|
||||||
@@ -1659,19 +1834,8 @@ bool InternalCppCompletionAssistProcessor::completeQtMethod(const QList<LookupIt
|
|||||||
o.showFunctionSignatures = true;
|
o.showFunctionSignatures = true;
|
||||||
|
|
||||||
QSet<QString> signatures;
|
QSet<QString> signatures;
|
||||||
foreach (const LookupItem &p, results) {
|
foreach (const LookupItem &lookupItem, results) {
|
||||||
FullySpecifiedType ty = p.type().simplified();
|
ClassOrNamespace *b = classOrNamespaceFromLookupItem(lookupItem, context);
|
||||||
|
|
||||||
if (PointerType *ptrTy = ty->asPointerType())
|
|
||||||
ty = ptrTy->elementType().simplified();
|
|
||||||
else
|
|
||||||
continue; // not a pointer or a reference to a pointer.
|
|
||||||
|
|
||||||
NamedType *namedTy = ty->asNamedType();
|
|
||||||
if (!namedTy) // not a class name.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ClassOrNamespace *b = context.lookupType(namedTy->name(), p.scope());
|
|
||||||
if (!b)
|
if (!b)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1712,7 +1876,7 @@ bool InternalCppCompletionAssistProcessor::completeQtMethod(const QList<LookupIt
|
|||||||
unsigned count = fun->argumentCount();
|
unsigned count = fun->argumentCount();
|
||||||
while (true) {
|
while (true) {
|
||||||
const QString completionText = wantQt5SignalOrSlot
|
const QString completionText = wantQt5SignalOrSlot
|
||||||
? createQt5SignalOrSlot(fun, klass)
|
? createQt5SignalOrSlot(fun, o)
|
||||||
: createQt4SignalOrSlot(fun, o);
|
: createQt4SignalOrSlot(fun, o);
|
||||||
|
|
||||||
if (!signatures.contains(completionText)) {
|
if (!signatures.contains(completionText)) {
|
||||||
@@ -1736,6 +1900,34 @@ bool InternalCppCompletionAssistProcessor::completeQtMethod(const QList<LookupIt
|
|||||||
return !m_completions.isEmpty();
|
return !m_completions.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InternalCppCompletionAssistProcessor::completeQtMethodClassName(
|
||||||
|
const QList<LookupItem> &results, Scope *cursorScope)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(cursorScope, return false);
|
||||||
|
|
||||||
|
if (results.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const LookupContext &context = m_model->m_typeOfExpression->context();
|
||||||
|
Overview overview;
|
||||||
|
|
||||||
|
foreach (const LookupItem &lookupItem, results) {
|
||||||
|
Class *klass = classFromLookupItem(lookupItem, context);
|
||||||
|
QTC_ASSERT(klass, continue);
|
||||||
|
const Name *name = minimalName(klass, cursorScope, context);
|
||||||
|
QTC_ASSERT(name, continue);
|
||||||
|
|
||||||
|
AssistProposalItem *item = new CppAssistProposalItem;
|
||||||
|
item->setText(overview.prettyName(name));
|
||||||
|
item->setDetail(overview.prettyType(klass->type(), klass->name()));
|
||||||
|
item->setData(QVariant::fromValue(static_cast<Symbol *>(klass)));
|
||||||
|
m_completions.append(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !m_completions.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void InternalCppCompletionAssistProcessor::addKeywords()
|
void InternalCppCompletionAssistProcessor::addKeywords()
|
||||||
{
|
{
|
||||||
int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
|
int keywordLimit = T_FIRST_OBJC_AT_KEYWORD;
|
||||||
|
@@ -139,7 +139,9 @@ private:
|
|||||||
CompleteQt5Slots,
|
CompleteQt5Slots,
|
||||||
};
|
};
|
||||||
bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results, CompleteQtMethodMode type);
|
bool completeQtMethod(const QList<CPlusPlus::LookupItem> &results, CompleteQtMethodMode type);
|
||||||
void globalCompletion(CPlusPlus::Scope *scope);
|
bool completeQtMethodClassName(const QList<CPlusPlus::LookupItem> &results,
|
||||||
|
CPlusPlus::Scope *cursorScope);
|
||||||
|
bool globalCompletion(CPlusPlus::Scope *scope);
|
||||||
|
|
||||||
void addCompletionItem(const QString &text,
|
void addCompletionItem(const QString &text,
|
||||||
const QIcon &icon = QIcon(),
|
const QIcon &icon = QIcon(),
|
||||||
@@ -155,9 +157,11 @@ private:
|
|||||||
QSet<QString> *definedMacros);
|
QSet<QString> *definedMacros);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CompleteQt5SignalTrigger = CPlusPlus::T_LAST_TOKEN + 1,
|
CompleteQt5SignalOrSlotClassNameTrigger = CPlusPlus::T_LAST_TOKEN + 1,
|
||||||
CompleteQtSlotTrigger
|
CompleteQt5SignalTrigger,
|
||||||
|
CompleteQt5SlotTrigger
|
||||||
};
|
};
|
||||||
|
|
||||||
CPlusPlus::LanguageFeatures m_languageFeatures;
|
CPlusPlus::LanguageFeatures m_languageFeatures;
|
||||||
QScopedPointer<const CppCompletionAssistInterface> m_interface;
|
QScopedPointer<const CppCompletionAssistInterface> m_interface;
|
||||||
QScopedPointer<CppAssistProposalModel> m_model;
|
QScopedPointer<CppAssistProposalModel> m_model;
|
||||||
|
Reference in New Issue
Block a user