diff options
author | Erik Verbruggen <erik.verbruggen@digia.com> | 2012-10-08 13:23:21 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@digia.com> | 2012-10-11 16:13:32 +0200 |
commit | ba75725a7a6855538a1a5516786440e5ab189f93 (patch) | |
tree | 513e654894d0f7be4444a37ea57b93d12e37e2cd /src | |
parent | cc69195c6f4ee00475c5659fc3ff8a492224ced0 (diff) |
C++: fix member rewriting when doing template instantiation.
Task-number: QTCREATORBUG-7964
Change-Id: Icc7d87bb4f2d1ab0560a6c06187d9c23da9fe3e9
Reviewed-by: David Schulz <david.schulz@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/3rdparty/cplusplus/Name.cpp | 15 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Name.h | 6 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Templates.cpp | 2 | ||||
-rw-r--r-- | src/libs/3rdparty/cplusplus/Templates.h | 3 | ||||
-rw-r--r-- | src/libs/cplusplus/LookupContext.cpp | 52 | ||||
-rw-r--r-- | src/libs/cplusplus/LookupContext.h | 18 | ||||
-rw-r--r-- | src/libs/cplusplus/TypeOfExpression.cpp | 5 | ||||
-rw-r--r-- | src/libs/cplusplus/TypeOfExpression.h | 5 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcompletion_test.cpp | 72 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcompletionassist.cpp | 4 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolsplugin.h | 2 |
11 files changed, 159 insertions, 25 deletions
diff --git a/src/libs/3rdparty/cplusplus/Name.cpp b/src/libs/3rdparty/cplusplus/Name.cpp index 6c1240b279..8fec45f5c0 100644 --- a/src/libs/3rdparty/cplusplus/Name.cpp +++ b/src/libs/3rdparty/cplusplus/Name.cpp @@ -18,10 +18,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include "Literals.h" #include "Name.h" #include "Names.h" #include "NameVisitor.h" +#include <cstring> + using namespace CPlusPlus; Name::Name() @@ -65,4 +68,16 @@ void Name::accept(const Name *name, NameVisitor *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; +} diff --git a/src/libs/3rdparty/cplusplus/Name.h b/src/libs/3rdparty/cplusplus/Name.h index 8a34b36479..43dcf3d35c 100644 --- a/src/libs/3rdparty/cplusplus/Name.h +++ b/src/libs/3rdparty/cplusplus/Name.h @@ -23,6 +23,7 @@ #include "CPlusPlusForwardDeclarations.h" +#include <functional> namespace CPlusPlus { @@ -55,6 +56,11 @@ public: void accept(NameVisitor *visitor) const; 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: virtual void accept0(NameVisitor *visitor) const = 0; }; diff --git a/src/libs/3rdparty/cplusplus/Templates.cpp b/src/libs/3rdparty/cplusplus/Templates.cpp index 095fa010a9..1c4ec61ced 100644 --- a/src/libs/3rdparty/cplusplus/Templates.cpp +++ b/src/libs/3rdparty/cplusplus/Templates.cpp @@ -514,6 +514,8 @@ Symbol *Clone::instantiate(Template *templ, const FullySpecifiedType *const args // // substitutions // + + FullySpecifiedType Subst::apply(const Name *name) const { if (name) { diff --git a/src/libs/3rdparty/cplusplus/Templates.h b/src/libs/3rdparty/cplusplus/Templates.h index 0057d7fcbf..04064a8906 100644 --- a/src/libs/3rdparty/cplusplus/Templates.h +++ b/src/libs/3rdparty/cplusplus/Templates.h @@ -24,6 +24,7 @@ #include "CPlusPlusForwardDeclarations.h" #include "TypeVisitor.h" #include "FullySpecifiedType.h" +#include "Name.h" #include "NameVisitor.h" #include "SymbolVisitor.h" #include <map> @@ -56,7 +57,7 @@ public: private: Control *_control; Subst *_previous; - std::map<const Name *, FullySpecifiedType> _map; + std::map<const Name *, FullySpecifiedType, Name::Compare> _map; }; class CPLUSPLUS_EXPORT CloneType: protected TypeVisitor diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 51efb92a29..1fbe5c5e60 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -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() : _control(new Control()) + , m_expandTemplates(false) { } LookupContext::LookupContext(Document::Ptr thisDocument, @@ -142,7 +133,8 @@ LookupContext::LookupContext(Document::Ptr thisDocument, : _expressionDocument(Document::create("<LookupContext>")), _thisDocument(thisDocument), _snapshot(snapshot), - _control(new Control()) + _control(new Control()), + m_expandTemplates(false) { } @@ -152,7 +144,8 @@ LookupContext::LookupContext(Document::Ptr expressionDocument, : _expressionDocument(expressionDocument), _thisDocument(thisDocument), _snapshot(snapshot), - _control(new Control()) + _control(new Control()), + m_expandTemplates(false) { } @@ -161,7 +154,8 @@ LookupContext::LookupContext(const LookupContext &other) _thisDocument(other._thisDocument), _snapshot(other._snapshot), _bindings(other._bindings), - _control(other._control) + _control(other._control), + m_expandTemplates(other.m_expandTemplates) { } LookupContext &LookupContext::operator = (const LookupContext &other) @@ -171,6 +165,7 @@ LookupContext &LookupContext::operator = (const LookupContext &other) _snapshot = other._snapshot; _bindings = other._bindings; _control = other._control; + m_expandTemplates = other.m_expandTemplates; return *this; } @@ -227,8 +222,10 @@ const Name *LookupContext::minimalName(Symbol *symbol, ClassOrNamespace *target, QSharedPointer<CreateBindings> LookupContext::bindings() const { - if (! _bindings) + if (! _bindings) { _bindings = QSharedPointer<CreateBindings>(new CreateBindings(_thisDocument, _snapshot, control())); + _bindings->setExpandTemplates(m_expandTemplates); + } return _bindings; } @@ -728,7 +725,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac instantiation->_instantiationOrigin = origin; // The instantiation should have all symbols, enums, and usings from the reference. - instantiation->_symbols.append(reference->symbols()); instantiation->_enums.append(reference->enums()); instantiation->_usings.append(reference->usings()); @@ -736,6 +732,28 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac // now must worry about dependent names in base classes. if (Template *templ = referenceClass->enclosingTemplate()) { 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; for (unsigned i = 0; i < templ->templateParameterCount(); ++i) templParams.insert(templ->templateParameterAt(i)->name(), i); @@ -794,6 +812,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac if (baseBinding && !knownUsings.contains(baseBinding)) instantiation->addUsing(baseBinding); } + } else { + instantiation->_symbols.append(reference->symbols()); } _alreadyConsideredTemplates.clear(templId); @@ -907,7 +927,7 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa } 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); _currentClassOrNamespace = _globalNamespace; diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 41b5ee9999..c7b556de43 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -119,12 +119,7 @@ private: ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin); private: - struct CompareName: std::binary_function<const Name *, const Name *, bool> { - bool operator()(const Name *name, const Name *other) const; - }; - -private: - typedef std::map<const Name *, ClassOrNamespace *, CompareName> Table; + typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table; CreateBindings *_factory; ClassOrNamespace *_parent; QList<Symbol *> _symbols; @@ -163,6 +158,11 @@ public: /// \internal 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. /// Store the result in \a results. /// \internal @@ -223,6 +223,7 @@ private: QList<ClassOrNamespace *> _entities; ClassOrNamespace *_globalNamespace; ClassOrNamespace *_currentClassOrNamespace; + bool _expandTemplates; }; class CPLUSPLUS_EXPORT LookupContext @@ -265,6 +266,9 @@ public: static const Name *minimalName(Symbol *symbol, ClassOrNamespace *target, Control *control); + void setExpandTemplates(bool expandTemplates) + { m_expandTemplates = expandTemplates; } + private: // The current expression. Document::Ptr _expressionDocument; @@ -279,6 +283,8 @@ private: mutable QSharedPointer<CreateBindings> _bindings; QSharedPointer<Control> _control; + + bool m_expandTemplates; }; bool CPLUSPLUS_EXPORT compareName(const Name *name, const Name *other); diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp index e8deecd5ae..379388de21 100644 --- a/src/libs/cplusplus/TypeOfExpression.cpp +++ b/src/libs/cplusplus/TypeOfExpression.cpp @@ -41,7 +41,8 @@ using namespace CPlusPlus; TypeOfExpression::TypeOfExpression(): m_ast(0), - m_scope(0) + m_scope(0), + m_expandTemplates(false) { } @@ -107,6 +108,7 @@ QList<LookupItem> TypeOfExpression::operator()(ExpressionAST *expression, m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot); m_lookupContext.setBindings(m_bindings); + m_lookupContext.setExpandTemplates(m_expandTemplates); ResolveExpression resolve(m_lookupContext); const QList<LookupItem> items = resolve(m_ast, scope); @@ -127,6 +129,7 @@ QList<LookupItem> TypeOfExpression::reference(ExpressionAST *expression, m_lookupContext = LookupContext(document, m_thisDocument, m_snapshot); m_lookupContext.setBindings(m_bindings); + m_lookupContext.setExpandTemplates(m_expandTemplates); ResolveExpression resolve(m_lookupContext); const QList<LookupItem> items = resolve.reference(m_ast, scope); diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h index fb425db08b..d0cf07da98 100644 --- a/src/libs/cplusplus/TypeOfExpression.h +++ b/src/libs/cplusplus/TypeOfExpression.h @@ -123,6 +123,9 @@ public: ExpressionAST *expressionAST() const; QByteArray preprocessedExpression(const QByteArray &utf8code) const; + void setExpandTemplates(bool expandTemplates) + { m_expandTemplates = expandTemplates; } + private: void processEnvironment(Document::Ptr doc, Environment *env, @@ -137,6 +140,8 @@ private: Scope *m_scope; LookupContext m_lookupContext; mutable QSharedPointer<Environment> m_environment; + + bool m_expandTemplates; }; ExpressionAST CPLUSPLUS_EXPORT *extractExpressionAST(Document::Ptr doc); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 559788e4d6..72438d114b 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -228,6 +228,78 @@ void CppToolsPlugin::test_completion_template_1() 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() { QFETCH(QByteArray, code); diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 2428b7c32b..8dd911aac8 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -102,7 +102,9 @@ public: , m_completionOperator(T_EOF_SYMBOL) , m_replaceDotForArrow(false) , m_typeOfExpression(new TypeOfExpression) - {} + { + m_typeOfExpression->setExpandTemplates(true); + } virtual bool isSortable(const QString &prefix) const; virtual IAssistProposalItem *proposalItem(int index) const; diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 80b05ba63f..6bc1ddef44 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -93,6 +93,8 @@ private slots: void test_completion_forward_declarations_present(); void test_completion_basic_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_data(); void test_completion_use_global_identifier_as_base_class(); |