// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef QQMLJSLOGGER_P_H #define QQMLJSLOGGER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include "qcoloroutput_p.h" #include "qqmljsloggingutils_p.h" #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE /*! \internal Used to print the line containing the location of a certain error */ class Q_QMLCOMPILER_EXPORT IssueLocationWithContext { public: /*! \internal \param code: The whole text of a translation unit \param location: The location where an error occurred. */ IssueLocationWithContext(QStringView code, const QQmlJS::SourceLocation &location) { quint32 before = qMax(0, code.lastIndexOf(QLatin1Char('\n'), location.offset)); if (before != 0 && before < location.offset) before++; m_beforeText = code.mid(before, location.offset - before); m_issueText = code.mid(location.offset, location.length); int after = code.indexOf(QLatin1Char('\n'), location.offset + location.length); m_afterText = code.mid(location.offset + location.length, after - (location.offset+location.length)); } // returns start of the line till first character of location QStringView beforeText() const { return m_beforeText; } // returns the text at location QStringView issueText() const { return m_issueText; } // returns any text after location until the end of the line is reached QStringView afterText() const { return m_afterText; } private: QStringView m_beforeText; QStringView m_issueText; QStringView m_afterText; }; class Q_QMLCOMPILER_EXPORT QQmlJSFixSuggestion { public: QQmlJSFixSuggestion() = default; QQmlJSFixSuggestion(const QString &fixDescription, const QQmlJS::SourceLocation &location, const QString &replacement = QString()); QString fixDescription() const { return m_fixDescription; } QQmlJS::SourceLocation location() const { return m_location; } QString replacement() const { return m_replacement; } void setFilename(const QString &filename) { m_filename = filename; } QString filename() const { return m_filename; } void setHint(const QString &hint) { m_hint = hint; } QString hint() const { return m_hint; } void setAutoApplicable(bool autoApply = true) { m_autoApplicable = autoApply; } bool isAutoApplicable() const { return m_autoApplicable; } bool operator==(const QQmlJSFixSuggestion &) const; bool operator!=(const QQmlJSFixSuggestion &) const; private: QQmlJS::SourceLocation m_location; QString m_fixDescription; QString m_replacement; QString m_filename; QString m_hint; bool m_autoApplicable = false; }; struct Message : public QQmlJS::DiagnosticMessage { // This doesn't need to be an owning-reference since the string is expected to outlive any // Message object by virtue of coming from a LoggerWarningId. QAnyStringView id; std::optional fixSuggestion; }; class Q_QMLCOMPILER_EXPORT QQmlJSLogger { Q_DISABLE_COPY_MOVE(QQmlJSLogger) public: QList categories() const; static const QList &defaultCategories(); void registerCategory(const QQmlJS::LoggerCategory &category); QQmlJSLogger(); ~QQmlJSLogger() = default; bool hasWarnings() const { return !m_warnings.isEmpty(); } bool hasErrors() const { return !m_errors.isEmpty(); } const QList &infos() const { return m_infos; } const QList &warnings() const { return m_warnings; } const QList &errors() const { return m_errors; } QtMsgType categoryLevel(QQmlJS::LoggerWarningId id) const { return m_categoryLevels[id.name().toString()]; } void setCategoryLevel(QQmlJS::LoggerWarningId id, QtMsgType level) { m_categoryLevels[id.name().toString()] = level; m_categoryChanged[id.name().toString()] = true; } bool isCategoryIgnored(QQmlJS::LoggerWarningId id) const { return m_categoryIgnored[id.name().toString()]; } void setCategoryIgnored(QQmlJS::LoggerWarningId id, bool error) { m_categoryIgnored[id.name().toString()] = error; m_categoryChanged[id.name().toString()] = true; } bool isCategoryFatal(QQmlJS::LoggerWarningId id) const { return m_categoryFatal[id.name().toString()]; } void setCategoryFatal(QQmlJS::LoggerWarningId id, bool error) { m_categoryFatal[id.name().toString()] = error; m_categoryChanged[id.name().toString()] = true; } bool wasCategoryChanged(QQmlJS::LoggerWarningId id) const { return m_categoryChanged[id.name().toString()]; } /*! \internal Logs \a message with severity deduced from \a category. Prefer using this function in most cases. \sa setCategoryLevel */ void log(const QString &message, QQmlJS::LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation, bool showContext = true, bool showFileName = true, const std::optional &suggestion = {}, const QString overrideFileName = QString()) { log(message, id, srcLocation, m_categoryLevels[id.name().toString()], showContext, showFileName, suggestion, overrideFileName); } void processMessages(const QList &messages, const QQmlJS::LoggerWarningId id); void ignoreWarnings(uint32_t line, const QSet &categories) { m_ignoredWarnings[line] = categories; } void setSilent(bool silent) { m_output.setSilent(silent); } bool isSilent() const { return m_output.isSilent(); } void setCode(const QString &code) { m_code = code; } QString code() const { return m_code; } void setFileName(const QString &fileName) { m_fileName = fileName; } QString fileName() const { return m_fileName; } private: QMap m_categories; void printContext(const QString &overrideFileName, const QQmlJS::SourceLocation &location); void printFix(const QQmlJSFixSuggestion &fix); void log(const QString &message, QQmlJS::LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation, QtMsgType type, bool showContext, bool showFileName, const std::optional &suggestion, const QString overrideFileName); QString m_fileName; QString m_code; QColorOutput m_output; QHash m_categoryLevels; QHash m_categoryIgnored; // If true, triggers qFatal on documents with "pragma Strict" // TODO: Works only for qmlCompiler category so far. QHash m_categoryFatal; QHash m_categoryChanged; QList m_infos; QList m_warnings; QList m_errors; QHash> m_ignoredWarnings; // the compiler needs private log() function at the moment friend class QQmlJSAotCompiler; }; QT_END_NAMESPACE #endif // QQMLJSLOGGER_P_H