diff options
author | Christian Kandeler <christian.kandeler@theqtcompany.com> | 2015-07-31 12:20:13 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@theqtcompany.com> | 2015-07-31 12:20:13 +0200 |
commit | 43ddde70dd61f9adb2c3b20ee86522494538ca0e (patch) | |
tree | 18e6fca3eb8e2122f2dc273acc5f875d32ba3760 /src | |
parent | 92cf9460c46d707aeac02ef8f6597a4037df0964 (diff) | |
parent | 33c9a2721b76e8a7affa19e924cbaf4e4c91060b (diff) |
Merge branch 1.4 into master.
Change-Id: I2ff37ef7c00063f738f7691071c4b638dd2dc7c8
Diffstat (limited to 'src')
76 files changed, 920 insertions, 736 deletions
diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp index 60b6d4aaa..ca58b5a7f 100644 --- a/src/app/qbs-setup-android/android-setup.cpp +++ b/src/app/qbs-setup-android/android-setup.cpp @@ -113,20 +113,20 @@ static QString detectPlatform(const QString &sdkDir) static QStringList expectedArchs() { - return QStringList({ - QStringLiteral("arm64"), - QStringLiteral("armv5"), - QStringLiteral("armv7"), - QStringLiteral("mipsel"), - QStringLiteral("mips64el"), - QStringLiteral("x86"), - QStringLiteral("x86_64")}); + return QStringList() + << QStringLiteral("arm64") + << QStringLiteral("armv5") + << QStringLiteral("armv7") + << QStringLiteral("mipsel") + << QStringLiteral("mips64el") + << QStringLiteral("x86") + << QStringLiteral("x86_64"); } static QString subProfileName(const QString &mainProfileName, const QString &arch) { - return mainProfileName + QLatin1Char('_') + arch; + return mainProfileName + QLatin1Char('-') + arch; } void setupSdk(qbs::Settings *settings, const QString &profileName, const QString &sdkDirPath) @@ -159,6 +159,7 @@ void setupNdk(qbs::Settings *settings, const QString &profileName, const QString Profile mainProfile(profileName, settings); mainProfile.setValue(qls("Android.ndk.ndkDir"), QDir::cleanPath(ndkDirPath)); mainProfile.setValue(qls("Android.sdk.ndkDir"), QDir::cleanPath(ndkDirPath)); + mainProfile.setValue(qls("qbs.toolchain"), QStringList() << qls("gcc")); foreach (const QString &arch, expectedArchs()) { Profile p(subProfileName(profileName, arch), settings); p.removeProfile(); diff --git a/src/app/qbs-setup-toolchains/msvcinfo.h b/src/app/qbs-setup-toolchains/msvcinfo.h index 0344c72f9..dbd8d2bcb 100644 --- a/src/app/qbs-setup-toolchains/msvcinfo.h +++ b/src/app/qbs-setup-toolchains/msvcinfo.h @@ -31,6 +31,7 @@ #ifndef QBS_MSVCINFO_H #define QBS_MSVCINFO_H +#include <QDir> #include <QHash> #include <QProcessEnvironment> #include <QStringList> @@ -40,16 +41,30 @@ class MSVC public: QString version; QString installPath; + QString pathPrefix; QStringList architectures; typedef QHash<QString, QProcessEnvironment> EnvironmentPerArch; EnvironmentPerArch environments; + + QString clPath(const QString &arch = QString()) { + return QDir::cleanPath( + installPath + QLatin1Char('/') + + pathPrefix + QLatin1Char('/') + + arch + QLatin1Char('/') + + QLatin1String("cl.exe")); + } }; class WinSDK : public MSVC { public: bool isDefault; + + WinSDK() + { + pathPrefix = QLatin1String("bin"); + } }; #endif // QBS_MSVCINFO_H diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp index 87c90bd01..3e2a7f216 100644 --- a/src/app/qbs-setup-toolchains/msvcprobe.cpp +++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp @@ -72,11 +72,6 @@ static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> p.setValue(QLatin1String("cpp.toolchainInstallPath"), installPath); p.setValue(QLatin1String("qbs.toolchain"), QStringList(QLatin1String("msvc"))); p.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture)); - if (msvc.version.toInt() >= 2013) { - const QStringList flags(QLatin1String("/FS")); - p.setValue(QLatin1String("cpp.platformCFlags"), flags); - p.setValue(QLatin1String("cpp.platformCxxFlags"), flags); - } const QProcessEnvironment compilerEnvironment = msvc.environments.value(architecture); setCompilerVersion(installPath + QLatin1String("/cl.exe"), QStringList(QLatin1String("msvc")), p, compilerEnvironment); @@ -84,12 +79,20 @@ static void addMSVCPlatform(const MSVC &msvc, Settings *settings, QList<Profile> profiles << p; } -static void findSupportedArchitectures(MSVC *msvc, const QString &pathPrefix = QString()) +static void findSupportedArchitectures(MSVC *msvc) { - if (QFile::exists(msvc->installPath + pathPrefix + QLatin1String("/cl.exe"))) + if (QFile::exists(msvc->clPath()) + || QFile::exists(msvc->clPath(QLatin1String("amd64_x86")))) msvc->architectures += QLatin1String("x86"); - if (QFile::exists(msvc->installPath + pathPrefix + QLatin1String("/amd64/cl.exe"))) + if (QFile::exists(msvc->clPath(QLatin1String("amd64"))) + || QFile::exists(msvc->clPath(QLatin1String("x86_amd64")))) msvc->architectures += QLatin1String("x86_64"); + if (QFile::exists(msvc->clPath(QLatin1String("ia64"))) + || QFile::exists(msvc->clPath(QLatin1String("x86_ia64")))) + msvc->architectures += QLatin1String("ia64"); + if (QFile::exists(msvc->clPath(QLatin1String("x86_arm"))) + || QFile::exists(msvc->clPath(QLatin1String("amd64_arm")))) + msvc->architectures += QLatin1String("armv7"); } static QString wow6432Key() @@ -123,7 +126,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles) continue; if (sdk.installPath.endsWith(QLatin1Char('\\'))) sdk.installPath.chop(1); - findSupportedArchitectures(&sdk, QLatin1String("/bin")); + findSupportedArchitectures(&sdk); if (sdk.isDefault) defaultWinSDK = sdk; winSDKs += sdk; diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp index 531bbf0c1..b20ab7229 100644 --- a/src/app/qbs-setup-toolchains/probe.cpp +++ b/src/app/qbs-setup-toolchains/probe.cpp @@ -120,50 +120,36 @@ static QString gccMachineName(const QString &compilerFilePath) return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed(); } -static void setupCompilerPathByLanguage(Profile &profile, const QStringList &toolchainTypes, - const QString &toolchainInstallPath, const QString &toolchainPrefix) +static QStringList standardCompilerFileNames() { - QVariantMap m; - if (toolchainTypes.contains(QLatin1String("clang"))) { - m[QLatin1String("c")] = m[QLatin1String("objc")] = QLatin1String("clang"); - m[QLatin1String("cpp")] = m[QLatin1String("objcpp")] = QLatin1String("clang++"); - } else if (toolchainTypes.contains(QLatin1String("gcc"))) { - m[QLatin1String("c")] = m[QLatin1String("objc")] = QLatin1String("gcc"); - m[QLatin1String("cpp")] = m[QLatin1String("objcpp")] = QLatin1String("g++"); - } else { - qDebug("WARNING: unexpected toolchain %s", qPrintable(toJSLiteral(toolchainTypes))); - return; - } - - const QString toolchainPathPrefix = toolchainInstallPath + QLatin1Char('/') + toolchainPrefix; - for (QVariantMap::iterator it = m.begin(); it != m.end();) { - const QString filePath = HostOsInfo::appendExecutableSuffix(toolchainPathPrefix - + it.value().toString()); - if (QFile::exists(filePath)) { - it.value() = filePath; - ++it; - continue; - } - qDebug("WARNING: Compiler %s for file tag %s not found.", - qPrintable(QDir::toNativeSeparators(filePath)), qPrintable(it.key())); - it = m.erase(it); - } - if (!m.isEmpty()) - profile.setValue(QLatin1String("cpp.compilerPathByLanguage"), m); + return QStringList() << QStringLiteral("gcc") << QStringLiteral("g++") + << QStringLiteral("clang") << QStringLiteral("clang++"); } static void setCommonProperties(Profile &profile, const QString &compilerFilePath, - const QString &toolchainPrefix, const QStringList &toolchainTypes, - const QString &architecture) + const QStringList &toolchainTypes, const QString &architecture) { - QFileInfo cfi(compilerFilePath); - const QString toolchainInstallPath = cfi.absolutePath(); - profile.setValue(QLatin1String("cpp.toolchainInstallPath"), toolchainInstallPath); - profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName()); + const QFileInfo cfi(compilerFilePath); + const QString compilerName = QFileInfo(compilerFilePath).fileName(); + if (!standardCompilerFileNames().contains(compilerName)) + qWarning("%s", qPrintable( + QString::fromLatin1("'%1' is not a standard compiler file name; " + "you must set the cpp.cCompilerName and " + "cpp.cxxCompilerName properties of this profile " + "manually").arg(compilerName))); + + + if (toolchainTypes.contains(QStringLiteral("mingw"))) + profile.setValue(QStringLiteral("qbs.targetOS"), QStringList(QStringLiteral("windows"))); + + const QString prefix = compilerName.left(compilerName.lastIndexOf(QLatin1Char('-')) + 1); + if (!prefix.isEmpty()) + profile.setValue(QLatin1String("cpp.toolchainPrefix"), prefix); + + profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath()); profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes); profile.setValue(QLatin1String("qbs.architecture"), canonicalArchitecture(architecture)); setCompilerVersion(compilerFilePath, toolchainTypes, profile); - setupCompilerPathByLanguage(profile, toolchainTypes, toolchainInstallPath, toolchainPrefix); } class ToolPathSetup @@ -200,10 +186,8 @@ static Profile createGccProfile(const QString &compilerFilePath, Settings *setti { const QString machineName = gccMachineName(compilerFilePath); const QStringList compilerTriplet = machineName.split(QLatin1Char('-')); - const bool isMingw = toolchainTypes.contains(QLatin1String("mingw")); - const bool isClang = toolchainTypes.contains(QLatin1String("clang")); - if (isMingw) { + if (toolchainTypes.contains(QLatin1String("mingw"))) { if (!validMinGWMachines().contains(machineName)) { throw ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.") .arg(machineName)); @@ -215,27 +199,14 @@ static Profile createGccProfile(const QString &compilerFilePath, Settings *setti Profile profile(!profileName.isEmpty() ? profileName : machineName, settings); profile.removeProfile(); - if (isMingw) { - profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows"))); - } - - const QString compilerName = QFileInfo(compilerFilePath).fileName(); - QString toolchainPrefix; - if (compilerName.contains(QLatin1Char('-'))) { - QStringList nameParts = compilerName.split(QLatin1Char('-')); - profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast()); - toolchainPrefix = nameParts.join(QLatin1Char('-')) + QLatin1Char('-'); - profile.setValue(QLatin1String("cpp.toolchainPrefix"), toolchainPrefix); - } - profile.setValue(QLatin1String("cpp.linkerName"), - isClang ? QLatin1String("clang++") : QLatin1String("g++")); - setCommonProperties(profile, compilerFilePath, toolchainPrefix, toolchainTypes, - compilerTriplet.first()); + setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first()); // Check whether auxiliary tools reside within the toolchain's install path. // This might not be the case when using icecc or another compiler wrapper. const QString compilerDirPath = QFileInfo(compilerFilePath).absolutePath(); - const ToolPathSetup toolPathSetup(&profile, compilerDirPath, toolchainPrefix); + const ToolPathSetup toolPathSetup(&profile, compilerDirPath, + profile.value(QStringLiteral("cpp.toolchainPrefix")) + .toString()); toolPathSetup.apply(QLatin1String("ar"), QLatin1String("cpp.archiverPath")); toolPathSetup.apply(QLatin1String("nm"), QLatin1String("cpp.nmPath")); if (HostOsInfo::isOsxHost()) diff --git a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp b/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp index 7fa6dfef5..bbd76c35c 100644 --- a/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp +++ b/src/app/qbs-setup-toolchains/vsenvironmentdetector.cpp @@ -118,6 +118,8 @@ static void batPrintVars(QTextStream &s, const QStringList &varnames) static QString vcArchitecture(const QString &arch) { + if (arch == QLatin1String("armv7")) + return QLatin1String("arm"); if (arch == QLatin1String("x86_64")) return QLatin1String("amd64"); return arch; diff --git a/src/lib/corelib/api/languageinfo.cpp b/src/lib/corelib/api/languageinfo.cpp index c885a1917..197e340b2 100644 --- a/src/lib/corelib/api/languageinfo.cpp +++ b/src/lib/corelib/api/languageinfo.cpp @@ -32,6 +32,8 @@ #include <language/builtindeclarations.h> +#include <QStringList> + namespace qbs { LanguageInfo::LanguageInfo() @@ -40,7 +42,7 @@ LanguageInfo::LanguageInfo() QByteArray LanguageInfo::qmlTypeInfo() { - Internal::BuiltinDeclarations builtins; + const Internal::BuiltinDeclarations &builtins = Internal::BuiltinDeclarations::instance(); // Header: QByteArray result; @@ -57,7 +59,7 @@ QByteArray LanguageInfo::qmlTypeInfo() result.append(" exports: [ \"qbs/"); result.append(utf8TypeName); result.append(" "); - result.append(builtins.languageVersion().toUtf8()); + result.append(builtins.languageVersion().toString().toUtf8()); result.append("\" ]\n"); result.append(" prototype: \"QQuickItem\"\n"); diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp index 0113c440d..94272e0d2 100644 --- a/src/lib/corelib/api/runenvironment.cpp +++ b/src/lib/corelib/api/runenvironment.cpp @@ -33,6 +33,7 @@ #include <api/projectdata.h> #include <buildgraph/productinstaller.h> #include <language/language.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <logging/logger.h> #include <logging/translator.h> diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp index bb8e86cc4..05226e7f0 100644 --- a/src/lib/corelib/buildgraph/buildgraph.cpp +++ b/src/lib/corelib/buildgraph/buildgraph.cpp @@ -39,11 +39,13 @@ #include <jsextensions/moduleproperties.h> #include <language/language.h> #include <language/preparescriptobserver.h> +#include <language/propertymapinternal.h> #include <language/resolvedfilecontext.h> #include <language/scriptengine.h> #include <logging/logger.h> #include <logging/translator.h> #include <tools/error.h> +#include <tools/fileinfo.h> #include <tools/scripttools.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp index f487badb8..a2f18bda8 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.cpp +++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp @@ -39,10 +39,13 @@ #include "projectbuilddata.h" #include "rulesevaluationcontext.h" #include "transformer.h" + #include <language/artifactproperties.h> #include <language/language.h> #include <language/loader.h> +#include <language/propertymapinternal.h> #include <logging/translator.h> +#include <tools/fileinfo.h> #include <tools/persistence.h> #include <tools/propertyfinder.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/buildgraph/depscanner.cpp b/src/lib/corelib/buildgraph/depscanner.cpp index 7bc996a87..311793f98 100644 --- a/src/lib/corelib/buildgraph/depscanner.cpp +++ b/src/lib/corelib/buildgraph/depscanner.cpp @@ -36,9 +36,11 @@ #include <tools/error.h> #include <logging/translator.h> #include <language/language.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <jsextensions/moduleproperties.h> #include <plugins/scanner/scanner.h> +#include <tools/fileinfo.h> #include <QVariantMap> #include <QSet> diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp index 2780a52a6..0bdffe74c 100644 --- a/src/lib/corelib/buildgraph/executor.cpp +++ b/src/lib/corelib/buildgraph/executor.cpp @@ -44,6 +44,7 @@ #include <buildgraph/transformer.h> #include <language/language.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <logging/translator.h> #include <tools/error.h> diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp index b94239f63..8f54b4358 100644 --- a/src/lib/corelib/buildgraph/productinstaller.cpp +++ b/src/lib/corelib/buildgraph/productinstaller.cpp @@ -31,7 +31,9 @@ #include "artifact.h" #include "productbuilddata.h" + #include <language/language.h> +#include <language/propertymapinternal.h> #include <logging/translator.h> #include <tools/qbsassert.h> #include <tools/error.h> @@ -121,13 +123,13 @@ QString ProductInstaller::targetFilePath(const TopLevelProject *project, // This has the same effect as if installSourceBase would equal the directory of the file. targetFilePath = FileInfo::fileName(sourceFilePath); } else { - const QString localAbsBasePath = QDir::cleanPath(productSourceDir + QLatin1Char('/') - + installSourceBase); + const QString localAbsBasePath = FileInfo::resolvePath(QDir::cleanPath(productSourceDir), + QDir::cleanPath(installSourceBase)); targetFilePath = sourceFilePath; if (!targetFilePath.startsWith(localAbsBasePath)) { throw ErrorInfo(Tr::tr("Cannot install '%1', because it doesn't start with the" " value of qbs.installSourceBase '%2'.").arg(sourceFilePath, - installSourceBase)); + localAbsBasePath)); } targetFilePath.remove(0, localAbsBasePath.length() + 1); diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp index e505fae5a..619a17ca6 100644 --- a/src/lib/corelib/buildgraph/projectbuilddata.cpp +++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp @@ -38,11 +38,13 @@ #include "rulenode.h" #include "rulesevaluationcontext.h" #include "transformer.h" + #include <language/language.h> #include <language/preparescriptobserver.h> #include <language/scriptengine.h> #include <logging/translator.h> #include <tools/error.h> +#include <tools/fileinfo.h> #include <tools/persistence.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp index 5b3e13ea6..d74e646d2 100644 --- a/src/lib/corelib/buildgraph/qtmocscanner.cpp +++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp @@ -34,6 +34,7 @@ #include "productbuilddata.h" #include "scanresultcache.h" #include <logging/translator.h> +#include <tools/fileinfo.h> #include <tools/scannerpluginmanager.h> #include <tools/scripttools.h> diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index df8f6cd66..d514047a9 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -37,14 +37,17 @@ #include "qtmocscanner.h" #include "rulesevaluationcontext.h" #include "transformer.h" + #include <jsextensions/moduleproperties.h> #include <language/artifactproperties.h> #include <language/builtindeclarations.h> #include <language/language.h> #include <language/preparescriptobserver.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <logging/translator.h> #include <tools/error.h> +#include <tools/fileinfo.h> #include <tools/scripttools.h> #include <tools/qbsassert.h> @@ -387,7 +390,7 @@ class ArtifactBindingsExtractor { QSet<QString> s; foreach (const PropertyDeclaration &pd, - BuiltinDeclarations().declarationsForType( + BuiltinDeclarations::instance().declarationsForType( QLatin1String("Artifact")).properties()) { s.insert(pd.name()); } diff --git a/src/lib/corelib/buildgraph/timestampsupdater.cpp b/src/lib/corelib/buildgraph/timestampsupdater.cpp index 994afac50..43c450199 100644 --- a/src/lib/corelib/buildgraph/timestampsupdater.cpp +++ b/src/lib/corelib/buildgraph/timestampsupdater.cpp @@ -33,7 +33,9 @@ #include "artifactvisitor.h" #include "productbuilddata.h" #include "projectbuilddata.h" + #include <language/language.h> +#include <tools/fileinfo.h> #include <tools/filetime.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp index 37f15e44c..c0ad6ed07 100644 --- a/src/lib/corelib/buildgraph/transformer.cpp +++ b/src/lib/corelib/buildgraph/transformer.cpp @@ -37,6 +37,7 @@ #include <language/scriptengine.h> #include <logging/translator.h> #include <tools/error.h> +#include <tools/fileinfo.h> #include <tools/persistence.h> #include <tools/scripttools.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index d0b42354b..c2a524d19 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -175,6 +175,8 @@ QbsLibrary { "moduleproperties.h", "process.cpp", "process.h", + "temporarydir.cpp", + "temporarydir.h", "textfile.cpp", "textfile.h", "domxml.cpp", @@ -230,6 +232,8 @@ QbsLibrary { "itemreader.h", "itemreaderastvisitor.cpp", "itemreaderastvisitor.h", + "itemreadervisitorstate.cpp", + "itemreadervisitorstate.h", "jsimports.h", "language.cpp", "language.h", diff --git a/src/lib/corelib/jsextensions/jsextensions.cpp b/src/lib/corelib/jsextensions/jsextensions.cpp index f0ff91007..317ce67fb 100644 --- a/src/lib/corelib/jsextensions/jsextensions.cpp +++ b/src/lib/corelib/jsextensions/jsextensions.cpp @@ -34,6 +34,7 @@ #include "file.h" #include "process.h" #include "propertylist.h" +#include "temporarydir.h" #include "textfile.h" #include <QScriptEngine> @@ -68,6 +69,7 @@ JsExtensions::InitializerMap JsExtensions::initializers() m_initializers.insert(QLatin1String("File"), &initializeJsExtensionFile); m_initializers.insert(QLatin1String("Process"), &initializeJsExtensionProcess); m_initializers.insert(QLatin1String("Xml"), &initializeJsExtensionXml); + m_initializers.insert(QLatin1String("TemporaryDir"), &initializeJsExtensionTemporaryDir); m_initializers.insert(QLatin1String("TextFile"), &initializeJsExtensionTextFile); m_initializers.insert(QLatin1String("PropertyList"), &initializeJsExtensionPropertyList); } diff --git a/src/lib/corelib/jsextensions/jsextensions.pri b/src/lib/corelib/jsextensions/jsextensions.pri index 228675e8d..e32f01111 100644 --- a/src/lib/corelib/jsextensions/jsextensions.pri +++ b/src/lib/corelib/jsextensions/jsextensions.pri @@ -2,6 +2,7 @@ QT += xml HEADERS += \ $$PWD/file.h \ + $$PWD/temporarydir.h \ $$PWD/textfile.h \ $$PWD/process.h \ $$PWD/moduleproperties.h \ @@ -10,6 +11,7 @@ HEADERS += \ SOURCES += \ $$PWD/file.cpp \ + $$PWD/temporarydir.cpp \ $$PWD/textfile.cpp \ $$PWD/process.cpp \ $$PWD/moduleproperties.cpp \ diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp index 6ae8322e6..d83fc34e9 100644 --- a/src/lib/corelib/jsextensions/moduleproperties.cpp +++ b/src/lib/corelib/jsextensions/moduleproperties.cpp @@ -32,6 +32,7 @@ #include <buildgraph/artifact.h> #include <language/language.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> #include <logging/translator.h> #include <tools/error.h> diff --git a/src/lib/corelib/jsextensions/temporarydir.cpp b/src/lib/corelib/jsextensions/temporarydir.cpp new file mode 100644 index 000000000..e01796eac --- /dev/null +++ b/src/lib/corelib/jsextensions/temporarydir.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Jake Petroules. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "temporarydir.h" + +#include <QScriptEngine> +#include <QScriptValue> +#include <QTemporaryDir> + +namespace qbs { +namespace Internal { + +void initializeJsExtensionTemporaryDir(QScriptValue extensionObject) +{ + QScriptEngine *engine = extensionObject.engine(); + QScriptValue obj = engine->newQMetaObject(&TemporaryDir::staticMetaObject, + engine->newFunction(&TemporaryDir::ctor)); + extensionObject.setProperty(QLatin1String("TemporaryDir"), obj); +} + +QScriptValue TemporaryDir::ctor(QScriptContext *context, QScriptEngine *engine) +{ + TemporaryDir *t = new TemporaryDir(context); + QScriptValue obj = engine->newQObject(t, QScriptEngine::ScriptOwnership); + return obj; +} + +TemporaryDir::TemporaryDir(QScriptContext *context) +{ + Q_UNUSED(context); +} + +bool TemporaryDir::isValid() const +{ + return dir.isValid(); +} + +QString TemporaryDir::path() const +{ + return dir.path(); +} + +bool TemporaryDir::remove() +{ + return dir.remove(); +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/jsextensions/temporarydir.h b/src/lib/corelib/jsextensions/temporarydir.h new file mode 100644 index 000000000..b2ab71cc8 --- /dev/null +++ b/src/lib/corelib/jsextensions/temporarydir.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Jake Petroules. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef QBS_TEMPORARYDIR_H +#define QBS_TEMPORARYDIR_H + +#include <QObject> +#include <QScriptable> +#include <QTemporaryDir> +#include <QVariant> + +namespace qbs { +namespace Internal { + +void initializeJsExtensionTemporaryDir(QScriptValue extensionObject); + +class TemporaryDir : public QObject, public QScriptable +{ + Q_OBJECT +public: + static QScriptValue ctor(QScriptContext *context, QScriptEngine *engine); + TemporaryDir(QScriptContext *context); + Q_INVOKABLE bool isValid() const; + Q_INVOKABLE QString path() const; + Q_INVOKABLE bool remove(); +private: + QTemporaryDir dir; +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_TEMPORARYDIR_H diff --git a/src/lib/corelib/language/artifactproperties.h b/src/lib/corelib/language/artifactproperties.h index 6a09c3022..242936bf7 100644 --- a/src/lib/corelib/language/artifactproperties.h +++ b/src/lib/corelib/language/artifactproperties.h @@ -31,8 +31,9 @@ #ifndef QBS_ARTIFACTPROPERTIES_H #define QBS_ARTIFACTPROPERTIES_H -#include "language.h" +#include "filetags.h" #include "forward_decls.h" + #include <tools/persistentobject.h> namespace qbs { diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp index e826f3981..973ae7a7b 100644 --- a/src/lib/corelib/language/builtindeclarations.cpp +++ b/src/lib/corelib/language/builtindeclarations.cpp @@ -31,18 +31,21 @@ #include "builtindeclarations.h" #include "deprecationinfo.h" -#include "item.h" #include <logging/translator.h> -#include <tools/error.h> + +#include <QStringList> namespace qbs { namespace Internal { +class AClassWithPublicConstructor : public BuiltinDeclarations { }; +Q_GLOBAL_STATIC(AClassWithPublicConstructor, theInstance) + const char QBS_LANGUAGE_VERSION[] = "1.0"; BuiltinDeclarations::BuiltinDeclarations() - : m_languageVersion(QLatin1String(QBS_LANGUAGE_VERSION)) + : m_languageVersion(Version::fromString(QLatin1String(QBS_LANGUAGE_VERSION))) { addArtifactItem(); addDependsItem(); @@ -61,7 +64,12 @@ BuiltinDeclarations::BuiltinDeclarations() addScannerItem(); } -QString BuiltinDeclarations::languageVersion() const +const BuiltinDeclarations &BuiltinDeclarations::instance() +{ + return *theInstance; +} + +Version BuiltinDeclarations::languageVersion() const { return m_languageVersion; } @@ -81,40 +89,6 @@ ItemDeclaration BuiltinDeclarations::declarationsForType(const QString &typeName return m_builtins.value(typeName); } -void BuiltinDeclarations::setupItemForBuiltinType(Item *item, Logger logger) const -{ - foreach (const PropertyDeclaration &pd, declarationsForType(item->typeName()).properties()) { - item->m_propertyDeclarations.insert(pd.name(), pd); - ValuePtr &value = item->m_properties[pd.name()]; - if (!value) { - JSSourceValuePtr sourceValue = JSSourceValue::create(); - sourceValue->setFile(item->file()); - static const QString undefinedKeyword = QLatin1String("undefined"); - sourceValue->setSourceCode(pd.initialValueSource().isEmpty() - ? QStringRef(&undefinedKeyword) - : QStringRef(&pd.initialValueSource())); - value = sourceValue; - } else if (pd.isDeprecated()) { - const DeprecationInfo &di = pd.deprecationInfo(); - if (di.removalVersion() <= Version::qbsVersion()) { - QString message = Tr::tr("The property '%1' is no longer valid for %2 items. " - "It was removed in qbs %3.") - .arg(pd.name(), item->typeName(), di.removalVersion().toString()); - ErrorInfo error(message, value->location()); - if (!di.additionalUserInfo().isEmpty()) - error.append(di.additionalUserInfo()); - throw error; - } - QString warning = Tr::tr("The property '%1' is deprecated and will be removed in " - "qbs %2.").arg(pd.name(), di.removalVersion().toString()); - ErrorInfo error(warning, value->location()); - if (!di.additionalUserInfo().isEmpty()) - error.append(di.additionalUserInfo()); - logger.printWarning(error); - } - } -} - void BuiltinDeclarations::insert(const ItemDeclaration &decl) { m_builtins.insert(decl.typeName(), decl); diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h index 99b71c38a..01a403d1d 100644 --- a/src/lib/corelib/language/builtindeclarations.h +++ b/src/lib/corelib/language/builtindeclarations.h @@ -33,26 +33,26 @@ #include "itemdeclaration.h" -#include <logging/logger.h> +#include <tools/version.h> -#include <QByteArray> #include <QMap> +#include <QString> namespace qbs { namespace Internal { -class Item; - class BuiltinDeclarations { public: - BuiltinDeclarations(); + static const BuiltinDeclarations &instance(); - QString languageVersion() const; + Version languageVersion() const; bool containsType(const QString &typeName) const; QStringList allTypeNames() const; ItemDeclaration declarationsForType(const QString &typeName) const; - void setupItemForBuiltinType(qbs::Internal::Item *item, Logger logger) const; + +protected: + BuiltinDeclarations(); private: void insert(const ItemDeclaration &decl); @@ -73,7 +73,7 @@ private: void addTransformerItem(); void addScannerItem(); - QString m_languageVersion; + const Version m_languageVersion; QMap<QString, ItemDeclaration> m_builtins; }; diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp index c8a2398f7..eedb6e497 100644 --- a/src/lib/corelib/language/evaluator.cpp +++ b/src/lib/corelib/language/evaluator.cpp @@ -29,23 +29,25 @@ ****************************************************************************/ #include "evaluator.h" + #include "evaluationdata.h" #include "evaluatorscriptclass.h" #include "filecontext.h" #include "filetags.h" #include "item.h" +#include "scriptengine.h" + #include <jsextensions/jsextensions.h> #include <logging/translator.h> #include <tools/error.h> #include <tools/scripttools.h> #include <tools/qbsassert.h> + #include <QDebug> -#include <QScriptEngine> namespace qbs { namespace Internal { - Evaluator::Evaluator(ScriptEngine *scriptEngine, const Logger &logger) : m_scriptEngine(scriptEngine) , m_scriptClass(new EvaluatorScriptClass(scriptEngine, logger)) diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h index 9781f5956..6806ce65c 100644 --- a/src/lib/corelib/language/evaluator.h +++ b/src/lib/corelib/language/evaluator.h @@ -33,16 +33,16 @@ #include "forward_decls.h" #include "itemobserver.h" -#include <language/scriptengine.h> #include <QHash> #include <QScriptValue> namespace qbs { namespace Internal { -class FileTags; - class EvaluatorScriptClass; +class FileTags; +class Logger; +class ScriptEngine; class Evaluator : private ItemObserver { @@ -52,7 +52,7 @@ public: Evaluator(ScriptEngine *scriptEngine, const Logger &logger); virtual ~Evaluator(); - ScriptEngine *engine() const; + ScriptEngine *engine() const { return m_scriptEngine; } QScriptValue property(const Item *item, const QString &name); QScriptValue value(const Item *item, const QString &name, bool *propertySet = 0); @@ -82,11 +82,6 @@ private: mutable QHash<FileContextConstPtr, QScriptValue> m_fileScopeMap; }; -inline ScriptEngine *Evaluator::engine() const -{ - return m_scriptEngine; -} - } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp index 06aa9a3f8..e9e6d8d36 100644 --- a/src/lib/corelib/language/evaluatorscriptclass.cpp +++ b/src/lib/corelib/language/evaluatorscriptclass.cpp @@ -30,7 +30,6 @@ #include "evaluatorscriptclass.h" -#include "builtinvalue.h" #include "evaluationdata.h" #include "evaluator.h" #include "filecontext.h" diff --git a/src/lib/corelib/language/evaluatorscriptclass.h b/src/lib/corelib/language/evaluatorscriptclass.h index cfc2da748..7dcda5619 100644 --- a/src/lib/corelib/language/evaluatorscriptclass.h +++ b/src/lib/corelib/language/evaluatorscriptclass.h @@ -31,8 +31,9 @@ #ifndef QBS_EVALUATORSCRIPTCLASS_H #define QBS_EVALUATORSCRIPTCLASS_H -#include "value.h" #include "builtinvalue.h" +#include "forward_decls.h" + #include <logging/logger.h> #include <QScriptClass> diff --git a/src/lib/corelib/language/filecontext.cpp b/src/lib/corelib/language/filecontext.cpp index cf6784be8..d8760f31a 100644 --- a/src/lib/corelib/language/filecontext.cpp +++ b/src/lib/corelib/language/filecontext.cpp @@ -30,6 +30,8 @@ #include "filecontext.h" +#include "item.h" + namespace qbs { namespace Internal { @@ -43,5 +45,13 @@ FileContextPtr FileContext::create() return FileContextPtr(new FileContext); } +void FileContext::ensureIdScope(ItemPool *itemPool) +{ + if (!m_idScope) { + m_idScope = Item::create(itemPool); + m_idScope->setTypeName(QLatin1String("IdScope")); + } +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/filecontext.h b/src/lib/corelib/language/filecontext.h index 3d669e0c6..14219cd5b 100644 --- a/src/lib/corelib/language/filecontext.h +++ b/src/lib/corelib/language/filecontext.h @@ -32,31 +32,27 @@ #define QBS_FILECONTEXT_H #include "filecontextbase.h" -#include "item.h" +#include "forward_decls.h" namespace qbs { namespace Internal { +class Item; +class ItemPool; class FileContext : public FileContextBase { - friend class ItemReaderASTVisitor; - - FileContext(); - public: static FileContextPtr create(); - Item *idScope() const; + Item *idScope() const { return m_idScope; } + void ensureIdScope(ItemPool *itemPool); private: + FileContext(); + Item *m_idScope; }; -inline Item *FileContext::idScope() const -{ - return m_idScope; -} - } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/filecontextbase.h b/src/lib/corelib/language/filecontextbase.h index eec9f9f9e..aa2bbbfbe 100644 --- a/src/lib/corelib/language/filecontextbase.h +++ b/src/lib/corelib/language/filecontextbase.h @@ -38,23 +38,21 @@ namespace Internal { class FileContextBase { - friend class ItemReaderASTVisitor; - public: - void setFilePath(const QString &filePath); - QString filePath() const; + void setFilePath(const QString &filePath) { m_filePath = filePath; } + QString filePath() const { return m_filePath; } - void setContent(const QString &content); - const QString &content() const; + void setContent(const QString &content) { m_content = content; } + const QString &content() const { return m_content; } - void setJsImports(const JsImports &jsImports); - JsImports jsImports() const; + void addJsImport(const JsImport &jsImport) { m_jsImports << jsImport; } + JsImports jsImports() const { return m_jsImports; } - void setJsExtensions(const QStringList &extensions); - QStringList jsExtensions() const; + void addJsExtension(const QString &extension) { m_jsExtensions << extension; } + QStringList jsExtensions() const { return m_jsExtensions; } - void setSearchPaths(const QStringList &paths); - QStringList searchPaths() const; + void setSearchPaths(const QStringList &paths) { m_searchPaths = paths; } + QStringList searchPaths() const { return m_searchPaths; } QString dirPath() const; @@ -69,56 +67,6 @@ protected: QStringList m_searchPaths; }; -inline void FileContextBase::setFilePath(const QString &filePath) -{ - m_filePath = filePath; -} - -inline QString FileContextBase::filePath() const -{ - return m_filePath; -} - -inline void FileContextBase::setContent(const QString &content) -{ - m_content = content; -} - -inline const QString &FileContextBase::content() const -{ - return m_content; -} - -inline void FileContextBase::setJsImports(const JsImports &jsImports) -{ - m_jsImports = jsImports; -} - -inline JsImports FileContextBase::jsImports() const -{ - return m_jsImports; -} - -inline void FileContextBase::setJsExtensions(const QStringList &extensions) -{ - m_jsExtensions = extensions; -} - -inline QStringList FileContextBase::jsExtensions() const -{ - return m_jsExtensions; -} - -inline void FileContextBase::setSearchPaths(const QStringList &paths) -{ - m_searchPaths = paths; -} - -inline QStringList FileContextBase::searchPaths() const -{ - return m_searchPaths; -} - } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/functiondeclaration.h b/src/lib/corelib/language/functiondeclaration.h index f0e0be62d..dcf63e2ee 100644 --- a/src/lib/corelib/language/functiondeclaration.h +++ b/src/lib/corelib/language/functiondeclaration.h @@ -33,6 +33,8 @@ #include <tools/codelocation.h> +#include <QString> + namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp index e2df88925..57ea4742b 100644 --- a/src/lib/corelib/language/item.cpp +++ b/src/lib/corelib/language/item.cpp @@ -29,8 +29,15 @@ ****************************************************************************/ #include "item.h" -#include "itempool.h" + +#include "builtindeclarations.h" +#include "deprecationinfo.h" #include "filecontext.h" +#include "itemobserver.h" +#include "itempool.h" +#include "value.h" + +#include <logging/logger.h> #include <logging/translator.h> #include <tools/error.h> #include <tools/qbsassert.h> @@ -62,9 +69,9 @@ Item *Item::create(ItemPool *pool) return pool->allocateItem(); } -Item *Item::clone(ItemPool *pool) const +Item *Item::clone() const { - Item *dup = create(pool); + Item *dup = create(pool()); dup->m_id = m_id; dup->m_typeName = m_typeName; dup->m_location = m_location; @@ -80,7 +87,7 @@ Item *Item::clone(ItemPool *pool) const dup->m_children.reserve(m_children.count()); foreach (const Item *child, m_children) { - Item *clonedChild = child->clone(pool); + Item *clonedChild = child->clone(); clonedChild->m_parent = dup; dup->m_children.append(clonedChild); } @@ -145,7 +152,7 @@ VariantValuePtr Item::variantProperty(const QString &name) const return v.staticCast<VariantValue>(); } -const PropertyDeclaration Item::propertyDeclaration(const QString &name) const +PropertyDeclaration Item::propertyDeclaration(const QString &name) const { const PropertyDeclaration decl = m_propertyDeclarations.value(name); return (!decl.isValid() && m_prototype) ? m_prototype->propertyDeclaration(name) : decl; @@ -163,6 +170,13 @@ void Item::setPropertyObserver(ItemObserver *observer) const m_propertyObserver = observer; } +void Item::setProperty(const QString &name, const ValuePtr &value) +{ + m_properties.insert(name, value); + if (m_propertyObserver) + m_propertyObserver->onItemPropertyChanged(this); +} + void Item::dump() const { dump(0); @@ -175,6 +189,46 @@ bool Item::isPresentModule() const return v && v->type() == Value::JSSourceValueType; } +void Item::setupForBuiltinType(Logger &logger) +{ + const BuiltinDeclarations &builtins = BuiltinDeclarations::instance(); + foreach (const PropertyDeclaration &pd, builtins.declarationsForType(typeName()).properties()) { + m_propertyDeclarations.insert(pd.name(), pd); + ValuePtr &value = m_properties[pd.name()]; + if (!value) { + JSSourceValuePtr sourceValue = JSSourceValue::create(); + sourceValue->setFile(file()); + static const QString undefinedKeyword = QLatin1String("undefined"); + sourceValue->setSourceCode(pd.initialValueSource().isEmpty() + ? QStringRef(&undefinedKeyword) + : QStringRef(&pd.initialValueSource())); + value = sourceValue; + } else if (pd.isDeprecated()) { + const DeprecationInfo &di = pd.deprecationInfo(); + if (di.removalVersion() <= Version::qbsVersion()) { + QString message = Tr::tr("The property '%1' is no longer valid for %2 items. " + "It was removed in qbs %3.") + .arg(pd.name(), typeName(), di.removalVersion().toString()); + ErrorInfo error(message, value->location()); + if (!di.additionalUserInfo().isEmpty()) + error.append(di.additionalUserInfo()); + throw error; + } + QString warning = Tr::tr("The property '%1' is deprecated and will be removed in " + "qbs %2.").arg(pd.name(), di.removalVersion().toString()); + ErrorInfo error(warning, value->location()); + if (!di.additionalUserInfo().isEmpty()) + error.append(di.additionalUserInfo()); + logger.printWarning(error); + } + } +} + +void Item::copyProperty(const QString &propertyName, Item *target) const +{ + target->setProperty(propertyName, property(propertyName)); +} + static const char *valueType(const Value *v) { switch (v->type()) { @@ -248,5 +302,16 @@ Item *Item::child(const QString &type, bool checkForMultiple) const return child; } +void Item::addChild(Item *parent, Item *child) +{ + parent->m_children.append(child); + child->setParent(parent); +} + +void Item::setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration) +{ + m_propertyDeclarations.insert(name, declaration); +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/item.h b/src/lib/corelib/language/item.h index cdf4905cd..bf926dae4 100644 --- a/src/lib/corelib/language/item.h +++ b/src/lib/corelib/language/item.h @@ -32,30 +32,24 @@ #define QBS_ITEM_H #include "forward_decls.h" -#include "itemobserver.h" -#include "value.h" #include "functiondeclaration.h" #include "propertydeclaration.h" #include "qualifiedid.h" #include <parser/qmljsmemorypool_p.h> #include <tools/codelocation.h> #include <tools/error.h> -#include <tools/weakpointer.h> #include <QList> #include <QMap> -#include <QSharedPointer> -#include <QStringList> namespace qbs { namespace Internal { - +class ItemObserver; class ItemPool; -class ProjectFile; +class Logger; class Item : public QbsQmlJS::Managed { - friend class BuiltinDeclarations; friend class ItemPool; friend class ItemReaderASTVisitor; Q_DISABLE_COPY(Item) @@ -80,24 +74,24 @@ public: typedef QMap<QString, ValuePtr> PropertyMap; static Item *create(ItemPool *pool); - Item *clone(ItemPool *pool) const; - ItemPool *pool() const; - - const QString &id() const; - const QString &typeName() const; - const CodeLocation &location() const; - Item *prototype() const; - Item *scope() const; - bool isModuleInstance() const; - Item *outerItem() const; - Item *parent() const; - const FileContextPtr file() const; - QList<Item *> children() const; + Item *clone() const; + ItemPool *pool() const { return m_pool; } + + const QString &id() const { return m_id; } + const QString &typeName() const { return m_typeName; } + const CodeLocation &location() const { return m_location; } + Item *prototype() const { return m_prototype; } + Item *scope() const { return m_scope; } + bool isModuleInstance() const { return m_moduleInstance; } + Item *outerItem() const { return m_outerItem; } + Item *parent() const { return m_parent; } + const FileContextPtr file() const { return m_file; } + QList<Item *> children() const { return m_children; } Item *child(const QString &type, bool checkForMultiple = true) const; - const PropertyMap &properties() const; - const PropertyDeclarationMap &propertyDeclarations() const; - const PropertyDeclaration propertyDeclaration(const QString &name) const; - const Modules &modules() const; + const PropertyMap &properties() const { return m_properties; } + const PropertyDeclarationMap &propertyDeclarations() const { return m_propertyDeclarations; } + PropertyDeclaration propertyDeclaration(const QString &name) const; + const Modules &modules() const { return m_modules; } void addModule(const Module &module); void removeModules() { m_modules.clear(); } void setModules(const Modules &modules) { m_modules = modules; } @@ -113,18 +107,20 @@ public: void setProperties(const PropertyMap &props) { m_properties = props; } void removeProperty(const QString &name); void setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration); - void setTypeName(const QString &name); - void setLocation(const CodeLocation &location); - void setPrototype(Item *prototype); - void setFile(const FileContextPtr &file); - void setScope(Item *item); - void setModuleInstanceFlag(bool b); - void setOuterItem(Item *item); - void setChildren(const QList<Item *> &children); - void setParent(Item *item); + void setTypeName(const QString &name) { m_typeName = name; } + void setLocation(const CodeLocation &location) { m_location = location; } + void setPrototype(Item *prototype) { m_prototype = prototype; } + void setFile(const FileContextPtr &file) { m_file = file; } + void setScope(Item *item) { m_scope = item; } + void setModuleInstanceFlag(bool b) { m_moduleInstance = b; } + void setOuterItem(Item *item) { m_outerItem = item; } + void setChildren(const QList<Item *> &children) { m_children = children; } + void setParent(Item *item) { m_parent = item; } static void addChild(Item *parent, Item *child); void dump() const; bool isPresentModule() const; + void setupForBuiltinType(Logger &logger); + void copyProperty(const QString &propertyName, Item *target) const; void setDelayedError(const ErrorInfo &e) { m_delayedError = e; } ErrorInfo delayedError() const { return m_delayedError; } @@ -151,140 +147,6 @@ private: ErrorInfo m_delayedError; }; -inline ItemPool *Item::pool() const -{ - return m_pool; -} - -inline const QString &Item::id() const -{ - return m_id; -} - -inline const QString &Item::typeName() const -{ - return m_typeName; -} - -inline const CodeLocation &Item::location() const -{ - return m_location; -} - -inline Item *Item::prototype() const -{ - return m_prototype; -} - -inline Item *Item::scope() const -{ - return m_scope; -} - -inline bool Item::isModuleInstance() const -{ - return m_moduleInstance; -} - -inline Item *Item::outerItem() const -{ - return m_outerItem; -} - -inline Item *Item::parent() const -{ - return m_parent; -} - -inline const FileContextPtr Item::file() const -{ - return m_file; -} - -inline QList<Item *> Item::children() const -{ - return m_children; -} - -inline const Item::PropertyMap &Item::properties() const -{ - return m_properties; -} - -inline const Item::PropertyDeclarationMap &Item::propertyDeclarations() const -{ - return m_propertyDeclarations; -} - -inline void Item::setProperty(const QString &name, const ValuePtr &value) -{ - m_properties.insert(name, value); - if (m_propertyObserver) - m_propertyObserver->onItemPropertyChanged(this); -} - -inline void Item::setPropertyDeclaration(const QString &name, - const PropertyDeclaration &declaration) -{ - m_propertyDeclarations.insert(name, declaration); -} - -inline void Item::setTypeName(const QString &name) -{ - m_typeName = name; -} - -inline void Item::setLocation(const CodeLocation &location) -{ - m_location = location; -} - -inline void Item::setPrototype(Item *prototype) -{ - m_prototype = prototype; -} - -inline void Item::setFile(const FileContextPtr &file) -{ - m_file = file; -} - -inline void Item::setScope(Item *item) -{ - m_scope = item; -} - -inline void Item::setModuleInstanceFlag(bool b) -{ - m_moduleInstance = b; -} - -inline void Item::setOuterItem(Item *item) -{ - m_outerItem = item; -} - -inline void Item::setChildren(const QList<Item *> &children) -{ - m_children = children; -} - -inline void Item::setParent(Item *item) -{ - m_parent = item; -} - -inline void Item::addChild(Item *parent, Item *child) -{ - parent->m_children.append(child); - child->setParent(parent); -} - -inline const Item::Modules &Item::modules() const -{ - return m_modules; -} - inline bool operator<(const Item::Module &m1, const Item::Module &m2) { return m1.name < m2.name; } } // namespace Internal diff --git a/src/lib/corelib/language/itemdeclaration.h b/src/lib/corelib/language/itemdeclaration.h index 2876e53e1..960e4ad75 100644 --- a/src/lib/corelib/language/itemdeclaration.h +++ b/src/lib/corelib/language/itemdeclaration.h @@ -32,7 +32,9 @@ #define QBS_ITEMDECLARATION_H #include "propertydeclaration.h" + #include <QSet> +#include <QString> namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/itemobserver.h b/src/lib/corelib/language/itemobserver.h index b2c823c9c..dbc4f5767 100644 --- a/src/lib/corelib/language/itemobserver.h +++ b/src/lib/corelib/language/itemobserver.h @@ -31,8 +31,6 @@ #ifndef QBS_ITEMOBSERVER_H #define QBS_ITEMOBSERVER_H -#include <QString> - namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/itemreader.cpp b/src/lib/corelib/language/itemreader.cpp index f23b45cfd..de3e78eca 100644 --- a/src/lib/corelib/language/itemreader.cpp +++ b/src/lib/corelib/language/itemreader.cpp @@ -29,81 +29,19 @@ ****************************************************************************/ #include "itemreader.h" -#include "asttools.h" -#include "itemreaderastvisitor.h" -#include <logging/translator.h> -#include <parser/qmljsengine_p.h> -#include <parser/qmljslexer_p.h> -#include <parser/qmljsparser_p.h> -#include <tools/error.h> -#include <QExplicitlySharedDataPointer> -#include <QFile> -#include <QFileInfo> -#include <QSharedData> -#include <QTextStream> + +#include "itemreadervisitorstate.h" namespace qbs { namespace Internal { -class ASTCacheValueData : public QSharedData -{ - Q_DISABLE_COPY(ASTCacheValueData) -public: - ASTCacheValueData() - : ast(0) - , processing(false) - { - } - - QString code; - QbsQmlJS::Engine engine; - QbsQmlJS::AST::UiProgram *ast; - bool processing; -}; - -class ASTCacheValue -{ -public: - ASTCacheValue() - : d(new ASTCacheValueData) - { - } - - ASTCacheValue(const ASTCacheValue &other) - : d(other.d) - { - } - - void setProcessingFlag(bool b) { d->processing = b; } - bool isProcessing() const { return d->processing; } - - void setCode(const QString &code) { d->code = code; } - QString code() const { return d->code; } - - QbsQmlJS::Engine *engine() const { return &d->engine; } - - void setAst(QbsQmlJS::AST::UiProgram *ast) { d->ast = ast; } - QbsQmlJS::AST::UiProgram *ast() const { return d->ast; } - bool isValid() const { return d->ast; } - -private: - QExplicitlySharedDataPointer<ASTCacheValueData> d; -}; - -class ItemReader::ASTCache : public QHash<QString, ASTCacheValue> {}; - - -ItemReader::ItemReader(BuiltinDeclarations *builtins, const Logger &logger) - : m_pool(0) - , m_builtins(builtins) - , m_logger(logger) - , m_astCache(new ASTCache) +ItemReader::ItemReader(const Logger &logger) : m_visitorState(new ItemReaderVisitorState(logger)) { } ItemReader::~ItemReader() { - delete m_astCache; + delete m_visitorState; } void ItemReader::setSearchPaths(const QStringList &searchPaths) @@ -135,70 +73,14 @@ QStringList ItemReader::searchPaths() const return paths; } -void ItemReader::cacheDirectoryEntries(const QString &dirPath, const QStringList &entries) -{ - m_directoryEntries.insert(dirPath, entries); -} - -bool ItemReader::findDirectoryEntries(const QString &dirPath, QStringList *entries) const -{ - const QHash<QString, QStringList>::ConstIterator it = m_directoryEntries.constFind(dirPath); - if (it == m_directoryEntries.constEnd()) - return false; - *entries = it.value(); - return true; -} - Item *ItemReader::readFile(const QString &filePath) { - return internalReadFile(filePath).rootItem; + return m_visitorState->readFile(filePath, searchPaths(), m_pool); } QSet<QString> ItemReader::filesRead() const { - return m_filesRead; -} - -ItemReaderResult ItemReader::internalReadFile(const QString &filePath) -{ - ASTCacheValue &cacheValue = (*m_astCache)[filePath]; - if (cacheValue.isValid()) { - if (Q_UNLIKELY(cacheValue.isProcessing())) - throw ErrorInfo(Tr::tr("Loop detected when importing '%1'.").arg(filePath)); - } else { - QFile file(filePath); - if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) - throw ErrorInfo(Tr::tr("Cannot open '%1'.").arg(filePath)); - - m_filesRead.insert(filePath); - const QString code = QTextStream(&file).readAll(); - QbsQmlJS::Lexer lexer(cacheValue.engine()); - lexer.setCode(code, 1); - QbsQmlJS::Parser parser(cacheValue.engine()); - - file.close(); - if (!parser.parse()) { - QList<QbsQmlJS::DiagnosticMessage> parserMessages = parser.diagnosticMessages(); - if (Q_UNLIKELY(!parserMessages.isEmpty())) { - ErrorInfo err; - foreach (const QbsQmlJS::DiagnosticMessage &msg, parserMessages) - err.append(msg.message, toCodeLocation(filePath, msg.loc)); - throw err; - } - } - - cacheValue.setCode(code); - cacheValue.setAst(parser.ast()); - } - - ItemReaderResult result; - ItemReaderASTVisitor itemReader(this, &result); - itemReader.setFilePath(QFileInfo(filePath).absoluteFilePath()); - itemReader.setSourceCode(cacheValue.code()); - cacheValue.setProcessingFlag(true); - cacheValue.ast()->accept(&itemReader); - cacheValue.setProcessingFlag(false); - return result; + return m_visitorState->filesRead(); } } // namespace Internal diff --git a/src/lib/corelib/language/itemreader.h b/src/lib/corelib/language/itemreader.h index de147ae9b..b77c16b82 100644 --- a/src/lib/corelib/language/itemreader.h +++ b/src/lib/corelib/language/itemreader.h @@ -34,7 +34,6 @@ #include "forward_decls.h" #include <logging/logger.h> -#include <QHash> #include <QSet> #include <QStack> #include <QStringList> @@ -42,18 +41,9 @@ namespace qbs { namespace Internal { -class BuiltinDeclarations; class Item; class ItemPool; - -struct ItemReaderResult -{ - ItemReaderResult() - : rootItem(0) - {} - - Item *rootItem; -}; +class ItemReaderVisitorState; /* * Reads a qbs file and creates a tree of Item objects. @@ -66,14 +56,10 @@ struct ItemReaderResult */ class ItemReader { - friend class ItemReaderASTVisitor; public: - ItemReader(BuiltinDeclarations *builtins, const Logger &logger); + ItemReader(const Logger &logger); ~ItemReader(); - BuiltinDeclarations *builtins() const { return m_builtins; } - Logger logger() const { return m_logger; } - void setPool(ItemPool *pool) { m_pool = pool; } void setSearchPaths(const QStringList &searchPaths); void pushExtraSearchPaths(const QStringList &extraSearchPaths); @@ -88,22 +74,10 @@ public: QSet<QString> filesRead() const; private: - ItemReaderResult internalReadFile(const QString &filePath); - - void cacheDirectoryEntries(const QString &dirPath, const QStringList &entries); - bool findDirectoryEntries(const QString &dirPath, QStringList *entries) const; - - ItemPool *m_pool; - BuiltinDeclarations *m_builtins; - Logger m_logger; + ItemPool *m_pool = nullptr; QStringList m_searchPaths; QStack<QStringList> m_extraSearchPaths; - QHash<const Item *, QSet<JSSourceValuePtr> > m_conditionalValuesPerScopeItem; - - class ASTCache; - ASTCache *m_astCache; - QSet<QString> m_filesRead; - QHash<QString, QStringList> m_directoryEntries; + ItemReaderVisitorState * const m_visitorState; }; } // namespace Internal diff --git a/src/lib/corelib/language/itemreaderastvisitor.cpp b/src/lib/corelib/language/itemreaderastvisitor.cpp index ff8f48e6f..712008d96 100644 --- a/src/lib/corelib/language/itemreaderastvisitor.cpp +++ b/src/lib/corelib/language/itemreaderastvisitor.cpp @@ -29,10 +29,15 @@ ****************************************************************************/ #include "itemreaderastvisitor.h" + #include "asttools.h" #include "builtindeclarations.h" +#include "filecontext.h" #include "identifiersearch.h" -#include "itemreader.h" +#include "item.h" +#include "itemreadervisitorstate.h" +#include "value.h" + #include <jsextensions/jsextensions.h> #include <parser/qmljsast_p.h> #include <tools/error.h> @@ -43,20 +48,19 @@ #include <QDirIterator> #include <QFileInfo> -#include <QStringList> using namespace QbsQmlJS; namespace qbs { namespace Internal { -ItemReaderASTVisitor::ItemReaderASTVisitor(ItemReader *reader, ItemReaderResult *result) - : m_reader(reader) - , m_readerResult(result) - , m_languageVersion(readImportVersion(reader->builtins()->languageVersion())) +ItemReaderASTVisitor::ItemReaderASTVisitor(ItemReaderVisitorState &visitorState, + ItemPool *itemPool, Logger logger, const QStringList &searchPaths) + : m_visitorState(visitorState) , m_file(FileContext::create()) - , m_item(0) - , m_sourceValue(0) + , m_itemPool(itemPool) + , m_logger(logger) + , m_searchPaths(searchPaths) { } @@ -78,7 +82,7 @@ bool ItemReaderASTVisitor::visit(AST::UiProgram *ast) { Q_UNUSED(ast); m_sourceValue.clear(); - m_file->m_searchPaths = m_reader->searchPaths(); + m_file->setSearchPaths(m_searchPaths); if (Q_UNLIKELY(!ast->members->member)) throw ErrorInfo(Tr::tr("No root item found in %1.").arg(m_file->filePath())); @@ -109,7 +113,7 @@ bool ItemReaderASTVisitor::addPrototype(const QString &fileName, const QString & void ItemReaderASTVisitor::collectPrototypes(const QString &path, const QString &as) { QStringList fileNames; // Yes, file *names*. - if (m_reader->findDirectoryEntries(path, &fileNames)) { + if (m_visitorState.findDirectoryEntries(path, &fileNames)) { foreach (const QString &fileName, fileNames) addPrototype(fileName, path + QLatin1Char('/') + fileName, as, false); return; @@ -122,12 +126,12 @@ void ItemReaderASTVisitor::collectPrototypes(const QString &path, const QString if (addPrototype(fileName, filePath, as, true)) fileNames << fileName; } - m_reader->cacheDirectoryEntries(path, fileNames); + m_visitorState.cacheDirectoryEntries(path, fileNames); } bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) { - foreach (const QString &searchPath, m_reader->searchPaths()) + foreach (const QString &searchPath, m_searchPaths) collectPrototypes(searchPath + QLatin1String("/imports"), QString()); const QString path = FileInfo::path(m_file->filePath()); @@ -151,8 +155,8 @@ bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) if (isBase) checkImportVersion(import->versionToken); else if (import->versionToken.length) - m_reader->logger().printWarning(ErrorInfo(Tr::tr("Superfluous version specification."), - toCodeLocation(import->versionToken))); + m_logger.printWarning(ErrorInfo(Tr::tr("Superfluous version specification."), + toCodeLocation(import->versionToken))); } QString as; @@ -169,11 +173,11 @@ bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) throw ErrorInfo(Tr::tr("Import of built-in extension '%1' " "must not have 'as' specifier.").arg(extensionName)); } - if (Q_UNLIKELY(m_file->m_jsExtensions.contains(extensionName))) { - m_reader->logger().printWarning(Tr::tr("Built-in extension '%1' already " - "imported.").arg(extensionName)); + if (Q_UNLIKELY(m_file->jsExtensions().contains(extensionName))) { + m_logger.printWarning(Tr::tr("Built-in extension '%1' already " + "imported.").arg(extensionName)); } else { - m_file->m_jsExtensions << extensionName; + m_file->addJsExtension(extensionName); } continue; } @@ -234,7 +238,7 @@ bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) ? QLatin1String("qbs/base") : importUri.join(QDir::separator()); bool found = m_typeNameToFile.contains(importUri); if (!found) { - foreach (const QString &searchPath, m_reader->searchPaths()) { + foreach (const QString &searchPath, m_searchPaths) { const QFileInfo fi(FileInfo::resolvePath( FileInfo::resolvePath(searchPath, QLatin1String("imports")), @@ -270,7 +274,7 @@ bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) for (QHash<QString, JsImport>::const_iterator it = jsImports.constBegin(); it != jsImports.constEnd(); ++it) { - m_file->m_jsImports += it.value(); + m_file->addJsImport(it.value()); } return false; @@ -280,7 +284,7 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) { const QString typeName = ast->qualifiedTypeNameId->name.toString(); - Item *item = Item::create(m_reader->m_pool); + Item *item = Item::create(m_itemPool); item->m_file = m_file; item->m_parent = m_item; item->m_typeName = typeName; @@ -293,7 +297,7 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) } else { // This is the root item. m_item = item; - m_readerResult->rootItem = item; + m_rootItem = item; } if (ast->initializer) { @@ -302,7 +306,7 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) qSwap(m_item, item); } - m_reader->m_builtins->setupItemForBuiltinType(item, m_reader->logger()); + item->setupForBuiltinType(m_logger); if (item->typeName() != QLatin1String("Properties") && item->typeName() != QLatin1String("SubProject")) { @@ -313,14 +317,15 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) const QStringList fullTypeName = toStringList(ast->qualifiedTypeNameId); const QString baseTypeFileName = m_typeNameToFile.value(fullTypeName); if (!baseTypeFileName.isEmpty()) { - const ItemReaderResult baseFile = m_reader->internalReadFile(baseTypeFileName); + const Item * const rootItem + = m_visitorState.readFile(baseTypeFileName, m_searchPaths, m_itemPool); - inheritItem(item, baseFile.rootItem); - if (baseFile.rootItem->m_file->m_idScope) { + inheritItem(item, rootItem); + if (rootItem->m_file->idScope()) { // Make ids from the derived file visible in the base file. // ### Do we want to turn off this feature? It's QMLish but kind of strange. - ensureIdScope(item->m_file); - baseFile.rootItem->m_file->m_idScope->setPrototype(item->m_file->m_idScope); + item->m_file->ensureIdScope(m_itemPool); + rootItem->m_file->idScope()->setPrototype(item->m_file->idScope()); } } @@ -390,8 +395,8 @@ bool ItemReaderASTVisitor::visit(AST::UiScriptBinding *ast) if (Q_UNLIKELY(!idExp || idExp->name.isEmpty())) throw ErrorInfo(Tr::tr("id: must be followed by identifier")); m_item->m_id = idExp->name.toString(); - ensureIdScope(m_file); - m_file->m_idScope->m_properties[m_item->m_id] = ItemValue::create(m_item); + m_file->ensureIdScope(m_itemPool); + m_file->idScope()->m_properties[m_item->m_id] = ItemValue::create(m_item); return false; } @@ -476,7 +481,7 @@ Item *ItemReaderASTVisitor::targetItemForBinding(Item *item, for (int i = 0; i < c; ++i) { ValuePtr v = targetItem->m_properties.value(bindingName.at(i)); if (!v) { - Item *newItem = Item::create(m_reader->m_pool); + Item *newItem = Item::create(m_itemPool); v = ItemValue::create(newItem); targetItem->m_properties.insert(bindingName.at(i), v); } @@ -497,10 +502,11 @@ void ItemReaderASTVisitor::checkImportVersion(const AST::SourceLocation &version const QString importVersionString = m_file->content().mid(versionToken.offset, versionToken.length); const Version importVersion = readImportVersion(importVersionString, toCodeLocation(versionToken)); - if (Q_UNLIKELY(importVersion != m_languageVersion)) + if (Q_UNLIKELY(importVersion != BuiltinDeclarations::instance().languageVersion())) throw ErrorInfo(Tr::tr("Incompatible qbs language version %1. This is version %2.").arg( - importVersionString, m_reader->builtins()->languageVersion()), - toCodeLocation(versionToken)); + importVersionString, + BuiltinDeclarations::instance().languageVersion().toString()), + toCodeLocation(versionToken)); } void ItemReaderASTVisitor::inheritItem(Item *dst, const Item *src) @@ -553,14 +559,6 @@ void ItemReaderASTVisitor::inheritItem(Item *dst, const Item *src) } } -void ItemReaderASTVisitor::ensureIdScope(const FileContextPtr &file) -{ - if (!file->m_idScope) { - file->m_idScope = Item::create(m_reader->m_pool); - file->m_idScope->m_typeName = QLatin1String("IdScope"); - } -} - void ItemReaderASTVisitor::setupAlternatives(Item *item) { QList<Item *>::iterator it = item->m_children.begin(); diff --git a/src/lib/corelib/language/itemreaderastvisitor.h b/src/lib/corelib/language/itemreaderastvisitor.h index 5f777f1bf..cf85b852f 100644 --- a/src/lib/corelib/language/itemreaderastvisitor.h +++ b/src/lib/corelib/language/itemreaderastvisitor.h @@ -31,24 +31,27 @@ #ifndef QBS_ITEMREADERASTVISITOR_H #define QBS_ITEMREADERASTVISITOR_H -#include "item.h" -#include "filecontext.h" +#include "forward_decls.h" +#include <logging/logger.h> #include <parser/qmljsastvisitor_p.h> -#include <tools/version.h> +#include <tools/codelocation.h> #include <QHash> +#include <QStringList> namespace qbs { namespace Internal { - -class ItemReader; -struct ItemReaderResult; +class Item; +class ItemPool; +class ItemReaderVisitorState; +class Version; class ItemReaderASTVisitor : public QbsQmlJS::AST::Visitor { public: - ItemReaderASTVisitor(ItemReader *reader, ItemReaderResult *result); + ItemReaderASTVisitor(ItemReaderVisitorState &visitorState, + ItemPool *itemPool, Logger logger, const QStringList &searchPaths); ~ItemReaderASTVisitor(); void setFilePath(const QString &filePath); @@ -61,6 +64,8 @@ public: bool visit(QbsQmlJS::AST::UiScriptBinding *ast); bool visit(QbsQmlJS::AST::FunctionDeclaration *ast); + Item *rootItem() const { return m_rootItem; } + private: static Version readImportVersion(const QString &str, const CodeLocation &location = CodeLocation()); @@ -72,7 +77,6 @@ private: const JSSourceValueConstPtr &value); void checkImportVersion(const QbsQmlJS::AST::SourceLocation &versionToken) const; static void inheritItem(Item *dst, const Item *src); - void ensureIdScope(const FileContextPtr &file); void setupAlternatives(Item *item); static void replaceConditionScopes(const JSSourceValuePtr &value, Item *newScope); void handlePropertiesBlock(Item *item, const Item *block); @@ -80,12 +84,14 @@ private: bool addPrototype(const QString &fileName, const QString &filePath, const QString &as, bool needsCheck); - ItemReader *m_reader; - ItemReaderResult *m_readerResult; - const Version m_languageVersion; - FileContextPtr m_file; + ItemReaderVisitorState &m_visitorState; + const FileContextPtr m_file; + ItemPool * const m_itemPool; + Logger m_logger; + const QStringList m_searchPaths; QHash<QStringList, QString> m_typeNameToFile; - Item *m_item; + Item *m_item = nullptr; + Item *m_rootItem = nullptr; JSSourceValuePtr m_sourceValue; }; diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp new file mode 100644 index 000000000..4eeb7df38 --- /dev/null +++ b/src/lib/corelib/language/itemreadervisitorstate.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#include "itemreadervisitorstate.h" + +#include "asttools.h" +#include "itemreaderastvisitor.h" + +#include <logging/translator.h> +#include <parser/qmljsengine_p.h> +#include <parser/qmljslexer_p.h> +#include <parser/qmljsparser_p.h> +#include <tools/error.h> + +#include <QExplicitlySharedDataPointer> +#include <QFile> +#include <QFileInfo> +#include <QSharedData> +#include <QTextStream> + +namespace qbs { +namespace Internal { + +class ASTCacheValueData : public QSharedData +{ + Q_DISABLE_COPY(ASTCacheValueData) +public: + ASTCacheValueData() + : ast(0) + , processing(false) + { + } + + QString code; + QbsQmlJS::Engine engine; + QbsQmlJS::AST::UiProgram *ast; + bool processing; +}; + +class ASTCacheValue +{ +public: + ASTCacheValue() + : d(new ASTCacheValueData) + { + } + + ASTCacheValue(const ASTCacheValue &other) + : d(other.d) + { + } + + void setProcessingFlag(bool b) { d->processing = b; } + bool isProcessing() const { return d->processing; } + + void setCode(const QString &code) { d->code = code; } + QString code() const { return d->code; } + + QbsQmlJS::Engine *engine() const { return &d->engine; } + + void setAst(QbsQmlJS::AST::UiProgram *ast) { d->ast = ast; } + QbsQmlJS::AST::UiProgram *ast() const { return d->ast; } + bool isValid() const { return d->ast; } + +private: + QExplicitlySharedDataPointer<ASTCacheValueData> d; +}; + +class ItemReaderVisitorState::ASTCache : public QHash<QString, ASTCacheValue> {}; + + +ItemReaderVisitorState::ItemReaderVisitorState(Logger logger) + : m_logger(logger) + , m_astCache(new ASTCache) +{ + +} + +ItemReaderVisitorState::~ItemReaderVisitorState() +{ + delete m_astCache; +} + +Item *ItemReaderVisitorState::readFile(const QString &filePath, const QStringList &searchPaths, + ItemPool *itemPool) +{ + ASTCacheValue &cacheValue = (*m_astCache)[filePath]; + if (cacheValue.isValid()) { + if (Q_UNLIKELY(cacheValue.isProcessing())) + throw ErrorInfo(Tr::tr("Loop detected when importing '%1'.").arg(filePath)); + } else { + QFile file(filePath); + if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) + throw ErrorInfo(Tr::tr("Cannot open '%1'.").arg(filePath)); + + m_filesRead.insert(filePath); + const QString code = QTextStream(&file).readAll(); + QbsQmlJS::Lexer lexer(cacheValue.engine()); + lexer.setCode(code, 1); + QbsQmlJS::Parser parser(cacheValue.engine()); + + file.close(); + if (!parser.parse()) { + QList<QbsQmlJS::DiagnosticMessage> parserMessages = parser.diagnosticMessages(); + if (Q_UNLIKELY(!parserMessages.isEmpty())) { + ErrorInfo err; + foreach (const QbsQmlJS::DiagnosticMessage &msg, parserMessages) + err.append(msg.message, toCodeLocation(filePath, msg.loc)); + throw err; + } + } + + cacheValue.setCode(code); + cacheValue.setAst(parser.ast()); + } + + ItemReaderASTVisitor astVisitor(*this, itemPool, m_logger, searchPaths); + astVisitor.setFilePath(QFileInfo(filePath).absoluteFilePath()); + astVisitor.setSourceCode(cacheValue.code()); + cacheValue.setProcessingFlag(true); + cacheValue.ast()->accept(&astVisitor); + cacheValue.setProcessingFlag(false); + return astVisitor.rootItem(); +} + +void ItemReaderVisitorState::cacheDirectoryEntries(const QString &dirPath, const QStringList &entries) +{ + m_directoryEntries.insert(dirPath, entries); +} + +bool ItemReaderVisitorState::findDirectoryEntries(const QString &dirPath, QStringList *entries) const +{ + const auto it = m_directoryEntries.constFind(dirPath); + if (it == m_directoryEntries.constEnd()) + return false; + *entries = it.value(); + return true; +} + + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/language/itemreadervisitorstate.h b/src/lib/corelib/language/itemreadervisitorstate.h new file mode 100644 index 000000000..6f6934f3a --- /dev/null +++ b/src/lib/corelib/language/itemreadervisitorstate.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of the Qt Build Suite. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef QBS_ITEMREADERVISITORSTATE_H +#define QBS_ITEMREADERVISITORSTATE_H + +#include <logging/logger.h> + +#include <QSet> +#include <QStack> +#include <QStringList> + +namespace qbs { +namespace Internal { +class Item; +class ItemPool; + +class ItemReaderVisitorState +{ +public: + ItemReaderVisitorState(Logger logger); + ~ItemReaderVisitorState(); + + QSet<QString> filesRead() const { return m_filesRead; } + + Item *readFile(const QString &filePath, const QStringList &searchPaths, ItemPool *itemPool); + + void cacheDirectoryEntries(const QString &dirPath, const QStringList &entries); + bool findDirectoryEntries(const QString &dirPath, QStringList *entries) const; + +private: + Logger m_logger; + QSet<QString> m_filesRead; + QHash<QString, QStringList> m_directoryEntries; + + class ASTCache; + ASTCache * const m_astCache; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/corelib/language/jsimports.h b/src/lib/corelib/language/jsimports.h index cb90ae98d..0cbceeea2 100644 --- a/src/lib/corelib/language/jsimports.h +++ b/src/lib/corelib/language/jsimports.h @@ -32,8 +32,8 @@ #define QBS_JSIMPORTS_H #include <tools/codelocation.h> + #include <QHash> -#include <QSet> #include <QStringList> namespace qbs { diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index cde38d86c..18f7024f1 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -31,9 +31,12 @@ #include "language.h" #include "artifactproperties.h" +#include "propertymapinternal.h" #include "resolvedfilecontext.h" #include "scriptengine.h" + #include <buildgraph/artifact.h> +#include <buildgraph/artifactset.h> #include <buildgraph/productbuilddata.h> #include <buildgraph/projectbuilddata.h> #include <buildgraph/rulegraph.h> // TODO: Move to language? @@ -43,7 +46,7 @@ #include <tools/buildgraphlocker.h> #include <tools/hostosinfo.h> #include <tools/error.h> -#include <tools/propertyfinder.h> +#include <tools/fileinfo.h> #include <tools/persistence.h> #include <tools/qbsassert.h> diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index f93ef01e9..b86cba33d 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -34,22 +34,18 @@ #include "filetags.h" #include "forward_decls.h" #include "jsimports.h" -#include "propertymapinternal.h" -#include <buildgraph/artifactset.h> + #include <buildgraph/forward_decls.h> #include <tools/codelocation.h> -#include <tools/fileinfo.h> +#include <tools/filetime.h> #include <tools/persistentobject.h> -#include <tools/settings.h> #include <tools/weakpointer.h> -#include <QByteArray> #include <QDataStream> #include <QHash> #include <QMutex> #include <QProcessEnvironment> #include <QRegExp> -#include <QScriptProgram> #include <QScriptValue> #include <QScopedPointer> #include <QSet> diff --git a/src/lib/corelib/language/language.pri b/src/lib/corelib/language/language.pri index 7c984176f..68c8139d7 100644 --- a/src/lib/corelib/language/language.pri +++ b/src/lib/corelib/language/language.pri @@ -21,6 +21,7 @@ HEADERS += \ $$PWD/itempool.h \ $$PWD/itemreader.h \ $$PWD/itemreaderastvisitor.h \ + $$PWD/itemreadervisitorstate.h \ $$PWD/jsimports.h \ $$PWD/language.h \ $$PWD/loader.h \ @@ -53,6 +54,7 @@ SOURCES += \ $$PWD/itempool.cpp \ $$PWD/itemreader.cpp \ $$PWD/itemreaderastvisitor.cpp \ + $$PWD/itemreadervisitorstate.cpp \ $$PWD/language.cpp \ $$PWD/loader.cpp \ $$PWD/moduleloader.cpp \ diff --git a/src/lib/corelib/language/loader.cpp b/src/lib/corelib/language/loader.cpp index cb15c1ec8..7c2a0bf72 100644 --- a/src/lib/corelib/language/loader.cpp +++ b/src/lib/corelib/language/loader.cpp @@ -30,10 +30,11 @@ #include "loader.h" -#include "builtindeclarations.h" -#include "item.h" +#include "language.h" #include "moduleloader.h" #include "projectresolver.h" +#include "scriptengine.h" + #include <logging/translator.h> #include <tools/fileinfo.h> #include <tools/progressobserver.h> @@ -41,6 +42,7 @@ #include <tools/setupprojectparameters.h> #include <QDir> +#include <QObject> #include <QTimer> namespace qbs { @@ -49,25 +51,13 @@ namespace Internal { Loader::Loader(ScriptEngine *engine, const Logger &logger) : m_logger(logger) , m_progressObserver(0) - , m_builtins(new BuiltinDeclarations) - , m_moduleLoader(new ModuleLoader(engine, m_builtins, logger)) - , m_projectResolver(new ProjectResolver(m_moduleLoader, m_builtins, logger)) , m_engine(engine) { } -Loader::~Loader() -{ - delete m_projectResolver; - delete m_moduleLoader; - delete m_builtins; -} - void Loader::setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; - m_moduleLoader->setProgressObserver(observer); - m_projectResolver->setProgressObserver(observer); } void Loader::setSearchPaths(const QStringList &_searchPaths) @@ -82,7 +72,7 @@ void Loader::setSearchPaths(const QStringList &_searchPaths) } } - m_moduleLoader->setSearchPaths(searchPaths); + m_searchPaths = searchPaths; } TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) @@ -91,6 +81,8 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) m_engine->setEnvironment(parameters.adjustedEnvironment()); m_engine->clearExceptions(); + m_engine->clearImportsCache(); + m_engine->clearRequestedProperties(); QTimer cancelationTimer; @@ -103,13 +95,22 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) .arg(TopLevelProject::deriveId(parameters.topLevelProfile(), parameters.finalBuildConfigurationTree())), 1); cancelationTimer.setSingleShot(false); - QObject::connect(&cancelationTimer, SIGNAL(timeout()), SLOT(checkForCancelation())); + QObject::connect(&cancelationTimer, &QTimer::timeout, [this]() { + QBS_ASSERT(m_progressObserver, return); + if (m_progressObserver->canceled()) + m_engine->cancel(); + }); cancelationTimer.start(1000); } const FileTime resolveTime = FileTime::currentTime(); - ModuleLoaderResult loadResult = m_moduleLoader->load(parameters); - const TopLevelProjectPtr project = m_projectResolver->resolve(loadResult, parameters); + ModuleLoader moduleLoader(m_engine, m_logger); + moduleLoader.setProgressObserver(m_progressObserver); + moduleLoader.setSearchPaths(m_searchPaths); + ModuleLoaderResult loadResult = moduleLoader.load(parameters); + ProjectResolver resolver(&moduleLoader, m_logger); + resolver.setProgressObserver(m_progressObserver); + const TopLevelProjectPtr project = resolver.resolve(loadResult, parameters); project->lastResolveTime = resolveTime; // E.g. if the top-level project is disabled. @@ -119,12 +120,5 @@ TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) return project; } -void Loader::checkForCancelation() -{ - QBS_ASSERT(m_progressObserver, return); - if (m_progressObserver->canceled()) - m_engine->cancel(); -} - } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/loader.h b/src/lib/corelib/language/loader.h index 827f9113e..ee2e85c7a 100644 --- a/src/lib/corelib/language/loader.h +++ b/src/lib/corelib/language/loader.h @@ -33,41 +33,30 @@ #include "forward_decls.h" #include <logging/logger.h> -#include <QObject> #include <QStringList> namespace qbs { class Settings; class SetupProjectParameters; namespace Internal { -class BuiltinDeclarations; class Logger; -class ModuleLoader; class ProgressObserver; class ScriptEngine; -class ProjectResolver; -class Loader : public QObject +class Loader { - Q_OBJECT public: Loader(ScriptEngine *engine, const Logger &logger); - ~Loader(); void setProgressObserver(ProgressObserver *observer); void setSearchPaths(const QStringList &searchPaths); TopLevelProjectPtr loadProject(const SetupProjectParameters ¶meters); -private slots: - void checkForCancelation(); - private: Logger m_logger; ProgressObserver *m_progressObserver; - BuiltinDeclarations *m_builtins; - ModuleLoader *m_moduleLoader; - ProjectResolver *m_projectResolver; ScriptEngine * const m_engine; + QStringList m_searchPaths; }; } // namespace Internal diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 77340d179..367e186be 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -36,20 +36,20 @@ #include "filecontext.h" #include "item.h" #include "itemreader.h" +#include "qualifiedid.h" #include "scriptengine.h" #include "value.h" + #include <language/language.h> #include <language/scriptengine.h> #include <logging/logger.h> #include <logging/translator.h> #include <tools/error.h> #include <tools/fileinfo.h> -#include <tools/hostosinfo.h> #include <tools/preferences.h> #include <tools/profile.h> #include <tools/progressobserver.h> #include <tools/qbsassert.h> -#include <tools/qttools.h> #include <tools/scripttools.h> #include <tools/settings.h> @@ -65,13 +65,13 @@ class ModuleLoader::ItemModuleList : public QList<Item::Module> {}; const QString moduleSearchSubDir = QLatin1String("modules"); -ModuleLoader::ModuleLoader(ScriptEngine *engine, BuiltinDeclarations *builtins, +ModuleLoader::ModuleLoader(ScriptEngine *engine, const Logger &logger) : m_engine(engine) , m_pool(0) , m_logger(logger) , m_progressObserver(0) - , m_reader(new ItemReader(builtins, logger)) + , m_reader(new ItemReader(logger)) , m_evaluator(new Evaluator(engine, logger)) { } @@ -425,7 +425,7 @@ QList<Item *> ModuleLoader::multiplexProductItem(ProductContext *dummyContext, I } if (i == 0) continue; // We use the original item for the first profile. - Item * const cloned = productItem->clone(productItem->pool()); + Item * const cloned = productItem->clone(); cloned->setProperty(profileKey, VariantValue::create(profileNames.at(i))); additionalProductItems << cloned; } @@ -641,7 +641,7 @@ Item *ModuleLoader::mergeExportItems(ModuleLoader::ProductContext *productContex } productContext->item->setChildren(children); Item::addChild(productContext->item, merged); - m_reader->builtins()->setupItemForBuiltinType(merged, m_logger); + merged->setupForBuiltinType(m_logger); return merged; } @@ -1261,8 +1261,8 @@ void ModuleLoader::instantiateModule(ProductContext *productContext, Item *expor QBS_CHECK(instanceScope->file()); moduleScope->setFile(instanceScope->file()); moduleScope->setScope(instanceScope); - copyProperty(QLatin1String("project"), productContext->project->scope, moduleScope); - copyProperty(QLatin1String("product"), productContext->scope, moduleScope); + productContext->project->scope->copyProperty(QLatin1String("project"), moduleScope); + productContext->scope->copyProperty(QLatin1String("product"), moduleScope); if (isProduct) { exportingProduct = 0; @@ -1438,12 +1438,13 @@ bool ModuleLoader::checkItemCondition(Item *item) void ModuleLoader::checkItemTypes(Item *item) { if (Q_UNLIKELY(!item->typeName().isEmpty() - && !m_reader->builtins()->containsType(item->typeName()))) { + && !BuiltinDeclarations::instance().containsType(item->typeName()))) { const QString msg = Tr::tr("Unexpected item type '%1'."); throw ErrorInfo(msg.arg(item->typeName()), item->location()); } - const ItemDeclaration decl = m_reader->builtins()->declarationsForType(item->typeName()); + const ItemDeclaration decl + = BuiltinDeclarations::instance().declarationsForType(item->typeName()); foreach (Item *child, item->children()) { if (child->typeName().isEmpty()) continue; @@ -1477,8 +1478,8 @@ void ModuleLoader::copyProperties(const Item *sourceProject, Item *targetProject { if (!sourceProject) return; - const QList<PropertyDeclaration> &builtinProjectProperties - = m_reader->builtins()->declarationsForType(QLatin1String("Project")).properties(); + const QList<PropertyDeclaration> &builtinProjectProperties = BuiltinDeclarations::instance() + .declarationsForType(QLatin1String("Project")).properties(); QSet<QString> builtinProjectPropertyNames; foreach (const PropertyDeclaration &p, builtinProjectProperties) builtinProjectPropertyNames << p.name(); @@ -1496,7 +1497,7 @@ void ModuleLoader::copyProperties(const Item *sourceProject, Item *targetProject = targetProject->property(it.key()).dynamicCast<const JSSourceValue>(); QBS_ASSERT(v, continue); if (v->sourceCode() == QLatin1String("undefined")) - copyProperty(it.key(), sourceProject, targetProject); + sourceProject->copyProperty(it.key(), targetProject); continue; } @@ -1507,7 +1508,7 @@ void ModuleLoader::copyProperties(const Item *sourceProject, Item *targetProject continue; // Ignore stuff the target project already has. targetProject->setPropertyDeclaration(it.key(), it.value()); - copyProperty(it.key(), sourceProject, targetProject); + sourceProject->copyProperty(it.key(), targetProject); } } @@ -1519,7 +1520,7 @@ Item *ModuleLoader::wrapWithProject(Item *item) prj->setTypeName(QLatin1String("Project")); prj->setFile(item->file()); prj->setLocation(item->location()); - m_reader->builtins()->setupItemForBuiltinType(prj, m_logger); + prj->setupForBuiltinType(m_logger); return prj; } @@ -1535,12 +1536,6 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath, return dirPath; } -void ModuleLoader::copyProperty(const QString &propertyName, const Item *source, - Item *destination) -{ - destination->setProperty(propertyName, source->property(propertyName)); -} - void ModuleLoader::setScopeForDescendants(Item *item, Item *scope) { foreach (Item *child, item->children()) { diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h index 27fe83203..6adbc978f 100644 --- a/src/lib/corelib/language/moduleloader.h +++ b/src/lib/corelib/language/moduleloader.h @@ -33,7 +33,6 @@ #include "forward_decls.h" #include "itempool.h" -#include "qualifiedid.h" #include <logging/logger.h> #include <tools/setupprojectparameters.h> #include <tools/version.h> @@ -55,11 +54,11 @@ class CodeLocation; namespace Internal { -class BuiltinDeclarations; class Evaluator; class Item; class ItemReader; class ProgressObserver; +class QualifiedId; class ScriptEngine; struct ModuleLoaderResult @@ -99,7 +98,7 @@ struct ModuleLoaderResult class ModuleLoader { public: - ModuleLoader(ScriptEngine *engine, BuiltinDeclarations *builtins, const Logger &logger); + ModuleLoader(ScriptEngine *engine, const Logger &logger); ~ModuleLoader(); void setProgressObserver(ProgressObserver *progressObserver); @@ -156,7 +155,9 @@ private: struct ProductModuleInfo { - Item *exportItem = 0; + ProductModuleInfo() : exportItem() {} + + Item *exportItem; QList<ModuleLoaderResult::ProductInfo::Dependency> productDependencies; }; @@ -224,7 +225,6 @@ private: Item *wrapWithProject(Item *item); static QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName); - static void copyProperty(const QString &propertyName, const Item *source, Item *destination); static void setScopeForDescendants(Item *item, Item *scope); void overrideItemProperties(Item *item, const QString &buildConfigKey, const QVariantMap &buildConfig); diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp index 577f9098c..b32361b79 100644 --- a/src/lib/corelib/language/modulemerger.cpp +++ b/src/lib/corelib/language/modulemerger.cpp @@ -30,6 +30,8 @@ #include "modulemerger.h" +#include "value.h" + #include <logging/translator.h> #include <tools/qbsassert.h> @@ -199,9 +201,15 @@ void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QStr ValuePtr protoValue = moduleProto->property(propertyName); if (!protoValue) return; - ValuePtr cloned = protoValue->clone(); - cloned->setDefiningItem(moduleProto); - lastInNextChain(sv)->setNext(cloned); + Item * const clonedModulePrototype = moduleProto->clone(); + Item * const scope = Item::create(clonedModulePrototype->pool()); + scope->setFile(clonedModulePrototype->file()); + m_mergedModuleItem->scope()->copyProperty(QLatin1String("project"), scope); + m_mergedModuleItem->scope()->copyProperty(QLatin1String("product"), scope); + clonedModulePrototype->setScope(scope); + const ValuePtr clonedValue = protoValue->clone(); + clonedValue->setDefiningItem(clonedModulePrototype); + lastInNextChain(sv)->setNext(clonedValue); } ValuePtr ModuleMerger::lastInNextChain(const ValuePtr &v) diff --git a/src/lib/corelib/language/modulemerger.h b/src/lib/corelib/language/modulemerger.h index ae13b9143..3b417191b 100644 --- a/src/lib/corelib/language/modulemerger.h +++ b/src/lib/corelib/language/modulemerger.h @@ -32,11 +32,12 @@ #define QBS_MODULEMERGER_H #include "item.h" +#include "qualifiedid.h" + #include <logging/logger.h> #include <QHash> #include <QSet> -#include <QStringList> namespace qbs { namespace Internal { @@ -59,7 +60,7 @@ private: const Logger &m_logger; Item * const m_rootItem; Item *m_mergedModuleItem; - const QStringList m_moduleName; + const QualifiedId m_moduleName; QHash<ValuePtr, PropertyDeclaration> m_decls; QSet<const Item *> m_seenInstancesTopDown; QSet<const Item *> m_seenInstancesBottomUp; diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 6f80d4db0..5ab191fb6 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -31,15 +31,16 @@ #include "projectresolver.h" #include "artifactproperties.h" -#include "builtindeclarations.h" #include "evaluator.h" #include "filecontext.h" #include "item.h" -#include "moduleloader.h" +#include "language.h" #include "modulemerger.h" #include "propertymapinternal.h" #include "resolvedfilecontext.h" #include "scriptengine.h" +#include "value.h" + #include <jsextensions/moduleproperties.h> #include <logging/translator.h> #include <tools/error.h> @@ -49,10 +50,8 @@ #include <tools/qbsassert.h> #include <tools/qttools.h> -#include <QFileInfo> #include <QDir> #include <QQueue> -#include <QSet> #include <algorithm> #include <set> @@ -68,10 +67,9 @@ static const FileTag unknownFileTag() return tag; } -ProjectResolver::ProjectResolver(ModuleLoader *ldr, const BuiltinDeclarations *builtins, +ProjectResolver::ProjectResolver(ModuleLoader *ldr, const Logger &logger) : m_evaluator(ldr->evaluator()) - , m_builtins(builtins) , m_logger(logger) , m_engine(m_evaluator->engine()) , m_progressObserver(0) @@ -366,7 +364,7 @@ void ProjectResolver::resolveProduct(Item *item, ProjectContext *projectContext) fakeGroup->setProperty(QLatin1String("excludeFiles"), item->property(QLatin1String("excludeFiles"))); fakeGroup->setProperty(QLatin1String("overrideTags"), VariantValue::create(false)); - m_builtins->setupItemForBuiltinType(fakeGroup, m_logger); + fakeGroup->setupForBuiltinType(m_logger); subItems.prepend(fakeGroup); } diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h index 6787c459a..fc97422de 100644 --- a/src/lib/corelib/language/projectresolver.h +++ b/src/lib/corelib/language/projectresolver.h @@ -31,9 +31,7 @@ #ifndef PROJECTRESOLVER_H #define PROJECTRESOLVER_H -#include "evaluator.h" #include "filetags.h" -#include "language.h" #include "moduleloader.h" #include <logging/logger.h> @@ -45,10 +43,8 @@ namespace qbs { namespace Internal { -class BuiltinDeclarations; class Evaluator; class Item; -class ModuleLoader; class ProgressObserver; class ScriptEngine; class QualifiedIdSet; @@ -56,7 +52,7 @@ class QualifiedIdSet; class ProjectResolver { public: - ProjectResolver(ModuleLoader *ldr, const BuiltinDeclarations *builtins, const Logger &logger); + ProjectResolver(ModuleLoader *ldr, const Logger &logger); ~ProjectResolver(); void setProgressObserver(ProgressObserver *observer); @@ -153,7 +149,6 @@ private: const QList<SourceArtifactPtr> &artifacts); Evaluator *m_evaluator; - const BuiltinDeclarations *m_builtins; Logger m_logger; ScriptEngine *m_engine; ProgressObserver *m_progressObserver; diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp index c79aed4ab..8d5367ee8 100644 --- a/src/lib/corelib/language/propertydeclaration.cpp +++ b/src/lib/corelib/language/propertydeclaration.cpp @@ -32,7 +32,9 @@ #include "deprecationinfo.h" +#include <QScriptValue> #include <QSharedData> +#include <QStringList> namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/propertydeclaration.h b/src/lib/corelib/language/propertydeclaration.h index 8071b201a..f0e662a0c 100644 --- a/src/lib/corelib/language/propertydeclaration.h +++ b/src/lib/corelib/language/propertydeclaration.h @@ -32,9 +32,12 @@ #define QBS_PROPERTYDECLARATION_H #include <QSharedDataPointer> -#include <QString> -#include <QStringList> -#include <QScriptValue> + +QT_BEGIN_NAMESPACE +class QScriptValue; +class QString; +class QStringList; +QT_END_NAMESPACE namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/propertymapinternal.cpp b/src/lib/corelib/language/propertymapinternal.cpp index 91747cbac..577c7762f 100644 --- a/src/lib/corelib/language/propertymapinternal.cpp +++ b/src/lib/corelib/language/propertymapinternal.cpp @@ -80,7 +80,7 @@ static QString toJSLiteral_impl(const QVariantMap &vm, int level = 0) str += toJSLiteral_impl(it.value().toMap(), level + 1); str += indent + QLatin1String("}\n"); } else { - str += indent + it.key() + QLatin1String(": ") + qbs::toJSLiteral(it.value()) + str += indent + it.key() + QLatin1String(": ") + toJSLiteral(it.value()) + QLatin1Char('\n'); } } diff --git a/src/lib/corelib/language/resolvedfilecontext.h b/src/lib/corelib/language/resolvedfilecontext.h index b77f69042..b2c9d1741 100644 --- a/src/lib/corelib/language/resolvedfilecontext.h +++ b/src/lib/corelib/language/resolvedfilecontext.h @@ -33,7 +33,7 @@ #include "forward_decls.h" #include "filecontextbase.h" -#include "jsimports.h" + #include <tools/persistentobject.h> namespace qbs { diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index 5f2d62c96..e0816e712 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -32,9 +32,10 @@ #include "evaluatorscriptclass.h" #include "filecontextbase.h" -#include "item.h" +#include "jsimports.h" #include "propertymapinternal.h" #include "scriptpropertyobserver.h" + #include <buildgraph/artifact.h> #include <jsextensions/jsextensions.h> #include <tools/error.h> @@ -123,23 +124,20 @@ void ScriptEngine::import(const JsImport &jsImport, QScriptValue scope, QScriptV QBS_ASSERT(targetObject.engine() == this, return); if (debugJSImports) - m_logger.qbsDebug() << "[ENGINE] import into " << jsImport.scopeName; - - foreach (const QString &filePath, jsImport.filePaths) { - QScriptValue jsImportValue; - jsImportValue = m_jsImportCache.value(filePath); - if (jsImportValue.isValid()) { - if (debugJSImports) - m_logger.qbsDebug() << "[ENGINE] " << filePath << " (cache hit)"; - targetObject.setProperty(jsImport.scopeName, jsImportValue); - } else { - if (debugJSImports) - m_logger.qbsDebug() << "[ENGINE] " << filePath << " (cache miss)"; - jsImportValue = importFile(filePath, scope); - targetObject.setProperty(jsImport.scopeName, jsImportValue); - m_jsImportCache.insert(filePath, jsImportValue); - } + qDebug() << "[ENGINE] import into " << jsImport.scopeName; + + QScriptValue jsImportValue = m_jsImportCache.value(jsImport); + if (jsImportValue.isValid()) { + if (debugJSImports) + qDebug() << "[ENGINE] " << jsImport.filePaths << " (cache hit)"; + } else { + if (debugJSImports) + qDebug() << "[ENGINE] " << jsImport.filePaths << " (cache miss)"; + foreach (const QString &filePath, jsImport.filePaths) + importFile(filePath, scope, &jsImportValue); + m_jsImportCache.insert(jsImport, jsImportValue); } + targetObject.setProperty(jsImport.scopeName, jsImportValue); } void ScriptEngine::clearImportsCache() @@ -236,7 +234,8 @@ void ScriptEngine::setEnvironment(const QProcessEnvironment &env) m_environment = env; } -QScriptValue ScriptEngine::importFile(const QString &filePath, const QScriptValue &scope) +QScriptValue ScriptEngine::importFile(const QString &filePath, const QScriptValue &scope, + QScriptValue *targetObject) { QFile file(filePath); if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) @@ -244,11 +243,13 @@ QScriptValue ScriptEngine::importFile(const QString &filePath, const QScriptValu const QString sourceCode = QTextStream(&file).readAll(); file.close(); QScriptProgram program(sourceCode, filePath); - QScriptValue obj = newObject(); + QScriptValue obj; + if (!targetObject) + obj = newObject(); m_currentDirPathStack.push(FileInfo::path(filePath)); - importProgram(program, scope, obj); + importProgram(program, scope, targetObject ? *targetObject : obj); m_currentDirPathStack.pop(); - return obj; + return targetObject ? *targetObject : obj; } void ScriptEngine::importProgram(const QScriptProgram &program, const QScriptValue &scope, @@ -288,7 +289,7 @@ void ScriptEngine::importProgram(const QScriptProgram &program, const QScriptVal while (it.hasNext()) { it.next(); if (debugJSImports) - m_logger.qbsDebug() << "[ENGINE] Copying property " << it.name(); + qDebug() << "[ENGINE] Copying property " << it.name(); targetObject.setProperty(it.name(), it.value()); } } @@ -303,8 +304,8 @@ void ScriptEngine::importProgram(const QScriptProgram &program, const QScriptVal continue; if (debugJSImports) { - m_logger.qbsDebug() << "[ENGINE] inserting global property " - << it.name() << " " << it.value().toString(); + qDebug() << "[ENGINE] inserting global property " + << it.name() << " " << it.value().toString(); } targetObject.setProperty(it.name(), it.value()); @@ -452,14 +453,19 @@ void ScriptEngine::addDirectoryEntriesResult(const QString &path, QDir::Filters entries); } -void ScriptEngine::addFileLastModifiedResult(const QString &filePath, FileTime fileTime) +void ScriptEngine::addFileLastModifiedResult(const QString &filePath, const FileTime &fileTime) { m_fileLastModifiedResult.insert(filePath, fileTime); } QSet<QString> ScriptEngine::imports() const { - return QSet<QString>::fromList(m_jsImportCache.keys()); + QSet<QString> filePaths; + foreach (const JsImport &jsImport, m_jsImportCache.keys()) { + foreach (const QString &filePath, jsImport.filePaths) + filePaths << filePath; + } + return filePaths; } QScriptValueList ScriptEngine::argumentList(const QStringList &argumentNames, diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h index bf2b371d3..2cccc6dc7 100644 --- a/src/lib/corelib/language/scriptengine.h +++ b/src/lib/corelib/language/scriptengine.h @@ -32,7 +32,6 @@ #define QBS_SCRIPTENGINE_H #include "forward_decls.h" -#include "jsimports.h" #include "property.h" #include <logging/logger.h> #include <tools/filetime.h> @@ -48,7 +47,7 @@ namespace qbs { namespace Internal { class Artifact; - +class JsImport; class ScriptPropertyObserver; class ScriptEngine : public QScriptEngine @@ -99,7 +98,7 @@ public: void addFileExistsResult(const QString &filePath, bool exists); void addDirectoryEntriesResult(const QString &path, QDir::Filters filters, const QStringList &entries); - void addFileLastModifiedResult(const QString &filePath, FileTime fileTime); + void addFileLastModifiedResult(const QString &filePath, const FileTime &fileTime); QHash<QString, QString> canonicalFilePathResults() const { return m_canonicalFilePathResult; } QHash<QString, bool> fileExistsResults() const { return m_fileExistsResult; } QHash<QPair<QString, quint32>, QStringList> directoryEntriesResults() const @@ -133,7 +132,8 @@ private: void installQbsFunction(const QString &name, FunctionSignature f); void installImportFunctions(); void uninstallImportFunctions(); - QScriptValue importFile(const QString &filePath, const QScriptValue &scope); + QScriptValue importFile(const QString &filePath, const QScriptValue &scope, + QScriptValue *targetObject = nullptr); void importProgram(const QScriptProgram &program, const QScriptValue &scope, QScriptValue &targetObject); static QScriptValue js_loadExtension(QScriptContext *context, QScriptEngine *qtengine); @@ -157,7 +157,7 @@ private: friend bool operator==(const PropertyCacheKey &lhs, const PropertyCacheKey &rhs); friend uint qHash(const ScriptEngine::PropertyCacheKey &k, uint seed); - QHash<QString, QScriptValue> m_jsImportCache; + QHash<JsImport, QScriptValue> m_jsImportCache; bool m_propertyCacheEnabled; QHash<PropertyCacheKey, QVariant> m_propertyCache; PropertySet m_propertiesRequestedInScript; diff --git a/src/lib/corelib/language/scriptpropertyobserver.h b/src/lib/corelib/language/scriptpropertyobserver.h index 23077d4fb..93cc263a3 100644 --- a/src/lib/corelib/language/scriptpropertyobserver.h +++ b/src/lib/corelib/language/scriptpropertyobserver.h @@ -31,7 +31,12 @@ #ifndef QBS_SCRIPTPROPERTYOBSERVER_H #define QBS_SCRIPTPROPERTYOBSERVER_H -#include <QScriptValue> +#include <QtGlobal> + +QT_BEGIN_NAMESPACE +class QScriptValue; +class QString; +QT_END_NAMESPACE namespace qbs { namespace Internal { diff --git a/src/lib/corelib/language/testdata/import-collection/imports/Collection/file1.js b/src/lib/corelib/language/testdata/import-collection/imports/Collection/file1.js new file mode 100644 index 000000000..9f4785b2e --- /dev/null +++ b/src/lib/corelib/language/testdata/import-collection/imports/Collection/file1.js @@ -0,0 +1 @@ +function f1() { return "f1"; } diff --git a/src/lib/corelib/language/testdata/import-collection/imports/Collection/file2.js b/src/lib/corelib/language/testdata/import-collection/imports/Collection/file2.js new file mode 100644 index 000000000..887fd6fdb --- /dev/null +++ b/src/lib/corelib/language/testdata/import-collection/imports/Collection/file2.js @@ -0,0 +1 @@ +function f2() { return "f2"; } diff --git a/src/lib/corelib/language/testdata/import-collection/product.qbs b/src/lib/corelib/language/testdata/import-collection/product.qbs new file mode 100644 index 000000000..af240ddca --- /dev/null +++ b/src/lib/corelib/language/testdata/import-collection/product.qbs @@ -0,0 +1,6 @@ +import Collection + +Product { + name: "da product" + targetName: Collection.f1() + Collection.f2() +} diff --git a/src/lib/corelib/language/testdata/import-collection/project.qbs b/src/lib/corelib/language/testdata/import-collection/project.qbs new file mode 100644 index 000000000..ee34869b4 --- /dev/null +++ b/src/lib/corelib/language/testdata/import-collection/project.qbs @@ -0,0 +1,6 @@ +import qbs + +Project { + references: ["product.qbs"] +} + diff --git a/src/lib/corelib/language/testdata/moduleproperties.qbs b/src/lib/corelib/language/testdata/moduleproperties.qbs index 4777b7783..7b782751a 100644 --- a/src/lib/corelib/language/testdata/moduleproperties.qbs +++ b/src/lib/corelib/language/testdata/moduleproperties.qbs @@ -23,4 +23,11 @@ Project { Depends { name: "dummyqt"; submodules: ["gui", "network"] } Depends { name: "dummy" } } + + Product { + name: "list_property_that_references_product" + type: ["blubb"] + Depends { name: "dummy" } + dummy.listProp: ["x"] + } } diff --git a/src/lib/corelib/language/testdata/modules/dummy/dummy.qbs b/src/lib/corelib/language/testdata/modules/dummy/dummy.qbs index a04c7c463..9fdd73459 100644 --- a/src/lib/corelib/language/testdata/modules/dummy/dummy.qbs +++ b/src/lib/corelib/language/testdata/modules/dummy/dummy.qbs @@ -11,4 +11,5 @@ DummyBase { property string upperCaseProductName: productName.toUpperCase() property string zort: "zort in dummy" property pathList includePaths + property stringList listProp: product.type.contains("blubb") ? ["123"] : ["456"] } diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp index c73b26665..d07af317a 100644 --- a/src/lib/corelib/language/tst_language.cpp +++ b/src/lib/corelib/language/tst_language.cpp @@ -33,18 +33,23 @@ #include "tst_language.h" #include <language/evaluator.h> +#include <language/filecontext.h> #include <language/identifiersearch.h> #include <language/item.h> #include <language/itempool.h> #include <language/language.h> +#include <language/propertymapinternal.h> #include <language/scriptengine.h> +#include <language/value.h> #include <parser/qmljslexer_p.h> #include <parser/qmljsparser_p.h> #include <tools/scripttools.h> #include <tools/error.h> +#include <tools/fileinfo.h> #include <tools/hostosinfo.h> #include <tools/profile.h> #include <tools/propertyfinder.h> +#include <tools/settings.h> #include <QProcessEnvironment> @@ -800,6 +805,24 @@ void TestLanguage::idUsage() QVERIFY(!exceptionCaught); } +void TestLanguage::importCollection() +{ + bool exceptionCaught = false; + try { + defaultParameters.setProjectFilePath(testProject("import-collection/project.qbs")); + const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + QVERIFY(project); + QHash<QString, ResolvedProductPtr> products = productsFromProject(project); + const ResolvedProductConstPtr product = products.value("da product"); + QCOMPARE(product->productProperties.value("targetName").toString(), QLatin1String("f1f2")); + } + catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QVERIFY(!exceptionCaught); +} + void TestLanguage::invalidBindingInDisabledItem() { bool exceptionCaught = false; @@ -951,6 +974,9 @@ void TestLanguage::moduleProperties_data() QTest::newRow("merge_lists_with_prototype_values") << "rpaths" << (QStringList() << "/opt/qt/lib" << "$ORIGIN"); + QTest::newRow("list_property_that_references_product") + << "listProp" + << (QStringList() << "x" << "123"); QTest::newRow("cleanup") << QString() << QStringList(); } diff --git a/src/lib/corelib/language/tst_language.h b/src/lib/corelib/language/tst_language.h index a3c2838e3..624f5428b 100644 --- a/src/lib/corelib/language/tst_language.h +++ b/src/lib/corelib/language/tst_language.h @@ -70,7 +70,6 @@ private slots: void buildConfigStringListSyntax(); void builtinFunctionInSearchPathsProperty(); void canonicalArchitecture(); - void rfc1034Identifier(); void conditionalDepends(); void dependencyOnAllProfiles(); void environmentVariable(); @@ -78,14 +77,17 @@ private slots: void erroneousFiles(); void exports(); void fileContextProperties(); - void getNativeSetting(); + void fileTags_data(); + void fileTags(); void groupConditions_data(); void groupConditions(); void groupName(); + void getNativeSetting(); void homeDirectory(); void identifierSearch_data(); void identifierSearch(); void idUsage(); + void importCollection(); void invalidBindingInDisabledItem(); void itemPrototype(); void itemScope(); @@ -99,15 +101,14 @@ private slots: void modules(); void outerInGroup(); void pathProperties(); - void profileValuesAndOverriddenValues(); void productConditions(); void productDirectories(); + void profileValuesAndOverriddenValues(); void propertiesBlocks_data(); void propertiesBlocks(); void qualifiedId(); void recursiveProductDependencies(); - void fileTags_data(); - void fileTags(); + void rfc1034Identifier(); void wildcards_data(); void wildcards(); }; diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp index 141e1759d..fae97d0da 100644 --- a/src/lib/corelib/language/value.cpp +++ b/src/lib/corelib/language/value.cpp @@ -29,6 +29,8 @@ ****************************************************************************/ #include "value.h" + +#include "filecontext.h" #include "item.h" #include <tools/qbsassert.h> @@ -151,7 +153,7 @@ ItemValue::~ItemValue() ValuePtr ItemValue::clone() const { - Item *clonedItem = m_item ? m_item->clone(m_item->pool()) : 0; + Item *clonedItem = m_item ? m_item->clone() : 0; return ItemValuePtr(new ItemValue(clonedItem)); } diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h index 2dcc7ff17..8f17f0be9 100644 --- a/src/lib/corelib/language/value.h +++ b/src/lib/corelib/language/value.h @@ -31,14 +31,13 @@ #ifndef QBS_VALUE_H #define QBS_VALUE_H -#include "filecontext.h" -#include "item.h" +#include "forward_decls.h" #include <tools/codelocation.h> #include <QVariant> namespace qbs { namespace Internal { - +class Item; class ValueHandler; class Value @@ -150,7 +149,6 @@ private: Item *m_exportScope; }; -class Item; class ItemValue : public Value { diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp index 178dfba3e..6763ac147 100644 --- a/src/lib/corelib/tools/fileinfo.cpp +++ b/src/lib/corelib/tools/fileinfo.cpp @@ -193,6 +193,12 @@ QString FileInfo::resolvePath(const QString &base, const QString &rel) if (idx >= 0) r.truncate(idx); } + if (s == QLatin1String("..")) { + int idx = r.lastIndexOf(QLatin1Char('/')); + if (idx >= 0) + r.truncate(idx); + return r; + } r.reserve(r.length() + 1 + s.length()); r += QLatin1Char('/'); diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h index fc27853c4..12571c7e7 100644 --- a/src/lib/corelib/tools/hostosinfo.h +++ b/src/lib/corelib/tools/hostosinfo.h @@ -32,9 +32,11 @@ #define QBS_HOSTOSINFO_H #include "qbs_export.h" +#include "version.h" #include <QtGlobal> #include <QMap> +#include <QSettings> #include <QString> #include <QStringList> @@ -63,6 +65,25 @@ public: static inline HostOs hostOs(); + static inline Version hostOsVersion() { + Version v; + if (HostOsInfo::isWindowsHost()) { + QSettings settings(QString::fromLatin1("HKEY_LOCAL_MACHINE\\Software\\" + "Microsoft\\Windows NT\\CurrentVersion"), + QSettings::NativeFormat); + v = v.fromString(settings.value(QStringLiteral("CurrentVersion")).toString() + + QLatin1Char('.') + + settings.value(QStringLiteral("CurrentBuildNumber")).toString()); + Q_ASSERT(v.isValid()); + } else if (HostOsInfo::isOsxHost()) { + QSettings settings(QStringLiteral("/System/Library/CoreServices/SystemVersion.plist"), + QSettings::NativeFormat); + v = v.fromString(settings.value(QStringLiteral("ProductVersion")).toString()); + Q_ASSERT(v.isValid()); + } + return v; + } + static bool isWindowsHost() { return hostOs() == HostOsWindows; } static bool isLinuxHost() { return hostOs() == HostOsLinux; } static bool isOsxHost() { return hostOs() == HostOsOsx; } diff --git a/src/lib/corelib/tools/tst_tools.h b/src/lib/corelib/tools/tst_tools.h index b984639da..d9e4e8fc2 100644 --- a/src/lib/corelib/tools/tst_tools.h +++ b/src/lib/corelib/tools/tst_tools.h @@ -44,11 +44,11 @@ public: TestTools(Settings *settings); private slots: - void testFileInfo(); void fileCaseCheck(); - void testProfiles(); void testBuildConfigMerging(); + void testFileInfo(); void testProcessNameByPid(); + void testProfiles(); private: Settings * const m_settings; |