From ec14d91a099b8321daa3d828b1084d87168479ac Mon Sep 17 00:00:00 2001 From: Alexey Edelev Date: Thu, 6 Jul 2023 12:01:25 +0200 Subject: [PATCH] Add the 'version' argument to 'qt_deprecates' pragma syncqt uses qt_deprecates pragma to generate deprecated header files that might live forever in Qt packages. This adds the version argument to the pragma, that allows specifying the version when the respective header file should be removed. The new pragma format is the following: pragma qt_deprecates(
[,]) If deprecation version of the deprecated header file is lower than the current Qt version, syncqt will display the respective warning in the log and skip generating the deprectated header file. Also the user warning message now displays the exact version when the header file will be removed. Task-number: QTBUG-115029 Change-Id: Ifd7464b8539b8be93b95690fd1ca70ef0b14e436 Reviewed-by: Alexandru Croitor Reviewed-by: Edward Welbourne Reviewed-by: Joerg Bornemann (cherry picked from commit 4bc0a08bea3c262ebda26163f9271c946c430ff0) Reviewed-by: Qt Cherry-pick Bot --- src/tools/syncqt/main.cpp | 84 ++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/src/tools/syncqt/main.cpp b/src/tools/syncqt/main.cpp index 055f1f4f30c..9f4cad6718e 100644 --- a/src/tools/syncqt/main.cpp +++ b/src/tools/syncqt/main.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include enum ErrorCodes { @@ -90,6 +91,33 @@ std::string asciiToUpper(std::string s) return s; } +bool parseVersion(const std::string &version, int &major, int &minor) +{ + const size_t separatorPos = version.find('.'); + if (separatorPos == std::string::npos || separatorPos == (version.size() - 1) + || separatorPos == 0) + return false; + + try { + size_t pos = 0; + major = std::stoi(version.substr(0, separatorPos), &pos); + if (pos != separatorPos) + return false; + + const size_t nextPart = separatorPos + 1; + pos = 0; + minor = std::stoi(version.substr(nextPart), &pos); + if (pos != (version.size() - nextPart)) + return false; + } catch (const std::invalid_argument &) { + return false; + } catch (const std::out_of_range &) { + return false; + } + + return true; +} + class DummyOutputStream : public std::ostream { struct : public std::streambuf @@ -1015,10 +1043,13 @@ public: // - 'qt_class()' manually declares the 'symbol' that should be used to generate // the CaMeL case header alias. // - // - 'qt_deprecates()' indicates that this header file replaces - // the 'deprecated header file'. syncqt will create the deprecated header file' with - // the special deprecation content. See the 'generateDeprecatedHeaders' function - // for details. + // - 'qt_deprecates([,])' indicates that this header + // file replaces the 'deprecated header file'. syncqt will create the deprecated header + // file' with the special deprecation content. Pragma optionally accepts the Qt version + // where file should be removed. If the current Qt version is higher than the + // deprecation version, syncqt displays deprecation warning and skips generating the + // deprecated header. + // See the 'generateDeprecatedHeaders' function for details. // // - 'qt_no_master_include' indicates that syncqt should avoid including this header // files into the module master header file. @@ -1449,13 +1480,44 @@ public: { static std::regex cIdentifierSymbolsRegex("[^a-zA-Z0-9_]"); static std::string guard_base = "DEPRECATED_HEADER_" + m_commandLineArgs->moduleName(); + bool result = true; for (auto it = m_deprecatedHeaders.begin(); it != m_deprecatedHeaders.end(); ++it) { - std::string &replacement = it->second; + const std::string &descriptor = it->first; + const std::string &replacement = it->second; + + const auto separatorPos = descriptor.find(','); + std::string headerName = descriptor.substr(0, separatorPos); + std::string versionDisclaimer; + if (separatorPos != std::string::npos) { + std::string version = descriptor.substr(separatorPos + 1); + versionDisclaimer = " and will be removed in Qt " + version; + int minor = 0; + int major = 0; + if (!utils::parseVersion(version, minor, major)) { + std::cerr << ErrorMessagePreamble + << "Invalid version format specified for the deprecated header file " + << headerName << ": '" << version + << "'. Expected format: 'major.minor'.\n"; + result = false; + continue; + } + + if (QT_VERSION_MAJOR > major + || (QT_VERSION_MAJOR == major && QT_VERSION_MINOR >= minor)) { + std::cerr << WarningMessagePreamble << headerName + << " is marked as deprecated and will not be generated in Qt " + << QT_VERSION_STR + << ". The respective qt_deprecates pragma needs to be removed.\n"; + continue; + } + } + std::string qualifiedHeaderName = - std::regex_replace(it->first, cIdentifierSymbolsRegex, "_"); + std::regex_replace(headerName, cIdentifierSymbolsRegex, "_"); std::string guard = guard_base + "_" + qualifiedHeaderName; - std::string warningText = "Header <" + m_commandLineArgs->moduleName() + "/" + it->first - + "> is deprecated. Please include <" + replacement + "> instead."; + std::string warningText = "Header <" + m_commandLineArgs->moduleName() + "/" + + headerName + "> is deprecated" + versionDisclaimer + ". Please include <" + + replacement + "> instead."; std::stringstream buffer; buffer << "#ifndef " << guard << "\n" << "#define " << guard << "\n" @@ -1466,10 +1528,10 @@ public: << "#endif\n" << "#include <" << replacement << ">\n" << "#endif\n"; - writeIfDifferent(m_commandLineArgs->includeDir() + '/' + it->first, buffer.str()); - m_producedHeaders.insert(it->first); + writeIfDifferent(m_commandLineArgs->includeDir() + '/' + headerName, buffer.str()); + m_producedHeaders.insert(headerName); } - return true; + return result; } [[nodiscard]] bool generateHeaderCheckExceptions()