diff options
Diffstat (limited to 'src/lib')
157 files changed, 1768 insertions, 1321 deletions
diff --git a/src/lib/corelib/api/changeset.cpp b/src/lib/corelib/api/changeset.cpp index 5d375fd65..773af328d 100644 --- a/src/lib/corelib/api/changeset.cpp +++ b/src/lib/corelib/api/changeset.cpp @@ -48,8 +48,8 @@ ChangeSet::ChangeSet() { } -ChangeSet::ChangeSet(const QList<EditOp> &operations) - : m_string(nullptr), m_cursor(nullptr), m_operationList(operations), m_error(false) +ChangeSet::ChangeSet(QList<EditOp> operations) + : m_string(nullptr), m_cursor(nullptr), m_operationList(std::move(operations)), m_error(false) { } @@ -393,5 +393,5 @@ void ChangeSet::apply_helper() m_cursor->endEditBlock(); } -} // namespace Internal { +} // namespace QbsQmlJS diff --git a/src/lib/corelib/api/changeset.h b/src/lib/corelib/api/changeset.h index 13d3908d4..23248c48e 100644 --- a/src/lib/corelib/api/changeset.h +++ b/src/lib/corelib/api/changeset.h @@ -86,7 +86,7 @@ public: public: ChangeSet(); - ChangeSet(const QList<EditOp> &operations); + ChangeSet(QList<EditOp> operations); bool empty() const; diff --git a/src/lib/corelib/api/internaljobs.cpp b/src/lib/corelib/api/internaljobs.cpp index c74c3d8a4..c53cf3e33 100644 --- a/src/lib/corelib/api/internaljobs.cpp +++ b/src/lib/corelib/api/internaljobs.cpp @@ -225,9 +225,7 @@ InternalSetupProjectJob::InternalSetupProjectJob(const Logger &logger) { } -InternalSetupProjectJob::~InternalSetupProjectJob() -{ -} +InternalSetupProjectJob::~InternalSetupProjectJob() = default; void InternalSetupProjectJob::init(const TopLevelProjectPtr &existingProject, const SetupProjectParameters ¶meters) @@ -350,12 +348,10 @@ BuildGraphTouchingJob::BuildGraphTouchingJob(const Logger &logger, QObject *pare { } -BuildGraphTouchingJob::~BuildGraphTouchingJob() -{ -} +BuildGraphTouchingJob::~BuildGraphTouchingJob() = default; void BuildGraphTouchingJob::setup(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, bool dryRun) + const QVector<ResolvedProductPtr> &products, bool dryRun) { m_project = project; m_products = products; @@ -374,14 +370,14 @@ InternalBuildJob::InternalBuildJob(const Logger &logger, QObject *parent) } void InternalBuildJob::build(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const BuildOptions &buildOptions) + const QVector<ResolvedProductPtr> &products, const BuildOptions &buildOptions) { setup(project, products, buildOptions.dryRun()); setTimed(buildOptions.logElapsedTime()); m_executor = new Executor(logger()); m_executor->setProject(project); - m_executor->setProducts(std::vector<ResolvedProductPtr>(products.cbegin(), products.cend())); + m_executor->setProducts(products); m_executor->setBuildOptions(buildOptions); m_executor->setProgressObserver(observer()); @@ -418,7 +414,8 @@ InternalCleanJob::InternalCleanJob(const Logger &logger, QObject *parent) } void InternalCleanJob::init(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const CleanOptions &options) + const QVector<ResolvedProductPtr> &products, + const CleanOptions &options) { setup(project, products, options.dryRun()); setTimed(options.logElapsedTime()); @@ -443,12 +440,10 @@ InternalInstallJob::InternalInstallJob(const Logger &logger) { } -InternalInstallJob::~InternalInstallJob() -{ -} +InternalInstallJob::~InternalInstallJob() = default; void InternalInstallJob::init(const TopLevelProjectPtr &project, - const std::vector<ResolvedProductPtr> &products, const InstallOptions &options) + const QVector<ResolvedProductPtr> &products, const InstallOptions &options) { m_project = project; m_products = products; diff --git a/src/lib/corelib/api/internaljobs.h b/src/lib/corelib/api/internaljobs.h index 58127eb05..d66835941 100644 --- a/src/lib/corelib/api/internaljobs.h +++ b/src/lib/corelib/api/internaljobs.h @@ -151,7 +151,7 @@ class BuildGraphTouchingJob : public InternalJob { Q_OBJECT public: - const QList<ResolvedProductPtr> &products() const { return m_products; } + const QVector<ResolvedProductPtr> &products() const { return m_products; } const TopLevelProjectPtr &project() const { return m_project; } signals: @@ -162,13 +162,13 @@ protected: BuildGraphTouchingJob(const Logger &logger, QObject *parent = nullptr); ~BuildGraphTouchingJob() override; - void setup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void setup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, bool dryRun); void storeBuildGraph(); private: TopLevelProjectPtr m_project; - QList<ResolvedProductPtr> m_products; + QVector<ResolvedProductPtr> m_products; bool m_dryRun; }; @@ -179,7 +179,7 @@ class InternalBuildJob : public BuildGraphTouchingJob public: InternalBuildJob(const Logger &logger, QObject *parent = nullptr); - void build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const BuildOptions &buildOptions); private: @@ -196,8 +196,8 @@ class InternalCleanJob : public BuildGraphTouchingJob public: InternalCleanJob(const Logger &logger, QObject *parent = nullptr); - void init(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, - const CleanOptions &options); + void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, + const CleanOptions &options); private: void start() override; @@ -213,14 +213,14 @@ public: InternalInstallJob(const Logger &logger); ~InternalInstallJob() override; - void init(const TopLevelProjectPtr &project, const std::vector<ResolvedProductPtr> &products, + void init(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const InstallOptions &options); private: void start() override; TopLevelProjectPtr m_project; - std::vector<ResolvedProductPtr> m_products; + QVector<ResolvedProductPtr> m_products; InstallOptions m_options; }; diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp index 32b7accc7..7a845b0ac 100644 --- a/src/lib/corelib/api/jobs.cpp +++ b/src/lib/corelib/api/jobs.cpp @@ -309,7 +309,7 @@ BuildJob::BuildJob(const Logger &logger, QObject *parent) this, &BuildJob::reportProcessResult); } -void BuildJob::build(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, +void BuildJob::build(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const BuildOptions &options) { if (!lockProject(project)) @@ -340,7 +340,7 @@ CleanJob::CleanJob(const Logger &logger, QObject *parent) { } -void CleanJob::clean(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, +void CleanJob::clean(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const qbs::CleanOptions &options) { if (!lockProject(project)) @@ -361,15 +361,14 @@ InstallJob::InstallJob(const Logger &logger, QObject *parent) } void InstallJob::install(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const InstallOptions &options) + const QVector<ResolvedProductPtr> &products, + const InstallOptions &options) { if (!lockProject(project)) return; auto wrapper = qobject_cast<InternalJobThreadWrapper *>(internalJob()); auto installJob = qobject_cast<InternalInstallJob *>(wrapper->synchronousJob()); - installJob->init(project, - std::vector<ResolvedProductPtr>(products.cbegin(), products.cend()), - options); + installJob->init(project, products, options); wrapper->start(); } diff --git a/src/lib/corelib/api/jobs.h b/src/lib/corelib/api/jobs.h index 36c6b7a80..64929489e 100644 --- a/src/lib/corelib/api/jobs.h +++ b/src/lib/corelib/api/jobs.h @@ -136,7 +136,7 @@ private: BuildJob(const Internal::Logger &logger, QObject *parent); void build(const Internal::TopLevelProjectPtr &project, - const QList<qbs::Internal::ResolvedProductPtr> &products, + const QVector<Internal::ResolvedProductPtr> &products, const BuildOptions &options); void handleLauncherError(const ErrorInfo &error); @@ -153,7 +153,7 @@ private: CleanJob(const Internal::Logger &logger, QObject *parent); void clean(const Internal::TopLevelProjectPtr &project, - const QList<Internal::ResolvedProductPtr> &products, const CleanOptions &options); + const QVector<Internal::ResolvedProductPtr> &products, const CleanOptions &options); }; class QBS_EXPORT InstallJob : public AbstractJob @@ -164,7 +164,8 @@ private: InstallJob(const Internal::Logger &logger, QObject *parent); void install(const Internal::TopLevelProjectPtr &project, - const QList<Internal::ResolvedProductPtr> &products, const InstallOptions &options); + const QVector<Internal::ResolvedProductPtr> &products, + const InstallOptions &options); }; } // namespace qbs diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index d0fe7296e..2b07f1a8d 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -131,7 +131,7 @@ ProjectData ProjectPrivate::projectData() return m_projectData; } -static void addDependencies(QList<ResolvedProductPtr> &products) +static void addDependencies(QVector<ResolvedProductPtr> &products) { for (int i = 0; i < products.size(); ++i) { const ResolvedProductPtr &product = products.at(i); @@ -142,11 +142,11 @@ static void addDependencies(QList<ResolvedProductPtr> &products) } } -BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &products, +BuildJob *ProjectPrivate::buildProducts(const QVector<ResolvedProductPtr> &products, const BuildOptions &options, bool needsDepencencyResolving, QObject *jobOwner) { - QList<ResolvedProductPtr> productsToBuild = products; + QVector<ResolvedProductPtr> productsToBuild = products; if (needsDepencencyResolving) addDependencies(productsToBuild); @@ -156,7 +156,7 @@ BuildJob *ProjectPrivate::buildProducts(const QList<ResolvedProductPtr> &product return job; } -CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &products, +CleanJob *ProjectPrivate::cleanProducts(const QVector<ResolvedProductPtr> &products, const CleanOptions &options, QObject *jobOwner) { const auto job = new CleanJob(logger, jobOwner); @@ -165,10 +165,10 @@ CleanJob *ProjectPrivate::cleanProducts(const QList<ResolvedProductPtr> &product return job; } -InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &products, +InstallJob *ProjectPrivate::installProducts(const QVector<ResolvedProductPtr> &products, const InstallOptions &options, bool needsDepencencyResolving, QObject *jobOwner) { - QList<ResolvedProductPtr> productsToInstall = products; + QVector<ResolvedProductPtr> productsToInstall = products; if (needsDepencencyResolving) addDependencies(productsToInstall); const auto job = new InstallJob(logger, jobOwner); @@ -177,9 +177,9 @@ InstallJob *ProjectPrivate::installProducts(const QList<ResolvedProductPtr> &pro return job; } -QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const +QVector<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductData> &products) const { - QList<ResolvedProductPtr> internalProducts; + QVector<ResolvedProductPtr> internalProducts; for (const ProductData &product : products) { if (product.isEnabled()) internalProducts.push_back(internalProduct(product)); @@ -187,20 +187,21 @@ QList<ResolvedProductPtr> ProjectPrivate::internalProducts(const QList<ProductDa return internalProducts; } -static QList<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project, +static QVector<ResolvedProductPtr> enabledInternalProducts(const ResolvedProjectConstPtr &project, bool includingNonDefault) { - QList<ResolvedProductPtr> products; + QVector<ResolvedProductPtr> products; for (const ResolvedProductPtr &p : project->products) { if (p->enabled && (includingNonDefault || p->builtByDefault())) products.push_back(p); } - for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) + for (const auto &subProject : qAsConst(project->subProjects)) products << enabledInternalProducts(subProject, includingNonDefault); return products; } -QList<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts(bool includingNonDefault) const +QVector<ResolvedProductPtr> ProjectPrivate::allEnabledInternalProducts( + bool includingNonDefault) const { return enabledInternalProducts(internalProject, includingNonDefault); } @@ -218,7 +219,7 @@ static ResolvedProductPtr internalProductForProject(const ResolvedProjectConstPt if (matches(product, resolvedProduct)) return resolvedProduct; } - for (const ResolvedProjectConstPtr &subProject : qAsConst(project->subProjects)) { + for (const auto &subProject : qAsConst(project->subProjects)) { const ResolvedProductPtr &p = internalProductForProject(subProject, product); if (p) return p; @@ -272,13 +273,13 @@ GroupData ProjectPrivate::createGroupDataFromGroup(const GroupPtr &resolvedGroup group.d->name = resolvedGroup->name; group.d->prefix = resolvedGroup->prefix; group.d->location = resolvedGroup->location; - for (const SourceArtifactConstPtr &sa : resolvedGroup->files) { + for (const auto &sa : resolvedGroup->files) { ArtifactData artifact = createApiSourceArtifact(sa); setupInstallData(artifact, product); group.d->sourceArtifacts.push_back(artifact); } if (resolvedGroup->wildcards) { - for (const SourceArtifactConstPtr &sa : resolvedGroup->wildcards->files) { + for (const auto &sa : resolvedGroup->wildcards->files) { ArtifactData artifact = createApiSourceArtifact(sa); setupInstallData(artifact, product); group.d->sourceArtifactsFromWildcards.push_back(artifact); @@ -355,7 +356,7 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa QList<ProductData> products = findProductsByName(product.name()); if (products.empty()) throw ErrorInfo(Tr::tr("Product '%1' does not exist.").arg(product.name())); - const QList<ResolvedProductPtr> resolvedProducts = internalProducts(products); + const auto resolvedProducts = internalProducts(products); QBS_CHECK(products.size() == resolvedProducts.size()); for (const GroupPtr &resolvedGroup : resolvedProducts.front()->groups) { @@ -367,28 +368,6 @@ void ProjectPrivate::addGroup(const ProductData &product, const QString &groupNa ProjectFileGroupInserter groupInserter(products.front(), groupName); groupInserter.apply(); - - m_projectData.d.detach(); // The data we already gave out must stay as it is. - - updateInternalCodeLocations(internalProject, groupInserter.itemPosition(), - groupInserter.lineOffset()); - updateExternalCodeLocations(m_projectData, groupInserter.itemPosition(), - groupInserter.lineOffset()); - - products = findProductsByName(products.front().name()); // These are new objects. - QBS_CHECK(products.size() == resolvedProducts.size()); - for (int i = 0; i < products.size(); ++i) { - const GroupPtr resolvedGroup = ResolvedGroup::create(); - resolvedGroup->location = groupInserter.itemPosition(); - resolvedGroup->enabled = true; - resolvedGroup->name = groupName; - resolvedGroup->properties = resolvedProducts[i]->moduleProperties; - resolvedGroup->overrideTags = false; - resolvedProducts.at(i)->groups << resolvedGroup; - QList<GroupData> &groupData = products.at(i).d->groups; - groupData << createGroupDataFromGroup(resolvedGroup, resolvedProducts.at(i)); - std::sort(groupData.begin(), groupData.end()); - } } ProjectPrivate::GroupUpdateContext ProjectPrivate::getGroupContext(const ProductData &product, @@ -484,15 +463,6 @@ ProjectPrivate::FileListUpdateContext ProjectPrivate::getFileListContext(const P return filesContext; } -static SourceArtifactPtr createSourceArtifact(const QString &filePath, - const ResolvedProductPtr &product, const GroupPtr &group, bool wildcard) -{ - const SourceArtifactPtr artifact - = ProjectResolver::createSourceArtifact(product, filePath, group, wildcard); - ProjectResolver::applyFileTaggers(artifact, product); - return artifact; -} - void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths) { @@ -503,7 +473,7 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group // due to conditions. for (const GroupPtr &group : qAsConst(groupContext.resolvedGroups)) { for (const QString &filePath : qAsConst(filesContext.absoluteFilePaths)) { - for (const SourceArtifactConstPtr &sa : group->files) { + for (const auto &sa : group->files) { if (sa->absoluteFilePath == filePath) { throw ErrorInfo(Tr::tr("File '%1' already exists in group '%2'.") .arg(filePath, group->name)); @@ -516,57 +486,6 @@ void ProjectPrivate::addFiles(const ProductData &product, const GroupData &group group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); adder.apply(); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, adder.itemPosition(), adder.lineOffset()); - updateExternalCodeLocations(m_projectData, adder.itemPosition(), adder.lineOffset()); - - QHash<QString, std::pair<SourceArtifactPtr, ResolvedProductPtr>> addedSourceArtifacts; - for (int i = 0; i < groupContext.resolvedGroups.size(); ++i) { - const ResolvedProductPtr &resolvedProduct = groupContext.resolvedProducts.at(i); - const GroupPtr &resolvedGroup = groupContext.resolvedGroups.at(i); - for (const QString &file : qAsConst(filesContext.absoluteFilePaths)) { - const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup, - false); - addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct)); - } - for (const QString &file : qAsConst(filesContext.absoluteFilePathsFromWildcards)) { - QBS_CHECK(resolvedGroup->wildcards); - const SourceArtifactPtr sa = createSourceArtifact(file, resolvedProduct, resolvedGroup, - true); - addedSourceArtifacts.insert(file, std::make_pair(sa, resolvedProduct)); - } - if (resolvedProduct->enabled) { - for (const auto &pair : qAsConst(addedSourceArtifacts)) - createArtifact(resolvedProduct, pair.first); - } - } - doSanityChecks(internalProject, logger); - QList<ArtifactData> sourceArtifacts; - QList<ArtifactData> sourceArtifactsFromWildcards; - for (const QString &fp : qAsConst(filesContext.absoluteFilePaths)) { - const auto pair = addedSourceArtifacts.value(fp); - const SourceArtifactConstPtr sa = pair.first; - QBS_CHECK(sa); - ArtifactData artifactData = createApiSourceArtifact(sa); - setupInstallData(artifactData, pair.second); - sourceArtifacts << artifactData; - } - for (const QString &fp : qAsConst(filesContext.absoluteFilePathsFromWildcards)) { - const auto pair = addedSourceArtifacts.value(fp); - const SourceArtifactConstPtr sa = pair.first; - QBS_CHECK(sa); - ArtifactData artifactData = createApiSourceArtifact(sa); - setupInstallData(artifactData, pair.second); - sourceArtifactsFromWildcards << artifactData; - } - for (const GroupData &g : qAsConst(groupContext.groups)) { - g.d->sourceArtifacts << sourceArtifacts; - std::sort(g.d->sourceArtifacts.begin(), g.d->sourceArtifacts.end()); - g.d->sourceArtifactsFromWildcards << sourceArtifactsFromWildcards; - std::sort(g.d->sourceArtifactsFromWildcards.begin(), - g.d->sourceArtifactsFromWildcards.end()); - } } void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &group, @@ -595,134 +514,17 @@ void ProjectPrivate::removeFiles(const ProductData &product, const GroupData &gr group.isValid() ? groupContext.groups.front() : GroupData(), filesContext.relativeFilePaths); remover.apply(); - - for (int i = 0; i < groupContext.resolvedProducts.size(); ++i) { - removeFilesFromBuildGraph(groupContext.resolvedProducts.at(i), sourceArtifacts); - for (const SourceArtifactPtr &sa : sourceArtifacts) - removeOne(groupContext.resolvedGroups.at(i)->files, sa); - } - doSanityChecks(internalProject, logger); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset()); - updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset()); - for (const GroupData &g : qAsConst(groupContext.groups)) { - for (int i = g.d->sourceArtifacts.size() - 1; i >= 0; --i) { - if (filesContext.absoluteFilePaths.contains(g.d->sourceArtifacts.at(i).filePath())) - g.d->sourceArtifacts.removeAt(i); - } - } } void ProjectPrivate::removeGroup(const ProductData &product, const GroupData &group) { GroupUpdateContext context = getGroupContext(product, group); - ProjectFileGroupRemover remover(context.products.front(), context.groups.front()); remover.apply(); - for (int i = 0; i < context.resolvedProducts.size(); ++i) { - const ResolvedProductPtr &product = context.resolvedProducts.at(i); - const GroupPtr &group = context.resolvedGroups.at(i); - removeFilesFromBuildGraph(product, group->allFiles()); - const bool removed = removeOne(product->groups, group); - QBS_CHECK(removed); - } - doSanityChecks(internalProject, logger); - - m_projectData.d.detach(); - updateInternalCodeLocations(internalProject, remover.itemPosition(), remover.lineOffset()); - updateExternalCodeLocations(m_projectData, remover.itemPosition(), remover.lineOffset()); - for (int i = 0; i < context.products.size(); ++i) { - const bool removed = context.products.at(i).d->groups.removeOne(context.groups.at(i)); - QBS_CHECK(removed); - } } #endif // QBS_ENABLE_PROJECT_FILE_UPDATES -void ProjectPrivate::removeFilesFromBuildGraph(const ResolvedProductConstPtr &product, - const std::vector<SourceArtifactPtr> &files) -{ - if (!product->enabled) - return; - QBS_CHECK(internalProject->buildData); - ArtifactSet allRemovedArtifacts; - for (const SourceArtifactPtr &sa : files) { - ArtifactSet removedArtifacts; - Artifact * const artifact = lookupArtifact(product, sa->absoluteFilePath); - if (artifact) { // Can be null if the executor has not yet applied the respective rule. - internalProject->buildData->removeArtifactAndExclusiveDependents(artifact, logger, - true, &removedArtifacts); - } - allRemovedArtifacts.unite(removedArtifacts); - } - EmptyDirectoriesRemover(product->topLevelProject(), logger) - .removeEmptyParentDirectories(allRemovedArtifacts); - qDeleteAll(allRemovedArtifacts); -} - -static void updateLocationIfNecessary(CodeLocation &location, const CodeLocation &changeLocation, - int lineOffset) -{ - if (location.filePath() == changeLocation.filePath() - && location.line() >= changeLocation.line()) { - location = CodeLocation(location.filePath(), location.line() + lineOffset, - location.column()); - } -} - -void ProjectPrivate::updateInternalCodeLocations(const ResolvedProjectPtr &project, - const CodeLocation &changeLocation, int lineOffset) -{ - if (lineOffset == 0) - return; - updateLocationIfNecessary(project->location, changeLocation, lineOffset); - for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects)) - updateInternalCodeLocations(subProject, changeLocation, lineOffset); - for (const ResolvedProductPtr &product : project->products) { - updateLocationIfNecessary(product->location, changeLocation, lineOffset); - for (const GroupPtr &group : product->groups) - updateLocationIfNecessary(group->location, changeLocation, lineOffset); - for (const RulePtr &rule : qAsConst(product->rules)) { - updateLocationIfNecessary(rule->prepareScript.location(), changeLocation, lineOffset); - for (const RuleArtifactPtr &artifact : rule->artifacts) { - for (auto &binding : artifact->bindings) { - updateLocationIfNecessary(binding.location, changeLocation, lineOffset); - } - } - } - for (const ResolvedScannerConstPtr &scanner : product->scanners) { - updateLocationIfNecessary(scanner->searchPathsScript.location(), changeLocation, - lineOffset); - updateLocationIfNecessary(scanner->scanScript.location(), changeLocation, lineOffset); - } - for (const ResolvedModuleConstPtr &module : product->modules) { - updateLocationIfNecessary(module->setupBuildEnvironmentScript.location(), - changeLocation, lineOffset); - updateLocationIfNecessary(module->setupRunEnvironmentScript.location(), - changeLocation, lineOffset); - } - } -} - -void ProjectPrivate::updateExternalCodeLocations(const ProjectData &project, - const CodeLocation &changeLocation, int lineOffset) -{ - if (lineOffset == 0) - return; - updateLocationIfNecessary(project.d->location, changeLocation, lineOffset); - const auto subProjects = project.subProjects(); - for (const ProjectData &subProject : subProjects) - updateExternalCodeLocations(subProject, changeLocation, lineOffset); - const auto products = project.products(); - for (const ProductData &product : products) { - updateLocationIfNecessary(product.d->location, changeLocation, lineOffset); - const auto groups = product.groups(); - for (const GroupData &group : groups) - updateLocationIfNecessary(group.d->location, changeLocation, lineOffset); - } -} - void ProjectPrivate::prepareChangeToProject() { if (internalProject->locked) @@ -851,7 +653,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData, projectData.d->name = internalProject->name; projectData.d->location = internalProject->location; projectData.d->enabled = internalProject->enabled; - for (const ResolvedProductConstPtr &resolvedProduct : internalProject->products) { + for (const auto &resolvedProduct : internalProject->products) { ProductData product; product.d->type = resolvedProduct->fileTags.toStringList(); product.d->name = resolvedProduct->name; @@ -904,8 +706,7 @@ void ProjectPrivate::retrieveProjectData(ProjectData &projectData, product.d->isValid = true; projectData.d->products << product; } - for (const ResolvedProjectConstPtr &internalSubProject - : qAsConst(internalProject->subProjects)) { + for (const auto &internalSubProject : qAsConst(internalProject->subProjects)) { if (!internalSubProject->enabled) continue; ProjectData subProject; @@ -931,13 +732,9 @@ Project::Project(const TopLevelProjectPtr &internalProject, const Logger &logger { } -Project::Project(const Project &other) : d(other.d) -{ -} +Project::Project(const Project &other) = default; -Project::~Project() -{ -} +Project::~Project() = default; /*! * \brief Returns true if and only if this object was retrieved from a successful \c SetupProjectJob. @@ -957,11 +754,7 @@ QString Project::profile() const return d->internalProject->profile(); } -Project &Project::operator=(const Project &other) -{ - d = other.d; - return *this; -} +Project &Project::operator=(const Project &other) = default; /*! * \brief Sets up a \c Project from a source file, possibly re-using previously stored information. @@ -996,10 +789,7 @@ SetupProjectJob *Project::setupProject(const SetupProjectParameters ¶meters, return job; } -Project::Project() -{ -} - +Project::Project() = default; /*! * \brief Retrieves information for this project. @@ -1227,9 +1017,9 @@ Project::BuildGraphInfo Project::getBuildGraphInfo(const QString &bgFilePath, for (const QString &prop : requestedProperties) { QStringList components = prop.split(QLatin1Char('.')); const QString propName = components.takeLast(); - props.push_back(std::make_pair(components.join(QLatin1Char('.')), propName)); + props.emplace_back(components.join(QLatin1Char('.')), propName); } - for (const ResolvedProductConstPtr &product : project->allProducts()) { + for (const auto &product : project->allProducts()) { if (props.empty()) break; if (product->profile() != project->profile()) @@ -1283,10 +1073,10 @@ ErrorInfo Project::addGroup(const ProductData &product, const QString &groupName QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addGroup(product, groupName); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding group '%1' to product '%2'.") .arg(groupName, product.name())); return errorInfo; @@ -1310,10 +1100,10 @@ ErrorInfo Project::addFiles(const ProductData &product, const GroupData &group, QBS_CHECK(isValid()); d->prepareChangeToProject(); d->addFiles(product, group, filePaths); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure adding files to product.")); return errorInfo; } @@ -1336,10 +1126,10 @@ ErrorInfo Project::removeFiles(const ProductData &product, const GroupData &grou QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeFiles(product, group, filePaths); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing files from product '%1'.").arg(product.name())); return errorInfo; } @@ -1357,10 +1147,10 @@ ErrorInfo Project::removeGroup(const ProductData &product, const GroupData &grou QBS_CHECK(isValid()); d->prepareChangeToProject(); d->removeGroup(product, group); - d->internalProject->lastStartResolveTime = FileTime::currentTime(); d->internalProject->store(d->logger); return {}; - } catch (ErrorInfo errorInfo) { + } catch (const ErrorInfo &exception) { + auto errorInfo = exception; errorInfo.prepend(Tr::tr("Failure removing group '%1' from product '%2'.") .arg(group.name(), product.name())); return errorInfo; diff --git a/src/lib/corelib/api/project_p.h b/src/lib/corelib/api/project_p.h index 58f61a5bc..60c8311f3 100644 --- a/src/lib/corelib/api/project_p.h +++ b/src/lib/corelib/api/project_p.h @@ -62,22 +62,22 @@ namespace Internal { class ProjectPrivate : public QSharedData { public: - ProjectPrivate(const TopLevelProjectPtr &internalProject, const Logger &logger) - : internalProject(internalProject), logger(logger) + ProjectPrivate(TopLevelProjectPtr internalProject, Logger logger) + : internalProject(std::move(internalProject)), logger(std::move(logger)) { } ProjectData projectData(); - BuildJob *buildProducts(const QList<ResolvedProductPtr> &products, const BuildOptions &options, + BuildJob *buildProducts(const QVector<ResolvedProductPtr> &products, const BuildOptions &options, bool needsDepencencyResolving, QObject *jobOwner); - CleanJob *cleanProducts(const QList<ResolvedProductPtr> &products, const CleanOptions &options, + CleanJob *cleanProducts(const QVector<ResolvedProductPtr> &products, const CleanOptions &options, QObject *jobOwner); - InstallJob *installProducts(const QList<ResolvedProductPtr> &products, + InstallJob *installProducts(const QVector<ResolvedProductPtr> &products, const InstallOptions &options, bool needsDepencencyResolving, QObject *jobOwner); - QList<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const; - QList<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const; + QVector<ResolvedProductPtr> internalProducts(const QList<ProductData> &products) const; + QVector<ResolvedProductPtr> allEnabledInternalProducts(bool includingNonDefault) const; ResolvedProductPtr internalProduct(const ProductData &product) const; ProductData findProductData(const ProductData &product) const; QList<ProductData> findProductsByName(const QString &name) const; @@ -92,7 +92,7 @@ public: void setupInstallData(ArtifactData &artifact, const ResolvedProductConstPtr &product); struct GroupUpdateContext { - QList<ResolvedProductPtr> resolvedProducts; + QVector<ResolvedProductPtr> resolvedProducts; QList<GroupPtr> resolvedGroups; QList<ProductData> products; QList<GroupData> groups; @@ -114,12 +114,7 @@ public: void removeFiles(const ProductData &product, const GroupData &group, const QStringList &filePaths); void removeGroup(const ProductData &product, const GroupData &group); - void removeFilesFromBuildGraph(const ResolvedProductConstPtr &product, - const std::vector<SourceArtifactPtr> &files); - void updateInternalCodeLocations(const ResolvedProjectPtr &project, - const CodeLocation &changeLocation, int lineOffset); - void updateExternalCodeLocations(const ProjectData &project, - const CodeLocation &changeLocation, int lineOffset); + void prepareChangeToProject(); RuleCommandList ruleCommandListForTransformer(const Transformer *transformer); diff --git a/src/lib/corelib/api/projectfileupdater.cpp b/src/lib/corelib/api/projectfileupdater.cpp index 04f8e630f..0bc5bc7c4 100644 --- a/src/lib/corelib/api/projectfileupdater.cpp +++ b/src/lib/corelib/api/projectfileupdater.cpp @@ -115,7 +115,7 @@ private: }; -ProjectFileUpdater::ProjectFileUpdater(const QString &projectFile) : m_projectFile(projectFile) +ProjectFileUpdater::ProjectFileUpdater(QString projectFile) : m_projectFile(std::move(projectFile)) { } @@ -201,11 +201,10 @@ void ProjectFileUpdater::apply() } -ProjectFileGroupInserter::ProjectFileGroupInserter(const ProductData &product, - const QString &groupName) +ProjectFileGroupInserter::ProjectFileGroupInserter(ProductData product, QString groupName) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_groupName(groupName) + , m_product(std::move(product)) + , m_groupName(std::move(groupName)) { } @@ -222,7 +221,7 @@ void ProjectFileGroupInserter::doApply(QString &fileContent, UiProgram *ast) Rewriter rewriter(fileContent, &changeSet, QStringList()); QString groupItemString; const int productItemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int groupItemIndentation = productItemIndentation + 4; const QString groupItemIndentationString = QString(groupItemIndentation, QLatin1Char(' ')); groupItemString += groupItemIndentationString + QLatin1String("Group {\n"); @@ -252,7 +251,7 @@ static QString getNodeRepresentation(const QString &fileContent, const QbsQmlJS: { const quint32 start = node->firstSourceLocation().offset; const quint32 end = node->lastSourceLocation().end(); - return fileContent.mid(start, end - start); + return fileContent.mid(start, int(end - start)); } static const ChangeSet::EditOp &getEditOp(const ChangeSet &changeSet) @@ -273,12 +272,12 @@ static int getBindingLine(const ChangeSet &changeSet, const QString &fileContent } -ProjectFileFilesAdder::ProjectFileFilesAdder(const ProductData &product, const GroupData &group, - const QStringList &files) +ProjectFileFilesAdder::ProjectFileFilesAdder(ProductData product, GroupData group, + QStringList files) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) - , m_files(files) + , m_product(std::move(product)) + , m_group(std::move(group)) + , m_files(std::move(files)) { } @@ -319,7 +318,7 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast) } const int itemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; @@ -405,12 +404,12 @@ void ProjectFileFilesAdder::doApply(QString &fileContent, UiProgram *ast) changeSet.apply(&fileContent); } -ProjectFileFilesRemover::ProjectFileFilesRemover(const ProductData &product, const GroupData &group, - const QStringList &files) +ProjectFileFilesRemover::ProjectFileFilesRemover(ProductData product, GroupData group, + QStringList files) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) - , m_files(files) + , m_product(std::move(product)) + , m_group(std::move(group)) + , m_files(std::move(files)) { } @@ -444,7 +443,7 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast) Rewriter rewriter(fileContent, &changeSet, QStringList()); const int itemIndentation - = itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1; + = int(itemFinder.item()->qualifiedTypeNameId->firstSourceLocation().startColumn - 1); const int bindingIndentation = itemIndentation + 4; const int arrayElemIndentation = bindingIndentation + 4; @@ -512,10 +511,10 @@ void ProjectFileFilesRemover::doApply(QString &fileContent, UiProgram *ast) } -ProjectFileGroupRemover::ProjectFileGroupRemover(const ProductData &product, const GroupData &group) +ProjectFileGroupRemover::ProjectFileGroupRemover(ProductData product, GroupData group) : ProjectFileUpdater(product.location().filePath()) - , m_product(product) - , m_group(group) + , m_product(std::move(product)) + , m_group(std::move(group)) { } diff --git a/src/lib/corelib/api/projectfileupdater.h b/src/lib/corelib/api/projectfileupdater.h index c0d46c747..3459d788e 100644 --- a/src/lib/corelib/api/projectfileupdater.h +++ b/src/lib/corelib/api/projectfileupdater.h @@ -61,7 +61,7 @@ public: int lineOffset() const { return m_lineOffset; } protected: - ProjectFileUpdater(const QString &projectFile); + ProjectFileUpdater(QString projectFile); QString projectFile() const { return m_projectFile; } @@ -92,7 +92,7 @@ private: class ProjectFileGroupInserter : public ProjectFileUpdater { public: - ProjectFileGroupInserter(const ProductData &product, const QString &groupName); + ProjectFileGroupInserter(ProductData product, QString groupName); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -105,8 +105,7 @@ private: class ProjectFileFilesAdder : public ProjectFileUpdater { public: - ProjectFileFilesAdder(const ProductData &product, const GroupData &group, - const QStringList &files); + ProjectFileFilesAdder(ProductData product, GroupData group, QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -119,8 +118,8 @@ private: class ProjectFileFilesRemover : public ProjectFileUpdater { public: - ProjectFileFilesRemover(const ProductData &product, const GroupData &group, - const QStringList &files); + ProjectFileFilesRemover(ProductData product, GroupData group, + QStringList files); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; @@ -133,7 +132,7 @@ private: class ProjectFileGroupRemover : public ProjectFileUpdater { public: - ProjectFileGroupRemover(const ProductData &product, const GroupData &group); + ProjectFileGroupRemover(ProductData product, GroupData group); private: void doApply(QString &fileContent, QbsQmlJS::AST::UiProgram *ast) override; diff --git a/src/lib/corelib/api/qmljsrewriter.cpp b/src/lib/corelib/api/qmljsrewriter.cpp index 16817d682..5551e5650 100644 --- a/src/lib/corelib/api/qmljsrewriter.cpp +++ b/src/lib/corelib/api/qmljsrewriter.cpp @@ -63,12 +63,12 @@ static QString toString(UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Cha } -Rewriter::Rewriter(const QString &originalText, +Rewriter::Rewriter(QString originalText, ChangeSet *changeSet, - const QStringList &propertyOrder) - : m_originalText(originalText) + QStringList propertyOrder) + : m_originalText(std::move(originalText)) , m_changeSet(changeSet) - , m_propertyOrder(propertyOrder) + , m_propertyOrder(std::move(propertyOrder)) { Q_ASSERT(changeSet); } @@ -260,7 +260,7 @@ UiObjectMemberList *Rewriter::searchMemberToInsertAfter(UiObjectMemberList *memb idx = propertyOrder.size() - 1; for (; idx > 0; --idx) { - const QString prop = propertyOrder.at(idx - 1); + const QString &prop = propertyOrder.at(idx - 1); UiObjectMemberList *candidate = orderedMembers.value(prop, 0); if (candidate != nullptr) return candidate; @@ -649,7 +649,7 @@ Rewriter::Range Rewriter::addObject(UiObjectInitializer *ast, const QString &con textToInsert += content; m_changeSet->insert(insertionPoint, QLatin1String("\n") + textToInsert); - return Range(insertionPoint, insertionPoint); + return {insertionPoint, insertionPoint}; } Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content) @@ -672,7 +672,7 @@ Rewriter::Range Rewriter::addObject(UiArrayBinding *ast, const QString &content, m_changeSet->insert(insertionPoint, textToInsert); - return Range(insertionPoint, insertionPoint); + return {insertionPoint, insertionPoint}; } void Rewriter::removeObjectMember(UiObjectMember *member, UiObjectMember *parent) diff --git a/src/lib/corelib/api/qmljsrewriter.h b/src/lib/corelib/api/qmljsrewriter.h index 797b05459..3788035f2 100644 --- a/src/lib/corelib/api/qmljsrewriter.h +++ b/src/lib/corelib/api/qmljsrewriter.h @@ -60,9 +60,9 @@ public: using Range = ChangeSet::Range; public: - Rewriter(const QString &originalText, + Rewriter(QString originalText, ChangeSet *changeSet, - const QStringList &propertyOrder); + QStringList propertyOrder); Range addBinding(AST::UiObjectInitializer *ast, const QString &propertyName, diff --git a/src/lib/corelib/api/rulecommand.cpp b/src/lib/corelib/api/rulecommand.cpp index bc12140f3..e01cde7cc 100644 --- a/src/lib/corelib/api/rulecommand.cpp +++ b/src/lib/corelib/api/rulecommand.cpp @@ -65,17 +65,11 @@ RuleCommand::RuleCommand() : d(new Internal::RuleCommandPrivate) { } -RuleCommand::RuleCommand(const RuleCommand &other) : d(other.d) {} +RuleCommand::RuleCommand(const RuleCommand &other) = default; -RuleCommand::~RuleCommand() -{ -} +RuleCommand::~RuleCommand() = default; -RuleCommand& RuleCommand::operator=(const RuleCommand &other) -{ - d = other.d; - return *this; -} +RuleCommand& RuleCommand::operator=(const RuleCommand &other) = default; /*! * Returns the type of this object. If the value is \c InvalidType, the object is invalid. diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp index df5b4337d..94a74dac2 100644 --- a/src/lib/corelib/api/runenvironment.cpp +++ b/src/lib/corelib/api/runenvironment.cpp @@ -62,8 +62,8 @@ #include <QtCore/qtemporaryfile.h> #include <QtCore/qvariant.h> +#include <cstdlib> #include <regex> -#include <stdlib.h> namespace qbs { using namespace Internal; diff --git a/src/lib/corelib/api/runenvironment.h b/src/lib/corelib/api/runenvironment.h index 69603bf76..c5123ca9c 100644 --- a/src/lib/corelib/api/runenvironment.h +++ b/src/lib/corelib/api/runenvironment.h @@ -52,6 +52,8 @@ class QString; class QStringList; QT_END_NAMESPACE +class TestApi; + namespace qbs { class ErrorInfo; class InstallOptions; @@ -66,7 +68,7 @@ class QBS_EXPORT RunEnvironment { friend class CommandLineFrontend; friend class Project; - friend class TestApi; + friend class ::TestApi; public: ~RunEnvironment(); diff --git a/src/lib/corelib/api/transformerdata.cpp b/src/lib/corelib/api/transformerdata.cpp index b4ee61d0c..9724e641b 100644 --- a/src/lib/corelib/api/transformerdata.cpp +++ b/src/lib/corelib/api/transformerdata.cpp @@ -44,14 +44,10 @@ namespace qbs { TransformerData::TransformerData() : d(new Internal::TransformerDataPrivate) { } -TransformerData::TransformerData(const TransformerData &other) : d(other.d) {} -TransformerData::~TransformerData() { } +TransformerData::TransformerData(const TransformerData &other) = default; +TransformerData::~TransformerData() = default; -TransformerData& TransformerData::operator=(const TransformerData &other) -{ - d = other.d; - return *this; -} +TransformerData& TransformerData::operator=(const TransformerData &other) = default; QList<ArtifactData> TransformerData::inputs() const { return d->inputs; } QList<ArtifactData> TransformerData::outputs() const { return d->outputs; } diff --git a/src/lib/corelib/buildgraph/artifactcleaner.cpp b/src/lib/corelib/buildgraph/artifactcleaner.cpp index 000dfda02..03b327232 100644 --- a/src/lib/corelib/buildgraph/artifactcleaner.cpp +++ b/src/lib/corelib/buildgraph/artifactcleaner.cpp @@ -162,7 +162,7 @@ ArtifactCleaner::ArtifactCleaner(Logger logger, ProgressObserver *observer) } void ArtifactCleaner::cleanup(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const CleanOptions &options) + const QVector<ResolvedProductPtr> &products, const CleanOptions &options) { m_hasError = false; diff --git a/src/lib/corelib/buildgraph/artifactcleaner.h b/src/lib/corelib/buildgraph/artifactcleaner.h index 5112a75d6..8d0bef275 100644 --- a/src/lib/corelib/buildgraph/artifactcleaner.h +++ b/src/lib/corelib/buildgraph/artifactcleaner.h @@ -54,7 +54,7 @@ class ArtifactCleaner { public: ArtifactCleaner(Logger logger, ProgressObserver *observer); - void cleanup(const TopLevelProjectPtr &project, const QList<ResolvedProductPtr> &products, + void cleanup(const TopLevelProjectPtr &project, const QVector<ResolvedProductPtr> &products, const CleanOptions &options); private: diff --git a/src/lib/corelib/buildgraph/artifactvisitor.cpp b/src/lib/corelib/buildgraph/artifactvisitor.cpp index c28f07424..22c987572 100644 --- a/src/lib/corelib/buildgraph/artifactvisitor.cpp +++ b/src/lib/corelib/buildgraph/artifactvisitor.cpp @@ -61,7 +61,7 @@ void ArtifactVisitor::visitProduct(const ResolvedProductConstPtr &product) void ArtifactVisitor::visitProject(const ResolvedProjectConstPtr &project) { - for (const ResolvedProductConstPtr &product : project->allProducts()) + for (const auto &product : project->allProducts()) visitProduct(product); } diff --git a/src/lib/corelib/buildgraph/buildgraph.cpp b/src/lib/corelib/buildgraph/buildgraph.cpp index 3726c654d..0d5e8a1f0 100644 --- a/src/lib/corelib/buildgraph/buildgraph.cpp +++ b/src/lib/corelib/buildgraph/buildgraph.cpp @@ -278,7 +278,7 @@ private: } return result; } - for (const ResolvedModuleConstPtr &dependency : product->modules) { + for (const auto &dependency : product->modules) { if (dependency->isProduct) continue; QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass()); @@ -661,7 +661,7 @@ void provideFullFileTagsAndProperties(Artifact *artifact) artifact->properties = artifact->product->moduleProperties; FileTags allTags = artifact->pureFileTags.empty() ? artifact->product->fileTagsForFileName(artifact->fileName()) : artifact->pureFileTags; - for (const ArtifactPropertiesConstPtr &props : artifact->product->artifactProperties) { + for (const auto &props : artifact->product->artifactProperties) { if (allTags.intersects(props->fileTagsFilter())) { artifact->properties = props->propertyMap(); allTags += props->extraFileTags(); @@ -733,7 +733,7 @@ static void doSanityChecksForProduct(const ResolvedProductConstPtr &product, CycleDetector cycleDetector(logger); cycleDetector.visitProduct(product); const ProductBuildData * const buildData = product->buildData.get(); - for (const ResolvedModuleConstPtr &m : product->modules) + for (const auto &m : product->modules) QBS_CHECK(m->product == product.get()); qCDebug(lcBuildGraph) << "enabled:" << product->enabled << "build data:" << buildData; if (product->enabled) @@ -836,7 +836,7 @@ static void doSanityChecks(const ResolvedProjectPtr &project, for (const ResolvedProjectPtr &subProject : qAsConst(project->subProjects)) doSanityChecks(subProject, allProducts, productNames, logger); - for (const ResolvedProductConstPtr &product : project->products) { + for (const auto &product : project->products) { QBS_CHECK(product->project == project); QBS_CHECK(product->topLevelProject() == project->topLevelProject()); doSanityChecksForProduct(product, allProducts, logger); diff --git a/src/lib/corelib/buildgraph/buildgraphloader.cpp b/src/lib/corelib/buildgraph/buildgraphloader.cpp index bf6c30dcd..58a34b616 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.cpp +++ b/src/lib/corelib/buildgraph/buildgraphloader.cpp @@ -71,6 +71,7 @@ #include <algorithm> #include <functional> +#include <memory> #include <unordered_map> namespace qbs { @@ -273,7 +274,7 @@ static void updateProductAndRulePointers(const ResolvedProductPtr &newProduct) const auto it = ruleMap.find(oldRule); if (it != ruleMap.cend()) return it->second; - for (const RuleConstPtr &r : qAsConst(newProduct->rules)) { + for (const auto &r : qAsConst(newProduct->rules)) { if (*r == *oldRule) { ruleMap.insert(std::make_pair(oldRule, r)); return r; @@ -362,7 +363,7 @@ void BuildGraphLoader::trackProjectChanges() ChildListHash childLists; if (!changedProducts.empty()) { oldBuildData = std::make_shared<ProjectBuildData>(restoredProject->buildData.get()); - for (const ResolvedProductConstPtr &product : qAsConst(allRestoredProducts)) { + for (const auto &product : qAsConst(allRestoredProducts)) { if (!product->buildData) continue; @@ -451,7 +452,7 @@ void BuildGraphLoader::trackProjectChanges() updateGeneratedArtifacts(product.get()); } - for (const ResolvedProductConstPtr &changedProduct : qAsConst(changedProducts)) { + for (const auto &changedProduct : qAsConst(changedProducts)) { rescueOldBuildData(changedProduct, m_freshProductsByName.value(changedProduct->uniqueName()), childLists, rescuableArtifactData.value(changedProduct->uniqueName())); @@ -614,7 +615,7 @@ bool BuildGraphLoader::hasProductFileChanged(const std::vector<ResolvedProductPt FileInfo::path(group->location.filePath()), product->topLevelProject()->buildDirectory); Set<QString> wcFiles; - for (const SourceArtifactConstPtr &sourceArtifact : group->wildcards->files) + for (const auto &sourceArtifact : group->wildcards->files) wcFiles += sourceArtifact->absoluteFilePath; if (files == wcFiles) continue; @@ -741,9 +742,9 @@ static bool dependenciesAreEqual(const ResolvedProductConstPtr &p1, return false; Set<QString> names1; Set<QString> names2; - for (const ResolvedProductConstPtr &dep : qAsConst(p1->dependencies)) + for (const auto &dep : qAsConst(p1->dependencies)) names1 << dep->uniqueName(); - for (const ResolvedProductConstPtr &dep : qAsConst(p2->dependencies)) + for (const auto &dep : qAsConst(p2->dependencies)) names2 << dep->uniqueName(); return names1 == names2; } @@ -909,7 +910,7 @@ void BuildGraphLoader::rescueOldBuildData(const ResolvedProductConstPtr &restore if (!restoredProduct->buildData) return; if (!newlyResolvedProduct->buildData) - newlyResolvedProduct->buildData.reset(new ProductBuildData); + newlyResolvedProduct->buildData = std::make_unique<ProductBuildData>(); qCDebug(lcBuildGraph) << "rescue data of product" << restoredProduct->uniqueName(); QBS_CHECK(newlyResolvedProduct->buildData); diff --git a/src/lib/corelib/buildgraph/buildgraphloader.h b/src/lib/corelib/buildgraph/buildgraphloader.h index 9363b8358..c62ba7fa7 100644 --- a/src/lib/corelib/buildgraph/buildgraphloader.h +++ b/src/lib/corelib/buildgraph/buildgraphloader.h @@ -121,9 +121,9 @@ private: bool checkConfigCompatibility(); struct ChildrenInfo { - ChildrenInfo() {} - ChildrenInfo(const ArtifactSet &c1, const ArtifactSet &c2) - : children(c1), childrenAddedByScanner(c2) {} + ChildrenInfo() = default; + ChildrenInfo(ArtifactSet c1, ArtifactSet c2) + : children(std::move(c1)), childrenAddedByScanner(std::move(c2)) {} ArtifactSet children; ArtifactSet childrenAddedByScanner; }; diff --git a/src/lib/corelib/buildgraph/depscanner.h b/src/lib/corelib/buildgraph/depscanner.h index ffc0b83de..6b18004f9 100644 --- a/src/lib/corelib/buildgraph/depscanner.h +++ b/src/lib/corelib/buildgraph/depscanner.h @@ -61,7 +61,7 @@ class ScriptEngine; class DependencyScanner { public: - virtual ~DependencyScanner() {} + virtual ~DependencyScanner() = default; QString id() const; diff --git a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp index 7d82efb41..9dafbf296 100644 --- a/src/lib/corelib/buildgraph/environmentscriptrunner.cpp +++ b/src/lib/corelib/buildgraph/environmentscriptrunner.cpp @@ -129,12 +129,12 @@ void EnvironmentScriptRunner::setupEnvironment() return; QMap<QString, const ResolvedModule *> moduleMap; - for (const ResolvedModuleConstPtr &module : m_product->modules) + for (const auto &module : m_product->modules) moduleMap.insert(module->name, module.get()); QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleParents; QHash<const ResolvedModule*, QList<const ResolvedModule*> > moduleChildren; - for (const ResolvedModuleConstPtr &module : m_product->modules) { + for (const auto &module : m_product->modules) { for (const QString &moduleName : qAsConst(module->moduleDependencies)) { const ResolvedModule * const depmod = moduleMap.value(moduleName); QBS_ASSERT(depmod, return); @@ -144,7 +144,7 @@ void EnvironmentScriptRunner::setupEnvironment() } QList<const ResolvedModule *> rootModules; - for (const ResolvedModuleConstPtr &module : m_product->modules) { + for (const auto &module : m_product->modules) { if (moduleParents.value(module.get()).isEmpty()) { QBS_ASSERT(module, return); rootModules.push_back(module.get()); diff --git a/src/lib/corelib/buildgraph/executor.cpp b/src/lib/corelib/buildgraph/executor.cpp index de81ada20..377222d21 100644 --- a/src/lib/corelib/buildgraph/executor.cpp +++ b/src/lib/corelib/buildgraph/executor.cpp @@ -102,12 +102,8 @@ Executor::Executor(Logger logger, QObject *parent) Executor::~Executor() { - // jobs must be destroyed before deleting the shared scan result cache - for (ExecutorJob *job : qAsConst(m_availableJobs)) - delete job; - const auto processingJobs = m_processingJobs.keys(); - for (ExecutorJob *job : processingJobs) - delete job; + // jobs must be destroyed before deleting the m_inputArtifactScanContext + m_allJobs.clear(); delete m_inputArtifactScanContext; delete m_productInstaller; } @@ -153,7 +149,7 @@ void Executor::retrieveSourceFileTimestamp(Artifact *artifact) const void Executor::build() { try { - m_partialBuild = m_productsToBuild.size() != m_allProducts.size(); + m_partialBuild = size_t(m_productsToBuild.size()) != m_allProducts.size(); doBuild(); } catch (const ErrorInfo &e) { handleError(e); @@ -170,7 +166,7 @@ void Executor::setProject(const TopLevelProjectPtr &project) m_projectsByName.insert(std::make_pair(p->name, p.get())); } -void Executor::setProducts(const std::vector<ResolvedProductPtr> &productsToBuild) +void Executor::setProducts(const QVector<ResolvedProductPtr> &productsToBuild) { m_productsToBuild = productsToBuild; m_productsByName.clear(); @@ -266,8 +262,7 @@ void Executor::doBuild() doSanityChecks(); QBS_CHECK(!m_project->buildData->evaluationContext); - m_project->buildData->evaluationContext - = RulesEvaluationContextPtr(new RulesEvaluationContext(m_logger)); + m_project->buildData->evaluationContext = std::make_shared<RulesEvaluationContext>(m_logger); m_evalContext = m_project->buildData->evaluationContext; m_elapsedTimeRules = m_elapsedTimeScanners = m_elapsedTimeInstalling = 0; @@ -700,7 +695,7 @@ bool Executor::transformerHasMatchingInputFiles(const TransformerConstPtr &trans void Executor::setupJobLimits() { Settings settings(m_buildOptions.settingsDirectory()); - for (const ResolvedProductConstPtr &p : m_productsToBuild) { + for (const auto &p : qAsConst(m_productsToBuild)) { const Preferences prefs(&settings, p->profile()); const JobLimits &jobLimitsFromSettings = prefs.jobLimits(); JobLimits effectiveJobLimits; @@ -737,7 +732,7 @@ void Executor::setupProgressObserver() if (!m_progressObserver) return; int totalEffort = 1; // For the effort after the last rule application; - for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) { + for (const auto &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); const auto filtered = filterByType<RuleNode>(product->buildData->allNodes()); totalEffort += std::distance(filtered.begin(), filtered.end()); @@ -749,7 +744,7 @@ void Executor::doSanityChecks() { QBS_CHECK(m_project); QBS_CHECK(!m_productsToBuild.empty()); - for (const ResolvedProductConstPtr &product : qAsConst(m_productsToBuild)) { + for (const auto &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); QBS_CHECK(product->topLevelProject() == m_project.get()); } @@ -768,10 +763,13 @@ void Executor::handleError(const ErrorInfo &error) void Executor::addExecutorJobs() { - qCDebug(lcExec) << "preparing executor for" << m_buildOptions.maxJobCount() - << "jobs in parallel"; - for (int i = 1; i <= m_buildOptions.maxJobCount(); i++) { - const auto job = new ExecutorJob(m_logger, this); + const int count = m_buildOptions.maxJobCount(); + qCDebug(lcExec) << "preparing executor for" << count << "jobs in parallel"; + m_allJobs.reserve(count); + m_availableJobs.reserve(count); + for (int i = 1; i <= count; i++) { + m_allJobs.push_back(std::make_unique<ExecutorJob>(m_logger)); + const auto job = m_allJobs.back().get(); job->setMainThreadScriptEngine(m_evalContext->engine()); job->setObjectName(QStringLiteral("J%1").arg(i)); job->setDryRun(m_buildOptions.dryRun()); @@ -1084,7 +1082,7 @@ void Executor::checkForUnbuiltProducts() if (m_buildOptions.executeRulesOnly()) return; std::vector<ResolvedProductPtr> unbuiltProducts; - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { bool productBuilt = true; for (BuildGraphNode *rootNode : qAsConst(product->buildData->rootNodes())) { if (rootNode->buildState != BuildGraphNode::Built) { @@ -1206,7 +1204,7 @@ void Executor::prepareAllNodes() node->buildState = BuildGraphNode::Untouched; } } - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { QBS_CHECK(product->buildData); for (Artifact * const artifact : filterByType<Artifact>(product->buildData->allNodes())) prepareArtifact(artifact); @@ -1228,7 +1226,7 @@ void Executor::syncFileDependencies() "removing from lookup table"; m_project->buildData->removeFromLookupTable(dep); bool isReferencedByArtifact = false; - for (const ResolvedProductConstPtr &product : m_allProducts) { + for (const auto &product : m_allProducts) { if (!product->buildData) continue; const auto artifactList = filterByType<Artifact>(product->buildData->allNodes()); @@ -1310,7 +1308,7 @@ void Executor::prepareProducts() { ProductPrioritySetter prioritySetter(m_allProducts); prioritySetter.apply(); - for (const ResolvedProductPtr &product : m_productsToBuild) { + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) { EnvironmentScriptRunner(product.get(), m_evalContext.get(), m_project->environment) .setupForBuild(); } @@ -1319,7 +1317,7 @@ void Executor::prepareProducts() void Executor::setupRootNodes() { m_roots.clear(); - for (const ResolvedProductPtr &product : m_productsToBuild) + for (const ResolvedProductPtr &product : qAsConst(m_productsToBuild)) m_roots += product->buildData->rootNodes(); } diff --git a/src/lib/corelib/buildgraph/executor.h b/src/lib/corelib/buildgraph/executor.h index 1fd591176..cc879e125 100644 --- a/src/lib/corelib/buildgraph/executor.h +++ b/src/lib/corelib/buildgraph/executor.h @@ -81,7 +81,7 @@ public: ~Executor() override; void setProject(const TopLevelProjectPtr &project); - void setProducts(const std::vector<ResolvedProductPtr> &productsToBuild); + void setProducts(const QVector<ResolvedProductPtr> &productsToBuild); void setBuildOptions(const BuildOptions &buildOptions); void setProgressObserver(ProgressObserver *observer) { m_progressObserver = observer; } @@ -166,10 +166,11 @@ private: BuildOptions m_buildOptions; Logger m_logger; ProgressObserver *m_progressObserver; + std::vector<std::unique_ptr<ExecutorJob>> m_allJobs; QList<ExecutorJob*> m_availableJobs; ExecutorState m_state; TopLevelProjectPtr m_project; - std::vector<ResolvedProductPtr> m_productsToBuild; + QVector<ResolvedProductPtr> m_productsToBuild; std::vector<ResolvedProductPtr> m_allProducts; std::unordered_map<QString, const ResolvedProduct *> m_productsByName; std::unordered_map<QString, const ResolvedProject *> m_projectsByName; diff --git a/src/lib/corelib/buildgraph/executorjob.cpp b/src/lib/corelib/buildgraph/executorjob.cpp index 79f17377d..bc96cbb6e 100644 --- a/src/lib/corelib/buildgraph/executorjob.cpp +++ b/src/lib/corelib/buildgraph/executorjob.cpp @@ -71,9 +71,7 @@ ExecutorJob::ExecutorJob(const Logger &logger, QObject *parent) reset(); } -ExecutorJob::~ExecutorJob() -{ -} +ExecutorJob::~ExecutorJob() = default; void ExecutorJob::setMainThreadScriptEngine(ScriptEngine *engine) { diff --git a/src/lib/corelib/buildgraph/executorjob.h b/src/lib/corelib/buildgraph/executorjob.h index bc8954072..1f8f0cd73 100644 --- a/src/lib/corelib/buildgraph/executorjob.h +++ b/src/lib/corelib/buildgraph/executorjob.h @@ -65,7 +65,7 @@ class ExecutorJob : public QObject { Q_OBJECT public: - ExecutorJob(const Logger &logger, QObject *parent); + explicit ExecutorJob(const Logger &logger, QObject *parent = nullptr); ~ExecutorJob() override; void setMainThreadScriptEngine(ScriptEngine *engine); diff --git a/src/lib/corelib/buildgraph/filedependency.cpp b/src/lib/corelib/buildgraph/filedependency.cpp index 9420fa96b..cbee758c7 100644 --- a/src/lib/corelib/buildgraph/filedependency.cpp +++ b/src/lib/corelib/buildgraph/filedependency.cpp @@ -44,13 +44,9 @@ namespace qbs { namespace Internal { -FileResourceBase::FileResourceBase() -{ -} +FileResourceBase::FileResourceBase() = default; -FileResourceBase::~FileResourceBase() -{ -} +FileResourceBase::~FileResourceBase() = default; void FileResourceBase::setTimestamp(const FileTime &t) @@ -86,13 +82,9 @@ void FileResourceBase::store(PersistentPool &pool) } -FileDependency::FileDependency() -{ -} +FileDependency::FileDependency() = default; -FileDependency::~FileDependency() -{ -} +FileDependency::~FileDependency() = default; } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/inputartifactscanner.cpp b/src/lib/corelib/buildgraph/inputartifactscanner.cpp index 81cbe2178..1d00e29e1 100644 --- a/src/lib/corelib/buildgraph/inputartifactscanner.cpp +++ b/src/lib/corelib/buildgraph/inputartifactscanner.cpp @@ -77,6 +77,7 @@ static void resolveDepencency(const RawScannedDependency &dependency, FileDependency *fileDependencyArtifact = nullptr; Artifact *dependencyInProduct = nullptr; Artifact *dependencyInOtherProduct = nullptr; + bool productOfDependencyIsDependency = false; const auto files = project->topLevelProject() ->buildData->lookupFiles(absDirPath, dependency.fileName()); for (FileResourceBase *lookupResult : files) { @@ -86,10 +87,13 @@ static void resolveDepencency(const RawScannedDependency &dependency, break; case FileResourceBase::FileTypeArtifact: { auto const foundArtifact = static_cast<Artifact *>(lookupResult); - if (foundArtifact->product == product) + if (foundArtifact->product == product) { dependencyInProduct = foundArtifact; - else + } else if (!productOfDependencyIsDependency) { dependencyInOtherProduct = foundArtifact; + productOfDependencyIsDependency + = contains(product->dependencies, dependencyInOtherProduct->product.lock()); + } break; } } @@ -102,6 +106,14 @@ static void resolveDepencency(const RawScannedDependency &dependency, || (result->file = dependencyInOtherProduct) || (result->file = fileDependencyArtifact)) { result->filePath = result->file->filePath(); + + if (result->file == dependencyInOtherProduct && !productOfDependencyIsDependency) { + qCDebug(lcDepScan) << "product" << dependencyInOtherProduct->product->fullDisplayName() + << "of scanned dependency" << result->filePath + << "is not a dependency of product" << product->fullDisplayName() + << ". The file dependency might get lost during change tracking."; + } + return; } @@ -349,6 +361,8 @@ void InputArtifactScanner::handleDependency(ResolvedDependency &dependency) if (m_artifact == dependency.file) return; + if (artifactDependency && artifactDependency->transformer == m_artifact->transformer) + return; if (fileDependency) { m_artifact->fileDependencies << fileDependency; @@ -372,16 +386,14 @@ void InputArtifactScanner::scanWithScannerPlugin(DependencyScanner *scanner, const QStringList &dependencies = scanner->collectDependencies( inputArtifact, fileToBeScanned, m_fileTagsForScanner.constData()); for (const QString &s : dependencies) - scanResult->deps.push_back(RawScannedDependency(s)); + scanResult->deps.emplace_back(s); } InputArtifactScannerContext::DependencyScannerCacheItem::DependencyScannerCacheItem() : valid(false) { } -InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem() -{ -} +InputArtifactScannerContext::DependencyScannerCacheItem::~DependencyScannerCacheItem() = default; } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/nodetreedumper.cpp b/src/lib/corelib/buildgraph/nodetreedumper.cpp index 89975baf2..8475a46cf 100644 --- a/src/lib/corelib/buildgraph/nodetreedumper.cpp +++ b/src/lib/corelib/buildgraph/nodetreedumper.cpp @@ -51,13 +51,13 @@ namespace qbs { namespace Internal { -static unsigned int indentWidth() { return 4; } +static int indentWidth() { return 4; } NodeTreeDumper::NodeTreeDumper(QIODevice &outDevice) : m_outDevice(outDevice) { } -void NodeTreeDumper::start(const QList<ResolvedProductPtr> &products) +void NodeTreeDumper::start(const QVector<ResolvedProductPtr> &products) { m_indentation = 0; for (const ResolvedProductPtr &p : products) { diff --git a/src/lib/corelib/buildgraph/nodetreedumper.h b/src/lib/corelib/buildgraph/nodetreedumper.h index 4175ce727..38ccd6dae 100644 --- a/src/lib/corelib/buildgraph/nodetreedumper.h +++ b/src/lib/corelib/buildgraph/nodetreedumper.h @@ -57,7 +57,7 @@ class NodeTreeDumper : public BuildGraphVisitor public: NodeTreeDumper(QIODevice &outDevice); - void start(const QList<ResolvedProductPtr> &products); + void start(const QVector<ResolvedProductPtr> &products); private: bool visit(Artifact *artifact) override; @@ -74,7 +74,7 @@ private: QIODevice &m_outDevice; ResolvedProductPtr m_currentProduct; NodeSet m_visited; - unsigned int m_indentation = 0; + int m_indentation = 0; }; } // namespace Internal diff --git a/src/lib/corelib/buildgraph/processcommandexecutor.cpp b/src/lib/corelib/buildgraph/processcommandexecutor.cpp index 79edda320..7cde8553c 100644 --- a/src/lib/corelib/buildgraph/processcommandexecutor.cpp +++ b/src/lib/corelib/buildgraph/processcommandexecutor.cpp @@ -166,6 +166,7 @@ bool ProcessCommandExecutor::doStart() .arg(responseFile.fileName()))); return false; } + const auto separator = cmd->responseFileSeparator().toUtf8(); for (int i = cmd->responseFileArgumentIndex(); i < cmd->arguments().size(); ++i) { const QString arg = cmd->arguments().at(i); if (arg.startsWith(cmd->responseFileUsagePrefix())) { @@ -179,7 +180,7 @@ bool ProcessCommandExecutor::doStart() } else { responseFile.write(qbs::Internal::shellQuote(arg).toLocal8Bit()); } - responseFile.write("\n"); + responseFile.write(separator); } responseFile.close(); m_responseFileName = responseFile.fileName(); diff --git a/src/lib/corelib/buildgraph/productinstaller.cpp b/src/lib/corelib/buildgraph/productinstaller.cpp index d4acc9ace..80a76d7f5 100644 --- a/src/lib/corelib/buildgraph/productinstaller.cpp +++ b/src/lib/corelib/buildgraph/productinstaller.cpp @@ -60,7 +60,7 @@ namespace qbs { namespace Internal { ProductInstaller::ProductInstaller(TopLevelProjectPtr project, - std::vector<ResolvedProductPtr> products, InstallOptions options, + QVector<ResolvedProductPtr> products, InstallOptions options, ProgressObserver *observer, Logger logger) : m_project(std::move(project)), m_products(std::move(products)), @@ -96,7 +96,7 @@ void ProductInstaller::install() removeInstallRoot(); QList<const Artifact *> artifactsToInstall; - for (const ResolvedProductConstPtr &product : qAsConst(m_products)) { + for (const auto &product : qAsConst(m_products)) { QBS_CHECK(product->buildData); for (const Artifact *artifact : filterByType<Artifact>(product->buildData->allNodes())) { if (artifact->properties->qbsPropertyValue(StringConstants::installProperty()).toBool()) @@ -250,5 +250,5 @@ void ProductInstaller::handleError(const QString &message) m_logger.qbsWarning() << message; } -} // namespace Intern +} // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/buildgraph/productinstaller.h b/src/lib/corelib/buildgraph/productinstaller.h index 09828cfe9..c07e0b7cf 100644 --- a/src/lib/corelib/buildgraph/productinstaller.h +++ b/src/lib/corelib/buildgraph/productinstaller.h @@ -56,7 +56,7 @@ class ProductInstaller { public: ProductInstaller(TopLevelProjectPtr project, - std::vector<ResolvedProductPtr> products, + QVector<ResolvedProductPtr> products, InstallOptions options, ProgressObserver *observer, Logger logger); void install(); @@ -72,7 +72,7 @@ private: void handleError(const QString &message); const TopLevelProjectConstPtr m_project; - const std::vector<ResolvedProductPtr> m_products; + const QVector<ResolvedProductPtr> m_products; InstallOptions m_options; ProgressObserver * const m_observer; Logger m_logger; diff --git a/src/lib/corelib/buildgraph/projectbuilddata.cpp b/src/lib/corelib/buildgraph/projectbuilddata.cpp index 31012e23e..0ac6b1537 100644 --- a/src/lib/corelib/buildgraph/projectbuilddata.cpp +++ b/src/lib/corelib/buildgraph/projectbuilddata.cpp @@ -60,6 +60,8 @@ #include <tools/qttools.h> #include <tools/stlutils.h> +#include <memory> + namespace qbs { namespace Internal { @@ -276,7 +278,7 @@ void BuildDataResolver::resolveBuildData(const TopLevelProjectPtr &resolvedProje { QBS_CHECK(!resolvedProject->buildData); m_project = resolvedProject; - resolvedProject->buildData.reset(new ProjectBuildData); + resolvedProject->buildData = std::make_unique<ProjectBuildData>(); resolvedProject->buildData->evaluationContext = evalContext; const std::vector<ResolvedProductPtr> &allProducts = resolvedProject->allProducts(); evalContext->initializeObserver(Tr::tr("Setting up build graph for configuration %1") @@ -390,7 +392,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc evalContext()->checkForCancelation(); - product->buildData.reset(new ProductBuildData); + product->buildData = std::make_unique<ProductBuildData>(); ArtifactSetByFileTag artifactsPerFileTag; for (const auto &dependency : qAsConst(product->dependencies)) { @@ -411,7 +413,7 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc artifactsPerFileTag["qbs"].insert(qbsFileArtifact); // read sources - for (const SourceArtifactConstPtr &sourceArtifact : product->allEnabledFiles()) { + for (const auto &sourceArtifact : product->allEnabledFiles()) { QString filePath = sourceArtifact->absoluteFilePath; if (lookupArtifact(product, filePath)) continue; // ignore duplicate artifacts @@ -443,7 +445,7 @@ void BuildDataResolver::connectRulesToDependencies(const ResolvedProductPtr &pro std::vector<RuleNode *> ruleNodes; for (RuleNode *ruleNode : filterByType<RuleNode>(product->buildData->allNodes())) ruleNodes.push_back(ruleNode); - for (const ResolvedProductConstPtr &dep : dependencies) { + for (const auto &dep : dependencies) { if (!dep->buildData) continue; for (RuleNode *depRuleNode : filterByType<RuleNode>(dep->buildData->allNodes())) { diff --git a/src/lib/corelib/buildgraph/qtmocscanner.cpp b/src/lib/corelib/buildgraph/qtmocscanner.cpp index c834c60e6..4e054a636 100644 --- a/src/lib/corelib/buildgraph/qtmocscanner.cpp +++ b/src/lib/corelib/buildgraph/qtmocscanner.cpp @@ -167,7 +167,7 @@ static RawScanResult runScanner(ScannerPlugin *scanner, const Artifact *artifact if (FileInfo::exists(localFilePath)) includedFilePath = localFilePath; } - scanData.rawScanResult.deps.push_back(RawScannedDependency(includedFilePath)); + scanData.rawScanResult.deps.emplace_back(includedFilePath); } scanner->close(opaq); diff --git a/src/lib/corelib/buildgraph/requesteddependencies.cpp b/src/lib/corelib/buildgraph/requesteddependencies.cpp index f993b2518..b95c8db94 100644 --- a/src/lib/corelib/buildgraph/requesteddependencies.cpp +++ b/src/lib/corelib/buildgraph/requesteddependencies.cpp @@ -48,9 +48,9 @@ namespace Internal { static Set<QString> depNamesForProduct(const ResolvedProduct *p) { Set<QString> names; - for (const ResolvedProductConstPtr &dep : p->dependencies) + for (const auto &dep : p->dependencies) names.insert(dep->uniqueName()); - for (const ResolvedModuleConstPtr &m : p->modules) { + for (const auto &m : p->modules) { if (!m->isProduct) names.insert(m->name); } @@ -73,7 +73,7 @@ bool RequestedDependencies::isUpToDate(const TopLevelProject *project) const { if (m_depsPerProduct.empty()) return true; - for (const ResolvedProductConstPtr &product : project->allProducts()) { + for (const auto &product : project->allProducts()) { const auto it = m_depsPerProduct.find(product->uniqueName()); if (it == m_depsPerProduct.cend()) continue; diff --git a/src/lib/corelib/buildgraph/rescuableartifactdata.h b/src/lib/corelib/buildgraph/rescuableartifactdata.h index 3e4d6e25f..6dd10f76c 100644 --- a/src/lib/corelib/buildgraph/rescuableartifactdata.h +++ b/src/lib/corelib/buildgraph/rescuableartifactdata.h @@ -84,9 +84,12 @@ public: struct ChildData { - ChildData(const QString &n = QString(), const QString &m = QString(), - const QString &c = QString(), bool byScanner = false) - : productName(n), productMultiplexId(m), childFilePath(c), addedByScanner(byScanner) + ChildData(QString n = QString(), QString m = QString(), + QString c = QString(), bool byScanner = false) + : productName(std::move(n)) + , productMultiplexId(std::move(m)) + , childFilePath(std::move(c)) + , addedByScanner(byScanner) {} template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool) diff --git a/src/lib/corelib/buildgraph/rulecommands.cpp b/src/lib/corelib/buildgraph/rulecommands.cpp index 31ff6be4b..8fa3255f1 100644 --- a/src/lib/corelib/buildgraph/rulecommands.cpp +++ b/src/lib/corelib/buildgraph/rulecommands.cpp @@ -70,6 +70,7 @@ static QString responseFileUsagePrefixProperty() { return QStringLiteral("responseFileUsagePrefix"); } +static QString responseFileSeparatorProperty() { return QStringLiteral("responseFileSeparator"); } static QString silentProperty() { return QStringLiteral("silent"); } static QString stderrFilePathProperty() { return QStringLiteral("stderrFilePath"); } static QString stderrFilterFunctionProperty() { return QStringLiteral("stderrFilterFunction"); } @@ -78,7 +79,7 @@ static QString stdoutFilterFunctionProperty() { return QStringLiteral("stdoutFil static QString timeoutProperty() { return QStringLiteral("timeout"); } static QString workingDirProperty() { return QStringLiteral("workingDirectory"); } -static QString invokedSourceCode(const QScriptValue codeOrFunction) +static QString invokedSourceCode(const QScriptValue &codeOrFunction) { const QString &code = codeOrFunction.toString(); return codeOrFunction.isFunction() ? QStringLiteral("(") + code + QStringLiteral(")()") : code; @@ -94,9 +95,7 @@ AbstractCommand::AbstractCommand() { } -AbstractCommand::~AbstractCommand() -{ -} +AbstractCommand::~AbstractCommand() = default; bool AbstractCommand::equals(const AbstractCommand *other) const { @@ -218,6 +217,8 @@ static QScriptValue js_Command(QScriptContext *context, QScriptEngine *engine) engine->toScriptValue(commandPrototype->responseFileArgumentIndex())); cmd.setProperty(responseFileUsagePrefixProperty(), engine->toScriptValue(commandPrototype->responseFileUsagePrefix())); + cmd.setProperty(responseFileSeparatorProperty(), + engine->toScriptValue(commandPrototype->responseFileSeparator())); cmd.setProperty(stdoutFilePathProperty(), engine->toScriptValue(commandPrototype->stdoutFilePath())); cmd.setProperty(stderrFilePathProperty(), @@ -241,6 +242,7 @@ ProcessCommand::ProcessCommand() : m_maxExitCode(0) , m_responseFileThreshold(defaultResponseFileThreshold()) , m_responseFileArgumentIndex(0) + , m_responseFileSeparator(QStringLiteral("\n")) { } @@ -279,6 +281,7 @@ bool ProcessCommand::equals(const AbstractCommand *otherAbstractCommand) const && m_responseFileThreshold == other->m_responseFileThreshold && m_responseFileArgumentIndex == other->m_responseFileArgumentIndex && m_responseFileUsagePrefix == other->m_responseFileUsagePrefix + && m_responseFileSeparator == other->m_responseFileSeparator && m_stdoutFilePath == other->m_stdoutFilePath && m_stderrFilePath == other->m_stderrFilePath && m_relevantEnvVars == other->m_relevantEnvVars @@ -313,6 +316,8 @@ void ProcessCommand::fillFromScriptValue(const QScriptValue *scriptValue, const .toInt32(); m_responseFileUsagePrefix = scriptValue->property(responseFileUsagePrefixProperty()) .toString(); + m_responseFileSeparator = scriptValue->property(responseFileSeparatorProperty()) + .toString(); QStringList envList = scriptValue->property(environmentProperty()).toVariant() .toStringList(); getEnvironmentFromList(envList); @@ -399,9 +404,7 @@ void JavaScriptCommand::setupForJavaScript(QScriptValue targetObject) targetObject.setProperty(StringConstants::javaScriptCommandType(), ctor); } -JavaScriptCommand::JavaScriptCommand() -{ -} +JavaScriptCommand::JavaScriptCommand() = default; bool JavaScriptCommand::equals(const AbstractCommand *otherAbstractCommand) const { diff --git a/src/lib/corelib/buildgraph/rulecommands.h b/src/lib/corelib/buildgraph/rulecommands.h index d4d70d591..725cd6d89 100644 --- a/src/lib/corelib/buildgraph/rulecommands.h +++ b/src/lib/corelib/buildgraph/rulecommands.h @@ -136,6 +136,7 @@ public: int responseFileThreshold() const { return m_responseFileThreshold; } int responseFileArgumentIndex() const { return m_responseFileArgumentIndex; } QString responseFileUsagePrefix() const { return m_responseFileUsagePrefix; } + QString responseFileSeparator() const { return m_responseFileSeparator; } QProcessEnvironment environment() const { return m_environment; } QStringList relevantEnvVars() const; void clearRelevantEnvValues() { m_relevantEnvValues.clear(); } @@ -158,10 +159,10 @@ private: { pool.serializationOp<opType>(m_program, m_arguments, m_environment, m_workingDir, m_stdoutFilterFunction, m_stderrFilterFunction, - m_responseFileUsagePrefix, m_maxExitCode, - m_responseFileThreshold, m_responseFileArgumentIndex, - m_relevantEnvVars, m_relevantEnvValues, m_stdoutFilePath, - m_stderrFilePath); + m_responseFileUsagePrefix, m_responseFileSeparator, + m_maxExitCode, m_responseFileThreshold, + m_responseFileArgumentIndex, m_relevantEnvVars, + m_relevantEnvValues, m_stdoutFilePath, m_stderrFilePath); } QString m_program; @@ -173,6 +174,7 @@ private: int m_responseFileThreshold; // When to use response files? In bytes of (program name + arguments). int m_responseFileArgumentIndex; QString m_responseFileUsagePrefix; + QString m_responseFileSeparator; QProcessEnvironment m_environment; QStringList m_relevantEnvVars; QProcessEnvironment m_relevantEnvValues; diff --git a/src/lib/corelib/buildgraph/rulegraph.cpp b/src/lib/corelib/buildgraph/rulegraph.cpp index 23227ca09..23f22b7f2 100644 --- a/src/lib/corelib/buildgraph/rulegraph.cpp +++ b/src/lib/corelib/buildgraph/rulegraph.cpp @@ -46,9 +46,7 @@ namespace qbs { namespace Internal { -RuleGraph::RuleGraph() -{ -} +RuleGraph::RuleGraph() = default; void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &productFileTags) { @@ -63,7 +61,7 @@ void RuleGraph::build(const std::vector<RulePtr> &rules, const FileTags &product m_parents.resize(rules.size()); m_children.resize(rules.size()); - for (const RuleConstPtr &rule : qAsConst(m_rules)) { + for (const auto &rule : qAsConst(m_rules)) { FileTags inFileTags = rule->inputs; inFileTags += rule->auxiliaryInputs; inFileTags += rule->explicitlyDependsOn; @@ -100,7 +98,7 @@ void RuleGraph::dump() const QByteArray indent; printf("---rule graph dump:\n"); Set<int> rootRules; - for (const RuleConstPtr &rule : qAsConst(m_rules)) + for (const auto &rule : qAsConst(m_rules)) if (m_parents[rule->ruleGraphId].empty()) rootRules += rule->ruleGraphId; for (int idx : qAsConst(rootRules)) diff --git a/src/lib/corelib/buildgraph/rulenode.cpp b/src/lib/corelib/buildgraph/rulenode.cpp index bf25b1da8..0558ba144 100644 --- a/src/lib/corelib/buildgraph/rulenode.cpp +++ b/src/lib/corelib/buildgraph/rulenode.cpp @@ -56,13 +56,9 @@ namespace qbs { namespace Internal { -RuleNode::RuleNode() -{ -} +RuleNode::RuleNode() = default; -RuleNode::~RuleNode() -{ -} +RuleNode::~RuleNode() = default; void RuleNode::accept(BuildGraphVisitor *visitor) { @@ -182,7 +178,7 @@ void RuleNode::apply(const Logger &logger, if (removedInputForcesOutputRemoval) outputArtifactsToRemove += parent; else - connectionsToBreak.push_back(std::make_pair(parent, artifact)); + connectionsToBreak.emplace_back(parent, artifact); } disconnect(this, artifact); } @@ -262,7 +258,7 @@ ArtifactSet RuleNode::currentInputArtifacts() const } } - for (const ResolvedProductConstPtr &dep : qAsConst(product->dependencies)) { + for (const auto &dep : qAsConst(product->dependencies)) { if (!dep->buildData) continue; for (Artifact * const a : filterByType<Artifact>(dep->buildData->allNodes())) { diff --git a/src/lib/corelib/buildgraph/rulesapplicator.cpp b/src/lib/corelib/buildgraph/rulesapplicator.cpp index 16aa0c001..0d36e1e21 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.cpp +++ b/src/lib/corelib/buildgraph/rulesapplicator.cpp @@ -79,12 +79,13 @@ namespace Internal { RulesApplicator::RulesApplicator( ResolvedProductPtr product, - std::unordered_map<QString, const ResolvedProduct *> productsByName, - std::unordered_map<QString, const ResolvedProject *> projectsByName, + const std::unordered_map<QString, const ResolvedProduct *> &productsByName, + const std::unordered_map<QString, const ResolvedProject *> &projectsByName, Logger logger) : m_product(std::move(product)) - , m_productsByName(std::move(productsByName)) - , m_projectsByName(std::move(projectsByName)) + // m_productsByName and m_projectsByName are references, cannot move-construct + , m_productsByName(productsByName) + , m_projectsByName(projectsByName) , m_mocScanner(nullptr) , m_logger(std::move(logger)) { @@ -213,13 +214,13 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p ScriptEngine::argumentList(Rule::argumentNamesForOutputArtifacts(), scope())); } else { Set<QString> outputFilePaths; - for (const RuleArtifactConstPtr &ruleArtifact : m_rule->artifacts) { + for (const auto &ruleArtifact : m_rule->artifacts) { const OutputArtifactInfo outputInfo = createOutputArtifactFromRuleArtifact( ruleArtifact, inputArtifacts, &outputFilePaths); if (!outputInfo.artifact) continue; outputArtifacts.push_back(outputInfo.artifact); - ruleArtifactArtifactMap.push_back({ ruleArtifact.get(), outputInfo }); + ruleArtifactArtifactMap.emplace_back(ruleArtifact.get(), outputInfo); } if (m_rule->artifacts.empty()) { outputArtifacts.push_back(createOutputArtifactFromRuleArtifact( @@ -287,7 +288,7 @@ void RulesApplicator::doApply(const ArtifactSet &inputArtifacts, QScriptValue &p } const QVariant value = scriptValue.toVariant(); setConfigProperty(artifactModulesCfg, binding.name, value); - outputArtifact->pureProperties.push_back(std::make_pair(binding.name, value)); + outputArtifact->pureProperties.emplace_back(binding.name, value); } outputArtifact->properties->setValue(artifactModulesCfg); if (!outputInfo.newlyCreated && (outputArtifact->fileTags() != outputInfo.oldFileTags @@ -354,7 +355,7 @@ ArtifactSet RulesApplicator::collectAdditionalInputs(const FileTags &tags, const } if (inputsSources.testFlag(Dependencies)) { - for (const ResolvedProductConstPtr &depProduct : product->dependencies) { + for (const auto &depProduct : product->dependencies) { for (Artifact * const ta : depProduct->targetArtifacts()) { if (ta->fileTags().contains(fileTag) && !ta->fileTags().intersects(rule->excludedInputs)) { @@ -607,7 +608,7 @@ public: for (const auto &e : m_propertyValues) { const QStringList key{e.module, e.name}; setConfigProperty(artifactCfg, key, e.value); - outputArtifact->pureProperties.push_back(std::make_pair(key, e.value)); + outputArtifact->pureProperties.emplace_back(key, e.value); } outputArtifact->properties->setValue(artifactCfg); } diff --git a/src/lib/corelib/buildgraph/rulesapplicator.h b/src/lib/corelib/buildgraph/rulesapplicator.h index 1160f3d09..da7815014 100644 --- a/src/lib/corelib/buildgraph/rulesapplicator.h +++ b/src/lib/corelib/buildgraph/rulesapplicator.h @@ -63,8 +63,8 @@ class RulesApplicator { public: RulesApplicator(ResolvedProductPtr product, - std::unordered_map<QString, const ResolvedProduct *> productsByName, - std::unordered_map<QString, const ResolvedProject *> projectsByName, + const std::unordered_map<QString, const ResolvedProduct *> &productsByName, + const std::unordered_map<QString, const ResolvedProject *> &projectsByName, Logger logger); ~RulesApplicator(); diff --git a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h index f6154f993..b57072236 100644 --- a/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h +++ b/src/lib/corelib/buildgraph/scriptclasspropertyiterator.h @@ -57,10 +57,10 @@ class ScriptClassPropertyIterator : public QScriptClassPropertyIterator { public: ScriptClassPropertyIterator(const QScriptValue &object, const QVariantMap &properties, - const std::vector<QString> &additionalProperties) + std::vector<QString> additionalProperties) : QScriptClassPropertyIterator(object), m_it(properties), - m_additionalProperties(additionalProperties) + m_additionalProperties(std::move(additionalProperties)) { } diff --git a/src/lib/corelib/buildgraph/timestampsupdater.cpp b/src/lib/corelib/buildgraph/timestampsupdater.cpp index d31f57445..3f5279dd2 100644 --- a/src/lib/corelib/buildgraph/timestampsupdater.cpp +++ b/src/lib/corelib/buildgraph/timestampsupdater.cpp @@ -83,7 +83,7 @@ private: }; void TimestampsUpdater::updateTimestamps(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const Logger &logger) + const QVector<ResolvedProductPtr> &products, const Logger &logger) { TimestampsUpdateVisitor v; for (const ResolvedProductPtr &product : products) diff --git a/src/lib/corelib/buildgraph/timestampsupdater.h b/src/lib/corelib/buildgraph/timestampsupdater.h index cfe20df12..8184ca708 100644 --- a/src/lib/corelib/buildgraph/timestampsupdater.h +++ b/src/lib/corelib/buildgraph/timestampsupdater.h @@ -51,7 +51,7 @@ class TimestampsUpdater { public: void updateTimestamps(const TopLevelProjectPtr &project, - const QList<ResolvedProductPtr> &products, const Logger &logger); + const QVector<ResolvedProductPtr> &products, const Logger &logger); }; } // namespace Internal diff --git a/src/lib/corelib/buildgraph/transformer.cpp b/src/lib/corelib/buildgraph/transformer.cpp index cc0b4c923..29f2bcdf0 100644 --- a/src/lib/corelib/buildgraph/transformer.cpp +++ b/src/lib/corelib/buildgraph/transformer.cpp @@ -62,9 +62,7 @@ Transformer::Transformer() : alwaysRun(false) { } -Transformer::~Transformer() -{ -} +Transformer::~Transformer() = default; static QScriptValue js_baseName(QScriptContext *ctx, QScriptEngine *engine, const Artifact *artifact) @@ -196,7 +194,7 @@ void Transformer::setupInputs(QScriptValue targetScriptValue, const ArtifactSet targetScriptValue.setProperty(StringConstants::inputVar(), inputScriptValue); } -void Transformer::setupInputs(QScriptValue targetScriptValue) +void Transformer::setupInputs(const QScriptValue &targetScriptValue) { setupInputs(targetScriptValue, inputs, rule->module->name); } diff --git a/src/lib/corelib/buildgraph/transformer.h b/src/lib/corelib/buildgraph/transformer.h index 2f6a8e56d..8772ed868 100644 --- a/src/lib/corelib/buildgraph/transformer.h +++ b/src/lib/corelib/buildgraph/transformer.h @@ -95,7 +95,7 @@ public: const Artifact *artifact, const QString &defaultModuleName); ResolvedProductPtr product() const; - void setupInputs(QScriptValue targetScriptValue); + void setupInputs(const QScriptValue &targetScriptValue); void setupOutputs(QScriptValue targetScriptValue); void setupExplicitlyDependsOn(QScriptValue targetScriptValue); void createCommands(ScriptEngine *engine, const PrivateScriptFunction &script, diff --git a/src/lib/corelib/buildgraph/transformerchangetracking.cpp b/src/lib/corelib/buildgraph/transformerchangetracking.cpp index 505f0cbba..e44c31639 100644 --- a/src/lib/corelib/buildgraph/transformerchangetracking.cpp +++ b/src/lib/corelib/buildgraph/transformerchangetracking.cpp @@ -71,7 +71,7 @@ private: const char *context) const; bool isExportedModuleUpToDate(const QString &productName, const ExportedModule &module) const; bool areExportedModulesUpToDate( - const std::unordered_map<QString, ExportedModule> exportedModules) const; + const std::unordered_map<QString, ExportedModule> &exportedModules) const; const Artifact *getArtifact(const QString &filePath, const QString &productName) const; const ResolvedProduct *getProduct(const QString &name) const; @@ -207,7 +207,7 @@ bool TrafoChangeTracker::isExportedModuleUpToDate(const QString &productName, } bool TrafoChangeTracker::areExportedModulesUpToDate( - const std::unordered_map<QString, ExportedModule> exportedModules) const + const std::unordered_map<QString, ExportedModule> &exportedModules) const { for (const auto &kv : exportedModules) { if (!isExportedModuleUpToDate(kv.first, kv.second)) diff --git a/src/lib/corelib/corelib.qbs b/src/lib/corelib/corelib.qbs index bd44ac3ed..619c0f0e3 100644 --- a/src/lib/corelib/corelib.qbs +++ b/src/lib/corelib/corelib.qbs @@ -395,6 +395,8 @@ QbsLibrary { "buildgraphlocker.cpp", "buildgraphlocker.h", "buildoptions.cpp", + "clangclinfo.cpp", + "clangclinfo.h", "cleanoptions.cpp", "codelocation.cpp", "commandechomode.cpp", diff --git a/src/lib/corelib/generators/generatordata.h b/src/lib/corelib/generators/generatordata.h index da65815ad..fd9bdde31 100644 --- a/src/lib/corelib/generators/generatordata.h +++ b/src/lib/corelib/generators/generatordata.h @@ -99,7 +99,7 @@ template <typename U> struct IMultiplexableContainer { } protected: - IMultiplexableContainer() { } + IMultiplexableContainer() = default; }; struct QBS_EXPORT GeneratableProductData : public IMultiplexableContainer<ProductData> { @@ -114,7 +114,7 @@ struct QBS_EXPORT GeneratableProjectData : public IMultiplexableContainer<Projec struct Id { private: friend struct GeneratableProjectData; - Id() { } + Id() = default; QString value; public: diff --git a/src/lib/corelib/generators/generatorutils.h b/src/lib/corelib/generators/generatorutils.h index 9348ab18c..58e59cbf8 100644 --- a/src/lib/corelib/generators/generatorutils.h +++ b/src/lib/corelib/generators/generatorutils.h @@ -41,14 +41,17 @@ namespace gen { namespace utils { enum class Architecture { - Arm, - Avr, - Mcs51, - Stm8, - Msp430, - Unknown + Unknown = 0, + Arm = 1 << 1, + Avr = 1 << 2, + Mcs51 = 1 << 3, + Stm8 = 1 << 4, + Msp430 = 1 << 5 }; +Q_DECLARE_FLAGS(ArchitectureFlags, Architecture) +Q_DECLARE_OPERATORS_FOR_FLAGS(ArchitectureFlags) + QBS_EXPORT QString architectureName(Architecture arch); QBS_EXPORT Architecture architecture(const Project &qbsProject); QBS_EXPORT QString buildConfigurationName(const Project &qbsProject); diff --git a/src/lib/corelib/generators/generatorversioninfo.cpp b/src/lib/corelib/generators/generatorversioninfo.cpp index 3e2106b57..c5c8db03f 100644 --- a/src/lib/corelib/generators/generatorversioninfo.cpp +++ b/src/lib/corelib/generators/generatorversioninfo.cpp @@ -42,42 +42,10 @@ namespace qbs { namespace gen { -VersionInfo::VersionInfo(const Version &version, - const std::set<utils::Architecture> &archs) - : m_version(version), m_archs(archs) -{ -} - -bool VersionInfo::operator<(const VersionInfo &other) const -{ - return m_version < other.m_version; -} - -bool VersionInfo::operator==(const VersionInfo &other) const -{ - return m_version == other.m_version - && m_archs == other.m_archs; -} - -Version VersionInfo::version() const -{ - return m_version; -} - -bool VersionInfo::containsArchitecture(utils::Architecture arch) const -{ - return m_archs.find(arch) != m_archs.cend(); -} - int VersionInfo::marketingVersion() const { return m_version.majorVersion(); } -quint32 qHash(const VersionInfo &info) -{ - return qHash(info.version().toString()); -} - } // namespace gen } // namespace qbs diff --git a/src/lib/corelib/generators/generatorversioninfo.h b/src/lib/corelib/generators/generatorversioninfo.h index 65bfcf685..38616eb98 100644 --- a/src/lib/corelib/generators/generatorversioninfo.h +++ b/src/lib/corelib/generators/generatorversioninfo.h @@ -45,7 +45,7 @@ #include <tools/qbs_export.h> #include <tools/version.h> -#include <set> +#include <QFlags> namespace qbs { namespace gen { @@ -53,24 +53,31 @@ namespace gen { class QBS_EXPORT VersionInfo { public: - VersionInfo(const Version &version, - const std::set<utils::Architecture> &archs); - virtual ~VersionInfo() = default; + constexpr VersionInfo(const Version &version, utils::ArchitectureFlags archs) + : m_version(version), m_archs(archs) + { + } - bool operator<(const VersionInfo &other) const; - bool operator==(const VersionInfo &other) const; + constexpr bool operator<(const VersionInfo &other) const { return m_version < other.m_version; } + constexpr bool operator==(const VersionInfo &other) const + { + return m_version == other.m_version && m_archs == other.m_archs; + } - Version version() const; - bool containsArchitecture(utils::Architecture arch) const; + constexpr Version version() const { return m_version; } + constexpr bool containsArchitecture(utils::Architecture arch) const { return m_archs & arch; } - virtual int marketingVersion() const; + int marketingVersion() const; private: Version m_version; - std::set<utils::Architecture> m_archs; + utils::ArchitectureFlags m_archs; }; -quint32 qHash(const VersionInfo &info); +inline quint32 qHash(const VersionInfo &info) +{ + return qHash(info.version().toString()); +} } // namespace gen } // namespace qbs diff --git a/src/lib/corelib/generators/igeneratableprojectvisitor.h b/src/lib/corelib/generators/igeneratableprojectvisitor.h index c3bd28580..dbf73b4e0 100644 --- a/src/lib/corelib/generators/igeneratableprojectvisitor.h +++ b/src/lib/corelib/generators/igeneratableprojectvisitor.h @@ -46,7 +46,7 @@ namespace qbs { class IGeneratableProjectVisitor { public: - virtual ~IGeneratableProjectVisitor() { } + virtual ~IGeneratableProjectVisitor() = default; // Collapsed configurations virtual void visitProject(const GeneratableProject &project) { diff --git a/src/lib/corelib/generators/ixmlnodevisitor.h b/src/lib/corelib/generators/ixmlnodevisitor.h index d3d118975..278f4cf2e 100644 --- a/src/lib/corelib/generators/ixmlnodevisitor.h +++ b/src/lib/corelib/generators/ixmlnodevisitor.h @@ -47,7 +47,7 @@ class Workspace; class QBS_EXPORT INodeVisitor { public: - virtual ~INodeVisitor() {} + virtual ~INodeVisitor() = default; virtual void visitWorkspaceStart(const Workspace *workspace) { Q_UNUSED(workspace) } virtual void visitWorkspaceEnd(const Workspace *workspace) { Q_UNUSED(workspace) } diff --git a/src/lib/corelib/generators/xmlprojectwriter.cpp b/src/lib/corelib/generators/xmlprojectwriter.cpp index 5554e5935..190e1304f 100644 --- a/src/lib/corelib/generators/xmlprojectwriter.cpp +++ b/src/lib/corelib/generators/xmlprojectwriter.cpp @@ -33,6 +33,7 @@ #include "xmlproperty.h" #include "xmlpropertygroup.h" +#include <memory> #include <ostream> namespace qbs { @@ -42,7 +43,7 @@ namespace xml { ProjectWriter::ProjectWriter(std::ostream *device) : m_device(device) { - m_writer.reset(new QXmlStreamWriter(&m_buffer)); + m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer); m_writer->setAutoFormatting(true); } diff --git a/src/lib/corelib/generators/xmlpropertygroup.cpp b/src/lib/corelib/generators/xmlpropertygroup.cpp index 398d68e77..c9e6a97c1 100644 --- a/src/lib/corelib/generators/xmlpropertygroup.cpp +++ b/src/lib/corelib/generators/xmlpropertygroup.cpp @@ -45,10 +45,9 @@ void PropertyGroup::appendProperty(QByteArray name, QVariant value) appendChild<Property>(std::move(name), std::move(value)); } -void PropertyGroup::appendMultiLineProperty( - QByteArray key, QStringList values, QChar sep) +void PropertyGroup::appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep) { - const auto line = values.join(std::move(sep)); + const auto line = values.join(sep); appendProperty(std::move(key), QVariant::fromValue(line)); } diff --git a/src/lib/corelib/generators/xmlpropertygroup.h b/src/lib/corelib/generators/xmlpropertygroup.h index e63b515fc..e7e051a87 100644 --- a/src/lib/corelib/generators/xmlpropertygroup.h +++ b/src/lib/corelib/generators/xmlpropertygroup.h @@ -52,7 +52,7 @@ public: explicit PropertyGroup(QByteArray name); void appendProperty(QByteArray name, QVariant value); - void appendMultiLineProperty(QByteArray key, QStringList values, + void appendMultiLineProperty(QByteArray key, const QStringList &values, QChar sep = QLatin1Char(',')); void accept(INodeVisitor *visitor) const final; diff --git a/src/lib/corelib/generators/xmlworkspacewriter.cpp b/src/lib/corelib/generators/xmlworkspacewriter.cpp index c88cb06d0..d21b63c42 100644 --- a/src/lib/corelib/generators/xmlworkspacewriter.cpp +++ b/src/lib/corelib/generators/xmlworkspacewriter.cpp @@ -33,6 +33,7 @@ #include "xmlworkspace.h" #include "xmlworkspacewriter.h" +#include <memory> #include <ostream> namespace qbs { @@ -42,7 +43,7 @@ namespace xml { WorkspaceWriter::WorkspaceWriter(std::ostream *device) : m_device(device) { - m_writer.reset(new QXmlStreamWriter(&m_buffer)); + m_writer = std::make_unique<QXmlStreamWriter>(&m_buffer); m_writer->setAutoFormatting(true); } diff --git a/src/lib/corelib/jsextensions/binaryfile.cpp b/src/lib/corelib/jsextensions/binaryfile.cpp index 5f28f689b..f02f0bff6 100644 --- a/src/lib/corelib/jsextensions/binaryfile.cpp +++ b/src/lib/corelib/jsextensions/binaryfile.cpp @@ -235,7 +235,7 @@ void BinaryFile::write(const QVariantList &data) QByteArray bytes; std::for_each(data.constBegin(), data.constEnd(), [&bytes](const QVariant &v) { - bytes.append(v.toUInt() & 0xFF); }); + bytes.append(char(v.toUInt() & 0xFF)); }); const qint64 size = m_file->write(bytes); if (Q_UNLIKELY(size == -1)) { diff --git a/src/lib/corelib/jsextensions/domxml.cpp b/src/lib/corelib/jsextensions/domxml.cpp index 118e8d5e1..86e1574c6 100644 --- a/src/lib/corelib/jsextensions/domxml.cpp +++ b/src/lib/corelib/jsextensions/domxml.cpp @@ -85,7 +85,7 @@ public: Q_INVOKABLE QScriptValue previousSibling(const QString & tagName = QString()) const; Q_INVOKABLE QScriptValue nextSibling(const QString & tagName = QString()) const; - Q_INVOKABLE QScriptValue appendChild(QScriptValue newChild); + Q_INVOKABLE QScriptValue appendChild(const QScriptValue &newChild); Q_INVOKABLE QScriptValue insertBefore(const QScriptValue& newChild, const QScriptValue& refChild); Q_INVOKABLE QScriptValue insertAfter(const QScriptValue& newChild, const QScriptValue& refChild); Q_INVOKABLE QScriptValue replaceChild(const QScriptValue& newChild, const QScriptValue& oldChild); @@ -314,7 +314,6 @@ void XmlDomNode::setData(const QString &v) const if (m_domNode.isCharacterData()) return m_domNode.toCharacterData().setData(v); context()->throwError(QStringLiteral("Node '%1' is not a character data node").arg(m_domNode.nodeName())); - return; } void XmlDomNode::clear() @@ -365,7 +364,7 @@ QScriptValue XmlDomNode::nextSibling(const QString &tagName) const return engine()->newQObject(new XmlDomNode(m_domNode.nextSiblingElement(tagName)), QScriptEngine::ScriptOwnership); } -QScriptValue XmlDomNode::appendChild(QScriptValue newChild) +QScriptValue XmlDomNode::appendChild(const QScriptValue &newChild) { auto newNode = qobject_cast<XmlDomNode*>(newChild.toQObject()); if (!newNode) { diff --git a/src/lib/corelib/jsextensions/fileinfoextension.cpp b/src/lib/corelib/jsextensions/fileinfoextension.cpp index 0f2570ed0..038f3db41 100644 --- a/src/lib/corelib/jsextensions/fileinfoextension.cpp +++ b/src/lib/corelib/jsextensions/fileinfoextension.cpp @@ -53,6 +53,16 @@ namespace qbs { namespace Internal { +// removes duplicate separators from the path +static QString uniqueSeparators(QString path) +{ + const auto it = std::unique(path.begin(), path.end(), [](QChar c1, QChar c2) { + return c1 == c2 && c1 == QLatin1Char('/'); + }); + path.resize(int(it - path.begin())); + return path; +} + class FileInfoExtension : public QObject, QScriptable { Q_OBJECT @@ -268,9 +278,7 @@ QScriptValue FileInfoExtension::js_joinPaths(QScriptContext *context, QScriptEng paths.push_back(arg); } } - return engine->toScriptValue(QString::fromStdString( - std::regex_replace(paths.join(QLatin1Char('/')).toStdString(), - std::regex("/{2,}"), std::string("/")))); + return engine->toScriptValue(uniqueSeparators(paths.join(QLatin1Char('/')))); } } // namespace Internal diff --git a/src/lib/corelib/jsextensions/jsextensions.cpp b/src/lib/corelib/jsextensions/jsextensions.cpp index e5fbd3de8..052fb79e4 100644 --- a/src/lib/corelib/jsextensions/jsextensions.cpp +++ b/src/lib/corelib/jsextensions/jsextensions.cpp @@ -75,7 +75,7 @@ static InitializerMap &initializers() return theMap; } -void JsExtensions::setupExtensions(const QStringList &names, QScriptValue scope) +void JsExtensions::setupExtensions(const QStringList &names, const QScriptValue &scope) { for (const QString &name : names) initializers().value(name)(scope); diff --git a/src/lib/corelib/jsextensions/jsextensions.h b/src/lib/corelib/jsextensions/jsextensions.h index 8977dbe8a..f1ebfbdc3 100644 --- a/src/lib/corelib/jsextensions/jsextensions.h +++ b/src/lib/corelib/jsextensions/jsextensions.h @@ -54,7 +54,7 @@ namespace Internal { class JsExtensions { public: - static void setupExtensions(const QStringList &names, QScriptValue scope); + static void setupExtensions(const QStringList &names, const QScriptValue &scope); static QScriptValue loadExtension(QScriptEngine *engine, const QString &name); static bool hasExtension(const QString &name); static QStringList extensionNames(); diff --git a/src/lib/corelib/jsextensions/moduleproperties.cpp b/src/lib/corelib/jsextensions/moduleproperties.cpp index c0fd8ca84..f721e0016 100644 --- a/src/lib/corelib/jsextensions/moduleproperties.cpp +++ b/src/lib/corelib/jsextensions/moduleproperties.cpp @@ -195,7 +195,7 @@ static QScriptValue js_moduleDependencies(QScriptContext *, ScriptEngine *engine QScriptValue result = engine->newArray(); quint32 idx = 0; for (const QString &depName : qAsConst(module->moduleDependencies)) { - for (const ResolvedModuleConstPtr &dep : module->product->modules) { + for (const auto &dep : module->product->modules) { if (dep->name != depName) continue; QScriptValue obj = engine->newObject(engine->modulePropertyScriptClass()); diff --git a/src/lib/corelib/jsextensions/propertylist.mm b/src/lib/corelib/jsextensions/propertylist.mm index 6ac9d56c9..2ae422c41 100644 --- a/src/lib/corelib/jsextensions/propertylist.mm +++ b/src/lib/corelib/jsextensions/propertylist.mm @@ -95,7 +95,7 @@ public: QVariant propertyListObject; int propertyListFormat; - void readFromData(QScriptContext *context, QByteArray data); + void readFromData(QScriptContext *context, const QByteArray &data); QByteArray writeToData(QScriptContext *context, const QString &format); }; @@ -263,7 +263,7 @@ QString PropertyList::toJSON(const QString &style) const namespace qbs { namespace Internal { -void PropertyListPrivate::readFromData(QScriptContext *context, QByteArray data) +void PropertyListPrivate::readFromData(QScriptContext *context, const QByteArray &data) { @autoreleasepool { NSPropertyListFormat format; diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp index b425bb4a2..6c693cb61 100644 --- a/src/lib/corelib/jsextensions/utilitiesextension.cpp +++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp @@ -72,6 +72,7 @@ struct fat_arch_64 { #ifdef Q_OS_WIN +#include <tools/clangclinfo.h> #include <tools/msvcinfo.h> #include <tools/vsenvironmentdetector.h> #endif @@ -88,6 +89,10 @@ struct fat_arch_64 { namespace qbs { namespace Internal { +class DummyLogSink : public ILogSink { + void doPrintMessage(LoggerLevel, const QString &, const QString &) override { } +}; + class UtilitiesExtension : public QObject, QScriptable { Q_OBJECT @@ -110,6 +115,8 @@ public: static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_installedMSVCs(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_installedClangCls(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine); @@ -132,7 +139,7 @@ QScriptValue UtilitiesExtension::js_canonicalPlatform(QScriptContext *context, { const QScriptValue value = context->argument(0); if (value.isUndefined() || value.isNull()) - return value; + return engine->toScriptValue(QStringList()); if (context->argumentCount() == 1 && value.isString()) { return engine->toScriptValue([&value] { @@ -529,7 +536,11 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, QStringLiteral("clangClCompilerInfo expects 4 arguments")); const QString compilerFilePath = context->argument(0).toString(); - QString arch = context->argument(1).toString(); + // architecture cannot be empty as vcvarsall.bat requires at least 1 arg, so fallback + // to host architecture if none is present + QString arch = !context->argument(1).isNull() && !context->argument(1).isUndefined() + ? context->argument(1).toString() + : QString::fromStdString(HostOsInfo::hostOSArchitecture()); QString vcvarsallPath = context->argument(2).toString(); const QString compilerLanguage = context->argumentCount() > 3 ? context->argument(3).toString() @@ -551,6 +562,67 @@ QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, #endif } +QScriptValue UtilitiesExtension::js_installedMSVCs(QScriptContext *context, QScriptEngine *engine) +{ +#ifndef Q_OS_WIN + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QStringLiteral("installedMSVCs is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("installedMSVCs expects 1 arguments")); + } + + const auto value0 = context->argument(0); + const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture()); + const auto preferredArch = !value0.isNull() && !value0.isUndefined() + ? value0.toString() + : hostArch; + + DummyLogSink dummySink; + Logger dummyLogger(&dummySink); + auto msvcs = MSVC::installedCompilers(dummyLogger); + + const auto predicate = [&preferredArch, &hostArch](const MSVC &msvc) + { + auto archPair = MSVC::getHostTargetArchPair(msvc.architecture); + return archPair.first != hostArch || preferredArch != archPair.second; + }; + msvcs.erase(std::remove_if(msvcs.begin(), msvcs.end(), predicate), msvcs.end()); + QVariantList result; + for (const auto &msvc: msvcs) + result.append(msvc.toVariantMap()); + return engine->toScriptValue(result); +#endif +} + +QScriptValue UtilitiesExtension::js_installedClangCls( + QScriptContext *context, QScriptEngine *engine) +{ +#ifndef Q_OS_WIN + Q_UNUSED(engine); + return context->throwError(QScriptContext::UnknownError, + QStringLiteral("installedClangCls is not available on this platform")); +#else + if (Q_UNLIKELY(context->argumentCount() != 1)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("installedClangCls expects 1 arguments")); + } + + const auto value0 = context->argument(0); + const auto path = !value0.isNull() && !value0.isUndefined() ? value0.toString() : QString(); + + DummyLogSink dummySink; + Logger dummyLogger(&dummySink); + auto compilers = ClangClInfo::installedCompilers({path}, dummyLogger); + QVariantList result; + for (const auto &compiler: compilers) + result.append(compiler.toVariantMap()); + return engine->toScriptValue(result); +#endif +} + QScriptValue UtilitiesExtension::js_versionCompare(QScriptContext *context, QScriptEngine *engine) { if (context->argumentCount() == 2) { @@ -851,6 +923,10 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject) engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1)); environmentObj.setProperty(QStringLiteral("clangClCompilerInfo"), engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1)); + environmentObj.setProperty(QStringLiteral("installedMSVCs"), + engine->newFunction(UtilitiesExtension::js_installedMSVCs, 1)); + environmentObj.setProperty(QStringLiteral("installedClangCls"), + engine->newFunction(UtilitiesExtension::js_installedClangCls, 1)); environmentObj.setProperty(QStringLiteral("versionCompare"), engine->newFunction(UtilitiesExtension::js_versionCompare, 2)); environmentObj.setProperty(QStringLiteral("qmlTypeInfo"), diff --git a/src/lib/corelib/language/artifactproperties.cpp b/src/lib/corelib/language/artifactproperties.cpp index dd61bf1a2..011e58d88 100644 --- a/src/lib/corelib/language/artifactproperties.cpp +++ b/src/lib/corelib/language/artifactproperties.cpp @@ -48,9 +48,7 @@ ArtifactPropertiesPtr ArtifactProperties::create() return ArtifactPropertiesPtr(new ArtifactProperties); } -ArtifactProperties::ArtifactProperties() -{ -} +ArtifactProperties::ArtifactProperties() = default; FileTags ArtifactProperties::extraFileTags() const { @@ -66,6 +64,7 @@ bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2) { return ap1.fileTagsFilter() == ap2.fileTagsFilter() && ap1.extraFileTags() == ap2.extraFileTags() + && !ap1.propertyMap() == !ap2.propertyMap() && *ap1.propertyMap() == *ap2.propertyMap(); } diff --git a/src/lib/corelib/language/asttools.cpp b/src/lib/corelib/language/asttools.cpp index 617c8b95b..1b6abac7f 100644 --- a/src/lib/corelib/language/asttools.cpp +++ b/src/lib/corelib/language/asttools.cpp @@ -61,13 +61,13 @@ QString textOf(const QString &source, QbsQmlJS::AST::Node *node) if (!node) return {}; return source.mid(node->firstSourceLocation().begin(), - node->lastSourceLocation().end() - node->firstSourceLocation().begin()); + int(node->lastSourceLocation().end() - node->firstSourceLocation().begin())); } QStringRef textRefOf(const QString &source, QbsQmlJS::AST::Node *node) { const quint32 firstBegin = node->firstSourceLocation().begin(); - return source.midRef(firstBegin, node->lastSourceLocation().end() - firstBegin); + return source.midRef(firstBegin, int(node->lastSourceLocation().end() - firstBegin)); } } // namespace Internal diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp index 68355df51..13783d3b9 100644 --- a/src/lib/corelib/language/builtindeclarations.cpp +++ b/src/lib/corelib/language/builtindeclarations.cpp @@ -125,7 +125,7 @@ ItemDeclaration BuiltinDeclarations::declarationsForType(ItemType type) const } ItemType BuiltinDeclarations::typeForName(const QString &typeName, - const CodeLocation location) const + const CodeLocation &location) const { const auto it = m_typeMap.constFind(typeName); if (it == m_typeMap.constEnd()) diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h index 988f9ab81..9d7aee982 100644 --- a/src/lib/corelib/language/builtindeclarations.h +++ b/src/lib/corelib/language/builtindeclarations.h @@ -62,7 +62,7 @@ public: QStringList allTypeNames() const; ItemDeclaration declarationsForType(ItemType type) const; ItemType typeForName(const QString &typeName, - const CodeLocation location = CodeLocation()) const; + const CodeLocation &location = CodeLocation()) const; QString nameForType(ItemType itemType) const; QStringList argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const; diff --git a/src/lib/corelib/language/deprecationinfo.h b/src/lib/corelib/language/deprecationinfo.h index 502715b84..89cd07f4a 100644 --- a/src/lib/corelib/language/deprecationinfo.h +++ b/src/lib/corelib/language/deprecationinfo.h @@ -50,11 +50,11 @@ class DeprecationInfo { public: explicit DeprecationInfo(const Version &removalVersion, - const QString &additionalUserInfo = QString()) + QString additionalUserInfo = QString()) : m_removalVersion(removalVersion) - , m_additionalUserInfo(additionalUserInfo) + , m_additionalUserInfo(std::move(additionalUserInfo)) {} - DeprecationInfo() {} + DeprecationInfo() = default; bool isValid() const { return m_removalVersion.isValid(); } Version removalVersion() const { return m_removalVersion; } diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h index d8931a37e..f8535d0d7 100644 --- a/src/lib/corelib/language/evaluator.h +++ b/src/lib/corelib/language/evaluator.h @@ -64,7 +64,7 @@ class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver public: Evaluator(ScriptEngine *scriptEngine); - virtual ~Evaluator(); + ~Evaluator() override; ScriptEngine *engine() const { return m_scriptEngine; } QScriptValue property(const Item *item, const QString &name); diff --git a/src/lib/corelib/language/identifiersearch.cpp b/src/lib/corelib/language/identifiersearch.cpp index 973aae6a8..49ceab36c 100644 --- a/src/lib/corelib/language/identifiersearch.cpp +++ b/src/lib/corelib/language/identifiersearch.cpp @@ -43,9 +43,7 @@ namespace qbs { namespace Internal { -IdentifierSearch::IdentifierSearch() -{ -} +IdentifierSearch::IdentifierSearch() = default; void IdentifierSearch::start(QbsQmlJS::AST::Node *node) { diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp index 9f754bdd7..a86cfeac1 100644 --- a/src/lib/corelib/language/item.cpp +++ b/src/lib/corelib/language/item.cpp @@ -203,15 +203,15 @@ bool Item::isOfTypeOrhasParentOfType(ItemType type) const PropertyDeclaration Item::propertyDeclaration(const QString &name, bool allowExpired) const { - PropertyDeclaration decl = m_propertyDeclarations.value(name); - if (decl.isValid()) - return decl; + auto it = m_propertyDeclarations.find(name); + if (it != m_propertyDeclarations.end()) + return it.value(); if (allowExpired) { - decl = m_expiredPropertyDeclarations.value(name); - if (decl.isValid()) - return decl; + it = m_expiredPropertyDeclarations.find(name); + if (it != m_expiredPropertyDeclarations.end()) + return it.value(); } - return m_prototype ? m_prototype->propertyDeclaration(name) : decl; + return m_prototype ? m_prototype->propertyDeclaration(name) : PropertyDeclaration(); } void Item::addModule(const Item::Module &module) diff --git a/src/lib/corelib/language/itempool.cpp b/src/lib/corelib/language/itempool.cpp index 3da8b947b..ccd22fe2e 100644 --- a/src/lib/corelib/language/itempool.cpp +++ b/src/lib/corelib/language/itempool.cpp @@ -43,9 +43,7 @@ namespace qbs { namespace Internal { -ItemPool::ItemPool() -{ -} +ItemPool::ItemPool() = default; ItemPool::~ItemPool() { diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp index ca6ba2e12..20ddb5cfb 100644 --- a/src/lib/corelib/language/itemreadervisitorstate.cpp +++ b/src/lib/corelib/language/itemreadervisitorstate.cpp @@ -81,10 +81,7 @@ public: { } - ASTCacheValue(const ASTCacheValue &other) - : d(other.d) - { - } + ASTCacheValue(const ASTCacheValue &other) = default; void setProcessingFlag(bool b) { d->processing = b; } bool isProcessing() const { return d->processing; } diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 40549b836..3b3e7401e 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -188,15 +188,9 @@ void ResolvedGroup::store(PersistentPool &pool) * \sa Rule */ -ScriptFunction::ScriptFunction() -{ - -} - -ScriptFunction::~ScriptFunction() -{ +ScriptFunction::ScriptFunction() = default; -} +ScriptFunction::~ScriptFunction() = default; /*! * \variable ScriptFunction::script @@ -282,7 +276,7 @@ QString Rule::toString() const FileTags Rule::staticOutputFileTags() const { FileTags result; - for (const RuleArtifactConstPtr &artifact : artifacts) + for (const auto &artifact : artifacts) result.unite(artifact->fileTags); return result; } @@ -312,9 +306,7 @@ ResolvedProduct::ResolvedProduct() { } -ResolvedProduct::~ResolvedProduct() -{ -} +ResolvedProduct::~ResolvedProduct() = default; void ResolvedProduct::accept(BuildGraphVisitor *visitor) const { @@ -331,7 +323,7 @@ void ResolvedProduct::accept(BuildGraphVisitor *visitor) const std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const { std::vector<SourceArtifactPtr> lst; - for (const GroupConstPtr &group : groups) + for (const auto &group : groups) lst << group->allFiles(); return lst; } @@ -343,7 +335,7 @@ std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const std::vector<SourceArtifactPtr> ResolvedProduct::allEnabledFiles() const { std::vector<SourceArtifactPtr> lst; - for (const GroupConstPtr &group : groups) { + for (const auto &group : groups) { if (group->enabled) lst << group->allFiles(); } @@ -364,7 +356,7 @@ FileTags ResolvedProduct::fileTagsForFileName(const QString &fileName) const return result; } } else { - priority.reset(new int(tagger->priority())); + priority = std::make_unique<int>(tagger->priority()); } result.unite(tagger->fileTags()); break; @@ -524,9 +516,7 @@ ResolvedProject::ResolvedProject() : enabled(true), m_topLevelProject(nullptr) { } -ResolvedProject::~ResolvedProject() -{ -} +ResolvedProject::~ResolvedProject() = default; void ResolvedProject::accept(BuildGraphVisitor *visitor) const { @@ -551,7 +541,7 @@ TopLevelProject *ResolvedProject::topLevelProject() std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const { std::vector<ResolvedProjectPtr> projectList = subProjects; - for (const ResolvedProjectConstPtr &subProject : subProjects) + for (const auto &subProject : subProjects) projectList << subProject->allSubProjects(); return projectList; } @@ -559,7 +549,7 @@ std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const std::vector<ResolvedProductPtr> ResolvedProject::allProducts() const { std::vector<ResolvedProductPtr> productList = products; - for (const ResolvedProjectConstPtr &subProject : qAsConst(subProjects)) + for (const auto &subProject : qAsConst(subProjects)) productList << subProject->allProducts(); return productList; } @@ -765,7 +755,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr & if (baseDir.startsWith(buildDir)) return; - dirTimeStamps.push_back({ baseDir, FileInfo(baseDir).lastModified() }); + dirTimeStamps.emplace_back(baseDir, FileInfo(baseDir).lastModified()); QStringList changed_parts = parts; bool recursive = false; @@ -810,7 +800,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr & expandPatterns(result, group, changed_parts, filePath, buildDir); } else { if (parentDir != baseDir) - dirTimeStamps.push_back({parentDir, FileInfo(baseDir).lastModified()}); + dirTimeStamps.emplace_back(parentDir, FileInfo(baseDir).lastModified()); result += QDir::cleanPath(filePath); } } @@ -867,6 +857,7 @@ bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal && sa1.fileTags == sa2.fileTags && sa1.overrideFileTags == sa2.overrideFileTags && sa1.targetOfModule == sa2.targetOfModule + && !sa1.properties == !sa2.properties && *sa1.properties == *sa2.properties; } diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index 65879dd56..bbd851333 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -99,7 +99,7 @@ public: private: FileTagger(const QStringList &patterns, FileTags fileTags, int priority); - FileTagger() {} + FileTagger() = default; void setPatterns(const QStringList &patterns); @@ -139,20 +139,20 @@ public: } private: - Probe() {} - Probe(const QString &globalId, + Probe() = default; + Probe(QString globalId, const CodeLocation &location, bool condition, - const QString &configureScript, - const QVariantMap &properties, - const QVariantMap &initialProperties, - const std::vector<QString> &importedFilesUsed) - : m_globalId(globalId) + QString configureScript, + QVariantMap properties, + QVariantMap initialProperties, + std::vector<QString> importedFilesUsed) + : m_globalId(std::move(globalId)) , m_location(location) - , m_configureScript(configureScript) - , m_properties(properties) - , m_initialProperties(initialProperties) - , m_importedFilesUsed(importedFilesUsed) + , m_configureScript(std::move(configureScript)) + , m_properties(std::move(properties)) + , m_initialProperties(std::move(initialProperties)) + , m_importedFilesUsed(std::move(importedFilesUsed)) , m_condition(condition) {} @@ -378,7 +378,7 @@ public: } private: - ResolvedModule() {} + ResolvedModule() = default; }; bool operator==(const ResolvedModule &m1, const ResolvedModule &m2); inline bool operator!=(const ResolvedModule &m1, const ResolvedModule &m2) { return !(m1 == m2); } diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 9c8f9da1d..56fbc198e 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -71,20 +71,24 @@ #include <QtCore/qdebug.h> #include <QtCore/qdir.h> +#include <QtCore/qglobalstatic.h> #include <QtCore/qdiriterator.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> #include <QtCore/qtemporaryfile.h> #include <QtCore/qtextstream.h> +#include <QtCore/qthreadstorage.h> #include <QtScript/qscriptvalueiterator.h> #include <algorithm> +#include <memory> #include <utility> namespace qbs { namespace Internal { -static QString shadowProductPrefix() { return QStringLiteral("__shadow__"); } +using MultiplexConfigurationByIdTable = QThreadStorage<QHash<QString, QVariantMap> >; +Q_GLOBAL_STATIC(MultiplexConfigurationByIdTable, multiplexConfigurationsById); static void handlePropertyError(const ErrorInfo &error, const SetupProjectParameters ¶ms, Logger &logger) @@ -94,6 +98,20 @@ static void handlePropertyError(const ErrorInfo &error, const SetupProjectParame logger.printWarning(error); } +static bool multiplexConfigurationIntersects(const QVariantMap &lhs, const QVariantMap &rhs) +{ + QBS_CHECK(!lhs.isEmpty() && !rhs.isEmpty()); + + for (auto lhsProperty = lhs.constBegin(); lhsProperty != lhs.constEnd(); lhsProperty++) { + const auto rhsProperty = rhs.find(lhsProperty.key()); + const bool isCommonProperty = rhsProperty != rhs.constEnd(); + if (isCommonProperty && lhsProperty.value() != rhsProperty.value()) + return false; + } + + return true; +} + class ModuleLoader::ItemModuleList : public QList<Item::Module> {}; static QString probeGlobalId(Item *probe) @@ -292,7 +310,7 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters ¶meters) = m_elapsedTimePropertyChecking = 0; m_elapsedTimeProbes = 0; m_probesEncountered = m_probesRun = m_probesCachedCurrent = m_probesCachedOld = 0; - m_settings.reset(new Settings(parameters.settingsDirectory())); + m_settings = std::make_unique<Settings>(parameters.settingsDirectory()); const auto keys = m_parameters.overriddenValues().keys(); for (const QString &key : keys) { @@ -381,9 +399,9 @@ class PropertyDeclarationCheck : public ValueHandler Logger &m_logger; public: PropertyDeclarationCheck(const Set<Item *> &disabledItems, - const SetupProjectParameters ¶ms, Logger &logger) + SetupProjectParameters params, Logger &logger) : m_disabledItems(disabledItems) - , m_params(params) + , m_params(std::move(params)) , m_logger(logger) { } @@ -616,7 +634,7 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p for (ProductContext * const p : productSorter.sortedProducts()) { try { handleProduct(p); - if (p->name.startsWith(shadowProductPrefix())) + if (p->name.startsWith(StringConstants::shadowProductPrefix())) tlp.probes << p->info.probes; } catch (const ErrorInfo &err) { handleProductError(err, p); @@ -688,6 +706,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, m_qbsVersion.toString())); } + for (Item * const child : projectItem->children()) + child->setScope(projectContext.scope); + resolveProbes(&dummyProductContext, projectItem); projectContext.topLevelProject->probes << dummyProductContext.info.probes; @@ -695,7 +716,6 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, QList<Item *> multiplexedProducts; for (Item * const child : projectItem->children()) { - child->setScope(projectContext.scope); if (child->type() == ItemType::Product) multiplexedProducts << multiplexProductItem(&dummyProductContext, child); } @@ -762,9 +782,24 @@ QString ModuleLoader::MultiplexInfo::toIdString(size_t row) const const VariantValuePtr &mpvalue = mprow.at(column); multiplexConfiguration.insert(propertyName, mpvalue->value()); } - return QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration) - .toJson(QJsonDocument::Compact) - .toBase64()); + QString id = QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration) + .toJson(QJsonDocument::Compact) + .toBase64()); + // Cache for later use in:multiplexIdToVariantMap() + multiplexConfigurationsById->localData().insert(id, multiplexConfiguration); + return id; +} + +QVariantMap ModuleLoader::MultiplexInfo::multiplexIdToVariantMap(const QString &multiplexId) +{ + if (multiplexId.isEmpty()) + return QVariantMap(); + + QVariantMap result = multiplexConfigurationsById->localData().value(multiplexId); + // We assume that MultiplexInfo::toIdString() has been called for this + // particular multiplex configuration. + QBS_CHECK(!result.isEmpty()); + return result; } void qbs::Internal::ModuleLoader::ModuleLoader::dump(const ModuleLoader::MultiplexInfo &mpi) @@ -1085,66 +1120,111 @@ void ModuleLoader::adjustDependenciesForMultiplexing(const ProductContext &produ StringConstants::profilesProperty(), &profilesPropertyIsSet); const auto productRange = m_productsByName.equal_range(name); - std::vector<const ProductContext *> dependencies; + if (productRange.first == productRange.second) { + // Dependency is a module. Nothing to adjust. + return; + } + + std::vector<const ProductContext *> multiplexedDependencies; bool hasNonMultiplexedDependency = false; for (auto it = productRange.first; it != productRange.second; ++it) { - if (!it->second->multiplexConfigurationId.isEmpty()) { - dependencies.push_back(it->second); - if (productIsMultiplexed && !profilesPropertyIsSet) - break; - } else { + if (!it->second->multiplexConfigurationId.isEmpty()) + multiplexedDependencies.push_back(it->second); + else hasNonMultiplexedDependency = true; - break; - } } + bool hasMultiplexedDependencies = !multiplexedDependencies.empty(); // These are the allowed cases: // (1) Normal dependency with no multiplexing whatsoever. // (2) Both product and dependency are multiplexed. + // (2a) The profiles property is not set, we want to depend on the best + // matching variant. + // (2b) The profiles property is set, we want to depend on all variants + // with a matching profile. // (3) The product is not multiplexed, but the dependency is. - // (3a) The dependency has an aggregator. We want to depend on the aggregator. - // (3b) The dependency does not have an aggregator. We want to depend on all the - // multiplexed variants. - // (4) The product is multiplexed, but the dependency is not. This case is implicitly - // handled, because we don't have to adapt any Depends items. + // (3a) The profiles property is not set, the dependency has an aggregator. + // We want to depend on the aggregator. + // (3b) The profiles property is not set, the dependency does not have an + // aggregator. We want to depend on all the multiplexed variants. + // (3c) The profiles property is set, we want to depend on all variants + // with a matching profile regardless of whether an aggregator exists or not. + // (4) The product is multiplexed, but the dependency is not. We don't have to adapt + // any Depends items. // (5) The product is a "shadow product". In that case, we know which product // it should have a dependency on, and we make sure we depend on that. - // (1) and (3a) - if (!productIsMultiplexed && hasNonMultiplexedDependency) + // (1) and (4) + if (!hasMultiplexedDependencies) + return; + + // (3a) + if (!productIsMultiplexed && hasNonMultiplexedDependency && !profilesPropertyIsSet) return; QStringList multiplexIds; const ShadowProductInfo shadowProductInfo = getShadowProductInfo(product); const bool isShadowProduct = shadowProductInfo.first && shadowProductInfo.second == name; - for (const ProductContext *dependency : dependencies) { + const auto productMultiplexConfig = + MultiplexInfo::multiplexIdToVariantMap(product.multiplexConfigurationId); + + for (const ProductContext *dependency : multiplexedDependencies) { const bool depMatchesShadowProduct = isShadowProduct && dependency->item == product.item->parent(); const QString depMultiplexId = dependency->multiplexConfigurationId; if (depMatchesShadowProduct) { // (5) dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), VariantValue::create(depMultiplexId)); - multiplexIds.clear(); - break; - } - if (productIsMultiplexed && !profilesPropertyIsSet) { // (2) - const ValuePtr &multiplexId = product.item->property( - StringConstants::multiplexConfigurationIdProperty()); - dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), - multiplexId); - break; + return; } + if (productIsMultiplexed && !profilesPropertyIsSet) { // 2a + if (dependency->multiplexConfigurationId == product.multiplexConfigurationId) { + const ValuePtr &multiplexId = product.item->property( + StringConstants::multiplexConfigurationIdProperty()); + dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), + multiplexId); + return; - // (3b) (or (2) if Depends.profiles is set). - const bool profileMatch = !profilesPropertyIsSet || profiles.empty() - || profiles.contains(dependency->profileName); - if (profileMatch) - multiplexIds << depMultiplexId; - } - if (!multiplexIds.empty()) { - dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), - VariantValue::create(multiplexIds)); + } else { + // Otherwise collect partial matches and decide later + const auto dependencyMultiplexConfig = + MultiplexInfo::multiplexIdToVariantMap(dependency->multiplexConfigurationId); + + if (multiplexConfigurationIntersects(dependencyMultiplexConfig, productMultiplexConfig)) + multiplexIds << dependency->multiplexConfigurationId; + } + } else { + // (2b), (3b) or (3c) + const bool profileMatch = !profilesPropertyIsSet || profiles.empty() + || profiles.contains(dependency->profileName); + if (profileMatch) + multiplexIds << depMultiplexId; + } } + if (multiplexIds.empty()) { + const QString productName = ResolvedProduct::fullDisplayName( + product.name, product.multiplexConfigurationId); + throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' not fulfilled. " + "There are no eligible multiplex candidates.").arg(productName, + name), + dependsItem->location()); + } + + // In case of (2a), at most 1 match is allowed + if (productIsMultiplexed && !profilesPropertyIsSet && multiplexIds.size() > 1) { + const QString productName = ResolvedProduct::fullDisplayName( + product.name, product.multiplexConfigurationId); + QStringList candidateNames; + for (const auto &id : qAsConst(multiplexIds)) + candidateNames << ResolvedProduct::fullDisplayName(name, id); + throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' is ambiguous. " + "Eligible multiplex candidates: %3.").arg( + productName, name, candidateNames.join(QLatin1String(", "))), + dependsItem->location()); + } + + dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(), + VariantValue::create(multiplexIds)); } void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productItem) @@ -1216,7 +1296,8 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI // evaluate the product's exported properties in isolation in the project resolver. Item * const importer = Item::create(productItem->pool(), ItemType::Product); importer->setProperty(QStringLiteral("name"), - VariantValue::create(shadowProductPrefix() + productContext.name)); + VariantValue::create(StringConstants::shadowProductPrefix() + + productContext.name)); importer->setFile(productItem->file()); importer->setLocation(productItem->location()); importer->setScope(projectContext->scope); @@ -1281,7 +1362,6 @@ void ModuleLoader::createSortedModuleList(const Item::Module &parentModule, Item for (const Item::Module &dep : parentModule.item->modules()) createSortedModuleList(dep, modules); modules.push_back(parentModule); - return; } Item::Modules ModuleLoader::modulesSortedByDependency(const Item *productItem) @@ -1350,8 +1430,7 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) // set by the dependency module's merger (namely, scopes of defining items; see // ModuleMerger::replaceItemInScopes()). Item::Modules topSortedModules = modulesSortedByDependency(item); - for (Item::Module &module : topSortedModules) - ModuleMerger(m_logger, item, module).start(); + ModuleMerger::merge(m_logger, item, productContext->name, &topSortedModules); // Re-sort the modules by name. This is more stable; see QBS-818. // The list of modules in the product now has the same order as before, @@ -1585,7 +1664,7 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext const Item::PropertyMap &overriddenProperties = propertiesItem->properties(); for (Item::PropertyMap::ConstIterator it = overriddenProperties.constBegin(); it != overriddenProperties.constEnd(); ++it) { - loadedItem->setProperty(it.key(), overriddenProperties.value(it.key())); + loadedItem->setProperty(it.key(), it.value()); } } @@ -1806,7 +1885,7 @@ ProbeConstPtr ModuleLoader::findCurrentProbe( bool condition, const QVariantMap &initialProperties) const { - const QList<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location); + const std::vector<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location); for (const ProbeConstPtr &probe : cachedProbes) { if (probeMatches(probe, condition, initialProperties, QString(), CompareScript::No)) return probe; @@ -1964,7 +2043,7 @@ bool ModuleLoader::mergeExportItems(const ProductContext &productContext) productContext.project->topLevelProject->productModules.insert(productContext.name, pmi); if (hasDependenciesOnProductType) m_exportsWithDeferredDependsItems.insert(merged); - return exportItems.size() > 0; + return !exportItems.empty(); } Item *ModuleLoader::loadItemFromFile(const QString &filePath, @@ -2171,9 +2250,10 @@ void ModuleLoader::setSearchPathsForProduct(ModuleLoader::ProductContext *produc ModuleLoader::ShadowProductInfo ModuleLoader::getShadowProductInfo( const ModuleLoader::ProductContext &product) const { - const bool isShadowProduct = product.name.startsWith(shadowProductPrefix()); + const bool isShadowProduct = product.name.startsWith(StringConstants::shadowProductPrefix()); return std::make_pair(isShadowProduct, isShadowProduct - ? product.name.mid(shadowProductPrefix().size()) : QString()); + ? product.name.mid(StringConstants::shadowProductPrefix().size()) + : QString()); } void ModuleLoader::collectProductsByName(const TopLevelProjectContext &topLevelProject) @@ -2705,7 +2785,7 @@ void ModuleLoader::resolveParameterDeclarations(const Item *module) for (Item *param : moduleChildren) { if (param->type() != ItemType::Parameter) continue; - const auto paramDecls = param->propertyDeclarations(); + const auto ¶mDecls = param->propertyDeclarations(); for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it) decls.insert(it.key(), it.value()); } @@ -2756,7 +2836,8 @@ QVariantMap ModuleLoader::extractParameters(Item *dependsItem) const QScriptValue sv = m_evaluator->scriptValue(dependsItem); try { result = safeToVariant(sv); - } catch (ErrorInfo ei) { + } catch (const ErrorInfo &exception) { + auto ei = exception; ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location()); throw ei; } @@ -3024,72 +3105,67 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, FallbackMode fallbackMode, bool isRequired, Item *moduleInstance) { - bool triedToLoadModule = false; + auto existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName); + + if (existingPaths.isEmpty()) { // no suitable names found, try to use providers + bool moduleAlreadyKnown = false; + ModuleProviderResult result; + for (QualifiedId providerName = moduleName; !providerName.empty(); + providerName.pop_back()) { + if (!productContext->knownModuleProviders.insert(providerName).second) { + moduleAlreadyKnown = true; + break; + } + qCDebug(lcModuleLoader) << "Module" << moduleName.toString() + << "not found, checking for module providers"; + result = findModuleProvider(providerName, *productContext, + ModuleProviderLookup::Regular, dependsItemLocation); + if (result.providerFound) + break; + } + if (fallbackMode == FallbackMode::Enabled && !result.providerFound + && !moduleAlreadyKnown) { + qCDebug(lcModuleLoader) << "Specific module provider not found for" + << moduleName.toString() << ", setting up fallback."; + result = findModuleProvider(moduleName, *productContext, + ModuleProviderLookup::Fallback, dependsItemLocation); + } + if (result.providerAddedSearchPaths) { + qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString() + << "with newly added search paths from module provider"; + existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName); + } + } + const QString fullName = moduleName.toString(); + bool triedToLoadModule = false; std::vector<PrioritizedItem> candidates; - const QStringList &searchPaths = m_reader->allSearchPaths(); - bool matchingDirectoryFound = false; - for (int i = 0; i < searchPaths.size(); ++i) { - const QString &path = searchPaths.at(i); - const QString dirPath = findExistingModulePath(path, moduleName); - if (dirPath.isEmpty()) - continue; - matchingDirectoryFound = true; - QStringList moduleFileNames = m_moduleDirListCache.value(dirPath); - if (moduleFileNames.empty()) { - QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards()); - while (dirIter.hasNext()) - moduleFileNames += dirIter.next(); - - m_moduleDirListCache.insert(dirPath, moduleFileNames); - } - for (const QString &filePath : qAsConst(moduleFileNames)) { - triedToLoadModule = true; + candidates.reserve(size_t(existingPaths.size())); + for (int i = 0; i < existingPaths.size(); ++i) { + const QString &dirPath = existingPaths.at(i); + QStringList &moduleFileNames = getModuleFileNames(dirPath); + for (auto it = moduleFileNames.begin(); it != moduleFileNames.end(); ) { + const QString &filePath = *it; + bool triedToLoad = true; Item *module = loadModuleFile(productContext, fullName, isBaseModule(moduleName), - filePath, &triedToLoadModule, moduleInstance); + filePath, &triedToLoad, moduleInstance); if (module) candidates.emplace_back(module, 0, i); - if (!triedToLoadModule) - m_moduleDirListCache[dirPath].removeOne(filePath); + if (!triedToLoad) + it = moduleFileNames.erase(it); + else + ++it; + triedToLoadModule = triedToLoadModule || triedToLoad; } } if (candidates.empty()) { - if (!matchingDirectoryFound) { - bool moduleAlreadyKnown = false; - ModuleProviderResult result; - for (QualifiedId providerName = moduleName; !providerName.empty(); - providerName.pop_back()) { - if (!productContext->knownModuleProviders.insert(providerName).second) { - moduleAlreadyKnown = true; - break; - } - qCDebug(lcModuleLoader) << "Module" << moduleName.toString() - << "not found, checking for module providers"; - result = findModuleProvider(providerName, *productContext, - ModuleProviderLookup::Regular, dependsItemLocation); - if (result.providerFound) - break; - } - if (fallbackMode == FallbackMode::Enabled && !result.providerFound - && !moduleAlreadyKnown) { - qCDebug(lcModuleLoader) << "Specific module provider not found for" - << moduleName.toString() << ", setting up fallback."; - result = findModuleProvider(moduleName, *productContext, - ModuleProviderLookup::Fallback, dependsItemLocation); - } - if (result.providerAddedSearchPaths) { - qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString() - << "with newly added search paths from module provider"; - return searchAndLoadModuleFile(productContext, dependsItemLocation, moduleName, - fallbackMode, isRequired, moduleInstance); - } - } if (!isRequired) return createNonPresentModule(fullName, QStringLiteral("not found"), nullptr); - if (Q_UNLIKELY(triedToLoadModule)) + if (Q_UNLIKELY(triedToLoadModule)) { throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullName), dependsItemLocation); + } return nullptr; } @@ -3119,6 +3195,17 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext, return moduleItem; } +QStringList &ModuleLoader::getModuleFileNames(const QString &dirPath) +{ + QStringList &moduleFileNames = m_moduleDirListCache[dirPath]; + if (moduleFileNames.empty()) { + QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards()); + while (dirIter.hasNext()) + moduleFileNames += dirIter.next(); + } + return moduleFileNames; +} + // returns QVariant::Invalid for types that do not need conversion static QVariant::Type variantType(PropertyDeclaration::Type t) { @@ -3227,7 +3314,7 @@ Item *ModuleLoader::getModulePrototype(ProductContext *productContext, } } Item * const module = loadItemFromFile(filePath, CodeLocation()); - prototypeList.push_back(std::make_pair(module, productContext->profileName)); + prototypeList.emplace_back(module, productContext->profileName); if (module->type() != ItemType::Module) { qCDebug(lcModuleLoader).nospace() << "Alleged module " << fullModuleName << " has type '" @@ -3285,6 +3372,9 @@ void ModuleLoader::setupBaseModulePrototype(Item *prototype) prototype->setProperty(QStringLiteral("hostPlatform"), VariantValue::create(QString::fromStdString( HostOsInfo::hostOSIdentifier()))); + prototype->setProperty(QStringLiteral("hostArchitecture"), + VariantValue::create(QString::fromStdString( + HostOsInfo::hostOSArchitecture()))); prototype->setProperty(QStringLiteral("libexecPath"), VariantValue::create(m_parameters.libexecPath())); @@ -3327,7 +3417,7 @@ static std::vector<std::pair<QualifiedId, ItemValuePtr>> instanceItemProperties( if (itemValue->item()->type() == ItemType::ModulePrefix) f(itemValue->item()); else - result.push_back(std::make_pair(name, itemValue)); + result.emplace_back(name, itemValue); name.removeLast(); } }; @@ -3496,7 +3586,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It if (Q_UNLIKELY(configureScript->sourceCode() == StringConstants::undefinedValue())) throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location()); using ProbeProperty = std::pair<QString, QScriptValue>; - QList<ProbeProperty> probeBindings; + std::vector<ProbeProperty> probeBindings; QVariantMap initialProperties; for (Item *obj = probe; obj; obj = obj->prototype()) { const Item::PropertyMap &props = obj->properties(); @@ -3505,7 +3595,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It if (name == StringConstants::configureProperty()) continue; const QScriptValue value = m_evaluator->value(probe, name); - probeBindings += ProbeProperty(name, value); + probeBindings << ProbeProperty(name, value); if (name != StringConstants::conditionProperty()) initialProperties.insert(name, value.toVariant()); } @@ -3516,7 +3606,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It const QString &sourceCode = configureScript->sourceCode().toString(); ProbeConstPtr resolvedProbe; if (parent->type() == ItemType::Project - || productContext->name.startsWith(shadowProductPrefix())) { + || productContext->name.startsWith(StringConstants::shadowProductPrefix())) { resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode); } else { const QString &uniqueProductName = productContext->uniqueName(); @@ -3544,7 +3634,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It engine->currentContext()->pushScope(fileCtxScopes.fileScope); engine->currentContext()->pushScope(fileCtxScopes.importScope); configureScope = engine->newObject(); - for (const ProbeProperty &b : qAsConst(probeBindings)) + for (const ProbeProperty &b : probeBindings) configureScope.setProperty(b.first, b.second); engine->currentContext()->pushScope(configureScope); engine->clearRequestedProperties(); @@ -3560,7 +3650,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed(); } QVariantMap properties; - for (const ProbeProperty &b : qAsConst(probeBindings)) { + for (const ProbeProperty &b : probeBindings) { QVariant newValue; if (resolvedProbe) { newValue = resolvedProbe->properties().value(b.first); @@ -3678,12 +3768,36 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName) { QString dirPath = searchPath + QStringLiteral("/modules"); + + // isFileCaseCorrect is a very expensive call on macOS, so we cache the value for the + // modules and search paths we've already processed + auto &moduleInfo = m_existingModulePathCache[{searchPath, moduleName}]; + if (moduleInfo.first) // poor man's std::optional<QString> + return moduleInfo.second; + for (const QString &moduleNamePart : moduleName) { dirPath = FileInfo::resolvePath(dirPath, moduleNamePart); - if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) - return {}; + if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) { + moduleInfo.first = true; + return moduleInfo.second = QString(); + } } - return dirPath; + + moduleInfo.first = true; + return moduleInfo.second = dirPath; +} + +QStringList ModuleLoader::findExistingModulePaths( + const QStringList &searchPaths, const QualifiedId &moduleName) +{ + QStringList result; + result.reserve(searchPaths.size()); + for (const auto &path: searchPaths) { + const QString dirPath = findExistingModulePath(path, moduleName); + if (!dirPath.isEmpty()) + result.append(dirPath); + } + return result; } QVariantMap ModuleLoader::moduleProviderConfig(ModuleLoader::ProductContext &product) @@ -3769,6 +3883,7 @@ ModuleLoader::ModuleProviderResult ModuleLoader::findModuleProvider(const Qualif const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name); const QVariant moduleConfig = moduleProviderConfig(product).value(name.toString()); QTextStream stream(&dummyItemFile); + using Qt::endl; stream.setCodec("UTF-8"); stream << "import qbs.FileInfo" << endl; stream << "import qbs.Utilities" << endl; diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h index 85a2467f2..942f93c83 100644 --- a/src/lib/corelib/language/moduleloader.h +++ b/src/lib/corelib/language/moduleloader.h @@ -218,7 +218,7 @@ private: { Q_DISABLE_COPY(TopLevelProjectContext) public: - TopLevelProjectContext() {} + TopLevelProjectContext() = default; ~TopLevelProjectContext() { qDeleteAll(projects); } std::vector<ProjectContext *> projects; @@ -252,6 +252,7 @@ private: VariantValuePtr multiplexedType; QString toIdString(size_t row) const; + static QVariantMap multiplexIdToVariantMap(const QString &multiplexId); }; void dump(const MultiplexInfo &mpi); @@ -317,6 +318,7 @@ private: Item *searchAndLoadModuleFile(ProductContext *productContext, const CodeLocation &dependsItemLocation, const QualifiedId &moduleName, FallbackMode fallbackMode, bool isRequired, Item *moduleInstance); + QStringList &getModuleFileNames(const QString &dirPath); Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName, bool isBaseModule, const QString &filePath, bool *triedToLoad, Item *moduleInstance); Item *getModulePrototype(ProductContext *productContext, const QString &fullModuleName, @@ -337,8 +339,9 @@ private: QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr); void copyProperties(const Item *sourceProject, Item *targetProject); Item *wrapInProjectIfNecessary(Item *item); - static QString findExistingModulePath(const QString &searchPath, - const QualifiedId &moduleName); + QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName); + QStringList findExistingModulePaths( + const QStringList &searchPaths, const QualifiedId &moduleName); enum class ModuleProviderLookup { Regular, Fallback }; struct ModuleProviderResult @@ -411,6 +414,7 @@ private: ItemReader *m_reader; Evaluator *m_evaluator; QMap<QString, QStringList> m_moduleDirListCache; + QHash<std::pair<QString, QualifiedId>, std::pair<bool, QString>> m_existingModulePathCache; // The keys are file paths, the values are module prototype items accompanied by a profile. std::unordered_map<QString, std::vector<std::pair<Item *, QString>>> m_modulePrototypes; @@ -425,8 +429,8 @@ private: struct DependsChainEntry { - DependsChainEntry(const QualifiedId &name, const CodeLocation &location) - : name(name), location(location) + DependsChainEntry(QualifiedId name, const CodeLocation &location) + : name(std::move(name)), location(location) { } @@ -437,10 +441,10 @@ private: class DependsChainManager; std::vector<DependsChainEntry> m_dependsChain; - QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes; + QHash<QString, std::vector<ProbeConstPtr>> m_oldProjectProbes; QHash<QString, std::vector<ProbeConstPtr>> m_oldProductProbes; FileTime m_lastResolveTime; - QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes; + QHash<CodeLocation, std::vector<ProbeConstPtr>> m_currentProbes; QVariantMap m_storedProfiles; QVariantMap m_localProfiles; std::multimap<QString, const ProductContext *> m_productsByName; diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp index 053e90d53..c5deaae04 100644 --- a/src/lib/corelib/language/modulemerger.cpp +++ b/src/lib/corelib/language/modulemerger.cpp @@ -50,15 +50,18 @@ namespace qbs { namespace Internal { -ModuleMerger::ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge) +ModuleMerger::ModuleMerger(Logger &logger, Item *productItem, const QString &productName, + const Item::Modules::iterator &modulesBegin, + const Item::Modules::iterator &modulesEnd) : m_logger(logger) - , m_rootItem(root) - , m_mergedModule(moduleToMerge) - , m_required(moduleToMerge.required) - , m_isBaseModule(moduleToMerge.name.first() == StringConstants::qbsModule()) - , m_versionRange(moduleToMerge.versionRange) + , m_productItem(productItem) + , m_mergedModule(*modulesBegin) + , m_isBaseModule(m_mergedModule.name.first() == StringConstants::qbsModule()) + , m_isShadowProduct(productName.startsWith(StringConstants::shadowProductPrefix())) + , m_modulesBegin(std::next(modulesBegin)) + , m_modulesEnd(modulesEnd) { - QBS_CHECK(moduleToMerge.item->type() == ItemType::ModuleInstance); + QBS_CHECK(modulesBegin->item->type() == ItemType::ModuleInstance); } void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace) @@ -83,48 +86,39 @@ void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerIt } } -void ModuleMerger::replaceItemInScopes(Item *toReplace) -{ - // In insertProperties(), we potentially call setDefiningItem() with the "wrong" - // (to-be-replaced) module instance as an argument. If such module instances - // are dependencies of other modules, they have the depending module's instance - // as their "instance scope", which is the scope of their scope. This function takes - // care that the "wrong" definingItem of values in sub-modules still has the "right" - // instance scope, namely our merged module instead of some other instance. - for (const Item::Module &module : toReplace->modules()) { - for (const ValuePtr &property : module.item->properties()) { - ValuePtr v = property; - do { - if (v->definingItem() && v->definingItem()->scope() - && v->definingItem()->scope()->scope() == toReplace) { - v->definingItem()->scope()->setScope(m_mergedModule.item); - } - v = v->next(); - } while (v); - } - } -} - void ModuleMerger::start() { + // Iterate over any module that our product depends on. These modules + // may depend on m_mergedModule and contribute property assignments. + Item::PropertyMap props; + for (auto module = m_modulesBegin; module != m_modulesEnd; module++) + mergeModule(&props, *module); + + // Module property assignments in the product have the highest priority + // and are thus prepended. Item::Module m; - m.item = m_rootItem; - const Item::PropertyMap props = dfs(m, Item::PropertyMap()); - if (m_required) - m_mergedModule.required = true; - m_mergedModule.versionRange.narrowDown(m_versionRange); - Item::PropertyMap mergedProps = m_mergedModule.item->properties(); + m.item = m_productItem; + mergeModule(&props, m); + // The module's prototype is the essential unmodified module as loaded + // from the cache. Item *moduleProto = m_mergedModule.item->prototype(); while (moduleProto->prototype()) moduleProto = moduleProto->prototype(); + // The prototype item might contain default values which get appended in + // case of list properties. Scalar properties will only be set if not + // already specified above. + Item::PropertyMap mergedProps = m_mergedModule.item->properties(); for (auto it = props.constBegin(); it != props.constEnd(); ++it) { appendPrototypeValueToNextChain(moduleProto, it.key(), it.value()); mergedProps[it.key()] = it.value(); } + m_mergedModule.item->setProperties(mergedProps); + // Update all sibling instances of the to-be-merged module to behave identical + // to the merged module. for (Item *moduleInstanceContainer : qAsConst(m_moduleInstanceContainers)) { Item::Modules modules; for (const Item::Module &dep : moduleInstanceContainer->modules()) { @@ -133,11 +127,9 @@ void ModuleMerger::start() if (isTheModule && m.item != m_mergedModule.item) { QBS_CHECK(m.item->type() == ItemType::ModuleInstance); replaceItemInValues(m.name, moduleInstanceContainer, m.item); - replaceItemInScopes(m.item); m.item = m_mergedModule.item; - if (m_required) - m.required = true; - m.versionRange.narrowDown(m_versionRange); + m.required = m_mergedModule.required; + m.versionRange = m_mergedModule.versionRange; } modules << m; } @@ -145,94 +137,26 @@ void ModuleMerger::start() } } -Item::PropertyMap ModuleMerger::dfs(const Item::Module &m, Item::PropertyMap props) +void ModuleMerger::mergeModule(Item::PropertyMap *dstProps, const Item::Module &module) { - Item *moduleInstance = nullptr; - size_t numberOfOutprops = m.item->modules().size(); - for (const Item::Module &dep : m.item->modules()) { - if (dep.name == m_mergedModule.name) { - --numberOfOutprops; - moduleInstance = dep.item; - insertProperties(&props, moduleInstance, ScalarProperties); - m_moduleInstanceContainers << m.item; - if (dep.required) - m_required = true; - m_versionRange.narrowDown(dep.versionRange); - break; - } - } - - std::vector<Item::PropertyMap> outprops; - outprops.reserve(numberOfOutprops); - for (const Item::Module &dep : m.item->modules()) { - if (dep.item != moduleInstance) - outprops.push_back(dfs(dep, props)); - } - - if (!outprops.empty()) { - props = outprops.front(); - for (size_t i = 1; i < outprops.size(); ++i) - mergeOutProps(&props, outprops.at(i)); - } - - if (moduleInstance) - insertProperties(&props, moduleInstance, ListProperties); - - const bool isNonPresentModule = m.item->type() != ItemType::Product - && !m.item->isPresentModule(); - return isNonPresentModule ? Item::PropertyMap() : props; -} - -void ModuleMerger::mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src) -{ - for (auto it = src.constBegin(); it != src.constEnd(); ++it) { - ValuePtr &v = (*dst)[it.key()]; - if (!v) { - v = it.value(); - QBS_ASSERT(it.value(), continue); - continue; - } - if (v->type() != Value::JSSourceValueType) - continue; - if (it.value()->type() != Value::JSSourceValueType) - continue; - // possible conflict - const JSSourceValuePtr dstVal = std::static_pointer_cast<JSSourceValue>(v); - JSSourceValuePtr srcVal = std::static_pointer_cast<JSSourceValue>(it.value()); - - const PropertyDeclaration pd = m_decls.value(srcVal); - QBS_CHECK(pd.isValid()); - - if (pd.isScalar()) { - if (dstVal->sourceCode() != srcVal->sourceCode()) { - m_logger.qbsWarning() << Tr::tr("Conflicting scalar values at %1 and %2.").arg( - dstVal->location().toString(), - srcVal->location().toString()); - // TODO: yield error with a hint how to solve the conflict. - } - v = it.value(); - } else { - lastInNextChain(dstVal)->setNext(srcVal); - } - } -} + const Item::Module *dep = findModule(module.item, m_mergedModule.name); + if (!dep) + return; -void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type) -{ - Set<const Item *> &seenInstances = type == ScalarProperties - ? m_seenInstancesTopDown : m_seenInstancesBottomUp; + const bool mergingProductItem = (module.item == m_productItem); + Item *srcItem = dep->item; Item *origSrcItem = srcItem; do { - if (seenInstances.insert(srcItem).second) { - for (Item::PropertyMap::const_iterator it = srcItem->properties().constBegin(); - it != srcItem->properties().constEnd(); ++it) { + if (m_seenInstances.insert(srcItem).second) { + for (auto it = srcItem->properties().constBegin(); + it != srcItem->properties().constEnd(); ++it) { const ValuePtr &srcVal = it.value(); if (srcVal->type() == Value::ItemValueType) continue; if (it.key() == StringConstants::qbsSourceDirPropertyInternal()) continue; const PropertyDeclaration srcDecl = srcItem->propertyDeclaration(it.key()); - if (!srcDecl.isValid() || srcDecl.isScalar() != (type == ScalarProperties)) + if (!srcDecl.isValid()) continue; // Scalar variant values could stem from product multiplexing, in which case @@ -242,21 +166,51 @@ void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, Prope continue; } - ValuePtr &v = (*dst)[it.key()]; - if (v && type == ScalarProperties) - continue; - ValuePtr clonedVal = srcVal->clone(); - m_decls[clonedVal] = srcDecl; - clonedVal->setDefiningItem(origSrcItem); - if (v) { - QBS_CHECK(!clonedVal->next()); - clonedVal->setNext(v); + ValuePtr clonedSrcVal = srcVal->clone(); + clonedSrcVal->setDefiningItem(origSrcItem); + + ValuePtr &dstVal = (*dstProps)[it.key()]; + if (dstVal) { + if (srcDecl.isScalar()) { + // Scalar properties get replaced. + if ((dstVal->type() == Value::JSSourceValueType) + && (srcVal->type() == Value::JSSourceValueType)) { + // Warn only about conflicting source code values + const JSSourceValuePtr dstJsVal = + std::static_pointer_cast<JSSourceValue>(dstVal); + const JSSourceValuePtr srcJsVal = + std::static_pointer_cast<JSSourceValue>(srcVal); + const bool overriddenInProduct = + m_mergedModule.item->properties().contains(it.key()); + + if (dstJsVal->sourceCode() != srcJsVal->sourceCode() + && !mergingProductItem && !overriddenInProduct + && !m_isShadowProduct) { + m_logger.qbsWarning() + << Tr::tr("Conflicting scalar values at %1 and %2.").arg( + dstJsVal->location().toString(), + srcJsVal->location().toString()); + } + } + } else { + // List properties get prepended + QBS_CHECK(!clonedSrcVal->next()); + clonedSrcVal->setNext(dstVal); + } } - v = clonedVal; + dstVal = clonedSrcVal; } } srcItem = srcItem->prototype(); } while (srcItem && srcItem->type() == ItemType::ModuleInstance); + + // Update dependency constraints + if (dep->required) + m_mergedModule.required = true; + m_mergedModule.versionRange.narrowDown(dep->versionRange); + + // We need to touch the unmerged module instances later once more + m_moduleInstanceContainers << module.item; } void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName, @@ -288,5 +242,23 @@ ValuePtr ModuleMerger::lastInNextChain(const ValuePtr &v) return n; } +const Item::Module *ModuleMerger::findModule(const Item *item, const QualifiedId &name) +{ + for (const auto &module : item->modules()) { + if (module.name == name) + return &module; + } + return nullptr; +} + +void ModuleMerger::merge(Logger &logger, Item *product, const QString &productName, + Item::Modules *topSortedModules) +{ + for (auto it = topSortedModules->begin(); it != topSortedModules->end(); ++it) + ModuleMerger(logger, product, productName, it, topSortedModules->end()).start(); +} + + + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/modulemerger.h b/src/lib/corelib/language/modulemerger.h index 3cc3ba08a..469dc86c4 100644 --- a/src/lib/corelib/language/modulemerger.h +++ b/src/lib/corelib/language/modulemerger.h @@ -54,32 +54,33 @@ namespace Internal { class ModuleMerger { public: - ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge); - void start(); + static void merge(Logger &logger, Item *productItem, const QString &productName, + Item::Modules *topSortedModules); private: - Item::PropertyMap dfs(const Item::Module &m, Item::PropertyMap props); - void mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src); + ModuleMerger(Logger &logger, Item *productItem, const QString &productName, + const Item::Modules::iterator &modulesBegin, + const Item::Modules::iterator &modulesEnd); + void appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName, const ValuePtr &sv); - static ValuePtr lastInNextChain(const ValuePtr &v); - - enum PropertiesType { ScalarProperties, ListProperties }; - void insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type); + void mergeModule(Item::PropertyMap *props, const Item::Module &m); void replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace); - void replaceItemInScopes(Item *toReplace); + void start(); + + static ValuePtr lastInNextChain(const ValuePtr &v); + static const Item::Module *findModule(const Item *item, const QualifiedId &name); Logger &m_logger; - Item * const m_rootItem; + Item * const m_productItem; Item::Module &m_mergedModule; Item *m_clonedModulePrototype = nullptr; - QHash<ValuePtr, PropertyDeclaration> m_decls; - Set<const Item *> m_seenInstancesTopDown; - Set<const Item *> m_seenInstancesBottomUp; + Set<const Item *> m_seenInstances; Set<Item *> m_moduleInstanceContainers; - bool m_required; const bool m_isBaseModule; - VersionRange m_versionRange; + const bool m_isShadowProduct; + const Item::Modules::iterator m_modulesBegin; + const Item::Modules::iterator m_modulesEnd; }; } // namespace Internal diff --git a/src/lib/corelib/language/moduleproviderinfo.h b/src/lib/corelib/language/moduleproviderinfo.h index fef9d9765..4f757d3d9 100644 --- a/src/lib/corelib/language/moduleproviderinfo.h +++ b/src/lib/corelib/language/moduleproviderinfo.h @@ -55,9 +55,12 @@ class ModuleProviderInfo { public: ModuleProviderInfo() = default; - ModuleProviderInfo(const QualifiedId &name, const QVariantMap &config, - const QStringList &searchPaths, bool transientOutput) - : name(name), config(config), searchPaths(searchPaths), transientOutput(transientOutput) + ModuleProviderInfo(QualifiedId name, QVariantMap config, + QStringList searchPaths, bool transientOutput) + : name(std::move(name)) + , config(std::move(config)) + , searchPaths(std::move(searchPaths)) + , transientOutput(transientOutput) {} static QString outputBaseDirName() { return QStringLiteral("genmodules"); } diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index 049472310..fd6063381 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -71,6 +71,7 @@ #include <QtCore/qregexp.h> #include <algorithm> +#include <memory> #include <queue> namespace qbs { @@ -126,9 +127,7 @@ ProjectResolver::ProjectResolver(Evaluator *evaluator, ModuleLoaderResult loadRe QBS_CHECK(FileInfo::isAbsolute(m_setupParams.buildRoot())); } -ProjectResolver::~ProjectResolver() -{ -} +ProjectResolver::~ProjectResolver() = default; void ProjectResolver::setProgressObserver(ProgressObserver *observer) { @@ -812,7 +811,7 @@ void ProjectResolver::resolveGroupFully(Item *item, ProjectResolver::ProjectCont group->targetOfModule = moduleProp->value().toString(); ErrorInfo fileError; if (!patterns.empty()) { - group->wildcards = std::unique_ptr<SourceWildCards>(new SourceWildCards); + group->wildcards = std::make_unique<SourceWildCards>(); SourceWildCards *wildcards = group->wildcards.get(); wildcards->group = group.get(); wildcards->excludePatterns = m_evaluator->stringListValue( @@ -988,7 +987,7 @@ void ProjectResolver::resolveShadowProduct(Item *item, ProjectResolver::ProjectC try { adaptExportedPropertyValues(item); } catch (const ErrorInfo &) {} - m_productExportInfo.push_back(std::make_pair(m_productContext->product, item)); + m_productExportInfo.emplace_back(m_productContext->product, item); } void ProjectResolver::setupExportedProperties(const Item *item, const QString &namePrefix, @@ -1460,7 +1459,7 @@ void ProjectResolver::matchArtifactProperties(const ResolvedProductPtr &product, const std::vector<SourceArtifactPtr> &artifacts) { for (const SourceArtifactPtr &artifact : artifacts) { - for (const ArtifactPropertiesConstPtr &artifactProperties : product->artifactProperties) { + for (const auto &artifactProperties : product->artifactProperties) { if (!artifact->isTargetOfModule() && artifact->fileTags.intersects(artifactProperties->fileTagsFilter())) { artifact->properties = artifactProperties->propertyMap(); diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h index 428ba144d..a1e24a555 100644 --- a/src/lib/corelib/language/projectresolver.h +++ b/src/lib/corelib/language/projectresolver.h @@ -139,9 +139,9 @@ private: struct ProductDependencyInfo { - ProductDependencyInfo(const ResolvedProductPtr &product, - const QVariantMap ¶meters = QVariantMap()) - : product(product), parameters(parameters) + ProductDependencyInfo(ResolvedProductPtr product, + QVariantMap parameters = QVariantMap()) + : product(std::move(product)), parameters(std::move(parameters)) { } diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h index 204704672..78061bf6f 100644 --- a/src/lib/corelib/language/property.h +++ b/src/lib/corelib/language/property.h @@ -65,9 +65,13 @@ public: { } - Property(const QString &product, const QString &module, const QString &property, - const QVariant &v, Kind k) - : productName(product), moduleName(module), propertyName(property), value(v), kind(k) + Property(QString product, QString module, QString property, + QVariant v, Kind k) + : productName(std::move(product)) + , moduleName(std::move(module)) + , propertyName(std::move(property)) + , value(std::move(v)) + , kind(k) { } diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp index 5ea6a3d88..abe6a1626 100644 --- a/src/lib/corelib/language/propertydeclaration.cpp +++ b/src/lib/corelib/language/propertydeclaration.cpp @@ -84,20 +84,11 @@ PropertyDeclaration::PropertyDeclaration(const QString &name, Type type, d->flags = flags; } -PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) - : d(other.d) -{ -} +PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default; -PropertyDeclaration::~PropertyDeclaration() -{ -} +PropertyDeclaration::~PropertyDeclaration() = default; -PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) -{ - d = other.d; - return *this; -} +PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default; bool PropertyDeclaration::isValid() const { diff --git a/src/lib/corelib/language/propertymapinternal.cpp b/src/lib/corelib/language/propertymapinternal.cpp index 2a35e2a6a..fe0f672c5 100644 --- a/src/lib/corelib/language/propertymapinternal.cpp +++ b/src/lib/corelib/language/propertymapinternal.cpp @@ -58,13 +58,9 @@ namespace Internal { * \sa ResolvedProduct * \sa SourceArtifact */ -PropertyMapInternal::PropertyMapInternal() -{ -} +PropertyMapInternal::PropertyMapInternal() = default; -PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) : m_value(other.m_value) -{ -} +PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) = default; QVariant PropertyMapInternal::moduleProperty(const QString &moduleName, const QString &key, bool *isPresent) const diff --git a/src/lib/corelib/language/qualifiedid.cpp b/src/lib/corelib/language/qualifiedid.cpp index 5cc315bb1..9eb0e9463 100644 --- a/src/lib/corelib/language/qualifiedid.cpp +++ b/src/lib/corelib/language/qualifiedid.cpp @@ -44,9 +44,7 @@ namespace qbs { namespace Internal { -QualifiedId::QualifiedId() -{ -} +QualifiedId::QualifiedId() = default; QualifiedId::QualifiedId(const QString &singlePartName) : QStringList(singlePartName) diff --git a/src/lib/corelib/language/resolvedfilecontext.h b/src/lib/corelib/language/resolvedfilecontext.h index 81a3f7472..d783cf725 100644 --- a/src/lib/corelib/language/resolvedfilecontext.h +++ b/src/lib/corelib/language/resolvedfilecontext.h @@ -65,7 +65,7 @@ public: pool.serializationOp<opType>(m_filePath, m_jsExtensions, m_searchPaths, m_jsImports); } private: - ResolvedFileContext() {} + ResolvedFileContext() = default; ResolvedFileContext(const FileContextBase &ctx); }; diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp index 7c531e764..e79ec54d7 100644 --- a/src/lib/corelib/language/scriptengine.cpp +++ b/src/lib/corelib/language/scriptengine.cpp @@ -478,19 +478,18 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt return context->throwError( ScriptEngine::tr("require: internal error. No search paths.")); - const QString uri = moduleName; if (engine->m_logger.debugEnabled()) { engine->m_logger.qbsDebug() - << "[require] loading extension " << uri; + << "[require] loading extension " << moduleName; } - QString uriAsPath = uri; - uriAsPath.replace(QLatin1Char('.'), QLatin1Char('/')); + QString moduleNameAsPath = moduleName; + moduleNameAsPath.replace(QLatin1Char('.'), QLatin1Char('/')); const QStringList searchPaths = engine->m_extensionSearchPathsStack.top(); - const QString dirPath = findExtensionDir(searchPaths, uriAsPath); + const QString dirPath = findExtensionDir(searchPaths, moduleNameAsPath); if (dirPath.isEmpty()) { - if (uri.startsWith(QStringLiteral("qbs."))) - return loadInternalExtension(context, engine, uri); + if (moduleName.startsWith(QStringLiteral("qbs."))) + return loadInternalExtension(context, engine, moduleName); } else { QDirIterator dit(dirPath, StringConstants::jsFileWildcards(), QDir::Files | QDir::Readable); diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp index 656f38874..342fbd89a 100644 --- a/src/lib/corelib/language/value.cpp +++ b/src/lib/corelib/language/value.cpp @@ -61,9 +61,7 @@ Value::Value(const Value &other) { } -Value::~Value() -{ -} +Value::~Value() = default; Item *Value::definingItem() const { @@ -115,9 +113,7 @@ JSSourceValuePtr JSSourceValue::create(bool createdByPropertiesBlock) return JSSourceValuePtr(new JSSourceValue(createdByPropertiesBlock)); } -JSSourceValue::~JSSourceValue() -{ -} +JSSourceValue::~JSSourceValue() = default; ValuePtr JSSourceValue::clone() const { @@ -200,7 +196,7 @@ VariantValuePtr VariantValue::create(const QVariant &v) ValuePtr VariantValue::clone() const { - return VariantValuePtr(new VariantValue(*this)); + return std::make_shared<VariantValue>(*this); } const VariantValuePtr &VariantValue::falseValue() diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h index f27406f2d..d3a748d92 100644 --- a/src/lib/corelib/language/value.h +++ b/src/lib/corelib/language/value.h @@ -151,14 +151,14 @@ public: struct PropertyData { PropertyData() = default; - PropertyData(const QString &v, const CodeLocation &l) : value(v), location(l) {} + PropertyData(QString v, const CodeLocation &l) : value(std::move(v)), location(l) {} QString value; CodeLocation location; }; - Alternative() { } - Alternative(const PropertyData &c, const PropertyData &o, const JSSourceValuePtr &v) - : condition(c), overrideListProperties(o), value(v) {} + Alternative() = default; + Alternative(PropertyData c, PropertyData o, JSSourceValuePtr v) + : condition(std::move(c)), overrideListProperties(std::move(o)), value(std::move(v)) {} Alternative clone() const { return Alternative(condition, overrideListProperties, diff --git a/src/lib/corelib/logging/logger.cpp b/src/lib/corelib/logging/logger.cpp index 71ca6a96c..2ed29c4c2 100644 --- a/src/lib/corelib/logging/logger.cpp +++ b/src/lib/corelib/logging/logger.cpp @@ -50,9 +50,9 @@ #include <QtCore/qvariant.h> #include <cstdarg> +#include <cstdio> #include <mutex> #include <set> -#include <stdio.h> namespace qbs { namespace Internal { @@ -183,17 +183,20 @@ LogWriter operator<<(LogWriter w, const QVariant &variant) LogWriter operator<<(LogWriter w, int n) { - return w << QString::number(n); + w.write(QString::number(n)); + return w; } LogWriter operator<<(LogWriter w, qint64 n) { - return w << QString::number(n); + w.write(QString::number(n)); + return w; } LogWriter operator<<(LogWriter w, bool b) { - return w << QString::fromLatin1(b ? "true" : "false"); + w.write(QString::fromLatin1(b ? "true" : "false")); + return w; } LogWriter operator<<(LogWriter w, const MessageTag &tag) diff --git a/src/lib/corelib/logging/logger.h b/src/lib/corelib/logging/logger.h index b0b5dd6f3..389dc7e05 100644 --- a/src/lib/corelib/logging/logger.h +++ b/src/lib/corelib/logging/logger.h @@ -70,7 +70,7 @@ public: // a << chain prints the accumulated data LogWriter(const LogWriter &other); ~LogWriter(); - const LogWriter &operator=(const LogWriter &other); + const LogWriter &operator=(const LogWriter &other); // NOLINT void write(char c); void write(const char *str); @@ -90,7 +90,7 @@ private: class QBS_EXPORT MessageTag { public: - explicit MessageTag(const QString &tag) : m_tag(tag) {} + explicit MessageTag(QString tag) : m_tag(std::move(tag)) {} const QString &tag() const { return m_tag; } diff --git a/src/lib/corelib/parser/qmljsast_p.h b/src/lib/corelib/parser/qmljsast_p.h index 8c6f32140..dcee233da 100644 --- a/src/lib/corelib/parser/qmljsast_p.h +++ b/src/lib/corelib/parser/qmljsast_p.h @@ -221,7 +221,7 @@ public: // NOTE: node destructors are never called, // instead we block free the memory // (see the NodePool class) - virtual ~Node() {} + virtual ~Node() = default; virtual ExpressionNode *expressionCast(); virtual BinaryExpression *binaryExpressionCast(); @@ -245,7 +245,7 @@ public: class QML_PARSER_EXPORT ExpressionNode: public Node { public: - ExpressionNode() {} + ExpressionNode() = default; ExpressionNode *expressionCast() override; }; @@ -253,7 +253,7 @@ public: class QML_PARSER_EXPORT Statement: public Node { public: - Statement() {} + Statement() = default; Statement *statementCast() override; }; @@ -2303,7 +2303,7 @@ public: return imports->firstSourceLocation(); else if (members) return members->firstSourceLocation(); - return SourceLocation(); + return {}; } SourceLocation lastSourceLocation() const override @@ -2312,7 +2312,7 @@ public: return members->lastSourceLocation(); else if (imports) return imports->lastSourceLocation(); - return SourceLocation(); + return {}; } // attributes @@ -2519,7 +2519,7 @@ public: else if (const auto varStmt = cast<const VariableStatement *>(sourceElement)) return varStmt->firstSourceLocation(); - return SourceLocation(); + return {}; } SourceLocation lastSourceLocation() const override @@ -2529,7 +2529,7 @@ public: else if (const auto varStmt = cast<const VariableStatement *>(sourceElement)) return varStmt->lastSourceLocation(); - return SourceLocation(); + return {}; } void accept0(Visitor *visitor) override; diff --git a/src/lib/corelib/parser/qmljsastvisitor.cpp b/src/lib/corelib/parser/qmljsastvisitor.cpp index fcb84ec7e..f034a147e 100644 --- a/src/lib/corelib/parser/qmljsastvisitor.cpp +++ b/src/lib/corelib/parser/qmljsastvisitor.cpp @@ -42,13 +42,9 @@ namespace QbsQmlJS { namespace AST { -Visitor::Visitor() -{ -} +Visitor::Visitor() = default; -Visitor::~Visitor() -{ -} +Visitor::~Visitor() = default; } // namespace AST } // namespace QbsQmlJS diff --git a/src/lib/corelib/parser/qmljsengine_p.cpp b/src/lib/corelib/parser/qmljsengine_p.cpp index 211743190..92ac6452a 100644 --- a/src/lib/corelib/parser/qmljsengine_p.cpp +++ b/src/lib/corelib/parser/qmljsengine_p.cpp @@ -117,12 +117,9 @@ double integerFromString(const QString &str, int radix) } -Engine::Engine() - : _lexer(nullptr), _directives(nullptr) -{ } +Engine::Engine() = default; -Engine::~Engine() -{ } +Engine::~Engine() = default; void Engine::setCode(const QString &code) { _code = code; } diff --git a/src/lib/corelib/parser/qmljsengine_p.h b/src/lib/corelib/parser/qmljsengine_p.h index 6ff53a6e9..c55d525f8 100644 --- a/src/lib/corelib/parser/qmljsengine_p.h +++ b/src/lib/corelib/parser/qmljsengine_p.h @@ -59,6 +59,7 @@ #include <QtCore/qstring.h> #include <set> +#include <utility> namespace QbsQmlJS { @@ -74,8 +75,8 @@ public: DiagnosticMessage() : kind(Error) {} - DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message) - : kind(kind), loc(loc), message(message) {} + DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, QString message) + : kind(kind), loc(loc), message(std::move(message)) {} bool isWarning() const { return kind == Warning; } @@ -90,8 +91,8 @@ public: class QBS_AUTOTEST_EXPORT Engine { - Lexer *_lexer; - Directives *_directives; + Lexer *_lexer{nullptr}; + Directives *_directives{nullptr}; MemoryPool _pool; QList<AST::SourceLocation> _comments; QString _extraCode; diff --git a/src/lib/corelib/parser/qmljslexer.cpp b/src/lib/corelib/parser/qmljslexer.cpp index dc6ac8a0f..815f1ef0d 100644 --- a/src/lib/corelib/parser/qmljslexer.cpp +++ b/src/lib/corelib/parser/qmljslexer.cpp @@ -78,8 +78,8 @@ static QChar convertHex(QChar c1, QChar c2) static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4) { - return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()), - (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode())); + return {uchar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode())), + uchar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()))}; } Lexer::Lexer(Engine *engine) @@ -178,7 +178,7 @@ int Lexer::lex() _tokenSpell = QStringRef(); _tokenKind = scanToken(); - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); _delimited = false; _restrictedKeyword = false; @@ -397,7 +397,8 @@ again: scanChar(); if (_engine) { - _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4, + _engine->addComment(tokenOffset() + 2, + int(_codePtr - _tokenStartPtr - 1 - 4), tokenStartLine(), tokenStartColumn() + 2); } @@ -412,7 +413,7 @@ again: scanChar(); } if (_engine) { - _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2, + _engine->addComment(tokenOffset() + 2, int(_codePtr - _tokenStartPtr - 1 - 2), tokenStartLine(), tokenStartColumn() + 2); } goto again; @@ -554,7 +555,8 @@ again: if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) { break; } else if (_char == quote) { - _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode); + _tokenSpell = _engine->midRef( + int(startCode - _code.unicode() - 1), int(_codePtr - startCode)); scanChar(); return T_STRING_LITERAL; @@ -706,7 +708,7 @@ again: if (! identifierWithEscapeChars) { identifierWithEscapeChars = true; _tokenText.resize(0); - _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1); + _tokenText.insert(0, _tokenStartPtr, int(_codePtr - _tokenStartPtr - 1)); _validTokenText = true; } @@ -719,7 +721,7 @@ again: return T_ERROR; } } else { - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); int kind = T_IDENTIFIER; @@ -727,10 +729,12 @@ again: kind = classify(_tokenStartPtr, _tokenLength, _qmlMode); if (_engine) { - if (kind == T_IDENTIFIER && identifierWithEscapeChars) + if (kind == T_IDENTIFIER && identifierWithEscapeChars) { _tokenSpell = _engine->newStringRef(_tokenText); - else - _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength); + } else { + _tokenSpell = _engine->midRef( + int(_tokenStartPtr - _code.unicode()), _tokenLength); + } } return kind; @@ -891,7 +895,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix) scanChar(); } - _tokenLength = _codePtr - _tokenStartPtr - 1; + _tokenLength = int(_codePtr - _tokenStartPtr - 1); return true; case '\\': @@ -995,7 +999,7 @@ int Lexer::tokenEndLine() const int Lexer::tokenEndColumn() const { - return _codePtr - _lastLinePtr; + return int(_codePtr - _lastLinePtr); } QString Lexer::tokenText() const diff --git a/src/lib/corelib/parser/qmljslexer_p.h b/src/lib/corelib/parser/qmljslexer_p.h index e9dff1dd4..cf41fb255 100644 --- a/src/lib/corelib/parser/qmljslexer_p.h +++ b/src/lib/corelib/parser/qmljslexer_p.h @@ -62,7 +62,7 @@ class Engine; class QML_PARSER_EXPORT Directives { public: - virtual ~Directives() {} + virtual ~Directives() = default; virtual void pragmaLibrary() { diff --git a/src/lib/corelib/parser/qmljsmemorypool_p.h b/src/lib/corelib/parser/qmljsmemorypool_p.h index 897348712..f7de7bbfb 100644 --- a/src/lib/corelib/parser/qmljsmemorypool_p.h +++ b/src/lib/corelib/parser/qmljsmemorypool_p.h @@ -154,8 +154,8 @@ class QML_PARSER_EXPORT Managed void operator = (const Managed &other); public: - Managed() {} - ~Managed() {} + Managed() = default; + ~Managed() = default; void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); } void operator delete(void *) {} diff --git a/src/lib/corelib/parser/qmljsparser.cpp b/src/lib/corelib/parser/qmljsparser.cpp index 6390c8a9d..d2c87c7cb 100644 --- a/src/lib/corelib/parser/qmljsparser.cpp +++ b/src/lib/corelib/parser/qmljsparser.cpp @@ -40,7 +40,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qcoreapplication.h> -#include <string.h> +#include <cstring> #include "qmljsengine_p.h" #include "qmljslexer_p.h" @@ -328,7 +328,7 @@ case 26: { } break; case 27: { - const auto node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0); + const auto node = new (pool) AST::UiObjectInitializer(nullptr); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; @@ -614,7 +614,7 @@ case 80: { } break; case 81: { - const auto node = new (pool) AST::ArrayLiteral((AST::Elision *) 0); + const auto node = new (pool) AST::ArrayLiteral(static_cast<AST::Elision *>(nullptr)); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; @@ -635,8 +635,7 @@ case 83: { } break; case 84: { - const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), - (AST::Elision *) 0); + const auto node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), nullptr); node->lbracketToken = loc(1); node->commaToken = loc(3); node->rbracketToken = loc(4); @@ -700,7 +699,7 @@ case 89: { } break; case 90: { - sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); + sym(1).Node = new (pool) AST::ElementList(nullptr, sym(1).Expression); } break; case 91: { @@ -708,8 +707,7 @@ case 91: { } break; case 92: { - const auto node = new (pool) AST::ElementList(sym(1).ElementList, - (AST::Elision *) 0, sym(3).Expression); + const auto node = new (pool) AST::ElementList(sym(1).ElementList, nullptr, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; diff --git a/src/lib/corelib/tools/buildoptions.cpp b/src/lib/corelib/tools/buildoptions.cpp index 75417ab0b..e4e9ba17f 100644 --- a/src/lib/corelib/tools/buildoptions.cpp +++ b/src/lib/corelib/tools/buildoptions.cpp @@ -91,19 +91,11 @@ BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate) { } -BuildOptions::BuildOptions(const BuildOptions &other) : d(other.d) -{ -} +BuildOptions::BuildOptions(const BuildOptions &other) = default; -BuildOptions &BuildOptions::operator=(const BuildOptions &other) -{ - d = other.d; - return *this; -} +BuildOptions &BuildOptions::operator=(const BuildOptions &other) = default; -BuildOptions::~BuildOptions() -{ -} +BuildOptions::~BuildOptions() = default; /*! * \brief If non-empty, qbs pretends that only these files have changed. diff --git a/src/lib/corelib/tools/clangclinfo.cpp b/src/lib/corelib/tools/clangclinfo.cpp new file mode 100644 index 000000000..4e1022c28 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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 "clangclinfo.h" + +#include "hostosinfo.h" +#include "msvcinfo.h" +#include "stlutils.h" + +namespace qbs { +namespace Internal { + +static std::vector<MSVCInstallInfo> compatibleMsvcs(Logger &logger) +{ + auto msvcs = MSVCInstallInfo::installedMSVCs(logger); + auto filter = [](const MSVCInstallInfo &info) + { + const auto versions = info.version.split(QLatin1Char('.')); + if (versions.empty()) + return true; + bool ok = false; + const int major = versions.at(0).toInt(&ok); + return !(ok && major >= 15); // support MSVC2017 and above + }; + const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter); + msvcs.erase(it, msvcs.end()); + for (const auto &msvc: msvcs) { + auto vcvarsallPath = msvc.findVcvarsallBat(); + if (vcvarsallPath.isEmpty()) + continue; + } + return msvcs; +} + +static QString findCompatibleVcsarsallBat(const std::vector<MSVCInstallInfo> &msvcs) +{ + for (const auto &msvc: msvcs) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (!vcvarsallPath.isEmpty()) + return vcvarsallPath; + } + return {}; +} + +static QString wow6432Key() +{ +#ifdef Q_OS_WIN64 + return QStringLiteral("\\Wow6432Node"); +#else + return {}; +#endif +} + +static QString getToolchainInstallPath(const QFileInfo &compiler) +{ + return compiler.path(); // 1 level up +} + +QVariantMap ClangClInfo::toVariantMap() const +{ + return { + {QStringLiteral("toolchainInstallPath"), toolchainInstallPath}, + {QStringLiteral("vcvarsallPath"), vcvarsallPath}, + }; +} + +ClangClInfo ClangClInfo::fromCompilerFilePath(const QString &path, Logger &logger) +{ + const auto compilerName = QStringLiteral("clang-cl"); + const auto vcvarsallPath = findCompatibleVcsarsallBat(compatibleMsvcs(logger)); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + const auto toolchainInstallPath = getToolchainInstallPath(path); + return {toolchainInstallPath, vcvarsallPath}; +} + +std::vector<ClangClInfo> ClangClInfo::installedCompilers( + const std::vector<QString> &extraPaths, Logger &logger) +{ + std::vector<QString> compilerPaths; + compilerPaths.reserve(extraPaths.size()); + std::copy_if(extraPaths.begin(), extraPaths.end(), + std::back_inserter(compilerPaths), + [](const QString &path){ return !path.isEmpty(); }); + const auto compilerName = HostOsInfo::appendExecutableSuffix(QStringLiteral("clang-cl")); + + const QSettings registry( + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE%1\\LLVM\\LLVM").arg(wow6432Key()), + QSettings::NativeFormat); + const auto key = QStringLiteral("."); + if (registry.contains(key)) { + const auto compilerPath = QDir::fromNativeSeparators(registry.value(key).toString()) + + QStringLiteral("/bin/") + compilerName; + if (QFileInfo(compilerPath).exists()) + compilerPaths.push_back(compilerPath); + } + + // this branch can be useful in case user had two LLVM installations (e.g. 32bit & 64bit) + // but uninstalled one - in that case, registry will be empty + static const char * const envVarCandidates[] = {"ProgramFiles", "ProgramFiles(x86)"}; + for (const auto &envVar : envVarCandidates) { + const auto value + = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); + const auto compilerPath = value + QStringLiteral("/LLVM/bin/") + compilerName; + if (QFileInfo(compilerPath).exists() && !contains(compilerPaths, compilerPath)) + compilerPaths.push_back(compilerPath); + } + + const auto msvcs = compatibleMsvcs(logger); + const auto vcvarsallPath = findCompatibleVcsarsallBat(msvcs); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.") + .arg(compilerName); + return {}; + } + + std::vector<ClangClInfo> result; + result.reserve(compilerPaths.size() + msvcs.size()); + + for (const auto &path: compilerPaths) + result.push_back({getToolchainInstallPath(path), vcvarsallPath}); + + // If we didn't find custom LLVM installation, try to find if it's installed with Visual Studio + for (const auto &msvc : msvcs) { + const auto compilerPath = QStringLiteral("%1/VC/Tools/Llvm/bin/%2") + .arg(msvc.installDir, compilerName); + if (QFileInfo(compilerPath).exists()) { + const auto vcvarsallPath = msvc.findVcvarsallBat(); + if (vcvarsallPath.isEmpty()) { + logger.qbsWarning() + << Tr::tr("Found LLVM in %1, but vcvarsall.bat is missing.") + .arg(msvc.installDir); + } + + result.push_back({getToolchainInstallPath(compilerPath), vcvarsallPath}); + } + } + + return result; +} + +} // namespace Internal +} // namespace qbs diff --git a/src/lib/corelib/tools/clangclinfo.h b/src/lib/corelib/tools/clangclinfo.h new file mode 100644 index 000000000..76ae169f2 --- /dev/null +++ b/src/lib/corelib/tools/clangclinfo.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com) +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** 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_CLANGCLINFO_H +#define QBS_CLANGCLINFO_H + +#include "logging/logger.h" + +#include <QtCore/qstring.h> + +#include <vector> + +namespace qbs { +namespace Internal { + +class ClangClInfo +{ +public: + QString toolchainInstallPath; + QString vcvarsallPath; + + bool isEmpty() const { return toolchainInstallPath.isEmpty() && vcvarsallPath.isEmpty(); } + + QBS_EXPORT QVariantMap toVariantMap() const; + + QBS_EXPORT static ClangClInfo fromCompilerFilePath(const QString &path, Logger &logger); + QBS_EXPORT static std::vector<ClangClInfo> installedCompilers( + const std::vector<QString> &extraPaths, qbs::Internal::Logger &logger); +}; + +} // namespace Internal +} // namespace qbs + +#endif // QBS_CLANGCLINFO_H diff --git a/src/lib/corelib/tools/cleanoptions.cpp b/src/lib/corelib/tools/cleanoptions.cpp index b888fb1e8..affc9b3f7 100644 --- a/src/lib/corelib/tools/cleanoptions.cpp +++ b/src/lib/corelib/tools/cleanoptions.cpp @@ -58,7 +58,7 @@ public: bool logElapsedTime; }; -} +} // namespace Internal /*! * \class CleanOptions @@ -79,23 +79,15 @@ CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate) { } -CleanOptions::CleanOptions(const CleanOptions &other) : d(other.d) -{ -} +CleanOptions::CleanOptions(const CleanOptions &other) = default; CleanOptions::CleanOptions(CleanOptions &&other) Q_DECL_NOEXCEPT = default; -CleanOptions &CleanOptions::operator=(const CleanOptions &other) -{ - d = other.d; - return *this; -} +CleanOptions &CleanOptions::operator=(const CleanOptions &other) = default; CleanOptions &CleanOptions::operator=(CleanOptions &&other) Q_DECL_NOEXCEPT = default; -CleanOptions::~CleanOptions() -{ -} +CleanOptions::~CleanOptions() = default; /*! * \brief Returns true iff qbs will not actually remove any files, but just show what would happen. diff --git a/src/lib/corelib/tools/codelocation.cpp b/src/lib/corelib/tools/codelocation.cpp index 5eff378e1..542408795 100644 --- a/src/lib/corelib/tools/codelocation.cpp +++ b/src/lib/corelib/tools/codelocation.cpp @@ -75,9 +75,7 @@ public: int column = 0; }; -CodeLocation::CodeLocation() -{ -} +CodeLocation::CodeLocation() = default; CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, bool checkPath) : d(new CodeLocationPrivate) @@ -88,19 +86,11 @@ CodeLocation::CodeLocation(const QString &aFilePath, int aLine, int aColumn, boo d->column = aColumn; } -CodeLocation::CodeLocation(const CodeLocation &other) : d(other.d) -{ -} +CodeLocation::CodeLocation(const CodeLocation &other) = default; -CodeLocation &CodeLocation::operator=(const CodeLocation &other) -{ - d = other.d; - return *this; -} +CodeLocation &CodeLocation::operator=(const CodeLocation &other) = default; -CodeLocation::~CodeLocation() -{ -} +CodeLocation::~CodeLocation() = default; QString CodeLocation::filePath() const { diff --git a/src/lib/corelib/tools/error.cpp b/src/lib/corelib/tools/error.cpp index fc0b9377e..ff7ce46cf 100644 --- a/src/lib/corelib/tools/error.cpp +++ b/src/lib/corelib/tools/error.cpp @@ -89,6 +89,8 @@ ErrorItem::ErrorItem() : d(new ErrorItemPrivate) { } +ErrorItem::ErrorItem(ErrorItem &&rhs) noexcept = default; + ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocation, bool isBacktraceItem) : d(new ErrorItemPrivate) @@ -98,19 +100,12 @@ ErrorItem::ErrorItem(const QString &description, const CodeLocation &codeLocatio d->isBacktraceItem = isBacktraceItem; } -ErrorItem::ErrorItem(const ErrorItem &rhs) : d(rhs.d) -{ -} +ErrorItem::ErrorItem(const ErrorItem &rhs) = default; -ErrorItem &ErrorItem::operator=(const ErrorItem &other) -{ - d = other.d; - return *this; -} +ErrorItem &ErrorItem::operator=(const ErrorItem &other) = default; +ErrorItem &ErrorItem::operator=(ErrorItem &&other) noexcept = default; -ErrorItem::~ErrorItem() -{ -} +ErrorItem::~ErrorItem() = default; QString ErrorItem::description() const { @@ -194,9 +189,9 @@ ErrorInfo::ErrorInfo() : d(new ErrorInfoPrivate) { } -ErrorInfo::ErrorInfo(const ErrorInfo &rhs) : d(rhs.d) -{ -} +ErrorInfo::ErrorInfo(const ErrorInfo &rhs) = default; + +ErrorInfo::ErrorInfo(ErrorInfo &&rhs) noexcept = default; ErrorInfo::ErrorInfo(const QString &description, const CodeLocation &location, bool internalError) : d(new ErrorInfoPrivate) @@ -223,16 +218,11 @@ ErrorInfo::ErrorInfo(const QString &description, const QStringList &backtrace) } } +ErrorInfo &ErrorInfo::operator=(ErrorInfo &&other) noexcept = default; -ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) -{ - d = other.d; - return *this; -} +ErrorInfo &ErrorInfo::operator =(const ErrorInfo &other) = default; -ErrorInfo::~ErrorInfo() -{ -} +ErrorInfo::~ErrorInfo() = default; void ErrorInfo::appendBacktrace(const QString &description, const CodeLocation &location) { diff --git a/src/lib/corelib/tools/error.h b/src/lib/corelib/tools/error.h index abad85bad..36cf5e0ea 100644 --- a/src/lib/corelib/tools/error.h +++ b/src/lib/corelib/tools/error.h @@ -63,7 +63,9 @@ class QBS_EXPORT ErrorItem public: ErrorItem(); ErrorItem(const ErrorItem &rhs); + ErrorItem(ErrorItem &&rhs) noexcept; ErrorItem &operator=(const ErrorItem &other); + ErrorItem &operator=(ErrorItem &&other) noexcept; ~ErrorItem(); QString description() const; @@ -89,10 +91,12 @@ class QBS_EXPORT ErrorInfo public: ErrorInfo(); ErrorInfo(const ErrorInfo &rhs); + ErrorInfo(ErrorInfo &&rhs) noexcept; ErrorInfo(const QString &description, const CodeLocation &location = CodeLocation(), bool internalError = false); ErrorInfo(const QString &description, const QStringList &backtrace); ErrorInfo &operator=(const ErrorInfo &other); + ErrorInfo &operator=(ErrorInfo &&other) noexcept; ~ErrorInfo(); void appendBacktrace(const QString &description, const CodeLocation &location = CodeLocation()); diff --git a/src/lib/corelib/tools/executablefinder.cpp b/src/lib/corelib/tools/executablefinder.cpp index 4342c82f0..0dc06dd86 100644 --- a/src/lib/corelib/tools/executablefinder.cpp +++ b/src/lib/corelib/tools/executablefinder.cpp @@ -64,9 +64,9 @@ static QStringList populateExecutableSuffixes() QStringList ExecutableFinder::m_executableSuffixes = populateExecutableSuffixes(); -ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env) +ExecutableFinder::ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env) : m_product(std::move(product)) - , m_environment(std::move(env)) + , m_environment(env) // QProcessEnvironment doesn't have move-ctor, copy here { } diff --git a/src/lib/corelib/tools/executablefinder.h b/src/lib/corelib/tools/executablefinder.h index 9467756fc..ae834d911 100644 --- a/src/lib/corelib/tools/executablefinder.h +++ b/src/lib/corelib/tools/executablefinder.h @@ -53,7 +53,7 @@ namespace Internal { class ExecutableFinder { public: - ExecutableFinder(ResolvedProductPtr product, QProcessEnvironment env); + ExecutableFinder(ResolvedProductPtr product, const QProcessEnvironment &env); QString findExecutable(const QString &path, const QString &workingDirPath); diff --git a/src/lib/corelib/tools/fileinfo.cpp b/src/lib/corelib/tools/fileinfo.cpp index 8b0eedc27..1918117d6 100644 --- a/src/lib/corelib/tools/fileinfo.cpp +++ b/src/lib/corelib/tools/fileinfo.cpp @@ -50,7 +50,7 @@ #include <QtCore/qregexp.h> #if defined(Q_OS_UNIX) -#include <errno.h> +#include <cerrno> #include <sys/stat.h> #include <unistd.h> #elif defined(Q_OS_WIN) diff --git a/src/lib/corelib/tools/generateoptions.cpp b/src/lib/corelib/tools/generateoptions.cpp index 019e2eb48..596e0acb9 100644 --- a/src/lib/corelib/tools/generateoptions.cpp +++ b/src/lib/corelib/tools/generateoptions.cpp @@ -68,19 +68,11 @@ GenerateOptions::GenerateOptions() : d(new Internal::GenerateOptionsPrivate) { } -GenerateOptions::GenerateOptions(const GenerateOptions &other) : d(other.d) -{ -} +GenerateOptions::GenerateOptions(const GenerateOptions &other) = default; -GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) -{ - d = other.d; - return *this; -} +GenerateOptions &GenerateOptions::operator=(const GenerateOptions &other) = default; -GenerateOptions::~GenerateOptions() -{ -} +GenerateOptions::~GenerateOptions() = default; /*! * Returns the name of the generator used to create the external build system files. diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h index d7f718c19..0876d39ec 100644 --- a/src/lib/corelib/tools/hostosinfo.h +++ b/src/lib/corelib/tools/hostosinfo.h @@ -112,6 +112,13 @@ public: return finalName; } + static QString stripExecutableSuffix(const QString &executable) + { + constexpr QLatin1String suffix(QBS_HOST_EXE_SUFFIX, sizeof(QBS_HOST_EXE_SUFFIX) - 1); + return !suffix.isEmpty() && executable.endsWith(suffix) + ? executable.chopped(suffix.size()) : executable; + } + static QString dynamicLibraryName(const QString &libraryBaseName) { return QLatin1String(QBS_HOST_DYNAMICLIB_PREFIX) + libraryBaseName @@ -194,22 +201,21 @@ std::vector<std::string> HostOsInfo::hostOSIdentifiers() std::vector<std::string> HostOsInfo::canonicalOSIdentifiers(const std::string &name) { std::vector<std::string> list { name }; - if (contains(std::vector<std::string> {"ios-simulator"}, name)) + if (contains({"ios-simulator"}, name)) list << canonicalOSIdentifiers("ios"); - if (contains(std::vector<std::string> {"tvos-simulator"}, name)) + if (contains({"tvos-simulator"}, name)) list << canonicalOSIdentifiers("tvos"); - if (contains(std::vector<std::string> {"watchos-simulator"}, name)) + if (contains({"watchos-simulator"}, name)) list << canonicalOSIdentifiers("watchos"); - if (contains(std::vector<std::string> {"macos", "ios", "tvos", "watchos"}, name)) + if (contains({"macos", "ios", "tvos", "watchos"}, name)) list << canonicalOSIdentifiers("darwin"); - if (contains(std::vector<std::string> {"darwin", "freebsd", "netbsd", "openbsd"}, name)) + if (contains({"darwin", "freebsd", "netbsd", "openbsd"}, name)) list << canonicalOSIdentifiers("bsd"); - if (contains(std::vector<std::string> {"android"}, name)) + if (contains({"android"}, name)) list << canonicalOSIdentifiers("linux"); // Note: recognized non-Unix platforms include: windows, haiku, vxworks - if (contains(std::vector<std::string> { - "bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name)) + if (contains({"bsd", "aix", "hpux", "solaris", "linux", "hurd", "qnx", "integrity"}, name)) list << canonicalOSIdentifiers("unix"); return list; diff --git a/src/lib/corelib/tools/id.cpp b/src/lib/corelib/tools/id.cpp index 6dd1147f2..33cfd60f7 100644 --- a/src/lib/corelib/tools/id.cpp +++ b/src/lib/corelib/tools/id.cpp @@ -269,9 +269,9 @@ Id Id::withPrefix(const char *prefix) const bool Id::operator==(const char *name) const { - const char *string = getStringFromId(m_id); - if (string && name) - return strcmp(string, name) == 0; + const auto string = getStringFromId(m_id); + if (!string.isNull() && name) + return strcmp(string.data(), name) == 0; else return false; } diff --git a/src/lib/corelib/tools/id.h b/src/lib/corelib/tools/id.h index f0c3b1588..aa327833f 100644 --- a/src/lib/corelib/tools/id.h +++ b/src/lib/corelib/tools/id.h @@ -75,7 +75,7 @@ public: bool operator>(Id id) const { return m_id > id.m_id; } bool alphabeticallyBefore(Id other) const; int uniqueIdentifier() const { return m_id; } - static Id fromUniqueIdentifier(int uid) { return Id(uid); } + static Id fromUniqueIdentifier(int uid) { return {uid}; } static Id fromSetting(const QVariant &variant); // Good to use. private: diff --git a/src/lib/corelib/tools/installoptions.cpp b/src/lib/corelib/tools/installoptions.cpp index 93fd54efe..5e112e6de 100644 --- a/src/lib/corelib/tools/installoptions.cpp +++ b/src/lib/corelib/tools/installoptions.cpp @@ -92,23 +92,15 @@ InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate) { } -InstallOptions::InstallOptions(const InstallOptions &other) : d(other.d) -{ -} +InstallOptions::InstallOptions(const InstallOptions &other) = default; InstallOptions::InstallOptions(InstallOptions &&other) Q_DECL_NOEXCEPT = default; -InstallOptions &InstallOptions::operator=(const InstallOptions &other) -{ - d = other.d; - return *this; -} +InstallOptions &InstallOptions::operator=(const InstallOptions &other) = default; InstallOptions &InstallOptions::operator=(InstallOptions &&other) Q_DECL_NOEXCEPT = default; -InstallOptions::~InstallOptions() -{ -} +InstallOptions::~InstallOptions() = default; /*! * \brief The default install root, relative to the build directory. diff --git a/src/lib/corelib/tools/joblimits.cpp b/src/lib/corelib/tools/joblimits.cpp index 1a3e3a498..54c8c98ba 100644 --- a/src/lib/corelib/tools/joblimits.cpp +++ b/src/lib/corelib/tools/joblimits.cpp @@ -87,13 +87,9 @@ JobLimit::JobLimit() : JobLimit(QString(), -1) JobLimit::JobLimit(const QString &pool, int limit) : d(new Internal::JobLimitPrivate(pool, limit)) { } -JobLimit::JobLimit(const JobLimit &other) : d(other.d) { } -JobLimit &JobLimit::operator=(const JobLimit &other) -{ - d = other.d; - return *this; -} -JobLimit::~JobLimit() {} +JobLimit::JobLimit(const JobLimit &other) = default; +JobLimit &JobLimit::operator=(const JobLimit &other) = default; +JobLimit::~JobLimit() = default; QString JobLimit::pool() const { return d->jobLimit.first; } int JobLimit::limit() const { return d->jobLimit.second; } @@ -108,13 +104,9 @@ void JobLimit::store(Internal::PersistentPool &pool) } JobLimits::JobLimits() : d(new Internal::JobLimitsPrivate) { } -JobLimits::JobLimits(const JobLimits &other) : d(other.d) { } -JobLimits &JobLimits::operator=(const JobLimits &other) -{ - d = other.d; - return *this; -} -JobLimits::~JobLimits() {} +JobLimits::JobLimits(const JobLimits &other) = default; +JobLimits &JobLimits::operator=(const JobLimits &other) = default; +JobLimits::~JobLimits() = default; void JobLimits::setJobLimit(const JobLimit &limit) { diff --git a/src/lib/corelib/tools/jsonhelper.h b/src/lib/corelib/tools/jsonhelper.h index d87802c0a..991d6bd6c 100644 --- a/src/lib/corelib/tools/jsonhelper.h +++ b/src/lib/corelib/tools/jsonhelper.h @@ -78,9 +78,9 @@ template<> inline QProcessEnvironment fromJson(const QJsonValue &v) template<typename T> inline void setValueFromJson(T &targetValue, const QJsonObject &data, const char *jsonProperty) { - const QJsonValue v = data.value(QLatin1String(jsonProperty)); - if (!v.isNull()) - targetValue = fromJson<T>(v); + const auto it = data.find(QLatin1String(jsonProperty)); + if (it != data.end()) + targetValue = fromJson<T>(*it); } } // namespace Internal diff --git a/src/lib/corelib/tools/launcherinterface.cpp b/src/lib/corelib/tools/launcherinterface.cpp index f4e80c5e2..50ac659a9 100644 --- a/src/lib/corelib/tools/launcherinterface.cpp +++ b/src/lib/corelib/tools/launcherinterface.cpp @@ -108,9 +108,7 @@ void LauncherInterface::doStart() return; } m_process = new LauncherProcess(this); - connect(m_process, - static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error), - this, &LauncherInterface::handleProcessError); + connect(m_process, &QProcess::errorOccurred, this, &LauncherInterface::handleProcessError); connect(m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &LauncherInterface::handleProcessFinished); diff --git a/src/lib/corelib/tools/launcherpackets.cpp b/src/lib/corelib/tools/launcherpackets.cpp index aaa931a49..9c7946d73 100644 --- a/src/lib/corelib/tools/launcherpackets.cpp +++ b/src/lib/corelib/tools/launcherpackets.cpp @@ -45,7 +45,7 @@ namespace qbs { namespace Internal { -LauncherPacket::~LauncherPacket() { } +LauncherPacket::~LauncherPacket() = default; QByteArray LauncherPacket::serialize() const { diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp index cffec85b2..462f921a4 100644 --- a/src/lib/corelib/tools/msvcinfo.cpp +++ b/src/lib/corelib/tools/msvcinfo.cpp @@ -38,14 +38,20 @@ ****************************************************************************/ #include "msvcinfo.h" +#include "visualstudioversioninfo.h" +#include <logging/logger.h> #include <tools/error.h> #include <tools/profile.h> #include <tools/stringconstants.h> #include <QtCore/qbytearray.h> #include <QtCore/qdir.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonobject.h> #include <QtCore/qprocess.h> +#include <QtCore/qsettings.h> #include <QtCore/qstringlist.h> #include <QtCore/qtemporaryfile.h> @@ -54,6 +60,7 @@ #endif #include <algorithm> +#include <memory> #include <mutex> using namespace qbs; @@ -129,16 +136,18 @@ public: #ifdef Q_OS_WIN static QStringList parseCommandLine(const QString &commandLine) { - QStringList list; - const auto buf = new wchar_t[commandLine.size() + 1]; - buf[commandLine.toWCharArray(buf)] = 0; + const auto buf = std::make_unique<wchar_t[]>(size_t(commandLine.size()) + 1); + buf[size_t(commandLine.toWCharArray(buf.get()))] = 0; int argCount = 0; - LPWSTR *args = CommandLineToArgvW(buf, &argCount); + const auto argsDeleter = [](LPWSTR *p){ LocalFree(p); }; + const auto args = std::unique_ptr<LPWSTR[], decltype(argsDeleter)>( + CommandLineToArgvW(buf.get(), &argCount), argsDeleter); if (!args) throw ErrorInfo(mkStr("Could not parse command line arguments: ") + commandLine); + QStringList list; + list.reserve(argCount); for (int i = 0; i < argCount; ++i) - list.push_back(QString::fromWCharArray(args[i])); - delete[] buf; + list.push_back(QString::fromWCharArray(args[size_t(i)])); return list; } #endif @@ -163,7 +172,7 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath, QStringList out = QString::fromLocal8Bit(runProcess(compilerFilePath, QStringList() << QStringLiteral("/nologo") << backendSwitch - << QString::fromWCharArray(_wgetenv(L"COMSPEC")) + << qEnvironmentVariable("COMSPEC") << QStringLiteral("/c") << languageSwitch << QStringLiteral("NUL"), @@ -206,30 +215,32 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath, static QVariantMap getClangClDefines( const QString &compilerFilePath, const QProcessEnvironment &compilerEnv, - MSVC::CompilerLanguage language) + MSVC::CompilerLanguage language, + const QString &arch) { #ifdef Q_OS_WIN QFileInfo clInfo(compilerFilePath); - QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang.exe")); + QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang-cl.exe")); if (!clangInfo.exists()) throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath())); - QString languageSwitch; - switch (language) { - case MSVC::CLanguage: - languageSwitch = QStringLiteral("c"); - break; - case MSVC::CPlusPlusLanguage: - languageSwitch = QStringLiteral("c++"); - break; - } QStringList args = { - QStringLiteral("-dM"), - QStringLiteral("-E"), - QStringLiteral("-x"), - languageSwitch, - QStringLiteral("NUL"), + QStringLiteral("/d1PP"), // dump macros + QStringLiteral("/E") // preprocess to stdout }; + + if (language == MSVC::CLanguage) + args.append(QStringLiteral("/TC")); + else if (language == MSVC::CPlusPlusLanguage) + args.append(QStringLiteral("/TP")); + + if (arch == QLatin1String("x86")) + args.append(QStringLiteral("-m32")); + else if (arch == QLatin1String("x86_64")) + args.append(QStringLiteral("-m64")); + + args.append(QStringLiteral("NUL")); // filename + const auto lines = QString::fromLocal8Bit( runProcess( clangInfo.absoluteFilePath(), @@ -239,10 +250,8 @@ static QVariantMap getClangClDefines( QVariantMap result; for (const auto &line: lines) { static const auto defineString = QLatin1String("#define "); - if (!line.startsWith(defineString)) { - throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ") - + lines.join(QLatin1Char('\n'))); - } + if (!line.startsWith(defineString)) + continue; QStringView view(line.data() + defineString.size()); const auto it = std::find(view.begin(), view.end(), QLatin1Char(' ')); if (it == view.end()) { @@ -253,15 +262,230 @@ static QVariantMap getClangClDefines( QStringView value(it + 1, view.end()); result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString())); } + if (result.isEmpty()) { + throw ErrorInfo(QStringLiteral("Cannot determine macroses from compiler frontend output: ") + + lines.join(QLatin1Char('\n'))); + } return result; #else Q_UNUSED(compilerFilePath); Q_UNUSED(compilerEnv); Q_UNUSED(language); + Q_UNUSED(arch); return {}; #endif } +static QString formatVswhereOutput(const QString &out, const QString &err) +{ + QString ret; + if (!out.isEmpty()) { + ret.append(Tr::tr("stdout")).append(QLatin1String(":\n")); + for (const QString &line : out.split(QLatin1Char('\n'))) + ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); + } + if (!err.isEmpty()) { + ret.append(Tr::tr("stderr")).append(QLatin1String(":\n")); + for (const QString &line : err.split(QLatin1Char('\n'))) + ret.append(QLatin1Char('\t')).append(line).append(QLatin1Char('\n')); + } + return ret; +} + +static QString wow6432Key() +{ +#ifdef Q_OS_WIN64 + return QStringLiteral("\\Wow6432Node"); +#else + return {}; +#endif +} + +static QString vswhereFilePath() +{ + static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"}; + for (const char * const envVar : envVarCandidates) { + const QString value = QDir::fromNativeSeparators(QString::fromLocal8Bit(qgetenv(envVar))); + const QString cmd = value + + QStringLiteral("/Microsoft Visual Studio/Installer/vswhere.exe"); + if (QFileInfo(cmd).exists()) + return cmd; + } + return {}; +} + +enum class ProductType { VisualStudio, BuildTools }; +static std::vector<MSVCInstallInfo> retrieveInstancesFromVSWhere( + ProductType productType, Logger &logger) +{ + std::vector<MSVCInstallInfo> result; + const QString cmd = vswhereFilePath(); + if (cmd.isEmpty()) + return result; + QProcess vsWhere; + QStringList args = productType == ProductType::VisualStudio + ? QStringList({QStringLiteral("-all"), QStringLiteral("-legacy"), + QStringLiteral("-prerelease")}) + : QStringList({QStringLiteral("-products"), + QStringLiteral("Microsoft.VisualStudio.Product.BuildTools")}); + args << QStringLiteral("-format") << QStringLiteral("json") << QStringLiteral("-utf8"); + vsWhere.start(cmd, args); + if (!vsWhere.waitForStarted(-1)) + return result; + if (!vsWhere.waitForFinished(-1)) { + logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(": ")) + .append(vsWhere.errorString()); + return result; + } + if (vsWhere.exitCode() != 0) { + const QString stdOut = QString::fromLocal8Bit(vsWhere.readAllStandardOutput()); + const QString stdErr = QString::fromLocal8Bit(vsWhere.readAllStandardError()); + logger.qbsWarning() << Tr::tr("The vswhere tool failed to run").append(QLatin1String(".\n")) + .append(formatVswhereOutput(stdOut, stdErr)); + return result; + } + QJsonParseError parseError; + QJsonDocument jsonOutput = QJsonDocument::fromJson(vsWhere.readAllStandardOutput(), + &parseError); + if (parseError.error != QJsonParseError::NoError) { + logger.qbsWarning() << Tr::tr("The vswhere tool produced invalid JSON output: %1") + .arg(parseError.errorString()); + return result; + } + const auto jsonArray = jsonOutput.array(); + for (const QJsonValue &v : jsonArray) { + const QJsonObject o = v.toObject(); + MSVCInstallInfo info; + info.version = o.value(QStringLiteral("installationVersion")).toString(); + if (productType == ProductType::BuildTools) { + // For build tools, the version is e.g. "15.8.28010.2036", rather than "15.0". + const int dotIndex = info.version.indexOf(QLatin1Char('.')); + if (dotIndex != -1) + info.version = info.version.left(dotIndex); + } + info.installDir = o.value(QStringLiteral("installationPath")).toString(); + if (!info.version.isEmpty() && !info.installDir.isEmpty()) + result.push_back(info); + } + return result; +} + +static std::vector<MSVCInstallInfo> installedMSVCsFromVsWhere(Logger &logger) +{ + const std::vector<MSVCInstallInfo> vsInstallations + = retrieveInstancesFromVSWhere(ProductType::VisualStudio, logger); + const std::vector<MSVCInstallInfo> buildToolInstallations + = retrieveInstancesFromVSWhere(ProductType::BuildTools, logger); + std::vector<MSVCInstallInfo> all; + std::copy(vsInstallations.begin(), vsInstallations.end(), std::back_inserter(all)); + std::copy(buildToolInstallations.begin(), buildToolInstallations.end(), + std::back_inserter(all)); + return all; +} + +static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry() +{ + std::vector<MSVCInstallInfo> result; + + // Detect Visual Studio + const QSettings vsRegistry( + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + + QStringLiteral("\\Microsoft\\VisualStudio\\SxS\\VS7"), + QSettings::NativeFormat); + const auto vsNames = vsRegistry.childKeys(); + for (const QString &vsName : vsNames) { + MSVCInstallInfo entry; + entry.version = vsName; + entry.installDir = vsRegistry.value(vsName).toString(); + result.push_back(entry); + } + + // Detect Visual C++ Build Tools + QSettings vcbtRegistry( + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + + QStringLiteral("\\Microsoft\\VisualCppBuildTools"), + QSettings::NativeFormat); + const QStringList &vcbtRegistryChildGroups = vcbtRegistry.childGroups(); + for (const QString &childGroup : vcbtRegistryChildGroups) { + vcbtRegistry.beginGroup(childGroup); + bool ok; + int installed = vcbtRegistry.value(QStringLiteral("Installed")).toInt(&ok); + if (ok && installed) { + MSVCInstallInfo entry; + entry.version = childGroup; + const QSettings vsRegistry( + QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE") + wow6432Key() + + QStringLiteral("\\Microsoft\\VisualStudio\\") + childGroup + + QStringLiteral("\\Setup\\VC"), + QSettings::NativeFormat); + entry.installDir = vsRegistry.value(QStringLiteral("ProductDir")).toString(); + result.push_back(entry); + } + vcbtRegistry.endGroup(); + } + + return result; +} + +/* + Returns the list of compilers present in all MSVC installations + (Visual Studios or Build Tools) without the architecture, e.g. + [VC\Tools\MSVC\14.16.27023, VC\Tools\MSVC\14.14.26428, ...] +*/ +static std::vector<MSVC> installedCompilersHelper(Logger &logger) +{ + std::vector<MSVC> msvcs; + std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere(logger); + if (installInfos.empty()) + installInfos = installedMSVCsFromRegistry(); + for (const MSVCInstallInfo &installInfo : installInfos) { + MSVC msvc; + msvc.internalVsVersion = Version::fromString(installInfo.version, true); + if (!msvc.internalVsVersion.isValid()) + continue; + + QDir vsInstallDir(installInfo.installDir); + msvc.vsInstallPath = vsInstallDir.absolutePath(); + if (vsInstallDir.dirName() != QStringLiteral("VC") + && !vsInstallDir.cd(QStringLiteral("VC"))) { + continue; + } + + msvc.version = QString::number(Internal::VisualStudioVersionInfo( + msvc.internalVsVersion).marketingVersion()); + if (msvc.version.isEmpty()) { + logger.qbsWarning() + << Tr::tr("Unknown MSVC version %1 found.").arg(installInfo.version); + continue; + } + + if (msvc.internalVsVersion.majorVersion() < 15) { + QDir vcInstallDir = vsInstallDir; + if (!vcInstallDir.cd(QStringLiteral("bin"))) + continue; + msvc.vcInstallPath = vcInstallDir.absolutePath(); + msvcs.push_back(msvc); + } else { + QDir vcInstallDir = vsInstallDir; + vcInstallDir.cd(QStringLiteral("Tools/MSVC")); + const auto vcVersionStrs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &vcVersionStr : vcVersionStrs) { + const Version vcVersion = Version::fromString(vcVersionStr); + if (!vcVersion.isValid()) + continue; + QDir specificVcInstallDir = vcInstallDir; + if (!specificVcInstallDir.cd(vcVersionStr) + || !specificVcInstallDir.cd(QStringLiteral("bin"))) { + continue; + } + msvc.vcInstallPath = specificVcInstallDir.absolutePath(); + msvcs.push_back(msvc); + } + } + } + return msvcs; +} + void MSVC::init() { determineCompilerVersion(); @@ -280,6 +504,28 @@ QString MSVC::architectureFromClPath(const QString &clPath) return parentDirName; } +QString MSVC::canonicalArchitecture(const QString &arch) +{ + if (arch == QLatin1String("x64") || arch == QLatin1String("amd64")) + return QStringLiteral("x86_64"); + return arch; +} + +std::pair<QString, QString> MSVC::getHostTargetArchPair(const QString &arch) +{ + QString hostArch; + QString targetArch; + const int index = arch.indexOf(QLatin1Char('_')); + if (index != -1) { + hostArch = arch.mid(0, index); + targetArch = arch.mid(index); + } else { + hostArch = arch; + targetArch = arch; + } + return {canonicalArchitecture(hostArch), canonicalArchitecture(targetArch)}; +} + QString MSVC::binPathForArchitecture(const QString &arch) const { QString archSubDir; @@ -301,10 +547,106 @@ QVariantMap MSVC::compilerDefines(const QString &compilerFilePath, { const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower(); if (compilerName == QLatin1String("clang-cl.exe")) - return getClangClDefines(compilerFilePath, environment, language); + return getClangClDefines(compilerFilePath, environment, language, architecture); return getMsvcDefines(compilerFilePath, environment, language); } +std::vector<MSVCArchInfo> MSVC::findSupportedArchitectures(const MSVC &msvc) +{ + std::vector<MSVCArchInfo> result; + auto addResult = [&result](const MSVCArchInfo &ai) { + if (QFile::exists(ai.binPath + QLatin1String("/cl.exe"))) + result.push_back(ai); + }; + if (msvc.internalVsVersion.majorVersion() < 15) { + static const QStringList knownArchitectures = QStringList() + << QStringLiteral("x86") + << QStringLiteral("amd64_x86") + << QStringLiteral("amd64") + << QStringLiteral("x86_amd64") + << QStringLiteral("ia64") + << QStringLiteral("x86_ia64") + << QStringLiteral("x86_arm") + << QStringLiteral("amd64_arm"); + for (const QString &knownArchitecture : knownArchitectures) { + MSVCArchInfo ai; + ai.arch = knownArchitecture; + ai.binPath = msvc.binPathForArchitecture(knownArchitecture); + addResult(ai); + } + } else { + QDir vcInstallDir(msvc.vcInstallPath); + const auto hostArchs = vcInstallDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &hostArch : hostArchs) { + QDir subdir = vcInstallDir; + if (!subdir.cd(hostArch)) + continue; + const QString shortHostArch = hostArch.mid(4).toLower(); + const auto archs = subdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &arch : archs) { + MSVCArchInfo ai; + ai.binPath = subdir.absoluteFilePath(arch); + if (shortHostArch == arch) + ai.arch = arch; + else + ai.arch = shortHostArch + QLatin1Char('_') + arch; + addResult(ai); + } + } + } + return result; +} + +QVariantMap MSVC::toVariantMap() const +{ + return { + {QStringLiteral("version"), version}, + {QStringLiteral("internalVsVersion"), internalVsVersion.toString()}, + {QStringLiteral("vsInstallPath"), vsInstallPath}, + {QStringLiteral("vcInstallPath"), vcInstallPath}, + {QStringLiteral("binPath"), binPath}, + {QStringLiteral("architecture"), architecture}, + }; +} + +/*! + \internal + Returns the list of all compilers present in all MSVC installations + separated by host/target arch, e.g. + [ + VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\x86, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm, + VC\Tools\MSVC\14.16.27023\bin\Hostx64\arm64, + VC\Tools\MSVC\14.16.27023\bin\Hostx86\x64, + ... + ] + \note that MSVC.architecture can be either "x64" or "amd64" (depending on the MSVC version) + in case of 64-bit platform (but we use the "x86_64" name...) +*/ +std::vector<MSVC> MSVC::installedCompilers(Logger &logger) +{ + std::vector<MSVC> msvcs; + const auto instMsvcs = installedCompilersHelper(logger); + for (const MSVC &msvc : instMsvcs) { + if (msvc.internalVsVersion.majorVersion() < 15) { + // Check existence of various install scripts + const QString vcvars32bat = msvc.vcInstallPath + QLatin1String("/vcvars32.bat"); + if (!QFileInfo(vcvars32bat).isFile()) + continue; + } + + const auto ais = findSupportedArchitectures(msvc); + for (const MSVCArchInfo &ai : ais) { + MSVC specificMSVC = msvc; + specificMSVC.architecture = ai.arch; + specificMSVC.binPath = ai.binPath; + msvcs.push_back(specificMSVC); + } + } + return msvcs; +} + void MSVC::determineCompilerVersion() { QString cppFilePath; @@ -332,3 +674,24 @@ void MSVC::determineCompilerVersion() compilerVersion = Version(versionStr.mid(0, 2).toInt(), versionStr.mid(2, 2).toInt(), versionStr.mid(4).toInt()); } + +QString MSVCInstallInfo::findVcvarsallBat() const +{ + static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat"); + // 2015, 2013 and 2012 + static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat"); + QDir dir(installDir); + if (dir.exists(vcvarsall2017)) + return dir.absoluteFilePath(vcvarsall2017); + if (dir.exists(vcvarsallOld)) + return dir.absoluteFilePath(vcvarsallOld); + return {}; +} + +std::vector<MSVCInstallInfo> MSVCInstallInfo::installedMSVCs(Logger &logger) +{ + const auto installInfos = installedMSVCsFromVsWhere(logger); + if (installInfos.empty()) + return installedMSVCsFromRegistry(); + return installInfos; +} diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h index b5cf04e84..de4470bf0 100644 --- a/src/lib/corelib/tools/msvcinfo.h +++ b/src/lib/corelib/tools/msvcinfo.h @@ -53,6 +53,14 @@ namespace qbs { namespace Internal { +class Logger; + +struct MSVCArchInfo +{ + QString arch; + QString binPath; +}; + /** * Represents one MSVC installation for one specific target architecture. * There are potentially multiple MSVCs in one Visual Studio installation. @@ -75,7 +83,7 @@ public: QString architecture; QProcessEnvironment environment; - MSVC() { } + MSVC() = default; MSVC(const QString &clPath, QString arch): architecture(std::move(arch)) @@ -90,11 +98,19 @@ public: QBS_EXPORT void init(); QBS_EXPORT static QString architectureFromClPath(const QString &clPath); + QBS_EXPORT static QString canonicalArchitecture(const QString &arch); + QBS_EXPORT static std::pair<QString, QString> getHostTargetArchPair(const QString &arch); QBS_EXPORT QString binPathForArchitecture(const QString &arch) const; QBS_EXPORT QString clPathForArchitecture(const QString &arch) const; QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath, CompilerLanguage language) const; + QBS_EXPORT static std::vector<MSVCArchInfo> findSupportedArchitectures(const MSVC &msvc); + + QBS_EXPORT QVariantMap toVariantMap() const; + + QBS_EXPORT static std::vector<MSVC> installedCompilers(Logger &logger); + private: void determineCompilerVersion(); }; @@ -110,6 +126,16 @@ public: } }; +struct QBS_EXPORT MSVCInstallInfo +{ + QString version; + QString installDir; + + QString findVcvarsallBat() const; + + static std::vector<MSVCInstallInfo> installedMSVCs(Logger &logger); +}; + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/tools/persistence.cpp b/src/lib/corelib/tools/persistence.cpp index ea8adf023..3f2b57e01 100644 --- a/src/lib/corelib/tools/persistence.cpp +++ b/src/lib/corelib/tools/persistence.cpp @@ -48,7 +48,7 @@ namespace qbs { namespace Internal { -static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-127"; +static const char QBS_PERSISTENCE_MAGIC[] = "QBSPERSISTENCE-128"; NoBuildGraphError::NoBuildGraphError(const QString &filePath) : ErrorInfo(Tr::tr("Build graph not found for configuration '%1'. Expected location was '%2'.") @@ -62,10 +62,7 @@ PersistentPool::PersistentPool(Logger &logger) : m_logger(logger) m_stream.setVersion(QDataStream::Qt_4_8); } -PersistentPool::~PersistentPool() -{ - closeStream(); -} +PersistentPool::~PersistentPool() = default; void PersistentPool::load(const QString &filePath) { @@ -89,7 +86,7 @@ void PersistentPool::load(const QString &filePath) } m_stream >> m_headData.projectConfig; - file.release(); + m_file = std::move(file); m_loadedRaw.clear(); m_loaded.clear(); m_storageIndices.clear(); @@ -116,7 +113,8 @@ void PersistentPool::setupWriteStream(const QString &filePath) "Cannot open file '%1' for writing: %2").arg(filePath, file->errorString())); } - m_stream.setDevice(file.release()); + m_stream.setDevice(file.get()); + m_file = std::move(file); m_stream << QByteArray(qstrlen(QBS_PERSISTENCE_MAGIC), 0) << m_headData.projectConfig; m_lastStoredObjectId = 0; m_lastStoredStringId = 0; @@ -140,14 +138,6 @@ void PersistentPool::finalizeWriteStream() } } -void PersistentPool::closeStream() -{ - delete m_stream.device(); - m_stream.setDevice(nullptr); -} - - - void PersistentPool::storeVariant(const QVariant &variant) { const auto type = static_cast<quint32>(variant.type()); diff --git a/src/lib/corelib/tools/persistence.h b/src/lib/corelib/tools/persistence.h index 4bda59f7c..e00310321 100644 --- a/src/lib/corelib/tools/persistence.h +++ b/src/lib/corelib/tools/persistence.h @@ -128,7 +128,6 @@ public: void load(const QString &filePath); void setupWriteStream(const QString &filePath); void finalizeWriteStream(); - void closeStream(); void clear(); const HeadData &headData() const { return m_headData; } @@ -167,6 +166,7 @@ private: static const PersistentObjectId ValueNotFoundId = -1; static const PersistentObjectId EmptyValueId = -2; + std::unique_ptr<QIODevice> m_file; QDataStream m_stream; HeadData m_headData; std::vector<void *> m_loadedRaw; diff --git a/src/lib/corelib/tools/processresult.cpp b/src/lib/corelib/tools/processresult.cpp index 3fb2f8dbc..d5591a7ed 100644 --- a/src/lib/corelib/tools/processresult.cpp +++ b/src/lib/corelib/tools/processresult.cpp @@ -53,19 +53,11 @@ ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate) { } -ProcessResult::ProcessResult(const ProcessResult &other) : d(other.d) -{ -} +ProcessResult::ProcessResult(const ProcessResult &other) = default; -ProcessResult &ProcessResult::operator=(const ProcessResult &other) -{ - d = other.d; - return *this; -} +ProcessResult &ProcessResult::operator=(const ProcessResult &other) = default; -ProcessResult::~ProcessResult() -{ -} +ProcessResult::~ProcessResult() = default; /*! * \brief Returns true iff the command finished successfully. diff --git a/src/lib/corelib/tools/processutils.cpp b/src/lib/corelib/tools/processutils.cpp index 04a061e0c..b27592f88 100644 --- a/src/lib/corelib/tools/processutils.cpp +++ b/src/lib/corelib/tools/processutils.cpp @@ -92,7 +92,8 @@ QString processNameByPid(qint64 pid) char buf[PATH_MAX]; memset(buf, 0, sizeof(buf)); sprintf(exePath, "/proc/%lld/exe", pid); - readlink(exePath, buf, sizeof(buf)); + if (readlink(exePath, buf, sizeof(buf)) < 0) + return {}; return FileInfo::fileName(QString::fromUtf8(buf)); #elif defined(Q_OS_BSD4) # if defined(Q_OS_NETBSD) diff --git a/src/lib/corelib/tools/profile.cpp b/src/lib/corelib/tools/profile.cpp index 7e594fd2d..2eac25091 100644 --- a/src/lib/corelib/tools/profile.cpp +++ b/src/lib/corelib/tools/profile.cpp @@ -63,13 +63,13 @@ namespace qbs { /*! * \brief Creates an object giving access to the settings for profile \c name. */ -Profile::Profile(const QString &name, Settings *settings, const QVariantMap &profiles) - : m_name(name), +Profile::Profile(QString name, Settings *settings, QVariantMap profiles) + : m_name(std::move(name)), m_settings(settings), - m_values(profiles.value(name).toMap()), - m_profiles(profiles) + m_values(profiles.value(m_name).toMap()), + m_profiles(std::move(profiles)) { - QBS_ASSERT(name == cleanName(name), return); + QBS_ASSERT(m_name == cleanName(m_name), return); } bool Profile::exists() const diff --git a/src/lib/corelib/tools/profile.h b/src/lib/corelib/tools/profile.h index aa8b7ef10..0eee23ae4 100644 --- a/src/lib/corelib/tools/profile.h +++ b/src/lib/corelib/tools/profile.h @@ -55,7 +55,7 @@ class Settings; class QBS_EXPORT Profile { public: - Profile(const QString &name, Settings *settings, const QVariantMap &profiles = QVariantMap()); + Profile(QString name, Settings *settings, QVariantMap profiles = QVariantMap()); bool exists() const; QVariant value(const QString &key, const QVariant &defaultValue = QVariant(), diff --git a/src/lib/corelib/tools/progressobserver.h b/src/lib/corelib/tools/progressobserver.h index 72b9694ba..fc49d9eed 100644 --- a/src/lib/corelib/tools/progressobserver.h +++ b/src/lib/corelib/tools/progressobserver.h @@ -51,7 +51,7 @@ namespace Internal { class ProgressObserver { public: - virtual ~ProgressObserver() { } + virtual ~ProgressObserver() = default; virtual void initialize(const QString &task, int maximum) = 0; virtual void setProgressValue(int value) = 0; diff --git a/src/lib/corelib/tools/projectgeneratormanager.cpp b/src/lib/corelib/tools/projectgeneratormanager.cpp index 3991adfb9..53d72bcd1 100644 --- a/src/lib/corelib/tools/projectgeneratormanager.cpp +++ b/src/lib/corelib/tools/projectgeneratormanager.cpp @@ -52,9 +52,7 @@ namespace qbs { using namespace Internal; -ProjectGeneratorManager::~ProjectGeneratorManager() -{ -} +ProjectGeneratorManager::~ProjectGeneratorManager() = default; ProjectGeneratorManager *ProjectGeneratorManager::instance() { @@ -62,9 +60,7 @@ ProjectGeneratorManager *ProjectGeneratorManager::instance() return &generatorPlugin; } -ProjectGeneratorManager::ProjectGeneratorManager() -{ -} +ProjectGeneratorManager::ProjectGeneratorManager() = default; QStringList ProjectGeneratorManager::loadedGeneratorNames() { diff --git a/src/lib/corelib/tools/qttools.h b/src/lib/corelib/tools/qttools.h index c3b4d3a9f..04fd7d95e 100644 --- a/src/lib/corelib/tools/qttools.h +++ b/src/lib/corelib/tools/qttools.h @@ -42,6 +42,7 @@ #include <QtCore/qhash.h> #include <QtCore/qstringlist.h> +#include <QtCore/qtextstream.h> #include <functional> @@ -66,8 +67,16 @@ template<typename T1, typename T2> struct hash<std::pair<T1, T2>> } // namespace std QT_BEGIN_NAMESPACE + uint qHash(const QStringList &list); uint qHash(const QProcessEnvironment &env); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) +namespace Qt { +inline QTextStream &endl(QTextStream &stream) { return stream << QT_PREPEND_NAMESPACE(endl); } +} // namespace Qt +#endif + QT_END_NAMESPACE namespace qbs { @@ -82,6 +91,16 @@ QSet<T> toSet(const QList<T> &list) #endif } +template<class T> +QList<T> toList(const QSet<T> &set) +{ +#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) + return set.toList(); +#else + return QList<T>(set.begin(), set.end()); +#endif +} + } // namespace qbs diff --git a/src/lib/corelib/tools/scannerpluginmanager.cpp b/src/lib/corelib/tools/scannerpluginmanager.cpp index d6b564832..378f0e11b 100644 --- a/src/lib/corelib/tools/scannerpluginmanager.cpp +++ b/src/lib/corelib/tools/scannerpluginmanager.cpp @@ -51,9 +51,7 @@ public: std::map<FileTag, std::vector<ScannerPlugin* >> scannerPlugins; }; -ScannerPluginManager::~ScannerPluginManager() -{ -} +ScannerPluginManager::~ScannerPluginManager() = default; ScannerPluginManager *ScannerPluginManager::instance() { diff --git a/src/lib/corelib/tools/set.h b/src/lib/corelib/tools/set.h index eb3bf6632..d2af77d73 100644 --- a/src/lib/corelib/tools/set.h +++ b/src/lib/corelib/tools/set.h @@ -98,7 +98,7 @@ public: const_iterator constBegin() const { return m_data.cbegin(); } const_iterator constEnd() const { return m_data.cend(); } - Set() { } + Set() = default; Set(const std::initializer_list<T> &list); Set &unite(const Set &other); diff --git a/src/lib/corelib/tools/settings.cpp b/src/lib/corelib/tools/settings.cpp index 7312cd622..fccb9c9b2 100644 --- a/src/lib/corelib/tools/settings.cpp +++ b/src/lib/corelib/tools/settings.cpp @@ -91,8 +91,8 @@ Settings::Settings(const QString &baseDir) : Settings(baseDir, systemSettingsBas Settings::Settings(const QString &baseDir, const QString &systemBaseDir) : m_settings(SettingsCreator(baseDir).getQSettings()), - m_systemSettings(new QSettings(systemBaseDir + QStringLiteral("/qbs.conf"), - QSettings::IniFormat)), + m_systemSettings(std::make_unique<QSettings>(systemBaseDir + QStringLiteral("/qbs.conf"), + QSettings::IniFormat)), m_baseDir(baseDir) { // Actual qbs settings are stored transparently within a group, because QSettings @@ -100,11 +100,7 @@ Settings::Settings(const QString &baseDir, const QString &systemBaseDir) m_settings->beginGroup(QStringLiteral("org/qt-project/qbs")); } -Settings::~Settings() -{ - delete m_settings; - delete m_systemSettings; -} +Settings::~Settings() = default; QVariant Settings::value(const QString &key, Scopes scopes, const QVariant &defaultValue) const { @@ -241,7 +237,7 @@ void Settings::fixupKeys(QStringList &keys) const QSettings *Settings::settingsForScope(Settings::Scope scope) const { - return scope == UserScope ? m_settings : m_systemSettings; + return scope == UserScope ? m_settings.get() : m_systemSettings.get(); } QSettings *Settings::targetForWriting() const diff --git a/src/lib/corelib/tools/settings.h b/src/lib/corelib/tools/settings.h index d4de08490..638216669 100644 --- a/src/lib/corelib/tools/settings.h +++ b/src/lib/corelib/tools/settings.h @@ -45,6 +45,8 @@ #include <QtCore/qstring.h> #include <QtCore/qvariant.h> +#include <memory> + QT_BEGIN_NAMESPACE class QSettings; class QStringList; @@ -94,8 +96,8 @@ private: QSettings *targetForWriting() const; void checkForWriteError(); - QSettings * const m_settings; - QSettings * const m_systemSettings; + const std::unique_ptr<QSettings> m_settings; + const std::unique_ptr<QSettings> m_systemSettings; const QString m_baseDir; Scope m_scopeForWriting = UserScope; }; diff --git a/src/lib/corelib/tools/settingscreator.cpp b/src/lib/corelib/tools/settingscreator.cpp index eaaf2802c..36e67440c 100644 --- a/src/lib/corelib/tools/settingscreator.cpp +++ b/src/lib/corelib/tools/settingscreator.cpp @@ -1,3 +1,4 @@ +#include <memory> #include <utility> /**************************************************************************** @@ -64,11 +65,11 @@ SettingsCreator::SettingsCreator(QString baseDir) { } -QSettings *SettingsCreator::getQSettings() +std::unique_ptr<QSettings> SettingsCreator::getQSettings() { createQSettings(); migrate(); - return m_settings.release(); + return std::move(m_settings); } void SettingsCreator::migrate() @@ -104,7 +105,7 @@ void SettingsCreator::migrate() // Adapt all paths in settings that point to the old location. At the time of this writing, // that's only preferences.qbsSearchPaths as written by libqtprofilesetup, but we don't want // to hardcode that here. - m_settings.reset(new QSettings(m_newSettingsFilePath, format())); + m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, format()); const auto allKeys = m_settings->allKeys(); for (const QString &key : allKeys) { QVariant v = m_settings->value(key); @@ -136,7 +137,7 @@ void SettingsCreator::createQSettings() m_newSettingsDir = m_settingsBaseDir + QLatin1String("/qbs/") + m_qbsVersion.toString(); m_settingsFileName = fi.fileName(); m_newSettingsFilePath = m_newSettingsDir + QLatin1Char('/') + m_settingsFileName; - m_settings.reset(new QSettings(m_newSettingsFilePath, tmp->format())); + m_settings = std::make_unique<QSettings>(m_newSettingsFilePath, tmp->format()); } Version SettingsCreator::predecessor() const diff --git a/src/lib/corelib/tools/settingscreator.h b/src/lib/corelib/tools/settingscreator.h index 39da80a7f..ab491105c 100644 --- a/src/lib/corelib/tools/settingscreator.h +++ b/src/lib/corelib/tools/settingscreator.h @@ -58,7 +58,7 @@ class SettingsCreator public: SettingsCreator(QString baseDir); - QSettings *getQSettings(); + std::unique_ptr<QSettings> getQSettings(); private: void migrate(); diff --git a/src/lib/corelib/tools/settingsmodel.cpp b/src/lib/corelib/tools/settingsmodel.cpp index d67f1da5c..7283e959c 100644 --- a/src/lib/corelib/tools/settingsmodel.cpp +++ b/src/lib/corelib/tools/settingsmodel.cpp @@ -125,7 +125,7 @@ public: SettingsModel::SettingsModel(const QString &settingsDir, Settings::Scope scope, QObject *parent) : QAbstractItemModel(parent), d(new SettingsModelPrivate) { - d->settings.reset(new qbs::Settings(settingsDir)); + d->settings = std::make_unique<qbs::Settings>(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); } @@ -155,7 +155,7 @@ void SettingsModel::updateSettingsDir(const QString &settingsDir) { const Settings::Scope scope = d->scope(); beginResetModel(); - d->settings.reset(new qbs::Settings(settingsDir)); + d->settings = std::make_unique<qbs::Settings>(settingsDir); d->settings->setScopeForWriting(scope); d->readSettings(); endResetModel(); diff --git a/src/lib/corelib/tools/setupprojectparameters.cpp b/src/lib/corelib/tools/setupprojectparameters.cpp index 41af7b926..a06ffc4bd 100644 --- a/src/lib/corelib/tools/setupprojectparameters.cpp +++ b/src/lib/corelib/tools/setupprojectparameters.cpp @@ -107,21 +107,15 @@ SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectP { } -SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) : d(other.d) -{ -} +SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) = default; -SetupProjectParameters::SetupProjectParameters(SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; +SetupProjectParameters::SetupProjectParameters( + SetupProjectParameters &&other) Q_DECL_NOEXCEPT = default; -SetupProjectParameters::~SetupProjectParameters() -{ -} +SetupProjectParameters::~SetupProjectParameters() = default; -SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectParameters &other) -{ - d = other.d; - return *this; -} +SetupProjectParameters &SetupProjectParameters::operator=( + const SetupProjectParameters &other) = default; namespace Internal { template<> ErrorHandlingMode fromJson(const QJsonValue &v) @@ -355,7 +349,7 @@ static void provideValuesTree(const QVariantMap &values, QVariantMap *valueTree) valueTree->clear(); for (QVariantMap::const_iterator it = values.constBegin(); it != values.constEnd(); ++it) { - const QString name = it.key(); + const QString &name = it.key(); int idx = name.lastIndexOf(QLatin1Char('.')); const QStringList nameElements = (idx == -1) ? QStringList() << name diff --git a/src/lib/corelib/tools/shellutils.cpp b/src/lib/corelib/tools/shellutils.cpp index 01c177cce..dae98f337 100644 --- a/src/lib/corelib/tools/shellutils.cpp +++ b/src/lib/corelib/tools/shellutils.cpp @@ -205,12 +205,12 @@ void CommandLine::setProgram(const std::string &program, bool raw) void CommandLine::appendArgument(const QString &value) { - m_arguments.push_back(value); + m_arguments.emplace_back(value); } void CommandLine::appendArgument(const std::string &value) { - m_arguments.push_back(QString::fromStdString(value)); + m_arguments.emplace_back(QString::fromStdString(value)); } void CommandLine::appendArguments(const QList<QString> &args) diff --git a/src/lib/corelib/tools/shellutils.h b/src/lib/corelib/tools/shellutils.h index 6f1d82afb..f4ad35044 100644 --- a/src/lib/corelib/tools/shellutils.h +++ b/src/lib/corelib/tools/shellutils.h @@ -77,7 +77,7 @@ public: private: struct Argument { - Argument(const QString &value = QString()) : value(value) { } + Argument(QString value = QString()) : value(std::move(value)) { } QString value; bool isFilePath = false; bool shouldQuote = true; diff --git a/src/lib/corelib/tools/stlutils.h b/src/lib/corelib/tools/stlutils.h index ad00070cf..5c21c0672 100644 --- a/src/lib/corelib/tools/stlutils.h +++ b/src/lib/corelib/tools/stlutils.h @@ -54,11 +54,18 @@ C sorted(const C &container) return result; } -template <class C> -bool contains(const C &container, const typename C::value_type &v) +template <class C, class T> +bool contains(const C &container, const T &v) { - const auto &end = container.cend(); - return std::find(container.cbegin(), end, v) != end; + const auto &end = std::cend(container); + return std::find(std::cbegin(container), end, v) != end; +} + +template <class T, size_t N, class U> +bool contains(const T (&container)[N], const U &v) +{ + const auto &end = std::cend(container); + return std::find(std::cbegin(container), end, v) != end; } template <class C> diff --git a/src/lib/corelib/tools/stringconstants.h b/src/lib/corelib/tools/stringconstants.h index 79cbcd125..f2bc78446 100644 --- a/src/lib/corelib/tools/stringconstants.h +++ b/src/lib/corelib/tools/stringconstants.h @@ -153,6 +153,7 @@ public: QBS_STRING_CONSTANT(searchPathsProperty, "searchPaths") QBS_STRING_CONSTANT(setupBuildEnvironmentProperty, "setupBuildEnvironment") QBS_STRING_CONSTANT(setupRunEnvironmentProperty, "setupRunEnvironment") + QBS_STRING_CONSTANT(shadowProductPrefix, "__shadow__") QBS_STRING_CONSTANT(sourceCodeProperty, "sourceCode") QBS_STRING_CONSTANT(sourceDirectoryProperty, "sourceDirectory") QBS_STRING_CONSTANT(submodulesProperty, "submodules") diff --git a/src/lib/corelib/tools/stringutils.h b/src/lib/corelib/tools/stringutils.h index 7b551a544..59acdccbd 100644 --- a/src/lib/corelib/tools/stringutils.h +++ b/src/lib/corelib/tools/stringutils.h @@ -77,14 +77,14 @@ static inline std::string trimmed(const std::string &s) // trim from start static const auto ltrim = [](std::string &s) -> std::string & { s.erase(s.begin(), std::find_if(s.begin(), s.end(), - std::not1(std::ptr_fun<int, int>(std::isspace)))); + [](char c){ return !std::isspace(c); })); return s; }; // trim from end static const auto rtrim = [](std::string &s) -> std::string & { s.erase(std::find_if(s.rbegin(), s.rend(), - std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end()); + [](char c){ return !std::isspace(c); }).base(), s.end()); return s; }; diff --git a/src/lib/corelib/tools/toolchains.cpp b/src/lib/corelib/tools/toolchains.cpp index 0d793f8aa..6263fb199 100644 --- a/src/lib/corelib/tools/toolchains.cpp +++ b/src/lib/corelib/tools/toolchains.cpp @@ -49,9 +49,11 @@ namespace qbs { namespace Internal { static const QString clangToolchain() { return QStringLiteral("clang"); } +static const QString clangClToolchain() { return QStringLiteral("clang-cl"); } static const QString gccToolchain() { return QStringLiteral("gcc"); } static const QString llvmToolchain() { return QStringLiteral("llvm"); } static const QString mingwToolchain() { return QStringLiteral("mingw"); } +static const QString msvcToolchain() { return QStringLiteral("msvc"); } } using namespace Internal; @@ -64,7 +66,8 @@ QStringList canonicalToolchain(const QStringList &toolchain) llvmToolchain(), mingwToolchain(), gccToolchain(), - QStringLiteral("msvc") + clangClToolchain(), + msvcToolchain() }; // Canonicalize each toolchain in the toolchain list, @@ -110,6 +113,8 @@ QStringList canonicalToolchain(const QString &name) else if (toolchainName == llvmToolchain() || toolchainName == mingwToolchain()) { toolchains << canonicalToolchain(QStringLiteral("gcc")); + } else if (toolchainName == clangClToolchain()) { + toolchains << canonicalToolchain(msvcToolchain()); } return toolchains; } diff --git a/src/lib/corelib/tools/tools.pri b/src/lib/corelib/tools/tools.pri index 89d752671..00d87ecc7 100644 --- a/src/lib/corelib/tools/tools.pri +++ b/src/lib/corelib/tools/tools.pri @@ -10,6 +10,7 @@ QBS_SYSTEM_SETTINGS_DIR = $$(QBS_SYSTEM_SETTINGS_DIR) HEADERS += \ $$PWD/architectures.h \ $$PWD/buildgraphlocker.h \ + $$PWD/clangclinfo.h \ $$PWD/codelocation.h \ $$PWD/commandechomode.h \ $$PWD/dynamictypecheck.h \ @@ -68,6 +69,7 @@ HEADERS += \ SOURCES += \ $$PWD/architectures.cpp \ $$PWD/buildgraphlocker.cpp \ + $$PWD/clangclinfo.cpp \ $$PWD/codelocation.cpp \ $$PWD/commandechomode.cpp \ $$PWD/error.cpp \ diff --git a/src/lib/corelib/tools/version.cpp b/src/lib/corelib/tools/version.cpp index dfb7f49b7..f653256b3 100644 --- a/src/lib/corelib/tools/version.cpp +++ b/src/lib/corelib/tools/version.cpp @@ -44,50 +44,6 @@ namespace qbs { -Version::Version(int major, int minor, int patch, int buildNr) - : m_major(major), m_minor(minor), m_patch(patch), m_build(buildNr) -{ -} - -int Version::majorVersion() const -{ - return m_major; -} - -void Version::setMajorVersion(int major) -{ - m_major = major; -} - -int Version::minorVersion() const -{ - return m_minor; -} - -void Version::setMinorVersion(int minor) -{ - m_minor = minor; -} -int Version::patchLevel() const -{ - return m_patch; -} - -void Version::setPatchLevel(int patch) -{ - m_patch = patch; -} - -int Version::buildNumber() const -{ - return m_build; -} - -void Version::setBuildNumber(int nr) -{ - m_build = nr; -} - Version Version::fromString(const QString &versionString, bool buildNumberAllowed) { QString pattern = QStringLiteral("(\\d+)"); // At least one number. @@ -118,32 +74,6 @@ QString Version::toString(const QChar &separator, const QChar &buildSeparator) c QString::number(m_patch), separator); } -int compare(const Version &lhs, const Version &rhs) -{ - if (lhs.majorVersion() < rhs.majorVersion()) - return -1; - if (lhs.majorVersion() > rhs.majorVersion()) - return 1; - if (lhs.minorVersion() < rhs.minorVersion()) - return -1; - if (lhs.minorVersion() > rhs.minorVersion()) - return 1; - if (lhs.patchLevel() < rhs.patchLevel()) - return -1; - if (lhs.patchLevel() > rhs.patchLevel()) - return 1; - if (lhs.buildNumber() < rhs.buildNumber()) - return -1; - if (lhs.buildNumber() > rhs.buildNumber()) - return 1; - return 0; -} - -VersionRange::VersionRange(const Version &minVersion, const Version &maxVersion) - : minimum(minVersion), maximum(maxVersion) -{ -} - VersionRange &VersionRange::narrowDown(const VersionRange &other) { if (other.minimum > minimum) diff --git a/src/lib/corelib/tools/version.h b/src/lib/corelib/tools/version.h index a0239a6e4..63ad3f88c 100644 --- a/src/lib/corelib/tools/version.h +++ b/src/lib/corelib/tools/version.h @@ -54,22 +54,24 @@ namespace qbs { class QBS_EXPORT Version { public: - explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0, - int buildNr = 0); + constexpr explicit Version(int majorVersion = 0, int minorVersion = 0, int patchLevel = 0, + int buildNr = 0) + : m_major(majorVersion), m_minor(minorVersion), m_patch(patchLevel), m_build(buildNr) + { } - bool isValid() const { return m_major || m_minor || m_patch || m_build; } + constexpr bool isValid() const { return m_major || m_minor || m_patch || m_build; } - int majorVersion() const; - void setMajorVersion(int majorVersion); + constexpr int majorVersion() const { return m_major; } + constexpr void setMajorVersion(int majorVersion) { m_major = majorVersion; } - int minorVersion() const; - void setMinorVersion(int minorVersion); + constexpr int minorVersion() const { return m_minor; } + constexpr void setMinorVersion(int minorVersion) { m_minor = minorVersion;} - int patchLevel() const; - void setPatchLevel(int patchLevel); + constexpr int patchLevel() const { return m_patch; } + constexpr void setPatchLevel(int patchLevel) { m_patch = patchLevel; } - int buildNumber() const; - void setBuildNumber(int nr); + constexpr int buildNumber() const { return m_build; } + constexpr void setBuildNumber(int nr) { m_build = nr; } static Version fromString(const QString &versionString, bool buildNumberAllowed = false); QString toString(const QChar &separator = QLatin1Char('.'), @@ -85,8 +87,10 @@ private: class VersionRange { public: - VersionRange() = default; - VersionRange(const Version &minVersion, const Version &maxVersion); + constexpr VersionRange() = default; + constexpr VersionRange(const Version &minVersion, const Version &maxVersion) + : minimum(minVersion), maximum(maxVersion) + { } Version minimum; Version maximum; // exclusive @@ -94,13 +98,39 @@ public: VersionRange &narrowDown(const VersionRange &other); }; -QBS_EXPORT int compare(const Version &lhs, const Version &rhs); -inline bool operator==(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) == 0; } -inline bool operator!=(const Version &lhs, const Version &rhs) { return !operator==(lhs, rhs); } -inline bool operator<(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) < 0; } -inline bool operator>(const Version &lhs, const Version &rhs) { return compare(lhs, rhs) > 0; } -inline bool operator<=(const Version &lhs, const Version &rhs) { return !operator>(lhs, rhs); } -inline bool operator>=(const Version &lhs, const Version &rhs) { return !operator<(lhs, rhs); } +constexpr inline int compare(const Version &lhs, const Version &rhs) +{ + if (lhs.majorVersion() < rhs.majorVersion()) + return -1; + if (lhs.majorVersion() > rhs.majorVersion()) + return 1; + if (lhs.minorVersion() < rhs.minorVersion()) + return -1; + if (lhs.minorVersion() > rhs.minorVersion()) + return 1; + if (lhs.patchLevel() < rhs.patchLevel()) + return -1; + if (lhs.patchLevel() > rhs.patchLevel()) + return 1; + if (lhs.buildNumber() < rhs.buildNumber()) + return -1; + if (lhs.buildNumber() > rhs.buildNumber()) + return 1; + return 0; +} + +constexpr inline bool operator==(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) == 0; } +constexpr inline bool operator!=(const Version &lhs, const Version &rhs) +{ return !operator==(lhs, rhs); } +constexpr inline bool operator<(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) < 0; } +constexpr inline bool operator>(const Version &lhs, const Version &rhs) +{ return compare(lhs, rhs) > 0; } +constexpr inline bool operator<=(const Version &lhs, const Version &rhs) +{ return !operator>(lhs, rhs); } +constexpr inline bool operator>=(const Version &lhs, const Version &rhs) +{ return !operator<(lhs, rhs); } } // namespace qbs diff --git a/src/lib/corelib/tools/visualstudioversioninfo.cpp b/src/lib/corelib/tools/visualstudioversioninfo.cpp index d4f8844fa..b5ee3e719 100644 --- a/src/lib/corelib/tools/visualstudioversioninfo.cpp +++ b/src/lib/corelib/tools/visualstudioversioninfo.cpp @@ -46,9 +46,7 @@ namespace qbs { namespace Internal { -VisualStudioVersionInfo::VisualStudioVersionInfo() -{ -} +VisualStudioVersionInfo::VisualStudioVersionInfo() = default; VisualStudioVersionInfo::VisualStudioVersionInfo(const Version &version) : m_version(version) @@ -176,7 +174,7 @@ QString VisualStudioVersionInfo::platformToolsetVersion() const {16, QStringLiteral("v142")}, // VS 2019 {15, QStringLiteral("v141")} // VS 2017 }; - for (auto p : table) { + for (const auto &p : table) { if (p.first == m_version.majorVersion()) return p.second; } diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp index f8f98e7b7..95451435a 100644 --- a/src/lib/corelib/tools/vsenvironmentdetector.cpp +++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp @@ -193,13 +193,13 @@ bool VsEnvironmentDetector::startDetection(const std::vector<MSVC *> &compatible static void batClearVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) - s << "set " << varname << '=' << endl; + s << "set " << varname << '=' << Qt::endl; } static void batPrintVars(QTextStream &s, const QStringList &varnames) { for (const QString &varname : varnames) - s << "echo " << varname << "=%" << varname << '%' << endl; + s << "echo " << varname << "=%" << varname << '%' << Qt::endl; } static QString vcArchitecture(const MSVC *msvc) @@ -232,7 +232,10 @@ void VsEnvironmentDetector::writeBatchFile(QIODevice *device, const QString &vcv << QStringLiteral("INCLUDE") << QStringLiteral("LIB") << QStringLiteral("WindowsSdkDir") << QStringLiteral("WindowsSDKVersion") << QStringLiteral("VSINSTALLDIR"); QTextStream s(device); + using Qt::endl; s << "@echo off" << endl; + // Avoid execution of powershell (in vsdevcmd.bat), which is not in the cleared PATH + s << "set VSCMD_SKIP_SENDTELEMETRY=1" << endl; for (const MSVC *msvc : msvcs) { s << "echo --" << msvc->architecture << "--" << endl << "setlocal" << endl; diff --git a/src/lib/scriptengine/use_scriptengine.pri b/src/lib/scriptengine/use_scriptengine.pri index 6450e171f..e8f82a949 100644 --- a/src/lib/scriptengine/use_scriptengine.pri +++ b/src/lib/scriptengine/use_scriptengine.pri @@ -3,7 +3,15 @@ isEmpty(QBSLIBDIR) { QBSLIBDIR = $$shadowed($$PWD/../../../$${QBS_LIBRARY_DIRNAME}) } - LIBS += -L$$QBSLIBDIR -lqbsscriptengine$$qtPlatformTargetSuffix() + + LIBS += -L$$QBSLIBDIR + macos { + LIBS += -lqbsscriptengine + } + else { + LIBS += -lqbsscriptengine$$qtPlatformTargetSuffix() + } + } INCLUDEPATH += \ |