forked from qt-creator/qt-creator
C++: Handle recursive auto declarations
Remember auto declarations we have already looked up and stop if we try it again. Task-number: QTCREATORBUG-9503 Change-Id: I989b11609c98bf197ce916d79c9d452294355053 Reviewed-by: Przemyslaw Gorszkowski <pgorszkowski@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
@@ -77,11 +77,13 @@ static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// ResolveExpression
|
// ResolveExpression
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
ResolveExpression::ResolveExpression(const LookupContext &context)
|
ResolveExpression::ResolveExpression(const LookupContext &context,
|
||||||
|
const QSet<const Declaration *> &autoDeclarationsBeingResolved)
|
||||||
: ASTVisitor(context.expressionDocument()->translationUnit()),
|
: ASTVisitor(context.expressionDocument()->translationUnit()),
|
||||||
_scope(0),
|
_scope(0),
|
||||||
_context(context),
|
_context(context),
|
||||||
bind(context.expressionDocument()->translationUnit()),
|
bind(context.expressionDocument()->translationUnit()),
|
||||||
|
_autoDeclarationsBeingResolved(autoDeclarationsBeingResolved),
|
||||||
_reference(false)
|
_reference(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -521,6 +523,10 @@ bool ResolveExpression::visit(SimpleNameAST *ast)
|
|||||||
if (!decl)
|
if (!decl)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Stop on recursive auto declarations
|
||||||
|
if (_autoDeclarationsBeingResolved.contains(decl))
|
||||||
|
continue;
|
||||||
|
|
||||||
const StringLiteral *initializationString = decl->getInitializer();
|
const StringLiteral *initializationString = decl->getInitializer();
|
||||||
if (initializationString == 0)
|
if (initializationString == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -535,7 +541,8 @@ bool ResolveExpression::visit(SimpleNameAST *ast)
|
|||||||
|
|
||||||
TypeOfExpression exprTyper;
|
TypeOfExpression exprTyper;
|
||||||
Document::Ptr doc = _context.snapshot().document(QString::fromLocal8Bit(decl->fileName()));
|
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<const Declaration* >(_autoDeclarationsBeingResolved) << decl);
|
||||||
|
|
||||||
Document::Ptr exprDoc =
|
Document::Ptr exprDoc =
|
||||||
documentForExpression(exprTyper.preprocessedExpression(initializer));
|
documentForExpression(exprTyper.preprocessedExpression(initializer));
|
||||||
@@ -545,8 +552,8 @@ bool ResolveExpression::visit(SimpleNameAST *ast)
|
|||||||
if (deduceAuto._block)
|
if (deduceAuto._block)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QList<LookupItem> &typeItems =
|
const QList<LookupItem> &typeItems = exprTyper(extractExpressionAST(exprDoc), exprDoc,
|
||||||
exprTyper(extractExpressionAST(exprDoc), exprDoc, decl->enclosingScope());
|
decl->enclosingScope());
|
||||||
if (typeItems.empty())
|
if (typeItems.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@@ -43,7 +43,9 @@ namespace CPlusPlus {
|
|||||||
class CPLUSPLUS_EXPORT ResolveExpression: protected ASTVisitor
|
class CPLUSPLUS_EXPORT ResolveExpression: protected ASTVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResolveExpression(const LookupContext &context);
|
ResolveExpression(const LookupContext &context,
|
||||||
|
const QSet<const Declaration *> &autoDeclarationsBeingResolved
|
||||||
|
= QSet<const Declaration *>());
|
||||||
virtual ~ResolveExpression();
|
virtual ~ResolveExpression();
|
||||||
|
|
||||||
QList<LookupItem> operator()(ExpressionAST *ast, Scope *scope);
|
QList<LookupItem> operator()(ExpressionAST *ast, Scope *scope);
|
||||||
@@ -126,6 +128,7 @@ private:
|
|||||||
const LookupContext& _context;
|
const LookupContext& _context;
|
||||||
Bind bind;
|
Bind bind;
|
||||||
QList<LookupItem> _results;
|
QList<LookupItem> _results;
|
||||||
|
QSet<const Declaration *> _autoDeclarationsBeingResolved;
|
||||||
bool _reference;
|
bool _reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -60,7 +60,8 @@ void TypeOfExpression::reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot,
|
void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot,
|
||||||
QSharedPointer<CreateBindings> bindings)
|
QSharedPointer<CreateBindings> bindings,
|
||||||
|
const QSet<const Declaration *> &autoDeclarationsBeingResolved)
|
||||||
{
|
{
|
||||||
m_thisDocument = thisDocument;
|
m_thisDocument = thisDocument;
|
||||||
m_snapshot = snapshot;
|
m_snapshot = snapshot;
|
||||||
@@ -69,6 +70,7 @@ void TypeOfExpression::init(Document::Ptr thisDocument, const Snapshot &snapshot
|
|||||||
m_lookupContext = LookupContext();
|
m_lookupContext = LookupContext();
|
||||||
m_bindings = bindings;
|
m_bindings = bindings;
|
||||||
m_environment.clear();
|
m_environment.clear();
|
||||||
|
m_autoDeclarationsBeingResolved = autoDeclarationsBeingResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<LookupItem> TypeOfExpression::operator()(const QByteArray &utf8code,
|
QList<LookupItem> TypeOfExpression::operator()(const QByteArray &utf8code,
|
||||||
@@ -113,7 +115,7 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression,
|
|||||||
m_lookupContext.setBindings(m_bindings);
|
m_lookupContext.setBindings(m_bindings);
|
||||||
m_lookupContext.setExpandTemplates(m_expandTemplates);
|
m_lookupContext.setExpandTemplates(m_expandTemplates);
|
||||||
|
|
||||||
ResolveExpression resolve(m_lookupContext);
|
ResolveExpression resolve(m_lookupContext, m_autoDeclarationsBeingResolved);
|
||||||
const QList<LookupItem> items = resolve(m_ast, scope);
|
const QList<LookupItem> items = resolve(m_ast, scope);
|
||||||
|
|
||||||
if (! m_bindings)
|
if (! m_bindings)
|
||||||
@@ -135,7 +137,7 @@ QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression,
|
|||||||
m_lookupContext.setBindings(m_bindings);
|
m_lookupContext.setBindings(m_bindings);
|
||||||
m_lookupContext.setExpandTemplates(m_expandTemplates);
|
m_lookupContext.setExpandTemplates(m_expandTemplates);
|
||||||
|
|
||||||
ResolveExpression resolve(m_lookupContext);
|
ResolveExpression resolve(m_lookupContext, m_autoDeclarationsBeingResolved);
|
||||||
const QList<LookupItem> items = resolve.reference(m_ast, scope);
|
const QList<LookupItem> items = resolve.reference(m_ast, scope);
|
||||||
|
|
||||||
if (! m_bindings)
|
if (! m_bindings)
|
||||||
|
@@ -59,8 +59,11 @@ public:
|
|||||||
* Also clears the lookup context, so can be used to make sure references
|
* Also clears the lookup context, so can be used to make sure references
|
||||||
* to the documents previously used are removed.
|
* to the documents previously used are removed.
|
||||||
*/
|
*/
|
||||||
void init(Document::Ptr thisDocument, const Snapshot &snapshot,
|
void init(Document::Ptr thisDocument,
|
||||||
QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>());
|
const Snapshot &snapshot,
|
||||||
|
QSharedPointer<CreateBindings> bindings = QSharedPointer<CreateBindings>(),
|
||||||
|
const QSet<const Declaration *> &autoDeclarationsBeingResolved
|
||||||
|
= QSet<const Declaration *>());
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
@@ -152,6 +155,8 @@ private:
|
|||||||
// Keep the expression documents and thus all the symbols and
|
// Keep the expression documents and thus all the symbols and
|
||||||
// their types alive until they are not needed any more.
|
// their types alive until they are not needed any more.
|
||||||
QList<Document::Ptr> m_documents;
|
QList<Document::Ptr> m_documents;
|
||||||
|
|
||||||
|
QSet<const Declaration *> m_autoDeclarationsBeingResolved;
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc);
|
ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc);
|
||||||
|
@@ -2273,3 +2273,56 @@ void CppToolsPlugin::test_completion_crash_cloning_template_class_QTCREATORBUG93
|
|||||||
QVERIFY(completions.contains(QLatin1String("Templ")));
|
QVERIFY(completions.contains(QLatin1String("Templ")));
|
||||||
QVERIFY(completions.contains(QLatin1String("f")));
|
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);
|
||||||
|
}
|
||||||
|
@@ -138,6 +138,8 @@ private slots:
|
|||||||
void test_completion_instantiate_template_with_anonymous_class();
|
void test_completion_instantiate_template_with_anonymous_class();
|
||||||
void test_completion_instantiate_template_function();
|
void test_completion_instantiate_template_function();
|
||||||
void test_completion_crash_cloning_template_class_QTCREATORBUG9329();
|
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();
|
||||||
void test_format_pointerdeclaration_in_simpledeclarations_data();
|
void test_format_pointerdeclaration_in_simpledeclarations_data();
|
||||||
|
Reference in New Issue
Block a user