Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmlcodemarker.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include <QtCore/qregularexpression.h>
7
8#include "atom.h"
9#include "node.h"
11#include "text.h"
12
13#include <private/qqmljsast_p.h>
14#include <private/qqmljsastfwd_p.h>
15#include <private/qqmljsengine_p.h>
16#include <private/qqmljslexer_p.h>
17#include <private/qqmljsparser_p.h>
18
20
21/*!
22 Returns \c true if the \a code is recognized by the parser.
23 */
24bool QmlCodeMarker::recognizeCode(const QString &code)
25{
26 // Naive pre-check; starts with an import statement or 'CamelCase {'
27 static const QRegularExpression regExp(QStringLiteral("^\\s*(import |([A-Z][a-z0-9]*)+\\s?{)"));
28 if (!regExp.match(code).hasMatch())
29 return false;
30
31 QQmlJS::Engine engine;
32 QQmlJS::Lexer lexer(&engine);
33 QQmlJS::Parser parser(&engine);
34
35 QString newCode = code;
36 extractPragmas(newCode);
37 lexer.setCode(newCode, 1);
38
39 return parser.parse();
40}
41
42/*!
43 Returns \c true if \a ext is any of a list of file extensions
44 for the QML language.
45 */
46bool QmlCodeMarker::recognizeExtension(const QString &ext)
47{
48 return ext == "qml";
49}
50
51/*!
52 Returns \c true if the \a language is recognized. Only "QML" is
53 recognized by this marker.
54 */
55bool QmlCodeMarker::recognizeLanguage(const QString &language)
56{
57 return language == "QML";
58}
59
60/*!
61 Returns the type of atom used to represent QML code in the documentation.
62*/
64{
65 return Atom::Qml;
66}
67
68QString QmlCodeMarker::markedUpCode(const QString &code, const Node *relative,
69 const Location &location)
70{
71 return addMarkUp(code, relative, location);
72}
73
74/*!
75 Constructs and returns the marked up name for the \a node.
76 If the node is any kind of QML function (a method,
77 signal, or handler), "()" is appended to the marked up name.
78 */
80{
81 QString name = linkTag(node, taggedNode(node));
82 if (node->isFunction())
83 name += "()";
84 return name;
85}
86
87QString QmlCodeMarker::addMarkUp(const QString &code, const Node * /* relative */,
88 const Location &location)
89{
90 QQmlJS::Engine engine;
91 QQmlJS::Lexer lexer(&engine);
92
93 QString newCode = code;
94 QList<QQmlJS::SourceLocation> pragmas = extractPragmas(newCode);
95 lexer.setCode(newCode, 1);
96
97 QQmlJS::Parser parser(&engine);
98 QString output;
99
100 if (parser.parse()) {
101 QQmlJS::AST::UiProgram *ast = parser.ast();
102 // Pass the unmodified code to the visitor so that pragmas and other
103 // unhandled source text can be output.
104 QmlMarkupVisitor visitor(code, pragmas, &engine);
105 QQmlJS::AST::Node::accept(ast, &visitor);
106 if (visitor.hasError()) {
107 location.warning(
108 location.fileName()
109 + QStringLiteral("Unable to analyze QML snippet. The output is incomplete."));
110 }
111 output = visitor.markedUpCode();
112 } else {
113 location.warning(QStringLiteral("Unable to parse QML snippet: \"%1\" at line %2, column %3")
114 .arg(parser.errorMessage())
115 .arg(parser.errorLineNumber())
116 .arg(parser.errorColumnNumber()));
117 output = protect(code);
118 }
119
120 return output;
121}
122
123/*
124 Copied and pasted from
125 src/declarative/qml/qqmlscriptparser.cpp.
126*/
127void replaceWithSpace(QString &str, int idx, int n); // qmlcodeparser.cpp
128
129/*
130 Copied and pasted from
131 src/declarative/qml/qqmlscriptparser.cpp then modified to
132 return a list of removed pragmas.
133
134 Searches for ".pragma <value>" or ".import <stuff>" declarations
135 in \a script. Currently supported pragmas are: library
136*/
137QList<QQmlJS::SourceLocation> QmlCodeMarker::extractPragmas(QString &script)
138{
139 QList<QQmlJS::SourceLocation> removed;
140
141 QQmlJS::Lexer l(nullptr);
142 l.setCode(script, 0);
143
144 int token = l.lex();
145
146 while (true) {
147 if (token != QQmlJSGrammar::T_DOT)
148 break;
149
150 int startOffset = l.tokenOffset();
151 int startLine = l.tokenStartLine();
152 int startColumn = l.tokenStartColumn();
153
154 token = l.lex();
155
156 if (token != QQmlJSGrammar::T_PRAGMA && token != QQmlJSGrammar::T_IMPORT)
157 break;
158 int endOffset = 0;
159 while (startLine == l.tokenStartLine()) {
160 endOffset = l.tokenLength() + l.tokenOffset();
161 token = l.lex();
162 }
163 replaceWithSpace(script, startOffset, endOffset - startOffset);
164 removed.append(QQmlJS::SourceLocation(startOffset, endOffset - startOffset, startLine,
165 startColumn));
166 }
167 return removed;
168}
169
170QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:18
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
Definition atom.h:20
@ Qml
Definition atom.h:76
The Location class provides a way to mark a location in a file.
Definition location.h:15
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:135
LinkType
An unsigned char value that probably should be moved out of the Node base class.
Definition node.h:112
QString markedUpName(const Node *node) override
Constructs and returns the marked up name for the node.
Atom::AtomType atomType() const override
Returns the type of atom used to represent QML code in the documentation.
Combined button and popup list for selecting options.
void replaceWithSpace(QString &str, int idx, int n)
Copy and paste from src/declarative/qml/qdeclarativescriptparser.cpp.