Commit 9b30795c authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

C++: Fix lookup for instantiation by class object

Task-number: QTCREATORBUG-14352
Change-Id: I2ce4bc1d0dba2414afe050e80607b581686081a9
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent ee37f60b
......@@ -601,7 +601,7 @@ public:
QSet<const Declaration *> _alreadyConsideredTypedefs;
Class *_rootClass;
const Name *_name; // For debug
const Name *_name;
bool _hasTypedefs;
};
......@@ -1118,6 +1118,13 @@ LookupScope *LookupScopePrivate::lookupType_helper(
return r;
}
}
if (_instantiationOrigin) {
if (LookupScope *o = _instantiationOrigin->lookupType_helper(
name, processed, /*searchInEnclosingScope =*/ true, origin)) {
return o;
}
}
}
if (_parent && searchInEnclosingScope)
......@@ -1529,6 +1536,10 @@ void Instantiator::instantiate(LookupScopePrivate *lookupScope,
if (!clone->enclosingScope()) // Not from the cache but just cloned.
clone->setEnclosingScope(s->enclosingScope());
instantiation->_symbols.append(clone);
if (s == instantiation->_rootClass) {
clone->setName(instantiation->_name);
instantiation->_rootClass = clone->asClass();
}
if (Q_UNLIKELY(debug)) {
Overview oo;
oo.showFunctionSignatures = true;
......
......@@ -915,61 +915,47 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu
if (accessOp == T_ARROW) {
if (PointerType *ptrTy = ty->asPointerType()) {
FullySpecifiedType type = ptrTy->elementType();
if (LookupScope *binding
= findClassForTemplateParameterInExpressionScope(r.binding(),
type)) {
return binding;
}
if (LookupScope *binding = findClass(type, scope))
return binding;
} else {
LookupScope *binding
= findClassForTemplateParameterInExpressionScope(r.binding(),
ty);
} else if (LookupScope *binding = findClass(ty, scope, r.binding())) {
// lookup for overloads of operator->
if (! binding)
binding = findClass(ty, scope, r.binding());
if (binding){
// lookup for overloads of operator->
const OperatorNameId *arrowOp
= control()->operatorNameId(OperatorNameId::ArrowOp);
foreach (const LookupItem &r, binding->find(arrowOp)) {
Symbol *overload = r.declaration();
if (! overload)
continue;
Scope *functionScope = overload->enclosingScope();
const OperatorNameId *arrowOp
= control()->operatorNameId(OperatorNameId::ArrowOp);
foreach (const LookupItem &r, binding->find(arrowOp)) {
Symbol *overload = r.declaration();
if (! overload)
continue;
Scope *functionScope = overload->enclosingScope();
if (Function *funTy = overload->type()->asFunctionType()) {
FullySpecifiedType retTy = funTy->returnType().simplified();
if (Function *funTy = overload->type()->asFunctionType()) {
FullySpecifiedType retTy = funTy->returnType().simplified();
typeResolver.resolve(&retTy, &functionScope, r.binding());
typeResolver.resolve(&retTy, &functionScope, r.binding());
if (! retTy->isPointerType() && ! retTy->isNamedType())
continue;
if (! retTy->isPointerType() && ! retTy->isNamedType())
continue;
if (PointerType *ptrTy = retTy->asPointerType())
retTy = ptrTy->elementType();
if (PointerType *ptrTy = retTy->asPointerType())
retTy = ptrTy->elementType();
if (LookupScope *retBinding = findClass(retTy, functionScope))
return retBinding;
if (LookupScope *retBinding = findClass(retTy, functionScope))
if (scope != functionScope) {
if (LookupScope *retBinding = findClass(retTy, scope))
return retBinding;
}
if (scope != functionScope) {
if (LookupScope *retBinding = findClass(retTy, scope))
return retBinding;
}
if (LookupScope *origin = binding->instantiationOrigin()) {
foreach (Symbol *originSymbol, origin->symbols()) {
Scope *originScope = originSymbol->asScope();
if (originScope && originScope != scope
&& originScope != functionScope) {
if (LookupScope *retBinding
= findClass(retTy, originScope))
return retBinding;
}
if (LookupScope *origin = binding->instantiationOrigin()) {
foreach (Symbol *originSymbol, origin->symbols()) {
Scope *originScope = originSymbol->asScope();
if (originScope && originScope != scope
&& originScope != functionScope) {
if (LookupScope *retBinding
= findClass(retTy, originScope))
return retBinding;
}
}
}
......@@ -983,12 +969,6 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu
ty = ptrTy->elementType();
}
if (LookupScope *binding
= findClassForTemplateParameterInExpressionScope(r.binding(),
ty)) {
return binding;
}
LookupScope *enclosingBinding = 0;
if (LookupScope *binding = r.binding()) {
if (binding->instantiationOrigin())
......@@ -1003,24 +983,6 @@ LookupScope *ResolveExpression::baseExpression(const QList<LookupItem> &baseResu
return 0;
}
LookupScope *ResolveExpression::findClassForTemplateParameterInExpressionScope(
LookupScope *resultBinding,
const FullySpecifiedType &ty) const
{
if (resultBinding) {
if (LookupScope *origin = resultBinding->instantiationOrigin()) {
foreach (Symbol *originSymbol, origin->symbols()) {
if (Scope *originScope = originSymbol->asScope()) {
if (LookupScope *retBinding = findClass(ty, originScope))
return retBinding;
}
}
}
}
return 0;
}
bool ResolveExpression::visit(PostIncrDecrAST *ast)
{
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
......
......@@ -125,10 +125,6 @@ protected:
private:
LookupScope *findClassForTemplateParameterInExpressionScope(
LookupScope *resultBinding,
const FullySpecifiedType &ty) const;
Scope *_scope;
const LookupContext& _context;
Bind bind;
......
......@@ -38,6 +38,7 @@
#include <cplusplus/ExpressionUnderCursor.h>
#include <cplusplus/ResolveExpression.h>
#include <cplusplus/SimpleLexer.h>
#include <cplusplus/Templates.h>
#include <cplusplus/TypeOfExpression.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/functionutils.h>
......
......@@ -152,8 +152,8 @@ public:
QTC_ASSERT(m_params.staticClass, return 0);
QTC_ASSERT(!m_params.snapshot.isEmpty(), return 0);
Class *functionsClass = m_finder.findMatchingClassDeclaration(m_params.function,
m_params.snapshot);
Class *functionsClass = m_finder.findMatchingClassDeclaration(
m_params.function, m_params.snapshot, &m_params.typeOfExpression->context());
if (!functionsClass)
return 0;
......
......@@ -1371,7 +1371,7 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_data()
"template <class T> struct A { virtual void virt() {} };\n"
"void f(A<int> *l) { l->$@virt(); }\n")
<< (OverrideItemList()
<< OverrideItem(QLatin1String("A::virt"), 1));
<< OverrideItem(QLatin1String("A<int>::virt"), 1));
/// Check: Static type is nicely resolved, especially for QSharedPointers.
QTest::newRow("QSharedPointer") << _(
......
......@@ -332,7 +332,6 @@ void CppToolsPlugin::test_completion()
QEXPECT_FAIL("enum_in_function_in_struct_in_function_anon", "QTCREATORBUG-13757", Abort);
QEXPECT_FAIL("enum_in_class_accessed_in_member_func_cxx11", "QTCREATORBUG-13757", Abort);
QEXPECT_FAIL("enum_in_class_accessed_in_member_func_inline_cxx11", "QTCREATORBUG-13757", Abort);
QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort);
QCOMPARE(actualCompletions, expectedCompletions);
......@@ -2830,6 +2829,28 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("Foo")
<< QLatin1String("bar"));
QTest::newRow("instantiation_of_indirect_typedef") << _(
"template<typename _Tp>\n"
"struct Indirect { _Tp t; };\n"
"\n"
"template<typename T>\n"
"struct Temp\n"
"{\n"
" typedef T MyT;\n"
" typedef Indirect<MyT> indirect;\n"
"};\n"
"\n"
"struct Foo { int bar; };\n"
"\n"
"void func()\n"
"{\n"
" Temp<Foo>::indirect i;\n"
" @\n"
"}\n"
) << _("i.t.") << (QStringList()
<< QLatin1String("Foo")
<< QLatin1String("bar"));;
QTest::newRow("pointer_indirect_specialization_double_indirection_with_base") << _(
"template<typename _Tp>\n"
"struct Traits { };\n"
......
......@@ -212,13 +212,15 @@ Function *SymbolFinder::findMatchingDefinition(Symbol *declaration,
return 0;
}
Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot)
Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Snapshot &snapshot,
const LookupContext *context)
{
if (!declaration->identifier())
return 0;
QString declFile = QString::fromUtf8(declaration->fileName(), declaration->fileNameLength());
const bool useLocalContext = !context;
foreach (const QString &file, fileIterationOrder(declFile, snapshot)) {
Document::Ptr doc = snapshot.document(file);
if (!doc) {
......@@ -230,9 +232,13 @@ Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Sna
declaration->identifier()->size()))
continue;
LookupContext context(doc, snapshot);
QScopedPointer<LookupContext> localContext;
if (useLocalContext) {
localContext.reset(new LookupContext(doc, snapshot));
context = localContext.data();
}
LookupScope *type = context.lookupType(declaration);
LookupScope *type = context->lookupType(declaration);
if (!type)
continue;
......
......@@ -59,7 +59,8 @@ public:
bool strict = false);
CPlusPlus::Class *findMatchingClassDeclaration(CPlusPlus::Symbol *declaration,
const CPlusPlus::Snapshot &snapshot);
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::LookupContext *context = 0);
void findMatchingDeclaration(const CPlusPlus::LookupContext &context,
CPlusPlus::Function *functionType,
......
......@@ -118,6 +118,7 @@ public:
// Processs source
const Document::Ptr document = createDocument(filePath, source);
QVERIFY(document);
Snapshot snapshot;
snapshot.insert(document);
......@@ -1202,7 +1203,6 @@ void tst_CheckSymbols::findField()
source[position] = ' ';
BaseTestCase tc(source);
Use use = tc.findUse(line, column);
QEXPECT_FAIL("pointer_indirect_specialization_double_indirection", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("pointer_indirect_specialization_double_indirection_with_base", "QTCREATORBUG-14141", Abort);
QEXPECT_FAIL("recursive_instantiation_of_template_type", "QTCREATORBUG-14237", Abort);
QVERIFY(use.isValid());
......@@ -1281,6 +1281,26 @@ void tst_CheckSymbols::findField_data()
"}\n"
);
QTest::newRow("instantiation_of_indirect_typedef") << _(
"template<typename _Tp>\n"
"struct Indirect { _Tp t; };\n"
"\n"
"template<typename T>\n"
"struct Temp\n"
"{\n"
" typedef T MyT;\n"
" typedef Indirect<MyT> indirect;\n"
"};\n"
"\n"
"struct Foo { int bar; };\n"
"\n"
"void func()\n"
"{\n"
" Temp<Foo>::indirect i;\n"
" i.t.@bar;\n"
"}\n"
);
QTest::newRow("pointer_indirect_specialization_double_indirection") << _(
"template<typename _Tp>\n"
"struct Traits { };\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment