aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2012-10-08 13:23:21 +0200
committerErik Verbruggen <erik.verbruggen@digia.com>2012-10-11 16:13:32 +0200
commitba75725a7a6855538a1a5516786440e5ab189f93 (patch)
tree513e654894d0f7be4444a37ea57b93d12e37e2cd /src
parentcc69195c6f4ee00475c5659fc3ff8a492224ced0 (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.cpp15
-rw-r--r--src/libs/3rdparty/cplusplus/Name.h6
-rw-r--r--src/libs/3rdparty/cplusplus/Templates.cpp2
-rw-r--r--src/libs/3rdparty/cplusplus/Templates.h3
-rw-r--r--src/libs/cplusplus/LookupContext.cpp52
-rw-r--r--src/libs/cplusplus/LookupContext.h18
-rw-r--r--src/libs/cplusplus/TypeOfExpression.cpp5
-rw-r--r--src/libs/cplusplus/TypeOfExpression.h5
-rw-r--r--src/plugins/cpptools/cppcompletion_test.cpp72
-rw-r--r--src/plugins/cpptools/cppcompletionassist.cpp4
-rw-r--r--src/plugins/cpptools/cpptoolsplugin.h2
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();