summaryrefslogtreecommitdiffstats
path: root/generator/parser/binder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'generator/parser/binder.cpp')
-rw-r--r--generator/parser/binder.cpp906
1 files changed, 906 insertions, 0 deletions
diff --git a/generator/parser/binder.cpp b/generator/parser/binder.cpp
new file mode 100644
index 0000000..b41758a
--- /dev/null
+++ b/generator/parser/binder.cpp
@@ -0,0 +1,906 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+**
+** This file is part of the Qt Script Generator project on Trolltech Labs.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.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.trolltech.com/products/qt/opensource.html
+**
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://www.trolltech.com/products/qt/licensing.html or contact the
+** sales department at sales@trolltech.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>
+
+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:
+ std::cerr << "** WARNING unrecognized class type" << std::endl;
+ }
+ 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)
+ {
+ std::cerr << "** WARNING expected a declarator id" << std::endl;
+ return;
+ }
+
+ CodeModelFinder finder(model(), this);
+ ScopeModelItem symbolScope = finder.resolveScope(id, currentScope());
+ if (! symbolScope)
+ {
+ name_cc.run(id);
+ std::cerr << "** WARNING scope not found for symbol:"
+ << qPrintable(name_cc.name()) << std::endl;
+ 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);
+ std::cerr << "** WARNING scope not found for function definition:"
+ << qPrintable(name_cc.name()) << std::endl
+ << "\tdefinition *ignored*"
+ << std::endl;
+ 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) {
+ // QtScript: we want to visit the declaration still, so that
+ // e.g. QMetaTypeId<Foo> is added to the code model
+ visit(node->declaration);
+ 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 ())
+ {
+ std::cerr << "** 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);
+
+ std::cerr << std::string (&tk.text[tk.position], end_tk.position - tk.position) << "''"
+ << std::endl << std::endl;
+ 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);
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;