view generator/parser/binder.cpp @ 414:b2a803c73b89 default tip

Declare tabArray const.
author David Nadlinger <code@klickverbot.at>
date Fri, 06 May 2011 13:39:49 +0200
parents 09a0f1d048f2
children
line wrap: on
line source

/****************************************************************************
**
** Copyright (C) 1992-2009 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 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.

In addition, as a special exception, Nokia gives you certain
additional rights. These rights are described in the Nokia Qt LGPL
Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
package.

GNU General Public License Usage
Alternatively, this file may be used under the terms of the GNU
General Public License version 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 the GNU General Public License version 3.0 requirements will be
met: http://www.gnu.org/copyleft/gpl.html.

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;