ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session, TopDUContext::Features features, IncludeFileContexts& includedFiles, ClangIndex* index) { if (includedFiles.contains(file)) { return {}; } // prevent recursion includedFiles.insert(file, {}); // ensure DUChain for imports are build properly foreach(const auto& import, imports.values(file)) { buildDUChain(import.file, imports, session, features, includedFiles, index); } const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath()); if (path.isEmpty()) { // may happen when the file gets removed before the job is run return {}; } const auto& environment = session.environment(); bool update = false; UrlParseLock urlLock(path); ReferencedTopDUContext context; { DUChainWriteLocker lock; context = DUChain::self()->chainForDocument(path, &environment); if (!context) { context = ::createTopContext(path, environment); } else { update = true; } includedFiles.insert(file, context); if (update) { auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data())); Q_ASSERT(envFile); if (!envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) { return context; } else { //TODO: don't attempt to update if this environment is worse quality than the outdated one if (index && envFile->environmentQuality() < environment.quality()) { index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path); } envFile->setEnvironment(environment); envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url())); } context->clearImportedParentContexts(); } context->setFeatures(features); foreach(const auto& import, imports.values(file)) { Q_ASSERT(includedFiles.contains(import.file)); auto ctx = includedFiles.value(import.file); if (!ctx) { // happens for cyclic imports continue; } context->addImportedParentContext(ctx, import.location); } context->updateImportsCache(); } const auto problems = session.problemsForFile(file); { DUChainWriteLocker lock; context->setProblems(problems); } Builder::visit(session.unit(), file, includedFiles, update); return context; }
ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session, TopDUContext::Features features, IncludeFileContexts& includedFiles, ClangIndex* index, const std::function<bool()>& abortFunction) { if (includedFiles.contains(file)) { return {}; } if (abortFunction && abortFunction()) { return {}; } // prevent recursion includedFiles.insert(file, {}); // ensure DUChain for imports are build properly foreach(const auto& import, imports.values(file)) { buildDUChain(import.file, imports, session, features, includedFiles, index, abortFunction); } const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath()); if (path.isEmpty()) { // may happen when the file gets removed before the job is run return {}; } const auto& environment = session.environment(); bool update = false; UrlParseLock urlLock(path); ReferencedTopDUContext context; { DUChainWriteLocker lock; context = DUChain::self()->chainForDocument(path, &environment); if (!context) { context = ::createTopContext(path, environment); } else { update = true; } includedFiles.insert(file, context); if (update) { auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data())); Q_ASSERT(envFile); if (!envFile) return context; /* NOTE: When we are here, then either the translation unit or one of its headers was changed. * Thus we must always update the translation unit to propagate the change(s). * See also: https://bugs.kde.org/show_bug.cgi?id=356327 * This assumes that headers are independent, we may need to improve that in the future * and also update header files more often when other files included therein got updated. */ if (path != environment.translationUnitUrl() && !envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) { return context; } else { //TODO: don't attempt to update if this environment is worse quality than the outdated one if (index && envFile->environmentQuality() < environment.quality()) { index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path); } envFile->setEnvironment(environment); envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url())); } context->clearImportedParentContexts(); } context->setFeatures(features); foreach(const auto& import, imports.values(file)) { auto ctx = includedFiles.value(import.file); if (!ctx) { // happens for cyclic imports continue; } context->addImportedParentContext(ctx, import.location); } context->updateImportsCache(); } const auto problems = session.problemsForFile(file); { DUChainWriteLocker lock; context->setProblems(problems); } Builder::visit(session.unit(), file, includedFiles, update); DUChain::self()->emitUpdateReady(path, context); return context; }