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; }
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; }