bool ItemReaderASTVisitor::visit(AST::UiPublicMember *ast)
{
    PropertyDeclaration p;
    if (Q_UNLIKELY(ast->name.isEmpty()))
        throw ErrorInfo(Tr::tr("public member without name"));
    if (Q_UNLIKELY(ast->memberType.isEmpty()))
        throw ErrorInfo(Tr::tr("public member without type"));
    if (Q_UNLIKELY(ast->type == AST::UiPublicMember::Signal))
        throw ErrorInfo(Tr::tr("public member with signal type not supported"));
    p.setName(ast->name.toString());
    p.setType(PropertyDeclaration::propertyTypeFromString(ast->memberType.toString()));
    if (p.type() == PropertyDeclaration::UnknownType) {
        throw ErrorInfo(Tr::tr("Unknown type '%1' in property declaration.")
                        .arg(ast->memberType.toString()), toCodeLocation(ast->typeToken));
    }
    if (ast->typeModifier.compare(QLatin1String("list"))) {
        p.setFlags(p.flags() | PropertyDeclaration::ListProperty);
    } else if (Q_UNLIKELY(!ast->typeModifier.isEmpty())) {
        throw ErrorInfo(Tr::tr("public member with type modifier '%1' not supported").arg(
                        ast->typeModifier.toString()));
    }

    m_item->m_propertyDeclarations.insert(p.name(), p);

    const JSSourceValuePtr value = JSSourceValue::create();
    value->setFile(m_file);
    if (ast->statement) {
        handleBindingRhs(ast->statement, value);
        const QStringList bindingName(p.name());
        checkDuplicateBinding(m_item, bindingName, ast->colonToken);
    }

    m_item->setProperty(p.name(), value);
    return false;
}
Exemple #2
0
ItemReaderResult ItemReader::internalReadFile(const QString &filePath)
{
    ASTCacheValue &cacheValue = (*m_astCache)[filePath];
    if (cacheValue.isValid()) {
        if (Q_UNLIKELY(cacheValue.isProcessing()))
            throw ErrorInfo(Tr::tr("Loop detected when importing '%1'.").arg(filePath));
    } else {
        QFile file(filePath);
        if (Q_UNLIKELY(!file.open(QFile::ReadOnly)))
            throw ErrorInfo(Tr::tr("Cannot open '%1'.").arg(filePath));

        m_filesRead.insert(filePath);
        const QString code = QTextStream(&file).readAll();
        QbsQmlJS::Lexer lexer(cacheValue.engine());
        lexer.setCode(code, 1);
        QbsQmlJS::Parser parser(cacheValue.engine());

        file.close();
        if (!parser.parse()) {
            QList<QbsQmlJS::DiagnosticMessage> parserMessages = parser.diagnosticMessages();
            if (Q_UNLIKELY(!parserMessages.isEmpty())) {
                ErrorInfo err;
                foreach (const QbsQmlJS::DiagnosticMessage &msg, parserMessages)
                    err.append(msg.message, toCodeLocation(filePath, msg.loc));
                throw err;
            }
        }
bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast)
{
    const QString typeName = ast->qualifiedTypeNameId->name.toString();
    Item *item = Item::create(m_itemPool);
    item->setFile(m_file);
    item->setTypeName(typeName);
    item->setLocation(toCodeLocation(ast->qualifiedTypeNameId->identifierToken));

    if (m_item)
        Item::addChild(m_item, item); // Add this item to the children of the parent item.
    else
        m_item = item; // This is the root item.

    const Item *inheritorItem = nullptr;

    // Inheritance resolving, part 1: Find out our actual type name (needed for setting
    // up children and alternatives).
    const QStringList fullTypeName = toStringList(ast->qualifiedTypeNameId);
    const QString baseTypeFileName = m_typeNameToFile.value(fullTypeName);
    if (!baseTypeFileName.isEmpty()) {
        inheritorItem = m_visitorState.readFile(baseTypeFileName, m_file->searchPaths(),
                                                m_itemPool);
        QBS_CHECK(inheritorItem->type() <= ItemType::LastActualItem);
        item->setType(inheritorItem->type());
    } else {
        item->setType(BuiltinDeclarations::instance().typeForName(typeName));
        if (item->type() == ItemType::Properties && item->parent()
                && item->parent()->type() == ItemType::SubProject) {
            item->setType(ItemType::PropertiesInSubProject);
        }
    }

    if (ast->initializer) {
        qSwap(m_item, item);
        ast->initializer->accept(this);
        qSwap(m_item, item);
    }

    ASTPropertiesItemHandler(item).handlePropertiesItems();

    // Inheritance resolving, part 2 (depends on alternatives having been set up).
    if (inheritorItem) {
        inheritItem(item, inheritorItem);
        if (inheritorItem->file()->idScope()) {
            // Make ids from the derived file visible in the base file.
            // ### Do we want to turn off this feature? It's QMLish but kind of strange.
            item->file()->ensureIdScope(m_itemPool);
            inheritorItem->file()->idScope()->setPrototype(item->file()->idScope());
        }
    } else {
        // Only the item at the top of the inheritance chain is a built-in item.
        // We cannot do this in "part 1", because then the visitor would complain about duplicate
        // bindings.
        item->setupForBuiltinType(m_logger);
    }

    return false;
}
void ItemReaderASTVisitor::checkDuplicateBinding(Item *item, const QStringList &bindingName,
                                                 const AST::SourceLocation &sourceLocation)
{
    if (Q_UNLIKELY(item->properties().contains(bindingName.last()))) {
        QString msg = Tr::tr("Duplicate binding for '%1'");
        throw ErrorInfo(msg.arg(bindingName.join(QLatin1Char('.'))),
                    toCodeLocation(sourceLocation));
    }
}
bool ItemReaderASTVisitor::visit(AST::FunctionDeclaration *ast)
{
    FunctionDeclaration f;
    if (Q_UNLIKELY(ast->name.isNull()))
        throw ErrorInfo(Tr::tr("function decl without name"));
    f.setName(ast->name.toString());

    // remove the name
    QString funcNoName = textOf(m_file->content(), ast);
    funcNoName.replace(QRegExp(QLatin1String("^(\\s*function\\s*)\\w*")), QLatin1String("(\\1"));
    funcNoName.append(QLatin1Char(')'));
    f.setSourceCode(funcNoName);

    f.setLocation(toCodeLocation(ast->firstSourceLocation()));
    m_item->m_functions += f;
    return false;
}