forked from qt-creator/qt-creator
C++: add support for local types
This change addes support for class, enum definition inside blocks({}) or
functions, e.g.:
void f()
{
struct S
{
int bar;
};
S s;
s.bar;
}
It fixes:
* code completion
* highlighting
* follow symbol
* marking
* find usages
It fixes also problem with namespace aliases inside blocks or functions.
This change can have also impact on performance(there are additional processing)
Task-number: QTCREATORBUG-166 (namespace aliases inside function/block)
Task-number: QTCREATORBUG-3620
Task-number: QTCREATORBUG-6013
Task-number: QTCREATORBUG-8020
Change-Id: Iaea6c6dfe276f1d7b2279b50bdd2e68e375d31eb
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
committed by
Erik Verbruggen
parent
2bc24b7a25
commit
68d6a762d9
@@ -348,7 +348,17 @@ ClassOrNamespace *LookupContext::lookupType(const Name *name, Scope *scope,
|
||||
}
|
||||
}
|
||||
}
|
||||
return lookupType(name, scope->enclosingScope());
|
||||
// try to find it in block (rare case but has priority before enclosing scope)
|
||||
// e.g.: void foo() { struct S {}; S s; }
|
||||
if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
|
||||
if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(name, block))
|
||||
return classOrNamespaceNestedInNestedBlock;
|
||||
}
|
||||
|
||||
// try to find type in enclosing scope(typical case)
|
||||
if (ClassOrNamespace *found = lookupType(name, scope->enclosingScope()))
|
||||
return found;
|
||||
|
||||
} else if (ClassOrNamespace *b = bindings()->lookupType(scope, enclosingTemplateInstantiation)) {
|
||||
return b->lookupType(name);
|
||||
}
|
||||
@@ -397,6 +407,15 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
||||
if (! candidates.isEmpty())
|
||||
return candidates;
|
||||
|
||||
if (ClassOrNamespace *binding = bindings()->lookupType(scope)) {
|
||||
if (ClassOrNamespace *block = binding->findBlock(scope->asBlock())) {
|
||||
candidates = block->find(name);
|
||||
|
||||
if (! candidates.isEmpty())
|
||||
return candidates;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (Function *fun = scope->asFunction()) {
|
||||
bindings()->lookupInScope(name, fun, &candidates, /*templateId = */ 0, /*binding=*/ 0);
|
||||
|
||||
@@ -455,6 +474,17 @@ QList<LookupItem> LookupContext::lookup(const Name *name, Scope *scope) const
|
||||
if (! candidates.isEmpty())
|
||||
return candidates;
|
||||
|
||||
// the scope can be defined inside a block, try to find it
|
||||
if (Block *block = scope->enclosingBlock()) {
|
||||
if (ClassOrNamespace *b = bindings()->lookupType(block)) {
|
||||
if (ClassOrNamespace *classOrNamespaceNestedInNestedBlock = b->lookupType(scope->name(), block))
|
||||
candidates = classOrNamespaceNestedInNestedBlock->find(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (! candidates.isEmpty())
|
||||
return candidates;
|
||||
|
||||
} else if (scope->isObjCClass() || scope->isObjCProtocol()) {
|
||||
if (ClassOrNamespace *binding = bindings()->lookupType(scope))
|
||||
candidates = binding->find(name);
|
||||
@@ -723,12 +753,54 @@ ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name)
|
||||
return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ true, this);
|
||||
}
|
||||
|
||||
ClassOrNamespace *ClassOrNamespace::lookupType(const Name *name, Block *block)
|
||||
{
|
||||
flush();
|
||||
|
||||
QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.find(block);
|
||||
if (citBlock != _blocks.end()) {
|
||||
ClassOrNamespace *nestedBlock = citBlock.value();
|
||||
QSet<ClassOrNamespace *> processed;
|
||||
if (ClassOrNamespace *foundInNestedBlock
|
||||
= nestedBlock->lookupType_helper(name,
|
||||
&processed,
|
||||
/*searchInEnclosingScope = */ true,
|
||||
this)) {
|
||||
return foundInNestedBlock;
|
||||
}
|
||||
}
|
||||
|
||||
for (citBlock = _blocks.begin(); citBlock != _blocks.end(); ++citBlock) {
|
||||
if (ClassOrNamespace *foundNestedBlock = citBlock.value()->lookupType(name, block))
|
||||
return foundNestedBlock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ClassOrNamespace *ClassOrNamespace::findType(const Name *name)
|
||||
{
|
||||
QSet<ClassOrNamespace *> processed;
|
||||
return lookupType_helper(name, &processed, /*searchInEnclosingScope =*/ false, this);
|
||||
}
|
||||
|
||||
ClassOrNamespace *ClassOrNamespace::findBlock(Block *block)
|
||||
{
|
||||
flush();
|
||||
|
||||
QHash<Block *, ClassOrNamespace *>::const_iterator citBlock = _blocks.find(block);
|
||||
if (citBlock != _blocks.end()) {
|
||||
return citBlock.value();
|
||||
}
|
||||
|
||||
for (citBlock = _blocks.begin(); citBlock != _blocks.end(); ++citBlock) {
|
||||
if (ClassOrNamespace *foundNestedBlock = citBlock.value()->findBlock(block))
|
||||
return foundNestedBlock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Symbol *ClassOrNamespace::lookupInScope(const QList<const Name *> &fullName)
|
||||
{
|
||||
if (!_scopeLookupCache) {
|
||||
@@ -1490,8 +1562,46 @@ bool CreateBindings::visit(Declaration *decl)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CreateBindings::visit(Function *)
|
||||
bool CreateBindings::visit(Function *function)
|
||||
{
|
||||
for (unsigned i = 0, count = function->memberCount(); i < count; ++i) {
|
||||
Symbol *s = function->memberAt(i);
|
||||
if (Block *b = s->asBlock())
|
||||
visit(b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CreateBindings::visit(Block *block)
|
||||
{
|
||||
ClassOrNamespace *previous = _currentClassOrNamespace;
|
||||
|
||||
ClassOrNamespace *binding = new ClassOrNamespace(this, previous);
|
||||
binding->_control = control();
|
||||
|
||||
_currentClassOrNamespace = binding;
|
||||
_currentClassOrNamespace->addSymbol(block);
|
||||
|
||||
for (unsigned i = 0; i < block->memberCount(); ++i)
|
||||
// we cannot use lazy processing here, because we have to know
|
||||
// does this block contain any other blocks or classOrNamespaces
|
||||
process(block->memberAt(i), _currentClassOrNamespace);
|
||||
|
||||
// we add this block to parent ClassOrNamespace only if it contains
|
||||
// any nested ClassOrNamespaces or other blocks(which have to contain
|
||||
// nested ClassOrNamespaces)
|
||||
if (! _currentClassOrNamespace->_blocks.empty()
|
||||
|| ! _currentClassOrNamespace->_classOrNamespaces.empty()
|
||||
|| ! _currentClassOrNamespace->_enums.empty()) {
|
||||
previous->_blocks[block] = binding;
|
||||
_entities.append(binding);
|
||||
} else {
|
||||
delete binding;
|
||||
binding = 0;
|
||||
}
|
||||
|
||||
_currentClassOrNamespace = previous;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,9 @@ public:
|
||||
QList<LookupItem> find(const Name *name);
|
||||
|
||||
ClassOrNamespace *lookupType(const Name *name);
|
||||
ClassOrNamespace *lookupType(const Name *name, Block *block);
|
||||
ClassOrNamespace *findType(const Name *name);
|
||||
ClassOrNamespace *findBlock(Block *block);
|
||||
|
||||
Symbol *lookupInScope(const QList<const Name *> &fullName);
|
||||
|
||||
@@ -126,6 +128,7 @@ private:
|
||||
QList<Symbol *> _symbols;
|
||||
QList<ClassOrNamespace *> _usings;
|
||||
Table _classOrNamespaces;
|
||||
QHash<Block *, ClassOrNamespace *> _blocks;
|
||||
QList<Enum *> _enums;
|
||||
QList<Symbol *> _todo;
|
||||
QSharedPointer<Control> _control;
|
||||
@@ -238,7 +241,9 @@ protected:
|
||||
virtual bool visit(ForwardClassDeclaration *klass);
|
||||
virtual bool visit(Enum *e);
|
||||
virtual bool visit(Declaration *decl);
|
||||
virtual bool visit(Function *);
|
||||
virtual bool visit(Function *function);
|
||||
virtual bool visit(Block *block);
|
||||
|
||||
virtual bool visit(BaseClass *b);
|
||||
virtual bool visit(UsingNamespaceDirective *u);
|
||||
virtual bool visit(UsingDeclaration *u);
|
||||
|
||||
Reference in New Issue
Block a user