/* * This file is part of KDevelop * * Copyright 2006 Adam Treat * Copyright 2007-2009 David Nolden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "preprocessjob.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpplanguagesupport.h" #include "cppparsejob.h" #include "parser/ast.h" #include "parser/parsesession.h" #include "parser/rpp/pp-engine.h" #include "parser/rpp/pp-macro.h" #include "parser/rpp/preprocessor.h" #include "environmentmanager.h" #include "cpppreprocessenvironment.h" #include "cppdebughelper.h" #include "codegen/unresolvedincludeassistant.h" // #define ifDebug(x) x #include "cpputils.h" #include const uint maxIncludeDepth = 50; static QString pathsToString(const Path::List& paths) { QString str; foreach( const Path& p, paths ) { str += p.pathOrUrl() + "\n"; } return str; } PreprocessJob::PreprocessJob(CPPParseJob * parent) : ThreadWeaver::Job(parent) , m_currentEnvironment(0) , m_firstEnvironmentFile( new Cpp::EnvironmentFile( parent->document(), 0 ) ) , m_success(true) , m_headerSectionEnded(false) , m_pp(0) { } PreprocessJob::~PreprocessJob() { delete m_currentEnvironment; } KDevelop::ParsingEnvironment* PreprocessJob::createStandardEnvironment() { CppPreprocessEnvironment* ret = new CppPreprocessEnvironment(Cpp::EnvironmentFilePointer()); ret->merge( CppUtils::standardMacros() ); return ret; } CPPParseJob * PreprocessJob::parentJob() const { return static_cast(const_cast(parent())); } void PreprocessJob::foundHeaderGuard(rpp::Stream& stream, KDevelop::IndexedString guardName) { Q_UNUSED(stream); KDevelop::DUChainWriteLocker lock(KDevelop::DUChain::lock()); m_currentEnvironment->environmentFile()->setHeaderGuard(guardName); //In naive matching mode, we ignore the dependence on header-guards if(Cpp::EnvironmentManager::self()->matchingLevel() <= Cpp::EnvironmentManager::Naive) m_currentEnvironment->removeString(guardName); } void PreprocessJob::run() { if(!ICore::self()->languageController()->language("C++")->languageSupport()) return; //If we have a parent, that parent already has locked the parse-lock QReadLocker lock(parentJob()->parentPreprocessor() ? 0 : parentJob()->cpp()->language()->parseLock()); //It seems like we cannot influence the actual thread priority in thread-weaver, so for now set it here. //It must be low so the GUI stays fluid. if(QThread::currentThread()) QThread::currentThread()->setPriority(QThread::LowestPriority); //kDebug(9007) << "Started pp job" << this << "parse" << parentJob()->parseJob() << "parent" << parentJob(); kDebug(9007) << "PreprocessJob: preprocessing" << parentJob()->document().str(); if( parentJob()->parentPreprocessor() ) kDebug(9007) << "PARENT:" << parentJob()->parentPreprocessor()->parentJob()->document().toUrl(); if (checkAbort()) return; { KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); if(Cpp::EnvironmentManager::self()->isSimplifiedMatching()) { //Make sure that proxy-contexts and content-contexts never have the same identity, even if they have the same content. m_firstEnvironmentFile->setIdentityOffset(1); //Mark the first environment-file as the proxy m_secondEnvironmentFile = new Cpp::EnvironmentFile( parentJob()->document(), 0 ); } } rpp::pp preprocessor(this); m_pp = &preprocessor; //Eventually initialize the environment with the parent-environment to get its macros m_currentEnvironment = new CppPreprocessEnvironment( m_firstEnvironmentFile ); //If we are included from another preprocessor, copy its macros if( parentJob()->parentPreprocessor() ) { m_currentEnvironment->swapMacros( parentJob()->parentPreprocessor()->m_currentEnvironment ); } else { //Insert standard-macros m_currentEnvironment->merge( CppUtils::standardMacros() ); parentJob()->mergeDefines(static_cast(*m_currentEnvironment)); } const auto& macroNamesAtBeginning = m_currentEnvironment->macroNameSet(); KDevelop::ParsingEnvironmentFilePointer updatingEnvironmentFile; { ///Find a context that can be updated, and eventually break processing right here, if we notice we don't need to update KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); //Make sure we only match proxy-contexts for updating m_currentEnvironment->setIdentityOffsetRestriction(m_firstEnvironmentFile->identityOffset()); updatingEnvironmentFile = KDevelop::ParsingEnvironmentFilePointer( KDevelop::DUChain::self()->environmentFileForDocument(parentJob()->document(), m_currentEnvironment, (bool)m_secondEnvironmentFile) ); if(parentJob()->masterJob() == parentJob() && updatingEnvironmentFile) { //Check whether we need to run at all, or whether the file is already up to date bool fileFeaturesSatisfied = updatingEnvironmentFile->featuresSatisfied(parentJob()->minimumFeatures()); bool slaveFeaturesSatisfied = updatingEnvironmentFile->featuresSatisfied(parentJob()->slaveMinimumFeatures()); if(fileFeaturesSatisfied && slaveFeaturesSatisfied) { Path localPath = Path(parentJob()->document().str()).parent(); Cpp::EnvironmentFile* cppEnv = dynamic_cast(updatingEnvironmentFile.data()); Q_ASSERT(cppEnv); //When possible, we determine whether an update is needed without getting the include-paths, because that's very expensive bool needsUpdate = cppEnv->needsUpdate(); if(!cppEnv->missingIncludeFiles().isEmpty() && !needsUpdate) { for(Cpp::ReferenceCountedStringSet::Iterator it = cppEnv->missingIncludeFiles().iterator(); it; ++it) kDebug(9007) << updatingEnvironmentFile->url().str() << "has missing include:" << (*it).str(); readLock.unlock(); Path::List includePaths = parentJob()->includePathUrls(); readLock.lock(); needsUpdate = CppUtils::needsUpdate(Cpp::EnvironmentFilePointer(cppEnv), localPath, includePaths); } if(!needsUpdate) { parentJob()->setNeedsUpdate(false); return; } } else if (fileFeaturesSatisfied && !slaveFeaturesSatisfied) { // This is strange, because importees should not require more features than the importer kDebug() << "Slaves require more features than file itself" << parentJob()->slaveMinimumFeatures() << updatingEnvironmentFile->features() << parentJob()->document().toUrl(); } } } //We do this down here, so we eventually can prevent determining the include-paths if nothing needs to be updated m_firstEnvironmentFile->setIncludePaths( parentJob()->masterJob()->indexedIncludePaths() ); if(m_secondEnvironmentFile) m_secondEnvironmentFile->setIncludePaths(m_firstEnvironmentFile->includePaths()); if (checkAbort() || !readContents()) return; { ///Find a context that can be updated KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); KDevelop::ReferencedTopDUContext updating; if(updatingEnvironmentFile) updating = updatingEnvironmentFile->topContext(); if(m_secondEnvironmentFile) parentJob()->setUpdatingProxyContext( updating ); //The content-context to be updated will be searched later else parentJob()->setUpdatingContentContext( updating ); if( updating ) { //We don't need to change anything, because the EnvironmentFile will be replaced with a new one m_updatingEnvironmentFile = KSharedPtr( dynamic_cast(updating->parsingEnvironmentFile().data()) ); } if( m_secondEnvironmentFile && parentJob()->updatingProxyContext() ) { // Must be true, because we explicitly passed the flag to chainForDocument Q_ASSERT((parentJob()->updatingProxyContext()->parsingEnvironmentFile()->isProxyContext())); } } preprocessor.setEnvironment( m_currentEnvironment ); // Process files in include paths as #include "file" // this is analogous to -include command line option of clang/cc for (auto i: parentJob()->masterJob()->indexedIncludePaths()) { auto include = i.toUrl().toLocalFile(); QFileInfo info(include); if (info.isFile() && CppUtils::isHeader(include)) { sourceNeeded(include, IncludeLocal, -1, false); } } PreprocessedContents result = preprocessor.processFile(parentJob()->document().str(), m_contents); if(Cpp::EnvironmentManager::self()->matchingLevel() <= Cpp::EnvironmentManager::Naive && !m_headerSectionEnded && !m_firstEnvironmentFile->headerGuard().isEmpty()) { if(macroNamesAtBeginning.contains(m_firstEnvironmentFile->headerGuard())) { //Remove the header-guard, and re-preprocess, since we don't do real environment-management(We don't allow empty versions) // We also have to clear the location-table here, because it already contains 'wrong' contents from the previous preprocessing kDebug() << "Re-processing header with the header-guard disabled"; delete m_currentEnvironment->takeLocationTable(); m_currentEnvironment->removeMacro(m_firstEnvironmentFile->headerGuard()); result = preprocessor.processFile(parentJob()->document().str(), m_contents); } } if(!m_headerSectionEnded) { ifDebug( kDebug(9007) << parentJob()->document().str() << ": header-section was not ended"; ) headerSectionEndedInternal(0); } m_currentEnvironment->finishEnvironment(m_currentEnvironment->environmentFile() == m_updatingEnvironmentFile); foreach (KDevelop::ProblemPointer p, preprocessor.problems()) { p->setSource(KDevelop::ProblemData::Preprocessor); parentJob()->addPreprocessorProblem(p); } parentJob()->parseSession()->setContents( result, m_currentEnvironment->takeLocationTable() ); parentJob()->parseSession()->setUrl( parentJob()->document() ); if(m_secondEnvironmentFile) parentJob()->setProxyEnvironmentFile( m_firstEnvironmentFile.data() ); else parentJob()->setContentEnvironmentFile( m_firstEnvironmentFile.data() ); if(m_secondEnvironmentFile) {//Copy some information from the environment-file to its content-part KDevelop::DUChainWriteLocker readLock(KDevelop::DUChain::lock()); m_secondEnvironmentFile->setModificationRevision(m_firstEnvironmentFile->modificationRevision()); if(m_firstEnvironmentFile->headerGuard().isEmpty()) m_firstEnvironmentFile->setHeaderGuard(m_secondEnvironmentFile->headerGuard()); else m_secondEnvironmentFile->setHeaderGuard(m_firstEnvironmentFile->headerGuard()); } if( m_secondEnvironmentFile ) { //kDebug(9008) << parentJob()->document().str() << "Merging content-environment file into header environment-file"; KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); m_firstEnvironmentFile->merge(*m_secondEnvironmentFile); parentJob()->setContentEnvironmentFile(m_secondEnvironmentFile.data()); } if( PreprocessJob* parentPreprocessor = parentJob()->parentPreprocessor() ) { //If we are included from another preprocessor, give it back the modified macros, parentPreprocessor->m_currentEnvironment->swapMacros( m_currentEnvironment ); //Merge include-file-set, defined macros, used macros, and string-set KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); parentPreprocessor->m_currentEnvironment->environmentFile()->merge(*m_firstEnvironmentFile); }else{ /* kDebug(9007) << "Macros:"; for( rpp::Environment::EnvironmentMap::const_iterator it = m_currentEnvironment->environment().begin(); it != m_currentEnvironment->environment().end(); ++it ) { kDebug(9007) << (*it)->name.str() << " from: " << (*it)->file << ":" << (*it)->sourceLine; }*/ } ifDebug( kDebug(9007) << "PreprocessJob: finished" << parentJob()->document().str(); ) m_pp = 0; m_currentEnvironment = 0; //Was given to the pp-engine, and will be destroyed by that } void PreprocessJob::headerSectionEnded(rpp::Stream& stream) { headerSectionEndedInternal(&stream); } void PreprocessJob::headerSectionEndedInternal(rpp::Stream* stream) { bool closeStream = false; m_headerSectionEnded = true; ifDebug( kDebug(9007) << parentJob()->document().str() << "PreprocessJob::headerSectionEnded, " << parentJob()->includedFiles().count() << " included in header-section" << "upcoming identity-offset:" << m_pp->branchingHash()*19; ) if( m_secondEnvironmentFile ) { m_secondEnvironmentFile->setIdentityOffset(m_pp->branchingHash()*19); if( stream ) { m_secondEnvironmentFile->setContentStartLine(stream->originalInputPosition().line); m_firstEnvironmentFile->setContentStartLine(stream->originalInputPosition().line); } ///Only allow content-contexts that have the same branching hash, ///because else they were differently influenced earlier by macros in the header-section ///Example: A file that has completely different content depending on an #ifdef m_currentEnvironment->setIdentityOffsetRestriction(m_secondEnvironmentFile->identityOffset()); IndexedString u = parentJob()->document(); ///Find a matching content-context KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); KDevelop::ReferencedTopDUContext content; if(m_updatingEnvironmentFile) content = KDevelop::ReferencedTopDUContext(DUChainUtils::contentContextFromProxyContext(m_updatingEnvironmentFile->topContext())); else content = KDevelop::DUChain::self()->chainForDocument(u, m_currentEnvironment, false); m_currentEnvironment->disableIdentityOffsetRestriction(); if(content && content->parsingEnvironmentFile()->isProxyContext()) { kWarning() << "Got proxy-context as content-context for file" << content->url().str() << ", not updating"; content = KDevelop::ReferencedTopDUContext(); } if(content) { //We have found a content-context that we can use parentJob()->setUpdatingContentContext(content); Q_ASSERT(!content->parsingEnvironmentFile()->isProxyContext()); Cpp::EnvironmentFilePointer contentEnvironment(dynamic_cast(content->parsingEnvironmentFile().data())); Q_ASSERT(m_updatingEnvironmentFile || contentEnvironment->identityOffset() == m_secondEnvironmentFile->identityOffset()); ///@todo think whether localPath is needed Path localPath = Path(parentJob()->document().str()).parent(); if(contentEnvironment->matchEnvironment(m_currentEnvironment) && !CppUtils::needsUpdate(contentEnvironment, localPath, parentJob()->includePathUrls()) && (!parentJob()->masterJob()->needUpdateEverything() || parentJob()->masterJob()->wasUpdated(content)) && (content->parsingEnvironmentFile()->featuresSatisfied(parentJob()->minimumFeatures()) && content->parsingEnvironmentFile()->featuresSatisfied(parentJob()->slaveMinimumFeatures())) && Cpp::EnvironmentManager::self()->matchingLevel() != Cpp::EnvironmentManager::Disabled) { ///@todo We never keep the duchain while updating now in disabled environment matching mode. /// We don't need it there, and changes in imports may be simply ignored when the keeping is enabled. /// However when full environment management is enabled this is needed, as the same content may be shared for multiple proxy contexts. //We can completely re-use the specialized context: m_secondEnvironmentFile = dynamic_cast(content->parsingEnvironmentFile().data()); m_updatingEnvironmentFile = m_secondEnvironmentFile; //Merge the macros etc. into the current environment m_currentEnvironment->merge( m_secondEnvironmentFile.data() ); ifDebug( kDebug(9007) << "closing data-stream, body does not need to be processed"; ) closeStream = true; parentJob()->setKeepDuchain(true); //We truncate all following content, so we don't want to update the du-chain. Q_ASSERT(m_secondEnvironmentFile); } else { ifDebug( kDebug(9007) << "updating content-context"; ) m_updatingEnvironmentFile = KSharedPtr(dynamic_cast(content->parsingEnvironmentFile().data())); //We will re-use the specialized context, but it needs updating. So we keep processing here. //We don't need to change m_updatingEnvironmentFile, because we will create a new one. } } else { //We need to process the content ourselves ifDebug( kDebug(9007) << "could not find a matching content-context"; ) } m_currentEnvironment->finishEnvironment(); m_currentEnvironment->setEnvironmentFile(m_secondEnvironmentFile); } if( stream ) { if( closeStream ) stream->toEnd(); } } rpp::Stream* PreprocessJob::sourceNeeded(QString& _fileName, IncludeType type, int sourceLine, bool skipCurrentPath) { Q_UNUSED(type) if(0){ uint currentDepth = 0; CPPParseJob* job = parentJob(); while(job->parentPreprocessor()) { ++currentDepth; job = job->parentPreprocessor()->parentJob(); } if(currentDepth > maxIncludeDepth) { kDebug(9007) << "maximum depth reached while including" << _fileName << "into" << parentJob()->document().str(); return 0; } } KUrl fileNameUrl(_fileName); TopDUContext::Features slaveMinimumFeatures = parentJob()->slaveMinimumFeatures(); QString fileName = fileNameUrl.pathOrUrl(); if (checkAbort()) return 0; ifDebug( kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": searching for include" << fileName; ) Path from; if (skipCurrentPath) from = parentJob()->includedFromPath(); QPair included; QFileInfo info(fileName); if (info.isFile() && info.isAbsolute()) { //this is an auto included file i.e. there is no #include directive in the source file for it included.first = Path(fileNameUrl.toLocalFile()); included.second = Path(fileNameUrl.directory()); } else { included = CppUtils::findInclude(parentJob()->includePathUrls(), parentJob()->localPath(), fileName, type, from); } Path includedFile = included.first; if (includedFile.isValid()) { const IndexedString indexedFile(includedFile.pathOrUrl()); { //Prevent recursion that may cause a crash PreprocessJob* current = this; while(current) { if(current->parentJob()->document() == indexedFile) { KDevelop::ProblemPointer p(new Problem()); ///@todo create special include-problem p->setSource(KDevelop::ProblemData::Preprocessor); p->setDescription(i18n("File was included recursively from within itself: %1", fileName )); p->setFinalLocation(DocumentRange(parentJob()->document(), SimpleRange(sourceLine,0, sourceLine+1,0))); parentJob()->addPreprocessorProblem(p); return 0; } current = current->parentJob()->parentPreprocessor(); } } ifDebug( kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << "(" << m_currentEnvironment->environment().size() << "macros)" << ": found include-file" << fileName << ":" << includedFile; ) KDevelop::ReferencedTopDUContext includedContext; bool updateNeeded = false; bool updateForbidden = false; { KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); includedContext = KDevelop::DUChain::self()->chainForDocument(indexedFile, m_currentEnvironment, (bool)m_secondEnvironmentFile); //Check if the same file _is_ one of the parents, and if it is, import it later on if(Cpp::EnvironmentManager::self()->matchingLevel() <= Cpp::EnvironmentManager::Naive) { CPPParseJob* job = parentJob(); while(job->parentPreprocessor()) { job = job->parentPreprocessor()->parentJob(); if(job->document() == indexedFile) { parentJob()->addDelayedImport(CPPParseJob::LineJobPair(job, sourceLine)); return 0; } } // if(!includedContext) { // //Check if there is a parsed version that is disabled by its header-guard right now, and enventually use that one. // QList allVersions = DUChain::self()->allEnvironmentFiles(indexedFile); // foreach(ParsingEnvironmentFilePointer version, allVersions) { // Cpp::EnvironmentFile* envFile = dynamic_cast(version.data()); // // if(envFile && (envFile->isProxyContext() || !m_secondEnvironmentFile) && !envFile->headerGuard().isEmpty()) { // if(m_currentEnvironment->macroNameSet().contains(envFile->headerGuard())) { // includedContext = envFile->topContext(); // // break; // } // } // } // } } if(includedContext) { Cpp::EnvironmentFilePointer includedEnvironment(dynamic_cast(includedContext->parsingEnvironmentFile().data())); if( includedEnvironment ) { updateNeeded = CppUtils::needsUpdate(includedEnvironment, parentJob()->localPath(), parentJob()->includePathUrls()); //The ForceUpdateRecursive flag is removed before checking for satisfied features, so we can prevent double-updating through "wasUpdated()" below (see *1) updateNeeded |= !includedEnvironment->featuresSatisfied((TopDUContext::Features)(slaveMinimumFeatures & (~TopDUContext::ForceUpdateRecursive))); //(*1) Do not update again if ForceUpdate is given and the context was already updated during this run updateNeeded |= (slaveMinimumFeatures & TopDUContext::ForceUpdate) && !parentJob()->masterJob()->wasUpdated(includedContext.data()); #if 0 //If header-guards should be ignored, unguard the file if(Cpp::EnvironmentManager::self()->ignoreGuardsForImporting() && !includedEnvironment->headerGuard().isEmpty() && m_currentEnvironment->macroNameSet().contains(includedEnvironment->headerGuard())) { m_currentEnvironment->removeMacro(includedEnvironment->headerGuard()); } #endif if(!includedEnvironment->headerGuard().isEmpty() && m_currentEnvironment->macroNameSet().contains(includedEnvironment->headerGuard())) { updateForbidden = true; kDebug() << "forbidding update of" << includedFile; updateNeeded = false; } } } } if( includedContext && (updateForbidden || (!updateNeeded && (!parentJob()->masterJob()->needUpdateEverything() || parentJob()->masterJob()->wasUpdated(includedContext)))) ) { ifDebug( kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": took included file from the du-chain" << fileName; ) KDevelop::DUChainReadLocker readLock(KDevelop::DUChain::lock()); parentJob()->addIncludedFile(includedContext, sourceLine); KDevelop::ParsingEnvironmentFilePointer file = includedContext->parsingEnvironmentFile(); Cpp::EnvironmentFile* environmentFile = dynamic_cast (file.data()); if( environmentFile ) { m_currentEnvironment->merge( environmentFile, true ); ifDebug( kDebug() << "PreprocessJob" << parentJob()->document().str() << "Merging included file into environment-file"; ) } else { ifDebug( kDebug(9007) << "preprocessjob: included file" << includedFile << "found in du-chain, but it has no parse-environment information, or it was not parsed by c++ support"; ) } } else { if(updateNeeded) kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": need to update" << includedFile; else if(parentJob()->masterJob()->needUpdateEverything() && includedContext) kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": needUpateEverything, updating" << includedFile; else kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": no fitting entry for" << includedFile << "in du-chain, parsing"; /* if( updateNeeded && !parentJob()->masterJob()->needUpdateEverything() ) { //When a new include-file was found, that can influence not found declarations in all following encountered contexts, so they all need updating. kDebug(9007) << "Marking every following encountered context to be updated"; parentJob()->masterJob()->setNeedUpdateEverything( true ); //@todo make this a bit more intelligent, instead of updating everything that follows }*/ /// Why bother the threadweaver? We need the preprocessed text NOW so we simply parse the /// included file right here. Parallel parsing cannot be used here, because we need the /// macros before we can continue. // Create a slave-job that will take over our macros. // It will itself take our macros modify them, copy them back, // and merge information into our m_firstEnvironmentFile ///The second parameter is zero because we are in a background-thread and we here ///cannot create a slave of the foreground cpp-support-part. CPPParseJob* slaveJob = new CPPParseJob(indexedFile, parentJob()->cpp(), this); slaveJob->setMinimumFeatures(slaveMinimumFeatures); slaveJob->setIncludedFromPath(included.second); slaveJob->parseForeground(); // Add the included file. if(slaveJob->duChain()) parentJob()->addIncludedFile(slaveJob->duChain(), sourceLine); else kDebug(9007) << "parse-job for" << includedFile << "did not return a top-context"; delete slaveJob; } ifDebug( kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << "(" << m_currentEnvironment->environment().size() << "macros)" << ": file included"; ) { DUChainReadLocker lock(DUChain::lock()); if( m_updatingEnvironmentFile && m_updatingEnvironmentFile->missingIncludeFiles().contains(IndexedString(fileName)) ) { //We are finding a file that was not in the include-path last time //All following contexts need to be updated, because they may contain references to missing declarations parentJob()->masterJob()->setNeedUpdateEverything( true ); kDebug(9007) << "Marking every following encountered context to be updated"; } } } else { kDebug(9007) << "PreprocessJob" << parentJob()->document().str() << ": include not found:" << fileName; Cpp::MissingIncludePathProblem::Ptr p(new Cpp::MissingIncludePathProblem); ///@todo create special include-problem p->setSource(KDevelop::ProblemData::Preprocessor); p->setDescription(i18n("Included file was not found: %1", fileName )); p->setExplanation(i18n("Searched include path:\n%1", pathsToString(parentJob()->includePathUrls()))); p->setFinalLocation(DocumentRange(parentJob()->document(), SimpleRange(sourceLine,0, sourceLine+1,0))); p->setSolutionAssistant(KSharedPtr(new Cpp::MissingIncludePathAssistant(parentJob()->masterJob()->document(), _fileName))); parentJob()->addPreprocessorProblem(KSharedPtr::staticCast(p)); ///@todo respect all the specialties like starting search at a specific path ///Before doing that, model findInclude(..) exactly after the standard m_firstEnvironmentFile->addMissingIncludeFile(IndexedString(fileName)); } return 0; } bool PreprocessJob::checkAbort() { if(ICore::self()->shuttingDown()) { kDebug(9007) << "The application is shutting down"; return true; } if(!ICore::self()->languageController()->language("C++") || !ICore::self()->languageController()->language("C++")->languageSupport()) { kDebug(9007) << "Environment-manager disappeared" ; return true; } if (CPPParseJob* parent = parentJob()) { if (parent->abortRequested()) { parent->abortJob(); m_success = false; setFinished(true); return true; } } else { // What... the parent job got deleted?? kWarning(9007) << "Parent job disappeared!!" ; m_success = false; setFinished(true); return true; } return false; } bool PreprocessJob::readContents() { KDevelop::ProblemPointer p = parentJob()->readContents(); if(p) { parentJob()->addPreprocessorProblem(p); return false; } m_firstEnvironmentFile->setModificationRevision( parentJob()->contents().modification ); m_contents = parentJob()->contents().contents; ifDebug( kDebug( 9007 ) << "===-- PREPROCESSING --===> " << parentJob()->document().str() << endl; ) return true; } bool PreprocessJob::success() const { return m_success; } KDevelop::ParsingEnvironment * PreprocessJob::m_standardEnvironment = 0; const KDevelop::ParsingEnvironment * PreprocessJob::standardEnvironment() { if(!m_standardEnvironment) m_standardEnvironment = createStandardEnvironment(); return m_standardEnvironment; } #include "moc_preprocessjob.cpp"