Commit ba75725a authored by Erik Verbruggen's avatar Erik Verbruggen

C++: fix member rewriting when doing template instantiation.

Task-number: QTCREATORBUG-7964
Change-Id: Icc7d87bb4f2d1ab0560a6c06187d9c23da9fe3e9
Reviewed-by: default avatarDavid Schulz <david.schulz@digia.com>
parent cc69195c
...@@ -18,10 +18,13 @@ ...@@ -18,10 +18,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#include "Literals.h"
#include "Name.h" #include "Name.h"
#include "Names.h" #include "Names.h"
#include "NameVisitor.h" #include "NameVisitor.h"
#include <cstring>
using namespace CPlusPlus; using namespace CPlusPlus;
Name::Name() Name::Name()
...@@ -65,4 +68,16 @@ void Name::accept(const Name *name, NameVisitor *visitor) ...@@ -65,4 +68,16 @@ void Name::accept(const Name *name, NameVisitor *visitor)
name->accept(visitor); name->accept(visitor);
} }
bool Name::Compare::operator()(const Name *name, const Name *other) const
{
if (name == 0)
return other != 0;
if (other == 0)
return false;
if (name == other)
return false;
const Identifier *id = name->identifier();
const Identifier *otherId = other->identifier();
return std::strcmp(id->chars(), otherId->chars()) < 0;
}
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "CPlusPlusForwardDeclarations.h" #include "CPlusPlusForwardDeclarations.h"
#include <functional>
namespace CPlusPlus { namespace CPlusPlus {
...@@ -55,6 +56,11 @@ public: ...@@ -55,6 +56,11 @@ public:
void accept(NameVisitor *visitor) const; void accept(NameVisitor *visitor) const;
static void accept(const Name *name, NameVisitor *visitor); static void accept(const Name *name, NameVisitor *visitor);
public:
struct Compare: std::binary_function<const Name *, const Name *, bool> {
bool operator()(const Name *name, const Name *other) const;
};
protected: protected:
virtual void accept0(NameVisitor *visitor) const = 0; virtual void accept0(NameVisitor *visitor) const = 0;
}; };
......
...@@ -514,6 +514,8 @@ Symbol *Clone::instantiate(Template *templ, const FullySpecifiedType *const args ...@@ -514,6 +514,8 @@ Symbol *Clone::instantiate(Template *templ, const FullySpecifiedType *const args
// //
// substitutions // substitutions
// //
FullySpecifiedType Subst::apply(const Name *name) const FullySpecifiedType Subst::apply(const Name *name) const
{ {
if (name) { if (name) {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "CPlusPlusForwardDeclarations.h" #include "CPlusPlusForwardDeclarations.h"
#include "TypeVisitor.h" #include "TypeVisitor.h"
#include "FullySpecifiedType.h" #include "FullySpecifiedType.h"
#include "Name.h"
#include "NameVisitor.h" #include "NameVisitor.h"
#include "SymbolVisitor.h" #include "SymbolVisitor.h"
#include <map> #include <map>
...@@ -56,7 +57,7 @@ public: ...@@ -56,7 +57,7 @@ public:
private: private:
Control *_control; Control *_control;
Subst *_previous; Subst *_previous;
std::map<const Name *, FullySpecifiedType> _map; std::map<const Name *, FullySpecifiedType, Name::Compare> _map;
}; };
class CPLUSPLUS_EXPORT CloneType: protected TypeVisitor class CPLUSPLUS_EXPORT CloneType: protected TypeVisitor
......
...@@ -120,21 +120,12 @@ bool compareFullyQualifiedName(const QList<const Name *> &path, const QList<cons ...@@ -120,21 +120,12 @@ bool compareFullyQualifiedName(const QList<const Name *> &path, const QList<cons
} }
bool ClassOrNamespace::CompareName::operator()(const Name *name, const Name *other) const
{
Q_ASSERT(name != 0);
Q_ASSERT(other != 0);
const Identifier *id = name->identifier();
const Identifier *otherId = other->identifier();
return strcmp(id->chars(), otherId->chars()) < 0;
}
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// LookupContext // LookupContext
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
LookupContext::LookupContext() LookupContext::LookupContext()
: _control(new Control()) : _control(new Control())
, m_expandTemplates(false)
{ } { }
LookupContext::LookupContext(Document::Ptr thisDocument, LookupContext::LookupContext(Document::Ptr thisDocument,
...@@ -142,7 +133,8 @@ LookupContext::LookupContext(Document::Ptr thisDocument, ...@@ -142,7 +133,8 @@ LookupContext::LookupContext(Document::Ptr thisDocument,
: _expressionDocument(Document::create("<LookupContext>")), : _expressionDocument(Document::create("<LookupContext>")),
_thisDocument(thisDocument), _thisDocument(thisDocument),
_snapshot(snapshot), _snapshot(snapshot),
_control(new Control()) _control(new Control()),
m_expandTemplates(false)
{ {
} }
...@@ -152,7 +144,8 @@ LookupContext::LookupContext(Document::Ptr expressionDocument, ...@@ -152,7 +144,8 @@ LookupContext::LookupContext(Document::Ptr expressionDocument,
: _expressionDocument(expressionDocument), : _expressionDocument(expressionDocument),
_thisDocument(thisDocument), _thisDocument(thisDocument),
_snapshot(snapshot), _snapshot(snapshot),
_control(new Control()) _control(new Control()),
m_expandTemplates(false)
{ {
} }
...@@ -161,7 +154,8 @@ LookupContext::LookupContext(const LookupContext &other) ...@@ -161,7 +154,8 @@ LookupContext::LookupContext(const LookupContext &other)
_thisDocument(other._thisDocument), _thisDocument(other._thisDocument),
_snapshot(other._snapshot), _snapshot(other._snapshot),
_bindings(other._bindings), _bindings(other._bindings),
_control(other._control) _control(other._control),
m_expandTemplates(other.m_expandTemplates)
{ } { }
LookupContext &LookupContext::operator = (const LookupContext &other) LookupContext &LookupContext::operator = (const LookupContext &other)
...@@ -171,6 +165,7 @@ LookupContext &LookupContext::operator = (const LookupContext &other) ...@@ -171,6 +165,7 @@ LookupContext &LookupContext::operator = (const LookupContext &other)
_snapshot = other._snapshot; _snapshot = other._snapshot;
_bindings = other._bindings; _bindings = other._bindings;
_control = other._control; _control = other._control;
m_expandTemplates = other.m_expandTemplates;
return *this; return *this;
} }
...@@ -227,8 +222,10 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, ...@@ -227,8 +222,10 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target,
QSharedPointer<CreateBindings> LookupContext::bindings() const QSharedPointer<CreateBindings> LookupContext::bindings() const
{ {
if (! _bindings) if (! _bindings) {
_bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot, control())); _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot, control()));
_bindings->setExpandTemplates(m_expandTemplates);
}
return _bindings; return _bindings;
} }
...@@ -728,7 +725,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac ...@@ -728,7 +725,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
instantiation->_instantiationOrigin = origin; instantiation->_instantiationOrigin = origin;
// The instantiation should have all symbols, enums, and usings from the reference. // The instantiation should have all symbols, enums, and usings from the reference.
instantiation->_symbols.append(reference->symbols());
instantiation->_enums.append(reference->enums()); instantiation->_enums.append(reference->enums());
instantiation->_usings.append(reference->usings()); instantiation->_usings.append(reference->usings());
...@@ -736,6 +732,28 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac ...@@ -736,6 +732,28 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
// now must worry about dependent names in base classes. // now must worry about dependent names in base classes.
if (Template *templ = referenceClass->enclosingTemplate()) { if (Template *templ = referenceClass->enclosingTemplate()) {
const unsigned argumentCount = templId->templateArgumentCount(); const unsigned argumentCount = templId->templateArgumentCount();
if (_factory->expandTemplates()) {
Subst subst(_control.data());
for (unsigned i = 0, ei = std::min(argumentCount, templ->templateParameterCount()); i < ei; ++i) {
const TypenameArgument *tParam = templ->templateParameterAt(i)->asTypenameArgument();
if (!tParam)
continue;
const Name *name = tParam->name();
if (!name)
continue;
const FullySpecifiedType &ty = templId->templateArgumentAt(i);
subst.bind(name, ty);
}
Clone cloner(_control.data());
foreach (Symbol *s, reference->symbols()) {
instantiation->_symbols.append(cloner.symbol(s, &subst));
}
} else {
instantiation->_symbols.append(reference->symbols());
}
QHash<const Name*, unsigned> templParams; QHash<const Name*, unsigned> templParams;
for (unsigned i = 0; i < templ->templateParameterCount(); ++i) for (unsigned i = 0; i < templ->templateParameterCount(); ++i)
templParams.insert(templ->templateParameterAt(i)->name(), i); templParams.insert(templ->templateParameterAt(i)->name(), i);
...@@ -794,6 +812,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac ...@@ -794,6 +812,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
if (baseBinding && !knownUsings.contains(baseBinding)) if (baseBinding && !knownUsings.contains(baseBinding))
instantiation->addUsing(baseBinding); instantiation->addUsing(baseBinding);
} }
} else {
instantiation->_symbols.append(reference->symbols());
} }
_alreadyConsideredTemplates.clear(templId); _alreadyConsideredTemplates.clear(templId);
...@@ -907,7 +927,7 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa ...@@ -907,7 +927,7 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa
} }
CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot, QSharedPointer<Control> control) CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snapshot, QSharedPointer<Control> control)
: _snapshot(snapshot), _control(control) : _snapshot(snapshot), _control(control), _expandTemplates(false)
{ {
_globalNamespace = allocClassOrNamespace(/*parent = */ 0); _globalNamespace = allocClassOrNamespace(/*parent = */ 0);
_currentClassOrNamespace = _globalNamespace; _currentClassOrNamespace = _globalNamespace;
......
...@@ -119,12 +119,7 @@ private: ...@@ -119,12 +119,7 @@ private:
ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin); ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin);
private: private:
struct CompareName: std::binary_function<const Name *, const Name *, bool> { typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
bool operator()(const Name *name, const Name *other) const;
};
private:
typedef std::map<const Name *, ClassOrNamespace *, CompareName> Table;
CreateBindings *_factory; CreateBindings *_factory;
ClassOrNamespace *_parent; ClassOrNamespace *_parent;
QList<Symbol *> _symbols; QList<Symbol *> _symbols;
...@@ -163,6 +158,11 @@ public: ...@@ -163,6 +158,11 @@ public:
/// \internal /// \internal
QSharedPointer<Control> control() const; QSharedPointer<Control> control() const;
bool expandTemplates() const
{ return _expandTemplates; }
void setExpandTemplates(bool expandTemplates)
{ _expandTemplates = expandTemplates; }
/// Searches in \a scope for symbols with the given \a name. /// Searches in \a scope for symbols with the given \a name.
/// Store the result in \a results. /// Store the result in \a results.
/// \internal /// \internal
...@@ -223,6 +223,7 @@ private: ...@@ -223,6 +223,7 @@ private:
QList<ClassOrNamespace *> _entities; QList<ClassOrNamespace *> _entities;
ClassOrNamespace *_globalNamespace; ClassOrNamespace *_globalNamespace;
ClassOrNamespace *_currentClassOrNamespace; ClassOrNamespace *_currentClassOrNamespace;
bool _expandTemplates;
}; };
class CPLUSPLUS_EXPORT LookupContext class CPLUSPLUS_EXPORT LookupContext
...@@ -265,6 +266,9 @@ public: ...@@ -265,6 +266,9 @@ public:
static const Name *minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control); static const Name *minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control);
void setExpandTemplates(bool expandTemplates)
{ m_expandTemplates = expandTemplates; }
private: private:
// The current expression. // The current expression.
Document::Ptr _expressionDocument; Document::Ptr _expressionDocument;
...@@ -279,6 +283,8 @@ private: ...@@ -279,6 +283,8 @@ private:
mutable QSharedPointer<CreateBindings> _bindings; mutable QSharedPointer<CreateBindings> _bindings;
QSharedPointer<Control> _control; QSharedPointer<Control> _control;
bool m_expandTemplates;
}; };
bool CPLUSPLUS_EXPORT compareName(const Name *name, const Name *other); bool CPLUSPLUS_EXPORT compareName(const Name *name, const Name *other);
......
...@@ -41,7 +41,8 @@ using namespace CPlusPlus; ...@@ -41,7 +41,8 @@ using namespace CPlusPlus;
TypeOfExpression::TypeOfExpression(): TypeOfExpression::TypeOfExpression():
m_ast(0), m_ast(0),
m_scope(0) m_scope(0),
m_expandTemplates(false)
{ {
} }
...@@ -107,6 +108,7 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression, ...@@ -107,6 +108,7 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression,
m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot); m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot);
m_lookupContext.setBindings(m_bindings); m_lookupContext.setBindings(m_bindings);
m_lookupContext.setExpandTemplates(m_expandTemplates);
ResolveExpression resolve(m_lookupContext); ResolveExpression resolve(m_lookupContext);
const QList<LookupItem> items = resolve(m_ast, scope); const QList<LookupItem> items = resolve(m_ast, scope);
...@@ -127,6 +129,7 @@ QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression, ...@@ -127,6 +129,7 @@ QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression,
m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot); m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot);
m_lookupContext.setBindings(m_bindings); m_lookupContext.setBindings(m_bindings);
m_lookupContext.setExpandTemplates(m_expandTemplates);
ResolveExpression resolve(m_lookupContext); ResolveExpression resolve(m_lookupContext);
const QList<LookupItem> items = resolve.reference(m_ast, scope); const QList<LookupItem> items = resolve.reference(m_ast, scope);
......
...@@ -123,6 +123,9 @@ public: ...@@ -123,6 +123,9 @@ public:
ExpressionAST *expressionAST() const; ExpressionAST *expressionAST() const;
QByteArray preprocessedExpression(const QByteArray &utf8code) const; QByteArray preprocessedExpression(const QByteArray &utf8code) const;
void setExpandTemplates(bool expandTemplates)
{ m_expandTemplates = expandTemplates; }
private: private:
void processEnvironment(Document::Ptr doc, Environment *env, void processEnvironment(Document::Ptr doc, Environment *env,
...@@ -137,6 +140,8 @@ private: ...@@ -137,6 +140,8 @@ private:
Scope *m_scope; Scope *m_scope;
LookupContext m_lookupContext; LookupContext m_lookupContext;
mutable QSharedPointer<Environment> m_environment; mutable QSharedPointer<Environment> m_environment;
bool m_expandTemplates;
}; };
ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc); ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc);
......
...@@ -228,6 +228,78 @@ void CppToolsPlugin::test_completion_template_1() ...@@ -228,6 +228,78 @@ void CppToolsPlugin::test_completion_template_1()
QVERIFY(!completions.contains("func")); QVERIFY(!completions.contains("func"));
} }
void CppToolsPlugin::test_completion_template_2()
{
TestData data;
data.srcText = "\n"
"template <class T>\n"
"struct List\n"
"{\n"
" T &at(int);\n"
"};\n"
"\n"
"struct Tupple { int a; int b; };\n"
"\n"
"void func() {\n"
" List<Tupple> l;\n"
" @\n"
" // padding so we get the scope right\n"
"}";
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("l.at(0).");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 3);
QVERIFY(completions.contains("Tupple"));
QVERIFY(completions.contains("a"));
QVERIFY(completions.contains("b"));
}
void CppToolsPlugin::test_completion_template_3()
{
TestData data;
data.srcText = "\n"
"template <class T>\n"
"struct List\n"
"{\n"
" T t;\n"
"};\n"
"\n"
"struct Tupple { int a; int b; };\n"
"\n"
"void func() {\n"
" List<Tupple> l;\n"
" @\n"
" // padding so we get the scope right\n"
"}";
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("l.t.");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 3);
QVERIFY(completions.contains("Tupple"));
QVERIFY(completions.contains("a"));
QVERIFY(completions.contains("b"));
QVERIFY(completions.contains("a"));
QVERIFY(completions.contains("b"));
}
void CppToolsPlugin::test_completion() void CppToolsPlugin::test_completion()
{ {
QFETCH(QByteArray, code); QFETCH(QByteArray, code);
......
...@@ -102,7 +102,9 @@ public: ...@@ -102,7 +102,9 @@ public:
, m_completionOperator(T_EOF_SYMBOL) , m_completionOperator(T_EOF_SYMBOL)
, m_replaceDotForArrow(false) , m_replaceDotForArrow(false)
, m_typeOfExpression(new TypeOfExpression) , m_typeOfExpression(new TypeOfExpression)
{} {
m_typeOfExpression->setExpandTemplates(true);
}
virtual bool isSortable(const QString &prefix) const; virtual bool isSortable(const QString &prefix) const;
virtual IAssistProposalItem *proposalItem(int index) const; virtual IAssistProposalItem *proposalItem(int index) const;
......
...@@ -93,6 +93,8 @@ private slots: ...@@ -93,6 +93,8 @@ private slots:
void test_completion_forward_declarations_present(); void test_completion_forward_declarations_present();
void test_completion_basic_1(); void test_completion_basic_1();
void test_completion_template_1(); void test_completion_template_1();
void test_completion_template_2();
void test_completion_template_3();
void test_completion_template_as_base(); void test_completion_template_as_base();
void test_completion_template_as_base_data(); void test_completion_template_as_base_data();
void test_completion_use_global_identifier_as_base_class(); void test_completion_use_global_identifier_as_base_class();
......
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