Commit a77e3280 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh

C++: Ignore explicit template instantiations

Defined in section 14.7.2 of the standard.

Fixes completion for std::string.

The following explicit instantiation appears in bits/basic_string.tcc:
  extern template class basic_string<char>;

This is wrongfully considered a specialization for a forward declaration
(like `template<> class basic_string<char>` is).

Introduce a new Symbol type for explicit instantiations.

Use-case:
template<class T>
struct Foo { T bar; };

template class Foo<int>;

void func()
{
    Foo<int> foo;
    foo.bar; // bar not highlighted
}

Change-Id: I9e35c8c32f6b78fc87b4f4f1fc903b42cfbd2c2b
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent 70bc5e84
......@@ -3348,7 +3348,7 @@ public:
DeclarationAST *declaration;
public: // annotations
Template *symbol;
Scope *symbol;
public:
TemplateDeclarationAST()
......
......@@ -2367,11 +2367,15 @@ bool Bind::visit(ParameterDeclarationAST *ast)
bool Bind::visit(TemplateDeclarationAST *ast)
{
Template *templ = control()->newTemplate(ast->firstToken(), 0);
templ->setStartOffset(tokenAt(ast->firstToken()).utf16charsBegin());
templ->setEndOffset(tokenAt(ast->lastToken() - 1).utf16charsEnd());
ast->symbol = templ;
Scope *previousScope = switchScope(templ);
Scope *scope = 0;
if (ast->less_token)
scope = control()->newTemplate(ast->firstToken(), 0);
else
scope = control()->newExplicitInstantiation(ast->firstToken(), 0);
scope->setStartOffset(tokenAt(ast->firstToken()).utf16charsBegin());
scope->setEndOffset(tokenAt(ast->lastToken() - 1).utf16charsEnd());
ast->symbol = scope;
Scope *previousScope = switchScope(scope);
for (DeclarationListAST *it = ast->template_parameter_list; it; it = it->next) {
this->declaration(it->value);
......@@ -2380,12 +2384,17 @@ bool Bind::visit(TemplateDeclarationAST *ast)
this->declaration(ast->declaration);
(void) switchScope(previousScope);
if (Symbol *decl = templ->declaration()) {
templ->setSourceLocation(decl->sourceLocation(), translationUnit());
templ->setName(decl->name());
Symbol *decl = 0;
if (Template *templ = scope->asTemplate())
decl = templ->declaration();
else if (ExplicitInstantiation *inst = scope->asExplicitInstantiation())
decl = inst->declaration();
if (decl) {
scope->setSourceLocation(decl->sourceLocation(), translationUnit());
scope->setName(decl->name());
}
_scope->addMember(templ);
_scope->addMember(scope);
return false;
}
......
......@@ -112,6 +112,7 @@ class Function;
class Namespace;
class NamespaceAlias;
class Template;
class ExplicitInstantiation;
class BaseClass;
class Block;
class Class;
......
......@@ -366,9 +366,16 @@ public:
Template *newTemplate(unsigned sourceLocation, const Name *name)
{
Template *ns = new Template(translationUnit, sourceLocation, name);
symbols.push_back(ns);
return ns;
Template *templ = new Template(translationUnit, sourceLocation, name);
symbols.push_back(templ);
return templ;
}
ExplicitInstantiation *newExplicitInstantiation(unsigned sourceLocation, const Name *name)
{
ExplicitInstantiation *inst = new ExplicitInstantiation(translationUnit, sourceLocation, name);
symbols.push_back(inst);
return inst;
}
NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name)
......@@ -692,6 +699,9 @@ Namespace *Control::newNamespace(unsigned sourceLocation, const Name *name)
Template *Control::newTemplate(unsigned sourceLocation, const Name *name)
{ return d->newTemplate(sourceLocation, name); }
ExplicitInstantiation *Control::newExplicitInstantiation(unsigned sourceLocation, const Name *name)
{ return d->newExplicitInstantiation(sourceLocation, name); }
NamespaceAlias *Control::newNamespaceAlias(unsigned sourceLocation, const Name *name)
{ return d->newNamespaceAlias(sourceLocation, name); }
......
......@@ -120,6 +120,9 @@ public:
/// Creates a new Template symbol.
Template *newTemplate(unsigned sourceLocation, const Name *name = 0);
/// Creates a new ExplicitInstantiation symbol.
ExplicitInstantiation *newExplicitInstantiation(unsigned sourceLocation, const Name *name = 0);
/// Creates a new Namespace symbol.
NamespaceAlias *newNamespaceAlias(unsigned sourceLocation, const Name *name = 0);
......
......@@ -218,6 +218,17 @@ bool Matcher::match(const Template *type, const Template *otherType)
return true;
}
bool Matcher::match(const ExplicitInstantiation *type, const ExplicitInstantiation *otherType)
{
if (type == otherType)
return true;
if (! Matcher::match(type->name(), otherType->name(), this))
return false;
return true;
}
bool Matcher::match(const ForwardClassDeclaration *type, const ForwardClassDeclaration *otherType)
{
if (type == otherType)
......
......@@ -61,6 +61,7 @@ public:
virtual bool match(const Enum *type, const Enum *otherType);
virtual bool match(const Namespace *type, const Namespace *otherType);
virtual bool match(const Template *type, const Template *otherType);
virtual bool match(const ExplicitInstantiation *type, const ExplicitInstantiation *otherType);
virtual bool match(const ForwardClassDeclaration *type, const ForwardClassDeclaration *otherType);
virtual bool match(const Class *type, const Class *otherType);
virtual bool match(const ObjCClass *type, const ObjCClass *otherType);
......
......@@ -361,6 +361,9 @@ bool Symbol::isNamespace() const
bool Symbol::isTemplate() const
{ return asTemplate() != 0; }
bool Symbol::isExplicitInstantiation() const
{ return asExplicitInstantiation() != 0; }
bool Symbol::isClass() const
{ return asClass() != 0; }
......
......@@ -135,7 +135,7 @@ public:
/// Returns true if this Symbol is an Enum.
bool isEnum() const;
/// Returns true if this Symbol is an Function.
/// Returns true if this Symbol is a Function.
bool isFunction() const;
/// Returns true if this Symbol is a Namespace.
......@@ -144,6 +144,9 @@ public:
/// Returns true if this Symbol is a Template.
bool isTemplate() const;
/// Returns true if this Symbol is an ExplicitInstantiation.
bool isExplicitInstantiation() const;
/// Returns true if this Symbol is a Class.
bool isClass() const;
......@@ -203,6 +206,7 @@ public:
virtual const Function *asFunction() const { return 0; }
virtual const Namespace *asNamespace() const { return 0; }
virtual const Template *asTemplate() const { return 0; }
virtual const ExplicitInstantiation *asExplicitInstantiation() const { return 0; }
virtual const NamespaceAlias *asNamespaceAlias() const { return 0; }
virtual const Class *asClass() const { return 0; }
virtual const Block *asBlock() const { return 0; }
......@@ -229,6 +233,7 @@ public:
virtual Function *asFunction() { return 0; }
virtual Namespace *asNamespace() { return 0; }
virtual Template *asTemplate() { return 0; }
virtual ExplicitInstantiation *asExplicitInstantiation() { return 0; }
virtual NamespaceAlias *asNamespaceAlias() { return 0; }
virtual Class *asClass() { return 0; }
virtual Block *asBlock() { return 0; }
......
......@@ -51,6 +51,7 @@ public:
virtual bool visit(Function *) { return true; }
virtual bool visit(Namespace *) { return true; }
virtual bool visit(Template *) { return true; }
virtual bool visit(ExplicitInstantiation *) { return true; }
virtual bool visit(Class *) { return true; }
virtual bool visit(Block *) { return true; }
virtual bool visit(ForwardClassDeclaration *) { return true; }
......
......@@ -481,10 +481,12 @@ void Enum::visitSymbol0(SymbolVisitor *visitor)
Template::Template(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
: Scope(translationUnit, sourceLocation, name)
, _isExplicitInstantiation(false)
{ }
Template::Template(Clone *clone, Subst *subst, Template *original)
: Scope(clone, subst, original)
, _isExplicitInstantiation(original->_isExplicitInstantiation)
{ }
Template::~Template()
......@@ -537,6 +539,56 @@ bool Template::match0(const Type *otherType, Matcher *matcher) const
return false;
}
ExplicitInstantiation::ExplicitInstantiation(TranslationUnit *translationUnit,
unsigned sourceLocation, const Name *name)
: Scope(translationUnit, sourceLocation, name)
{ }
ExplicitInstantiation::ExplicitInstantiation(Clone *clone, Subst *subst, ExplicitInstantiation *original)
: Scope(clone, subst, original)
{ }
ExplicitInstantiation::~ExplicitInstantiation()
{ }
Symbol *ExplicitInstantiation::declaration() const
{
if (isEmpty())
return 0;
if (Symbol *s = memberAt(memberCount() - 1)) {
if (s->isClass() || s->isForwardClassDeclaration() ||
s->isTemplate() || s->isExplicitInstantiation() ||
s->isFunction() || s->isDeclaration()) {
return s;
}
}
return 0;
}
FullySpecifiedType ExplicitInstantiation::type() const
{ return FullySpecifiedType(const_cast<ExplicitInstantiation *>(this)); }
void ExplicitInstantiation::visitSymbol0(SymbolVisitor *visitor)
{
if (visitor->visit(this)) {
for (unsigned i = 0; i < memberCount(); ++i) {
visitSymbol(memberAt(i), visitor);
}
}
}
void ExplicitInstantiation::accept0(TypeVisitor *visitor)
{ visitor->visit(this); }
bool ExplicitInstantiation::match0(const Type *otherType, Matcher *matcher) const
{
if (const ExplicitInstantiation *otherTy = otherType->asExplicitInstantiationType())
return matcher->match(this, otherTy);
return false;
}
Namespace::Namespace(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name)
: Scope(translationUnit, sourceLocation, name)
, _isInline(false)
......
......@@ -423,8 +423,41 @@ protected:
virtual void visitSymbol0(SymbolVisitor *visitor);
virtual void accept0(TypeVisitor *visitor);
virtual bool match0(const Type *otherType, Matcher *matcher) const;
private:
bool _isExplicitInstantiation;
};
class CPLUSPLUS_EXPORT ExplicitInstantiation : public Scope, public Type
{
public:
ExplicitInstantiation(TranslationUnit *translationUnit, unsigned sourceLocation, const Name *name);
ExplicitInstantiation(Clone *clone, Subst *subst, ExplicitInstantiation *original);
virtual ~ExplicitInstantiation();
Symbol *declaration() const;
// Symbol's interface
virtual FullySpecifiedType type() const;
virtual const ExplicitInstantiation *asExplicitInstantiation() const
{ return this; }
virtual ExplicitInstantiation *asExplicitInstantiation()
{ return this; }
// Type's interface
virtual const ExplicitInstantiation *asExplicitInstantiationType() const
{ return this; }
virtual ExplicitInstantiation *asExplicitInstantiationType()
{ return this; }
protected:
virtual void visitSymbol0(SymbolVisitor *visitor);
virtual void accept0(TypeVisitor *visitor);
virtual bool match0(const Type *otherType, Matcher *matcher) const;
};
class CPLUSPLUS_EXPORT Namespace: public Scope, public Type
{
......
......@@ -125,6 +125,12 @@ void CloneType::visit(Template *type)
_type = templ;
}
void CloneType::visit(ExplicitInstantiation *type)
{
ExplicitInstantiation *inst = _clone->symbol(type, _subst)->asExplicitInstantiation();
_type = inst;
}
void CloneType::visit(Class *type)
{
Class *klass = _clone->symbol(type, _subst)->asClass();
......@@ -291,6 +297,14 @@ bool CloneSymbol::visit(Template *symbol)
return false;
}
bool CloneSymbol::visit(ExplicitInstantiation *symbol)
{
ExplicitInstantiation *inst = new ExplicitInstantiation(_clone, _subst, symbol);
_symbol = inst;
_control->addSymbol(inst);
return false;
}
bool CloneSymbol::visit(Class *symbol)
{
Class *klass = new Class(_clone, _subst, symbol);
......
......@@ -85,6 +85,7 @@ protected:
virtual void visit(Function *type);
virtual void visit(Namespace *type);
virtual void visit(Template *type);
virtual void visit(ExplicitInstantiation *type);
virtual void visit(Class *type);
virtual void visit(Enum *type);
virtual void visit(ForwardClassDeclaration *type);
......@@ -152,6 +153,7 @@ protected:
virtual bool visit(Function *symbol);
virtual bool visit(Namespace *symbol);
virtual bool visit(Template *symbol);
virtual bool visit(ExplicitInstantiation *symbol);
virtual bool visit(Class *symbol);
virtual bool visit(Block *symbol);
virtual bool visit(ForwardClassDeclaration *symbol);
......
......@@ -68,6 +68,9 @@ bool Type::isNamespaceType() const
bool Type::isTemplateType() const
{ return asTemplateType() != 0; }
bool Type::isExplicitInstantiationType() const
{ return asExplicitInstantiationType() != 0; }
bool Type::isClassType() const
{ return asClassType() != 0; }
......
......@@ -43,6 +43,7 @@ public:
bool isFunctionType() const;
bool isNamespaceType() const;
bool isTemplateType() const;
bool isExplicitInstantiationType() const;
bool isClassType() const;
bool isEnumType() const;
bool isForwardClassDeclarationType() const;
......@@ -64,6 +65,7 @@ public:
virtual const Function *asFunctionType() const { return 0; }
virtual const Namespace *asNamespaceType() const { return 0; }
virtual const Template *asTemplateType() const { return 0; }
virtual const ExplicitInstantiation *asExplicitInstantiationType() const { return 0; }
virtual const Class *asClassType() const { return 0; }
virtual const Enum *asEnumType() const { return 0; }
virtual const ForwardClassDeclaration *asForwardClassDeclarationType() const { return 0; }
......@@ -85,6 +87,7 @@ public:
virtual Function *asFunctionType() { return 0; }
virtual Namespace *asNamespaceType() { return 0; }
virtual Template *asTemplateType() { return 0; }
virtual ExplicitInstantiation *asExplicitInstantiationType() { return 0; }
virtual Class *asClassType() { return 0; }
virtual Enum *asEnumType() { return 0; }
virtual ForwardClassDeclaration *asForwardClassDeclarationType() { return 0; }
......
......@@ -51,6 +51,7 @@ public:
virtual void visit(Function *) {}
virtual void visit(Namespace *) {}
virtual void visit(Template *) {}
virtual void visit(ExplicitInstantiation *) {}
virtual void visit(Class *) {}
virtual void visit(Enum *) {}
virtual void visit(ForwardClassDeclaration *) {}
......
......@@ -1830,6 +1830,12 @@ bool CreateBindings::visit(Template *templ)
return false;
}
bool CreateBindings::visit(ExplicitInstantiation *inst)
{
Q_UNUSED(inst);
return false;
}
bool CreateBindings::visit(Namespace *ns)
{
LookupScope *previous = enterLookupScopeBinding(ns);
......
......@@ -178,6 +178,7 @@ protected:
void process(Symbol *root);
virtual bool visit(Template *templ);
virtual bool visit(ExplicitInstantiation *inst);
virtual bool visit(Namespace *ns);
virtual bool visit(Class *klass);
virtual bool visit(ForwardClassDeclaration *klass);
......
......@@ -796,6 +796,21 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("Data")
<< QLatin1String("dataMember"));
QTest::newRow("explicit_instantiation") << _(
"template<class T>\n"
"struct Foo { T bar; };\n"
"\n"
"template class Foo<int>;\n"
"\n"
"void func()\n"
"{\n"
" Foo<int> foo;\n"
" @\n"
"}\n"
) << _("foo.") << (QStringList()
<< QLatin1String("Foo")
<< QLatin1String("bar"));
QTest::newRow("use_global_identifier_as_base_class: derived as global and base as global") << _(
"struct Global\n"
"{\n"
......
......@@ -166,6 +166,7 @@ private slots:
void pointer_to_function_1();
void template_instance_1();
void explicit_instantiation_1();
void expression_under_cursor_1();
......@@ -523,6 +524,25 @@ void tst_Semantic::template_instance_1()
QCOMPARE(genDecl, QString::fromLatin1("void (const int &)"));
}
void tst_Semantic::explicit_instantiation_1()
{
QSharedPointer<Document> doc = document("template class basic_string<char>;");
QCOMPARE(doc->errorCount, 0U);
QCOMPARE(doc->globals->memberCount(), 1U);
ExplicitInstantiation *inst = doc->globals->memberAt(0)->asExplicitInstantiation();
QVERIFY(inst);
ForwardClassDeclaration *fwd = inst->memberAt(0)->asForwardClassDeclaration();
QVERIFY(fwd);
QVERIFY(inst->name()->match(fwd->name()));
Overview oo;
const QString name = oo.prettyName(inst->name());
QCOMPARE(name, QString::fromLatin1("basic_string<char>"));
}
void tst_Semantic::expression_under_cursor_1()
{
const QString plainText = "void *ptr = foo(10, bar";
......
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