Skip to content
Snippets Groups Projects
Commit 31e0b433 authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Initial work on the binding pass.

parent 2ac1f797
No related branches found
No related tags found
No related merge requests found
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#include "CppBindings.h"
#include "CppDocument.h"
#include "Overview.h"
#include <CoreTypes.h>
#include <Symbols.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Control.h>
#include <SymbolVisitor.h>
#include <QtDebug>
using namespace CPlusPlus;
////////////////////////////////////////////////////////////////////////////////
// Location
////////////////////////////////////////////////////////////////////////////////
Location::Location()
: _fileId(0),
_sourceLocation(0)
{ }
Location::Location(Symbol *symbol)
: _fileId(symbol->fileId()),
_sourceLocation(symbol->sourceLocation())
{ }
Location::Location(StringLiteral *fileId, unsigned sourceLocation)
: _fileId(fileId), _sourceLocation(sourceLocation)
{ }
////////////////////////////////////////////////////////////////////////////////
// NamespaceBinding
////////////////////////////////////////////////////////////////////////////////
NamespaceBinding::NamespaceBinding(NamespaceBinding *parent)
: parent(parent),
anonymousNamespaceBinding(0)
{
if (parent)
parent->children.append(this);
}
NamespaceBinding::~NamespaceBinding()
{
qDeleteAll(children);
qDeleteAll(classBindings);
}
NameId *NamespaceBinding::name() const
{
if (symbols.size()) {
if (Name *name = symbols.at(0)->name()) {
NameId *nameId = name->asNameId();
Q_ASSERT(nameId != 0);
return nameId;
}
}
return 0;
}
Identifier *NamespaceBinding::identifier() const
{
if (NameId *nameId = name())
return nameId->identifier();
return 0;
}
NamespaceBinding *NamespaceBinding::globalNamespaceBinding()
{
NamespaceBinding *it = this;
for (; it; it = it->parent) {
if (! it->parent)
break;
}
return it;
}
NamespaceBinding *NamespaceBinding::findNamespaceBinding(Name *name)
{
if (! name)
return anonymousNamespaceBinding;
else if (NameId *nameId = name->asNameId())
return findNamespaceBindingForNameId(nameId);
// invalid binding
return 0;
}
NamespaceBinding *NamespaceBinding::findNamespaceBindingForNameId(NameId *name)
{
foreach (NamespaceBinding *binding, children) {
Name *bindingName = binding->name();
if (! bindingName)
continue;
if (NameId *bindingNameId = bindingName->asNameId()) {
if (name->isEqualTo(bindingNameId))
return binding;
}
}
return 0;
}
NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symbol)
{
if (NamespaceBinding *binding = findNamespaceBinding(symbol->name())) {
int index = 0;
for (; index < binding->symbols.size(); ++index) {
Namespace *ns = binding->symbols.at(index);
if (ns == symbol)
break;
}
if (index == binding->symbols.size())
binding->symbols.append(symbol);
return binding;
}
NamespaceBinding *binding = new NamespaceBinding(this);
binding->symbols.append(symbol);
if (! symbol->name()) {
Q_ASSERT(! anonymousNamespaceBinding);
anonymousNamespaceBinding = binding;
}
return binding;
}
static void closure(const Location &loc,
NamespaceBinding *binding, Name *name,
QList<NamespaceBinding *> *bindings)
{
if (bindings->contains(binding))
return;
bindings->append(binding);
Q_ASSERT(name->isNameId());
Identifier *id = name->asNameId()->identifier();
bool ignoreUsingDirectives = false;
foreach (Namespace *symbol, binding->symbols) {
Scope *scope = symbol->members();
for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
if (symbol->name() != name || ! symbol->isNamespace())
continue;
const Location l(symbol);
if (l.fileId() == loc.fileId() && l.sourceLocation() < loc.sourceLocation()) {
ignoreUsingDirectives = true;
break;
}
}
}
if (ignoreUsingDirectives)
return;
foreach (NamespaceBinding *u, binding->usings)
closure(loc, u, name, bindings);
}
NamespaceBinding *NamespaceBinding::resolveNamespace(const Location &loc,
Name *name,
bool lookAtParent)
{
if (! name)
return 0;
else if (NameId *nameId = name->asNameId()) {
QList<NamespaceBinding *> bindings;
closure(loc, this, nameId, &bindings);
QList<NamespaceBinding *> results;
foreach (NamespaceBinding *binding, bindings) {
if (NamespaceBinding *b = binding->findNamespaceBinding(nameId))
results.append(b);
}
if (results.size() == 1)
return results.at(0);
else if (results.size() > 1) {
// ### FIXME: return 0;
return results.at(0);
}
else if (parent && lookAtParent)
return parent->resolveNamespace(loc, name);
} else if (QualifiedNameId *q = name->asQualifiedNameId()) {
if (q->nameCount() == 1) {
Q_ASSERT(q->isGlobal());
return globalNamespaceBinding()->resolveNamespace(loc, q->nameAt(0));
}
NamespaceBinding *current = this;
if (q->isGlobal())
current = globalNamespaceBinding();
current = current->resolveNamespace(loc, q->nameAt(0));
for (unsigned i = 1; current && i < q->nameCount(); ++i)
current = current->resolveNamespace(loc, q->nameAt(i), false);
return current;
}
return 0;
}
// ### rewrite me
QByteArray NamespaceBinding::qualifiedId() const
{
if (! parent)
return "<root>";
QByteArray s;
s.append(parent->qualifiedId());
s.append("::");
if (Identifier *id = identifier())
s.append(id->chars(), id->size());
else
s.append("<anonymous>");
return s;
}
// ### rewrite me
QByteArray ClassBinding::qualifiedId() const
{
QByteArray s = parent->qualifiedId();
s += "::";
if (Identifier *id = identifier())
s.append(id->chars(), id->size());
else
s.append("<anonymous>");
return s;
}
static int depth;
void NamespaceBinding::dump()
{
qDebug() << QByteArray(depth, ' ').constData() << "namespace" << qualifiedId().constData()
<< " # " << symbols.size();
++depth;
foreach (ClassBinding *classBinding, classBindings) {
classBinding->dump();
}
foreach (NamespaceBinding *child, children) {
child->dump();
}
--depth;
}
void ClassBinding::dump()
{
qDebug() << QByteArray(depth, ' ').constData() << "class" << qualifiedId().constData()
<< " # " << symbols.size();
++depth;
foreach (ClassBinding *classBinding, children) {
classBinding->dump();
}
--depth;
}
////////////////////////////////////////////////////////////////////////////////
// ClassBinding
////////////////////////////////////////////////////////////////////////////////
ClassBinding::ClassBinding(NamespaceBinding *parent)
: parent(parent)
{
parent->classBindings.append(this);
}
ClassBinding::ClassBinding(ClassBinding *parentClass)
{
parent = parentClass->parent;
parentClass->children.append(this);
}
ClassBinding::~ClassBinding()
{ qDeleteAll(children); }
NameId *ClassBinding::name() const
{
if (symbols.size()) {
if (Name *name = symbols.at(0)->name()) {
NameId *nameId = name->asNameId();
return nameId;
}
}
return 0;
}
Identifier *ClassBinding::identifier() const
{
if (NameId *nameId = name())
return nameId->identifier();
return 0;
}
namespace {
////////////////////////////////////////////////////////////////////////////////
// Binder
////////////////////////////////////////////////////////////////////////////////
class Binder: protected SymbolVisitor
{
public:
Binder(NamespaceBinding *globals);
virtual ~Binder();
NamespaceBinding *operator()(Document::Ptr doc, const Snapshot &snapshot)
{
namespaceBinding = _globals;
const Snapshot previousSnapshot = _snapshot;
_snapshot = snapshot;
(void) bind(doc);
_snapshot = previousSnapshot;
return _globals;
}
Snapshot _snapshot;
protected:
NamespaceBinding *bind(Document::Ptr doc)
{
QSet<QString> processed;
return bind(doc, &processed);
}
NamespaceBinding *bind(Document::Ptr doc, QSet<QString> *processed)
{
if (processed->contains(doc->fileName()))
return 0;
processed->insert(doc->fileName());
foreach (const Document::Include &i, doc->includes()) {
if (Document::Ptr includedDoc = _snapshot.value(i.fileName())) {
/*NamepaceBinding *binding = */ bind(includedDoc, processed);
}
}
Namespace *ns = doc->globalNamespace();
_globals->symbols.append(ns);
for (unsigned i = 0; i < ns->memberCount(); ++i) {
(void) bind(ns->memberAt(i), _globals);
}
return _globals;
}
NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding);
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc, Name *name);
NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding);
ClassBinding *findOrCreateClassBinding(Class *classSymbol);
ClassBinding *findClassBinding(Name *name);
ClassBinding *switchClassBinding(ClassBinding *binding);
using SymbolVisitor::visit;
virtual bool visit(Namespace *);
virtual bool visit(UsingNamespaceDirective *);
virtual bool visit(Class *);
virtual bool visit(Function *);
virtual bool visit(Block *);
private:
NamespaceBinding *_globals;
NamespaceBinding *namespaceBinding;
ClassBinding *classBinding;
};
Binder::Binder(NamespaceBinding *globals)
: _globals(globals),
namespaceBinding(0),
classBinding(0)
{ }
Binder::~Binder()
{ }
NamespaceBinding *Binder::bind(Symbol *symbol, NamespaceBinding *binding)
{
NamespaceBinding *previousBinding = switchNamespaceBinding(binding);
accept(symbol);
return switchNamespaceBinding(previousBinding);
}
NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol)
{ return namespaceBinding->findOrCreateNamespaceBinding(symbol); }
NamespaceBinding *Binder::resolveNamespace(const Location &loc, Name *name)
{
if (! namespaceBinding)
return 0;
return namespaceBinding->resolveNamespace(loc, name);
}
NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding)
{
NamespaceBinding *previousBinding = namespaceBinding;
namespaceBinding = binding;
return previousBinding;
}
ClassBinding *Binder::findOrCreateClassBinding(Class *classSymbol)
{
ClassBinding *binding = 0;
if (classBinding)
binding = new ClassBinding(classBinding);
else
binding = new ClassBinding(namespaceBinding);
binding->symbols.append(classSymbol);
return binding;
}
ClassBinding *Binder::findClassBinding(Name *name)
{
qDebug() << Q_FUNC_INFO;
return 0;
}
ClassBinding *Binder::switchClassBinding(ClassBinding *binding)
{
ClassBinding *previousClassBinding = classBinding;
classBinding = binding;
return previousClassBinding;
}
bool Binder::visit(Namespace *symbol)
{
NamespaceBinding *binding = findOrCreateNamespaceBinding(symbol);
for (unsigned i = 0; i < symbol->memberCount(); ++i) {
Symbol *member = symbol->memberAt(i);
bind(member, binding);
}
return false;
}
bool Binder::visit(UsingNamespaceDirective *u)
{
NamespaceBinding *resolved = resolveNamespace(Location(u), u->name());
if (! resolved)
return false;
namespaceBinding->usings.append(resolved);
return false;
}
bool Binder::visit(Class *classSymbol)
{
Overview oo;
ClassBinding *binding = findOrCreateClassBinding(classSymbol);
ClassBinding *previousClassBinding = switchClassBinding(binding);
#if 0
for (unsigned i = 0; i < classSymbol->baseClassCount(); ++i) {
BaseClass *baseClass = classSymbol->baseClassAt(i);
ClassBinding *baseClassBinding = findClassBinding(baseClass->name());
// ### wrong
binding->baseClassBindings.append(baseClassBinding);
}
#endif
for (unsigned i = 0; i < classSymbol->memberCount(); ++i)
accept(classSymbol->memberAt(i));
(void) switchClassBinding(previousClassBinding);
return false;
}
bool Binder::visit(Function *)
{ return false; }
bool Binder::visit(Block *)
{ return false; }
} // end of anonymous namespace
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CPPBINDINGS_H
#define CPPBINDINGS_H
#include <CPlusPlusForwardDeclarations.h>
#include <QtCore/QList>
#include <QtCore/QSharedPointer>
#include <QtCore/QString>
#include <QtCore/QByteArray>
namespace CPlusPlus {
class Location;
class Binding;
class NamespaceBinding;
class ClassBinding;
typedef QSharedPointer<Binding> BindingPtr;
typedef QSharedPointer<ClassBinding> ClassBindingPtr;
typedef QSharedPointer<NamespaceBinding> NamespaceBindingPtr;
class CPLUSPLUS_EXPORT Location
{
public:
Location();
Location(Symbol *symbol);
Location(StringLiteral *fileId, unsigned sourceLocation);
inline bool isValid() const
{ return _fileId != 0; }
inline operator bool() const
{ return _fileId != 0; }
inline StringLiteral *fileId() const
{ return _fileId; }
inline unsigned sourceLocation() const
{ return _sourceLocation; }
private:
StringLiteral *_fileId;
unsigned _sourceLocation;
};
class CPLUSPLUS_EXPORT Binding
{
Q_DISABLE_COPY(Binding)
public:
Binding() {}
virtual ~Binding() {}
virtual NamespaceBinding *asNamespaceBinding() { return 0; }
virtual ClassBinding *asClassBinding() { return 0; }
};
class CPLUSPLUS_EXPORT NamespaceBinding: public Binding
{
public:
/// Constructs a binding with the given parent.
NamespaceBinding(NamespaceBinding *parent = 0);
/// Destroys the binding.
virtual ~NamespaceBinding();
/// Returns this binding's name.
NameId *name() const;
/// Returns this binding's identifier.
Identifier *identifier() const;
/// Returns the binding for the global namespace (aka ::).
NamespaceBinding *globalNamespaceBinding();
/// Returns the binding for the given namespace symbol.
NamespaceBinding *findNamespaceBinding(Name *name);
/// Returns the binding associated with the given symbol.
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc,
Name *name,
bool lookAtParent = true);
/// Helpers.
QByteArray qualifiedId() const;
void dump();
virtual NamespaceBinding *asNamespaceBinding() { return this; }
private:
NamespaceBinding *findNamespaceBindingForNameId(NameId *name);
public: // attributes
/// This binding's parent.
NamespaceBinding *parent;
/// Binding for anonymous namespace symbols.
NamespaceBinding *anonymousNamespaceBinding;
/// This binding's connections.
QList<NamespaceBinding *> children;
/// This binding's list of using namespaces.
QList<NamespaceBinding *> usings;
/// This binding's namespace symbols.
QList<Namespace *> symbols;
QList<ClassBinding *> classBindings;
};
class CPLUSPLUS_EXPORT ClassBinding: public Binding
{
public:
ClassBinding(NamespaceBinding *parent);
ClassBinding(ClassBinding *parentClass);
virtual ~ClassBinding();
virtual ClassBinding *asClassBinding() { return this; }
/// Returns this binding's name.
NameId *name() const;
/// Returns this binding's identifier.
Identifier *identifier() const;
QByteArray qualifiedId() const;
void dump();
public: // attributes
NamespaceBinding *parent;
QList<ClassBinding *> children;
/// This binding's class symbols.
QList<Class *> symbols;
/// Bindings for the base classes.
QList<ClassBinding *> baseClassBindings;
};
} // end of namespace CPlusPlus
#endif // CPPBINDINGS_H
......@@ -26,6 +26,7 @@ HEADERS += \
$$PWD/TypePrettyPrinter.h \
$$PWD/ResolveExpression.h \
$$PWD/LookupContext.h \
$$PWD/CppBindings.h \
$$PWD/PreprocessorClient.h \
$$PWD/PreprocessorEnvironment.h \
$$PWD/Macro.h \
......@@ -44,6 +45,7 @@ SOURCES += \
$$PWD/TypePrettyPrinter.cpp \
$$PWD/ResolveExpression.cpp \
$$PWD/LookupContext.cpp \
$$PWD/CppBindings.cpp \
$$PWD/PreprocessorClient.cpp \
$$PWD/PreprocessorEnvironment.cpp \
$$PWD/Macro.cpp \
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment