1/****************************************************************************
2**
3** Copyright (C) 2016 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sergio Martins <sergio.martins@kdab.com>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "findunqualified.h"
30
31#include <QtQml/private/qqmljslexer_p.h>
32#include <QtQml/private/qqmljsparser_p.h>
33#include <QtQml/private/qqmljsengine_p.h>
34#include <QtQml/private/qqmljsastvisitor_p.h>
35#include <QtQml/private/qqmljsast_p.h>
36
37#include <QtCore/qdebug.h>
38#include <QtCore/qfile.h>
39#include <QtCore/qfileinfo.h>
40#include <QtCore/qcoreapplication.h>
41
42#if QT_CONFIG(commandlineparser)
43#include <QtCore/qcommandlineparser.h>
44#endif
45
46#ifndef QT_BOOTSTRAPPED
47#include <QtCore/qlibraryinfo.h>
48#endif
49
50static bool lint_file(const QString &filename, const bool silent, const bool warnUnqualied,
51 const QStringList &qmltypeDirs, const QStringList &qmltypeFiles)
52{
53 QFile file(filename);
54 if (!file.open(flags: QFile::ReadOnly)) {
55 if (!silent)
56 qWarning() << "Failed to open file" << filename << file.error();
57 return false;
58 }
59
60 QString code = QString::fromUtf8(str: file.readAll());
61 file.close();
62
63 QQmlJS::Engine engine;
64 QQmlJS::Lexer lexer(&engine);
65
66 QFileInfo info(filename);
67 const QString lowerSuffix = info.suffix().toLower();
68 const bool isESModule = lowerSuffix == QLatin1String("mjs");
69 const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
70
71 lexer.setCode(code, /*lineno = */ 1, /*qmlMode=*/ !isJavaScript);
72 QQmlJS::Parser parser(&engine);
73
74 bool success = isJavaScript ? (isESModule ? parser.parseModule() : parser.parseProgram())
75 : parser.parse();
76
77 if (!success && !silent) {
78 const auto diagnosticMessages = parser.diagnosticMessages();
79 for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
80 qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
81 .arg(filename).arg(m.loc.startLine).arg(m.message);
82 }
83 }
84
85 if (success && !isJavaScript && warnUnqualied) {
86 auto root = parser.rootNode();
87 FindUnqualifiedIDVisitor v { qmltypeDirs, qmltypeFiles, code, filename, silent };
88 root->accept(&v);
89 success = v.check();
90 }
91
92 return success;
93}
94
95int main(int argv, char *argc[])
96{
97 QCoreApplication app(argv, argc);
98 QCoreApplication::setApplicationName("qmllint");
99 QCoreApplication::setApplicationVersion("1.0");
100#if QT_CONFIG(commandlineparser)
101 QCommandLineParser parser;
102 parser.setApplicationDescription(QLatin1String("QML syntax verifier"));
103 parser.addHelpOption();
104 parser.addVersionOption();
105
106 QCommandLineOption silentOption(QStringList() << "s" << "silent",
107 QLatin1String("Don't output syntax errors"));
108 parser.addOption(commandLineOption: silentOption);
109
110 QCommandLineOption checkUnqualified(QStringList() << "U" << "check-unqualified",
111 QLatin1String("Warn about unqualified identifiers"));
112 parser.addOption(commandLineOption: checkUnqualified);
113
114 QCommandLineOption qmltypesDirsOption(
115 QStringList() << "I"
116 << "qmldirs",
117 QLatin1String("Look for qmltypes files in specified directory"),
118 QLatin1String("directory"));
119 parser.addOption(commandLineOption: qmltypesDirsOption);
120
121 QCommandLineOption qmltypesFilesOption(
122 QStringList() << "i"
123 << "qmltypes",
124 QLatin1String("Include the specified qmltypes files"),
125 QLatin1String("qmltypes"));
126 parser.addOption(commandLineOption: qmltypesFilesOption);
127
128 parser.addPositionalArgument(name: QLatin1String("files"),
129 description: QLatin1String("list of qml or js files to verify"));
130
131 parser.process(app);
132
133 const auto positionalArguments = parser.positionalArguments();
134 if (positionalArguments.isEmpty()) {
135 parser.showHelp(exitCode: -1);
136 }
137
138 bool silent = parser.isSet(option: silentOption);
139 bool warnUnqualified = parser.isSet(option: checkUnqualified);
140 // use host qml import path as a sane default if nothing else has been provided
141 QStringList qmltypeDirs = parser.isSet(option: qmltypesDirsOption)
142 ? parser.values(option: qmltypesDirsOption)
143# ifndef QT_BOOTSTRAPPED
144 : QStringList { QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath) };
145# else
146 : QStringList {};
147# endif
148
149 if (!parser.isSet(option: qmltypesFilesOption))
150 qmltypeDirs << ".";
151
152 QStringList qmltypeFiles = parser.isSet(option: qmltypesFilesOption) ? parser.values(option: qmltypesFilesOption) : QStringList {};
153#else
154 bool silent = false;
155 bool warnUnqualified = false;
156 QStringList qmltypeDirs {};
157 QStringList qmltypeFiles {};
158#endif
159 bool success = true;
160#if QT_CONFIG(commandlineparser)
161 for (const QString &filename : positionalArguments)
162#else
163 const auto arguments = app.arguments();
164 for (const QString &filename : arguments)
165#endif
166 success &= lint_file(filename, silent, warnUnqualied: warnUnqualified, qmltypeDirs, qmltypeFiles);
167
168 return success ? 0 : -1;
169}
170

source code of qtdeclarative/tools/qmllint/main.cpp