diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 55e1d694928..9b09c2c5b59 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -77,11 +77,13 @@ static QList<_Tp> removeDuplicates(const QList<_Tp> &results) ///////////////////////////////////////////////////////////////////// // ResolveExpression ///////////////////////////////////////////////////////////////////// -ResolveExpression::ResolveExpression(const LookupContext &context) +ResolveExpression::ResolveExpression(const LookupContext &context, + const QSet &autoDeclarationsBeingResolved) : ASTVisitor(context.expressionDocument()->translationUnit()), _scope(0), _context(context), bind(context.expressionDocument()->translationUnit()), + _autoDeclarationsBeingResolved(autoDeclarationsBeingResolved), _reference(false) { } @@ -521,6 +523,10 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (!decl) continue; + // Stop on recursive auto declarations + if (_autoDeclarationsBeingResolved.contains(decl)) + continue; + const StringLiteral *initializationString = decl->getInitializer(); if (initializationString == 0) continue; @@ -535,7 +541,8 @@ bool ResolveExpression::visit(SimpleNameAST *ast) TypeOfExpression exprTyper; Document::Ptr doc = _context.snapshot().document(QString::fromLocal8Bit(decl->fileName())); - exprTyper.init(doc, _context.snapshot(), _context.bindings()); + exprTyper.init(doc, _context.snapshot(), _context.bindings(), + QSet(_autoDeclarationsBeingResolved) << decl); Document::Ptr exprDoc = documentForExpression(exprTyper.preprocessedExpression(initializer)); @@ -545,8 +552,8 @@ bool ResolveExpression::visit(SimpleNameAST *ast) if (deduceAuto._block) continue; - const QList &typeItems = - exprTyper(extractExpressionAST(exprDoc), exprDoc, decl->enclosingScope()); + const QList &typeItems = exprTyper(extractExpressionAST(exprDoc), exprDoc, + decl->enclosingScope()); if (typeItems.empty()) continue; diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h index 157c51246e5..68720fae0f1 100644 --- a/src/libs/cplusplus/ResolveExpression.h +++ b/src/libs/cplusplus/ResolveExpression.h @@ -43,7 +43,9 @@ namespace CPlusPlus { class CPLUSPLUS_EXPORT ResolveExpression: protected ASTVisitor { public: - ResolveExpression(const LookupContext &context); + ResolveExpression(const LookupContext &context, + const QSet &autoDeclarationsBeingResolved + = QSet()); virtual ~ResolveExpression(); QList operator()(ExpressionAST *ast, Scope *scope); @@ -126,6 +128,7 @@ private: const LookupContext& _context; Bind bind; QList _results; + QSet _autoDeclarationsBeingResolved; bool _reference; }; diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp index b741eff2bdb..0808bf1a2a2 100644 --- a/src/libs/cplusplus/TypeOfExpression.cpp +++ b/src/libs/cplusplus/TypeOfExpression.cpp @@ -60,7 +60,8 @@ void TypeOfExpression::reset() } void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot, - QSharedPointer bindings) + QSharedPointer bindings, + const QSet &autoDeclarationsBeingResolved) { m_thisDocument = thisDocument; m_snapshot = snapshot; @@ -69,6 +70,7 @@ void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot m_lookupContext = LookupContext(); m_bindings = bindings; m_environment.clear(); + m_autoDeclarationsBeingResolved = autoDeclarationsBeingResolved; } QList TypeOfExpression::operator()(const QByteArray &utf8code, @@ -113,7 +115,7 @@ QList TypeOfExpression::operator()(ExpressionAST *expression, m_lookupContext.setBindings(m_bindings); m_lookupContext.setExpandTemplates(m_expandTemplates); - ResolveExpression resolve(m_lookupContext); + ResolveExpression resolve(m_lookupContext, m_autoDeclarationsBeingResolved); const QList items = resolve(m_ast, scope); if (! m_bindings) @@ -135,7 +137,7 @@ QList TypeOfExpression::reference(ExpressionAST *expression, m_lookupContext.setBindings(m_bindings); m_lookupContext.setExpandTemplates(m_expandTemplates); - ResolveExpression resolve(m_lookupContext); + ResolveExpression resolve(m_lookupContext, m_autoDeclarationsBeingResolved); const QList items = resolve.reference(m_ast, scope); if (! m_bindings) diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h index 656b01eb15d..b9674fa205d 100644 --- a/src/libs/cplusplus/TypeOfExpression.h +++ b/src/libs/cplusplus/TypeOfExpression.h @@ -59,8 +59,11 @@ public: * Also clears the lookup context, so can be used to make sure references * to the documents previously used are removed. */ - void init(Document::Ptr thisDocument, const Snapshot &snapshot, - QSharedPointer bindings = QSharedPointer()); + void init(Document::Ptr thisDocument, + const Snapshot &snapshot, + QSharedPointer bindings = QSharedPointer(), + const QSet &autoDeclarationsBeingResolved + = QSet()); void reset(); @@ -152,6 +155,8 @@ private: // Keep the expression documents and thus all the symbols and // their types alive until they are not needed any more. QList m_documents; + + QSet m_autoDeclarationsBeingResolved; }; ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index d3575c364e9..fd691023f84 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -2273,3 +2273,56 @@ void CppToolsPlugin::test_completion_crash_cloning_template_class_QTCREATORBUG93 QVERIFY(completions.contains(QLatin1String("Templ"))); QVERIFY(completions.contains(QLatin1String("f"))); } + +void CppToolsPlugin::test_completion_recursive_auto_declarations1_QTCREATORBUG9503() +{ + TestData data; + data.srcText = + "void f()\n" + "{\n" + " auto object2 = object1;\n" + " auto object1 = object2;\n" + " @;\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("object1."); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 0); +} + +void CppToolsPlugin::test_completion_recursive_auto_declarations2_QTCREATORBUG9503() +{ + TestData data; + data.srcText = + "void f()\n" + "{\n" + " auto object3 = object1;\n" + " auto object2 = object3;\n" + " auto object1 = object2;\n" + " @;\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("object1."); + change.insert(data.pos, txt); + QTextCursor cursor(data.doc); + change.apply(&cursor); + data.pos += txt.length(); + + QStringList completions = getCompletions(data); + + QCOMPARE(completions.size(), 0); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 10f033c0434..03c06ba58bd 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -138,6 +138,8 @@ private slots: void test_completion_instantiate_template_with_anonymous_class(); void test_completion_instantiate_template_function(); void test_completion_crash_cloning_template_class_QTCREATORBUG9329(); + void test_completion_recursive_auto_declarations1_QTCREATORBUG9503(); + void test_completion_recursive_auto_declarations2_QTCREATORBUG9503(); void test_format_pointerdeclaration_in_simpledeclarations(); void test_format_pointerdeclaration_in_simpledeclarations_data();