summaryrefslogtreecommitdiff
path: root/src/qdoc/qdoc/qmlcodeparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/qdoc/qmlcodeparser.cpp')
-rw-r--r--src/qdoc/qdoc/qmlcodeparser.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/qdoc/qdoc/qmlcodeparser.cpp b/src/qdoc/qdoc/qmlcodeparser.cpp
new file mode 100644
index 000000000..fadd7c307
--- /dev/null
+++ b/src/qdoc/qdoc/qmlcodeparser.cpp
@@ -0,0 +1,143 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qmlcodeparser.h"
+
+#include "node.h"
+#include "qmlvisitor.h"
+#include "utilities.h"
+
+#include <private/qqmljsast_p.h>
+
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Returns "QML".
+ */
+QString QmlCodeParser::language()
+{
+ return "QML";
+}
+
+/*!
+ Returns a string list containing "*.qml". This is the only
+ file type parsed by the QMLN parser.
+ */
+QStringList QmlCodeParser::sourceFileNameFilter()
+{
+ return QStringList() << "*.qml";
+}
+
+/*!
+ Parses the source file at \a filePath and inserts the contents
+ into the database. The \a location is used for error reporting.
+
+ If it can't open the file at \a filePath, it reports an error
+ and returns without doing anything.
+ */
+void QmlCodeParser::parseSourceFile(const Location &location, const QString &filePath, CppCodeParser&)
+{
+ static const QSet<QString> topic_commands{
+ COMMAND_VARIABLE, COMMAND_QMLCLASS, COMMAND_QMLTYPE, COMMAND_QMLPROPERTY,
+ COMMAND_QMLPROPERTYGROUP, COMMAND_QMLATTACHEDPROPERTY, COMMAND_QMLSIGNAL,
+ COMMAND_QMLATTACHEDSIGNAL, COMMAND_QMLMETHOD, COMMAND_QMLATTACHEDMETHOD,
+ COMMAND_QMLVALUETYPE, COMMAND_QMLBASICTYPE,
+ };
+
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
+ location.error(QStringLiteral("Cannot open QML file '%1'").arg(filePath));
+ return;
+ }
+
+ QString document = in.readAll();
+ in.close();
+
+ QString newCode = document;
+ extractPragmas(newCode);
+
+ QQmlJS::Engine engine{};
+ QQmlJS::Lexer lexer{&engine};
+ lexer.setCode(newCode, 1);
+
+ QQmlJS::Parser parser{&engine};
+
+ if (parser.parse()) {
+ QQmlJS::AST::UiProgram *ast = parser.ast();
+ QmlDocVisitor visitor(filePath, newCode, &engine, topic_commands + CodeParser::common_meta_commands,
+ topic_commands);
+ QQmlJS::AST::Node::accept(ast, &visitor);
+ if (visitor.hasError())
+ Location(filePath).warning("Could not analyze QML file, output is incomplete.");
+ }
+ const auto &messages = parser.diagnosticMessages();
+ for (const auto &msg : messages) {
+ qCDebug(lcQdoc, "%s: %d: %d: QML syntax error: %s", qUtf8Printable(filePath),
+ msg.loc.startLine, msg.loc.startColumn, qUtf8Printable(msg.message));
+ }
+}
+
+/*!
+ Copy and paste from src/declarative/qml/qdeclarativescriptparser.cpp.
+ This function blanks out the section of the \a str beginning at \a idx
+ and running for \a n characters.
+*/
+void replaceWithSpace(QString &str, int idx, int n) // Also used in qmlcodemarker.cpp.
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+/*!
+ Copy & paste from src/declarative/qml/qdeclarativescriptparser.cpp,
+ then modified to return no values.
+
+ Searches for ".pragma <value>" declarations within \a script.
+ Currently supported pragmas are: library
+*/
+void QmlCodeParser::extractPragmas(QString &script)
+{
+ const QString pragma(QLatin1String("pragma"));
+
+ QQmlJS::Lexer l(nullptr);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER || l.tokenStartLine() != startLine
+ || script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return;
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER || l.tokenStartLine() != startLine)
+ return;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return;
+
+ if (pragmaValue == QLatin1String("library"))
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ else
+ return;
+ }
+}
+
+QT_END_NAMESPACE