diff generator/parser/binder.cpp @ 1:e78566595089

initial import
author mandel
date Mon, 11 May 2009 16:01:50 +0000
parents
children 09a0f1d048f2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/generator/parser/binder.cpp	Mon May 11 16:01:50 2009 +0000
@@ -0,0 +1,928 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Nokia. All rights reserved.
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+**
+** This file is part of Qt Jambi.
+**
+** * 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 General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU
+* General Public License versions 2.0 or 3.0 as published by the Free
+* Software Foundation and appearing in the file LICENSE.GPL included in
+* the packaging of this file.  Please review the following information
+* to ensure GNU General Public Licensing requirements will be met:
+* http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+* http://www.gnu.org/copyleft/gpl.html.  In addition, as a special
+* exception, Nokia gives you certain additional rights. These rights
+* are described in the Nokia Qt GPL Exception version 1.2, included in
+* the file GPL_EXCEPTION.txt in this package.
+* 
+* Qt for Windows(R) Licensees
+* As a special exception, Nokia, as the sole copyright holder for Qt
+* Designer, grants users of the Qt/Eclipse Integration plug-in the
+* right for the Qt/Eclipse Integration to link to functionality
+* provided by Qt Designer and its related libraries.
+*
+*
+* If you are unsure which license is appropriate for your use, please
+* contact the sales department at qt-sales@nokia.com.
+
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "binder.h"
+#include "lexer.h"
+#include "control.h"
+#include "symbol.h"
+#include "codemodel_finder.h"
+#include "class_compiler.h"
+#include "compiler_utils.h"
+#include "tokens.h"
+#include "dumptree.h"
+
+#include <iostream>
+
+#include <qdebug.h>
+
+void binder_default_message_handler(const std::string &str) {
+    std::cerr << str;
+}
+
+MessageHandler Binder::_M_message_handler = binder_default_message_handler;
+
+Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control)
+  : _M_model(__model),
+    _M_location(__location),
+    _M_token_stream(&_M_location.token_stream),
+    _M_control(__control),
+    _M_current_function_type(CodeModel::Normal),
+    type_cc(this),
+    name_cc(this),
+    decl_cc(this)
+{
+  _M_qualified_types["char"] = QString();
+  _M_qualified_types["double"] = QString();
+  _M_qualified_types["float"] = QString();
+  _M_qualified_types["int"] = QString();
+  _M_qualified_types["long"] = QString();
+  _M_qualified_types["short"] = QString();
+  _M_qualified_types["void"] = QString();
+}
+
+Binder::~Binder()
+{
+}
+
+FileModelItem Binder::run(AST *node)
+{
+  FileModelItem old = _M_current_file;
+  _M_current_access = CodeModel::Public;
+
+  _M_current_file = model()->create<FileModelItem>();
+  updateItemPosition (_M_current_file->toItem(), node);
+  visit(node);
+  FileModelItem result = _M_current_file;
+
+  _M_current_file = old; // restore
+
+  return result;
+}
+
+ScopeModelItem Binder::currentScope()
+{
+  if (_M_current_class)
+    return model_static_cast<ScopeModelItem>(_M_current_class);
+  else if (_M_current_namespace)
+    return model_static_cast<ScopeModelItem>(_M_current_namespace);
+
+  return model_static_cast<ScopeModelItem>(_M_current_file);
+}
+
+TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters)
+{
+  TemplateParameterList old = _M_current_template_parameters;
+  _M_current_template_parameters = templateParameters;
+  return old;
+}
+
+CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType)
+{
+  CodeModel::FunctionType old = _M_current_function_type;
+  _M_current_function_type = functionType;
+  return old;
+}
+
+CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy)
+{
+  CodeModel::AccessPolicy old = _M_current_access;
+  _M_current_access = accessPolicy;
+  return old;
+}
+
+NamespaceModelItem Binder::changeCurrentNamespace(NamespaceModelItem item)
+{
+  NamespaceModelItem old = _M_current_namespace;
+  _M_current_namespace = item;
+  return old;
+}
+
+ClassModelItem Binder::changeCurrentClass(ClassModelItem item)
+{
+  ClassModelItem old = _M_current_class;
+  _M_current_class = item;
+  return old;
+}
+
+FunctionDefinitionModelItem Binder::changeCurrentFunction(FunctionDefinitionModelItem item)
+{
+  FunctionDefinitionModelItem old = _M_current_function;
+  _M_current_function = item;
+  return old;
+}
+
+int Binder::decode_token(std::size_t index) const
+{
+  return _M_token_stream->kind(index);
+}
+
+CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const
+{
+  switch (decode_token(index))
+    {
+      case Token_class:
+        return CodeModel::Private;
+
+      case Token_struct:
+      case Token_union:
+        return CodeModel::Public;
+
+      default:
+        return CodeModel::Public;
+    }
+}
+
+CodeModel::ClassType Binder::decode_class_type(std::size_t index) const
+{
+  switch (decode_token(index))
+    {
+      case Token_class:
+        return CodeModel::Class;
+      case Token_struct:
+        return CodeModel::Struct;
+      case Token_union:
+        return CodeModel::Union;
+      default:
+        _M_message_handler("** WARNING unrecognized class type");
+    }
+    return CodeModel::Class;
+}
+
+const NameSymbol *Binder::decode_symbol(std::size_t index) const
+{
+  return _M_token_stream->symbol(index);
+}
+
+void Binder::visitAccessSpecifier(AccessSpecifierAST *node)
+{
+  const ListNode<std::size_t> *it =  node->specs;
+  if (it == 0)
+    return;
+
+  it = it->toFront();
+  const ListNode<std::size_t> *end = it;
+
+  do
+    {
+      switch (decode_token(it->element))
+        {
+          default:
+            break;
+
+          case Token_public:
+            changeCurrentAccess(CodeModel::Public);
+            changeCurrentFunctionType(CodeModel::Normal);
+            break;
+          case Token_protected:
+            changeCurrentAccess(CodeModel::Protected);
+            changeCurrentFunctionType(CodeModel::Normal);
+            break;
+          case Token_private:
+            changeCurrentAccess(CodeModel::Private);
+            changeCurrentFunctionType(CodeModel::Normal);
+            break;
+          case Token_signals:
+            changeCurrentAccess(CodeModel::Protected);
+            changeCurrentFunctionType(CodeModel::Signal);
+            break;
+          case Token_slots:
+            changeCurrentFunctionType(CodeModel::Slot);
+            break;
+        }
+      it = it->next;
+    }
+  while (it != end);
+}
+
+void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node)
+{
+  visit(node->type_specifier);
+
+  if (const ListNode<InitDeclaratorAST*> *it = node->init_declarators)
+    {
+      it = it->toFront();
+      const ListNode<InitDeclaratorAST*> *end = it;
+      do
+        {
+          InitDeclaratorAST *init_declarator = it->element;
+          declare_symbol(node, init_declarator);
+          it = it->next;
+        }
+      while (it != end);
+    }
+}
+
+void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator)
+{
+  DeclaratorAST *declarator = init_declarator->declarator;
+
+  while (declarator && declarator->sub_declarator)
+    declarator = declarator->sub_declarator;
+
+  NameAST *id = declarator->id;
+  if (! declarator->id)
+    {
+      _M_message_handler("** WARNING expected a declarator id");
+      return;
+    }
+
+  CodeModelFinder finder(model(), this);
+  ScopeModelItem symbolScope = finder.resolveScope(id, currentScope());
+  if (! symbolScope)
+    {
+      name_cc.run(id);
+      _M_message_handler(std::string("** WARNING scope not found for symbol:") + qPrintable(name_cc.name()));
+      return;
+    }
+
+  decl_cc.run(declarator);
+
+  if (decl_cc.isFunction())
+    {
+      name_cc.run(id->unqualified_name);
+
+      FunctionModelItem fun = model()->create<FunctionModelItem>();
+      updateItemPosition (fun->toItem(), node);
+      fun->setAccessPolicy(_M_current_access);
+      fun->setFunctionType(_M_current_function_type);
+      fun->setName(name_cc.name());
+      fun->setAbstract(init_declarator->initializer != 0);
+      fun->setConstant(declarator->fun_cv != 0);
+      fun->setTemplateParameters(_M_current_template_parameters);
+      applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(fun));
+      applyFunctionSpecifiers(node->function_specifiers, fun);
+
+      // build the type
+      TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+                                                         declarator,
+                                                         this);
+
+      fun->setType(qualifyType(typeInfo, symbolScope->qualifiedName()));
+
+
+      fun->setVariadics (decl_cc.isVariadics ());
+
+      // ... and the signature
+      foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+        {
+          ArgumentModelItem arg = model()->create<ArgumentModelItem>();
+          arg->setType(qualifyType(p.type, _M_context));
+          arg->setName(p.name);
+          arg->setDefaultValue(p.defaultValue);
+          if (p.defaultValue)
+              arg->setDefaultValueExpression(p.defaultValueExpression);
+          fun->addArgument(arg);
+        }
+
+      fun->setScope(symbolScope->qualifiedName());
+      symbolScope->addFunction(fun);
+    }
+  else
+    {
+      VariableModelItem var = model()->create<VariableModelItem>();
+      updateItemPosition (var->toItem(), node);
+      var->setTemplateParameters(_M_current_template_parameters);
+      var->setAccessPolicy(_M_current_access);
+      name_cc.run(id->unqualified_name);
+      var->setName(name_cc.name());
+      TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier,
+                                                         declarator,
+                                                         this);
+      if (declarator != init_declarator->declarator
+            && init_declarator->declarator->parameter_declaration_clause != 0)
+        {
+          typeInfo.setFunctionPointer (true);
+          decl_cc.run (init_declarator->declarator);
+          foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+            typeInfo.addArgument(p.type);
+        }
+
+      var->setType(qualifyType(typeInfo, _M_context));
+      applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(var));
+
+      var->setScope(symbolScope->qualifiedName());
+      symbolScope->addVariable(var);
+    }
+}
+
+void Binder::visitFunctionDefinition(FunctionDefinitionAST *node)
+{
+  Q_ASSERT(node->init_declarator != 0);
+
+  ScopeModelItem scope = currentScope();
+
+  InitDeclaratorAST *init_declarator = node->init_declarator;
+  DeclaratorAST *declarator = init_declarator->declarator;
+
+  // in the case of "void (func)()" or "void ((func))()" we need to
+  // skip to the inner most.  This is in line with how the declarator
+  // node is generated in 'parser.cpp'
+  while (declarator && declarator->sub_declarator)
+      declarator = declarator->sub_declarator;
+  Q_ASSERT(declarator->id);
+
+  CodeModelFinder finder(model(), this);
+
+  ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope);
+  if (! functionScope)
+    {
+      name_cc.run(declarator->id);
+      _M_message_handler(std::string("** WARNING scope not found for function definition:")
+                         + qPrintable(name_cc.name())
+                         + std::string(" - definition *ignored*"));
+      return;
+    }
+
+  decl_cc.run(declarator);
+
+  Q_ASSERT(! decl_cc.id().isEmpty());
+
+  FunctionDefinitionModelItem
+    old = changeCurrentFunction(_M_model->create<FunctionDefinitionModelItem>());
+  _M_current_function->setScope(functionScope->qualifiedName());
+  updateItemPosition (_M_current_function->toItem(), node);
+
+  Q_ASSERT(declarator->id->unqualified_name != 0);
+  name_cc.run(declarator->id->unqualified_name);
+  QString unqualified_name = name_cc.name();
+
+  _M_current_function->setName(unqualified_name);
+  TypeInfo tmp_type = CompilerUtils::typeDescription(node->type_specifier,
+                                                     declarator, this);
+
+  _M_current_function->setType(qualifyType(tmp_type, _M_context));
+  _M_current_function->setAccessPolicy(_M_current_access);
+  _M_current_function->setFunctionType(_M_current_function_type);
+  _M_current_function->setConstant(declarator->fun_cv != 0);
+  _M_current_function->setTemplateParameters(_M_current_template_parameters);
+
+  applyStorageSpecifiers(node->storage_specifiers,
+                          model_static_cast<MemberModelItem>(_M_current_function));
+  applyFunctionSpecifiers(node->function_specifiers,
+                          model_static_cast<FunctionModelItem>(_M_current_function));
+
+  _M_current_function->setVariadics (decl_cc.isVariadics ());
+
+  foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+    {
+      ArgumentModelItem arg = model()->create<ArgumentModelItem>();
+      arg->setType(qualifyType(p.type, functionScope->qualifiedName()));
+      arg->setName(p.name);
+      arg->setDefaultValue(p.defaultValue);
+      if (p.defaultValue)
+        arg->setDefaultValueExpression(p.defaultValueExpression);
+      _M_current_function->addArgument(arg);
+    }
+
+  functionScope->addFunctionDefinition(_M_current_function);
+
+  FunctionModelItem prototype = model_static_cast<FunctionModelItem>(_M_current_function);
+  FunctionModelItem declared = functionScope->declaredFunction(prototype);
+
+  // try to find a function declaration for this definition..
+  if (! declared)
+    {
+      functionScope->addFunction(prototype);
+    }
+  else
+    {
+      applyFunctionSpecifiers(node->function_specifiers, declared);
+
+      // fix the function type and the access policy
+      _M_current_function->setAccessPolicy(declared->accessPolicy());
+      _M_current_function->setFunctionType(declared->functionType());
+    }
+
+  changeCurrentFunction(old);
+}
+
+void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node)
+{
+    const ListNode<TemplateParameterAST*> *it = node->template_parameters;
+    if (it == 0)
+        return;
+
+    TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList());
+
+    it = it->toFront();
+    const ListNode<TemplateParameterAST*> *end = it;
+
+    TemplateParameterList templateParameters;
+    do {
+        TemplateParameterAST *parameter = it->element;
+        TypeParameterAST *type_parameter = parameter->type_parameter;
+
+        NameAST *name;
+        if (!type_parameter) {
+            // A hacky hack to work around missing support for parameter declarations in
+            // templates. We just need the to get the name of the variable, since we
+            // aren't actually compiling these anyway. We are still not supporting much
+            // more, but we are refusing to fail for a few more declarations
+            if (parameter->parameter_declaration == 0 ||
+                parameter->parameter_declaration->declarator == 0 ||
+                parameter->parameter_declaration->declarator->id == 0) {
+
+                    /*std::cerr << "** WARNING template declaration not supported ``";
+                    Token const &tk = _M_token_stream->token ((int) node->start_token);
+                    Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+                    std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+                        << std::endl << std::endl;*/
+
+                    changeTemplateParameters(savedTemplateParameters);
+                    return;
+
+            }
+
+            name = parameter->parameter_declaration->declarator->id;
+        } else {
+            int tk = decode_token(type_parameter->type);
+            if (tk != Token_typename && tk != Token_class)
+            {
+                /*std::cerr << "** WARNING template declaration not supported ``";
+                Token const &tk = _M_token_stream->token ((int) node->start_token);
+                Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token);
+
+                std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''"
+                << std::endl << std::endl;*/
+
+                changeTemplateParameters(savedTemplateParameters);
+                return;
+            }
+            assert(tk == Token_typename || tk == Token_class);
+
+            name = type_parameter->name;
+        }
+
+        TemplateParameterModelItem p = model()->create<TemplateParameterModelItem>();
+        name_cc.run(name);
+        p->setName(name_cc.name());
+
+        _M_current_template_parameters.append(p);
+        it = it->next;
+    } while (it != end);
+
+    visit(node->declaration);
+
+    changeTemplateParameters(savedTemplateParameters);
+}
+
+void Binder::visitTypedef(TypedefAST *node)
+{
+  const ListNode<InitDeclaratorAST*> *it = node->init_declarators;
+  if (it == 0)
+    return;
+
+  it = it->toFront();
+  const ListNode<InitDeclaratorAST*> *end = it;
+
+  do
+    {
+      InitDeclaratorAST *init_declarator = it->element;
+      it = it->next;
+
+      Q_ASSERT(init_declarator->declarator != 0);
+
+      // the name
+      decl_cc.run (init_declarator->declarator);
+      QString alias_name = decl_cc.id ();
+
+      if (alias_name.isEmpty ())
+        {
+          _M_message_handler("** WARNING anonymous typedef not supported! ``");
+          Token const &tk = _M_token_stream->token ((int) node->start_token);
+          Token const &end_tk = _M_token_stream->token ((int) node->end_token);
+
+          _M_message_handler(std::string(&tk.text[tk.position], end_tk.position - tk.position));
+          continue;
+        }
+
+      // build the type
+      TypeInfo typeInfo = CompilerUtils::typeDescription (node->type_specifier,
+                                                          init_declarator->declarator,
+                                                          this);
+      DeclaratorAST *decl = init_declarator->declarator;
+      while (decl && decl->sub_declarator)
+        decl = decl->sub_declarator;
+
+      if (decl != init_declarator->declarator
+            && init_declarator->declarator->parameter_declaration_clause != 0)
+        {
+          typeInfo.setFunctionPointer (true);
+          decl_cc.run (init_declarator->declarator);
+          foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters())
+            typeInfo.addArgument(p.type);
+        }
+
+      ScopeModelItem scope = currentScope();
+      DeclaratorAST *declarator = init_declarator->declarator;
+      CodeModelFinder finder(model(), this);
+      ScopeModelItem typedefScope = finder.resolveScope(declarator->id, scope);
+
+      TypeAliasModelItem typeAlias = model ()->create<TypeAliasModelItem> ();
+      updateItemPosition (typeAlias->toItem (), node);
+      typeAlias->setName (alias_name);
+      typeAlias->setType (qualifyType (typeInfo, currentScope ()->qualifiedName ()));
+      typeAlias->setScope (typedefScope->qualifiedName());
+      _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString();
+      currentScope ()->addTypeAlias (typeAlias);
+    }
+  while (it != end);
+}
+
+void Binder::visitNamespace(NamespaceAST *node)
+{
+  bool anonymous = (node->namespace_name == 0);
+
+  ScopeModelItem scope = currentScope();
+
+  NamespaceModelItem old;
+  if (! anonymous)
+    {
+      QString name = decode_symbol(node->namespace_name)->as_string();
+
+      QStringList qualified_name = scope->qualifiedName();
+      qualified_name += name;
+      NamespaceModelItem ns =
+        model_safe_cast<NamespaceModelItem>(_M_model->findItem(qualified_name,
+                                                                  _M_current_file->toItem()));
+      if (!ns)
+        {
+          ns = _M_model->create<NamespaceModelItem>();
+          updateItemPosition (ns->toItem(), node);
+          ns->setName(name);
+          ns->setScope(scope->qualifiedName());
+        }
+      old = changeCurrentNamespace(ns);
+
+      _M_context.append(name);
+    }
+
+  DefaultVisitor::visitNamespace(node);
+
+  if (! anonymous)
+    {
+      Q_ASSERT(scope->kind() == _CodeModelItem::Kind_Namespace
+               || scope->kind() == _CodeModelItem::Kind_File);
+
+      _M_context.removeLast();
+
+      if (NamespaceModelItem ns = model_static_cast<NamespaceModelItem>(scope))
+        {
+          ns->addNamespace(_M_current_namespace);
+        }
+
+      changeCurrentNamespace(old);
+    }
+}
+
+void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *node)
+{
+    name_cc.run(node->name);
+    if (name_cc.name().isEmpty())
+        return;
+
+    ScopeModelItem scope = currentScope();
+    _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".") ] = QString();
+}
+
+void Binder::visitClassSpecifier(ClassSpecifierAST *node)
+{
+  ClassCompiler class_cc(this);
+  class_cc.run(node);
+
+  if (class_cc.name().isEmpty())
+    {
+      // anonymous not supported
+      return;
+    }
+
+  Q_ASSERT(node->name != 0 && node->name->unqualified_name != 0);
+
+  ScopeModelItem scope = currentScope();
+
+  ClassModelItem old = changeCurrentClass(_M_model->create<ClassModelItem>());
+  updateItemPosition (_M_current_class->toItem(), node);
+  _M_current_class->setName(class_cc.name());
+
+  QStringList baseClasses = class_cc.baseClasses(); TypeInfo info;
+  for (int i=0; i<baseClasses.size(); ++i)
+    {
+        info.setQualifiedName(baseClasses.at(i).split("::"));
+        baseClasses[i] = qualifyType(info, scope->qualifiedName()).qualifiedName().join("::");
+    }
+
+  _M_current_class->setBaseClasses(baseClasses);
+  _M_current_class->setClassType(decode_class_type(node->class_key));
+  _M_current_class->setTemplateParameters(_M_current_template_parameters);
+
+  if (! _M_current_template_parameters.isEmpty())
+    {
+      QString name = _M_current_class->name();
+      name += "<";
+      for (int i = 0; i<_M_current_template_parameters.size(); ++i)
+        {
+          if (i != 0)
+            name += ",";
+
+          name += _M_current_template_parameters.at(i)->name();
+        }
+
+      name += ">";
+      _M_current_class->setName(name);
+    }
+
+  CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key));
+  CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal);
+
+  _M_current_class->setScope(scope->qualifiedName());
+  _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString();
+
+  scope->addClass(_M_current_class);
+
+  name_cc.run(node->name->unqualified_name);
+  _M_context.append(name_cc.name());
+  visitNodes(this, node->member_specs);
+  _M_context.removeLast();
+
+  changeCurrentClass(old);
+  changeCurrentAccess(oldAccessPolicy);
+  changeCurrentFunctionType(oldFunctionType);
+}
+
+void Binder::visitLinkageSpecification(LinkageSpecificationAST *node)
+{
+  DefaultVisitor::visitLinkageSpecification(node);
+}
+
+void Binder::visitUsing(UsingAST *node)
+{
+  DefaultVisitor::visitUsing(node);
+}
+
+void Binder::visitEnumSpecifier(EnumSpecifierAST *node)
+{
+  CodeModelFinder finder(model(), this);
+  ScopeModelItem scope = currentScope();
+  ScopeModelItem enumScope = finder.resolveScope(node->name, scope);
+
+  name_cc.run(node->name);
+  QString name = name_cc.name();
+
+  if (name.isEmpty())
+    {
+      // anonymous enum
+      QString key = _M_context.join("::");
+      int current = ++_M_anonymous_enums[key];
+      name += QLatin1String("enum_");
+      name += QString::number(current);
+    }
+
+  _M_current_enum = model()->create<EnumModelItem>();
+  _M_current_enum->setAccessPolicy(_M_current_access);
+  updateItemPosition (_M_current_enum->toItem(), node);
+  _M_current_enum->setName(name);
+  _M_current_enum->setScope(enumScope->qualifiedName());
+
+  _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString();
+
+  enumScope->addEnum(_M_current_enum);
+
+  DefaultVisitor::visitEnumSpecifier(node);
+
+  _M_current_enum = 0;
+}
+
+static QString strip_preprocessor_lines(const QString &name)
+{
+    QStringList lst = name.split("\n");
+    QString s;
+    for (int i=0; i<lst.size(); ++i) {
+        if (!lst.at(i).startsWith('#'))
+            s += lst.at(i);
+    }
+    return s.trimmed();
+}
+
+void Binder::visitEnumerator(EnumeratorAST *node)
+{
+  Q_ASSERT(_M_current_enum != 0);
+  EnumeratorModelItem e = model()->create<EnumeratorModelItem>();
+  updateItemPosition (e->toItem(), node);
+  e->setName(decode_symbol(node->id)->as_string());
+
+  if (ExpressionAST *expr = node->expression)
+    {
+      const Token &start_token = _M_token_stream->token((int) expr->start_token);
+      const Token &end_token = _M_token_stream->token((int) expr->end_token);
+
+      e->setValue(strip_preprocessor_lines(QString::fromUtf8(&start_token.text[start_token.position],
+                                    (int) (end_token.position - start_token.position)).trimmed()).remove(' '));
+    }
+
+  _M_current_enum->addEnumerator(e);
+}
+
+void Binder::visitUsingDirective(UsingDirectiveAST *node)
+{
+  DefaultVisitor::visitUsingDirective(node);
+}
+
+void Binder::visitQEnums(QEnumsAST *node)
+{
+  const Token &start = _M_token_stream->token((int) node->start_token);
+  const Token &end = _M_token_stream->token((int) node->end_token);
+  QStringList enum_list = QString::fromLatin1(start.text + start.position,
+                                              end.position - start.position).split(' ');
+
+  ScopeModelItem scope = currentScope();
+  for (int i=0; i<enum_list.size(); ++i)
+    scope->addEnumsDeclaration(enum_list.at(i));
+}
+
+void Binder::visitQProperty(QPropertyAST *node)
+{
+    const Token &start = _M_token_stream->token((int) node->start_token);
+    const Token &end = _M_token_stream->token((int) node->end_token);
+    QString property = QString::fromLatin1(start.text + start.position,
+                                           end.position - start.position);
+    _M_current_class->addPropertyDeclaration(property);
+}
+
+void Binder::applyStorageSpecifiers(const ListNode<std::size_t> *it, MemberModelItem item)
+{
+  if (it == 0)
+    return;
+
+  it = it->toFront();
+  const ListNode<std::size_t> *end = it;
+
+  do
+    {
+      switch (decode_token(it->element))
+        {
+          default:
+            break;
+
+          case Token_friend:
+            item->setFriend(true);
+            break;
+          case Token_auto:
+            item->setAuto(true);
+            break;
+          case Token_register:
+            item->setRegister(true);
+            break;
+          case Token_static:
+            item->setStatic(true);
+            break;
+          case Token_extern:
+            item->setExtern(true);
+            break;
+          case Token_mutable:
+            item->setMutable(true);
+            break;
+        }
+      it = it->next;
+    }
+  while (it != end);
+}
+
+void Binder::applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item)
+{
+  if (it == 0)
+    return;
+
+  it = it->toFront();
+  const ListNode<std::size_t> *end = it;
+
+  do
+    {
+      switch (decode_token(it->element))
+        {
+          default:
+            break;
+
+          case Token_inline:
+            item->setInline(true);
+            break;
+
+          case Token_virtual:
+            item->setVirtual(true);
+            break;
+
+          case Token_explicit:
+            item->setExplicit(true);
+            break;
+
+          case Token_Q_INVOKABLE:
+            item->setInvokable(true);
+            break;
+        }
+      it = it->next;
+    }
+  while (it != end);
+}
+
+TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const
+{
+  // ### Potentially improve to use string list in the name table to
+  if (context.size() == 0)
+    {
+      // ### We can assume that this means global namespace for now...
+      return type;
+    }
+  else if (_M_qualified_types.contains(type.qualifiedName().join(".")))
+    {
+      return type;
+    }
+  else
+    {
+      QStringList expanded = context;
+      expanded << type.qualifiedName();
+      if (_M_qualified_types.contains(expanded.join(".")))
+        {
+          TypeInfo modified_type = type;
+          modified_type.setQualifiedName(expanded);
+          return modified_type;
+        }
+      else
+        {
+          CodeModelItem scope = model ()->findItem (context, _M_current_file->toItem ());
+
+          if (ClassModelItem klass = model_dynamic_cast<ClassModelItem> (scope))
+            {
+              foreach (QString base, klass->baseClasses ())
+                {
+                  QStringList ctx = context;
+                  ctx.removeLast();
+                  ctx.append (base);
+
+                  TypeInfo qualified = qualifyType (type, ctx);
+                  if (qualified != type)
+                    return qualified;
+                }
+            }
+
+          QStringList copy = context;
+          copy.removeLast();
+          return qualifyType(type, copy);
+        }
+    }
+}
+
+void Binder::updateItemPosition(CodeModelItem item, AST *node)
+{
+  QString filename;
+  int line, column;
+
+  assert (node != 0);
+  _M_location.positionAt (_M_token_stream->position(node->start_token), &line, &column, &filename);
+  item->setFileName (filename);
+}
+
+void Binder::installMessageHandler(MessageHandler handler)
+{
+    _M_message_handler = handler;
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;