/*************************************************************************** * Copyright 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 Library 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 "main.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool verbose=false, warnings=false; using namespace KDevelop; void messageOutput(QtMsgType type, const char *msg) { switch (type) { case QtDebugMsg: if(verbose) std::cerr << msg << std::endl; break; case QtWarningMsg: if(warnings) std::cerr << msg << std::endl; break; case QtCriticalMsg: std::cerr << msg << std::endl; break; case QtFatalMsg: std::cerr << msg << std::endl; abort(); } } Manager::Manager(KCmdLineArgs* args) : m_total(0), m_args(args), m_allFilesAdded(0) { } void Manager::init() { KUrl::List includes; if(m_args->count() == 0) { std::cerr << "Need directory to duchainify" << std::endl; QCoreApplication::exit(1); } uint features = TopDUContext::VisibleDeclarationsAndContexts; if(m_args->isSet("features")) { QString featuresStr = m_args->getOption("features"); if(featuresStr == "visible-declarations") { features = TopDUContext::VisibleDeclarationsAndContexts; } else if(featuresStr == "all-declarations") { features = TopDUContext::AllDeclarationsAndContexts; } else if(featuresStr == "all-declarations-and-uses") { features = TopDUContext::AllDeclarationsContextsAndUses; } else if(featuresStr == "all-declarations-and-uses-and-AST") { features = TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::AST; } else if(featuresStr == "empty") { features = TopDUContext::Empty; } else if(featuresStr == "simplified-visible-declarations") { features = TopDUContext::SimplifiedVisibleDeclarationsAndContexts; } else{ std::cerr << "Wrong feature-string given\n"; QCoreApplication::exit(2); return; } } if(m_args->isSet("force-update")) features |= TopDUContext::ForceUpdate; if(m_args->isSet("force-update-recursive")) features |= TopDUContext::ForceUpdateRecursive; if(m_args->isSet("threads")) { bool ok = false; int count = m_args->getOption("threads").toInt(&ok); ICore::self()->languageController()->backgroundParser()->setThreadCount(count); if(!ok) { std::cerr << "bad thread count\n"; QCoreApplication::exit(3); return; } } // quit when everything is done // background parser emits hideProgress() signal in two situations: // when everything is done and when bgparser is suspended // later doesn't happen in duchain, so just rely on hideProgress() // and quit when it's emitted connect(ICore::self()->languageController()->backgroundParser(), SIGNAL(hideProgress(KDevelop::IStatus*)), this, SLOT(finish())); for(int i=0; icount(); i++) { addToBackgroundParser(m_args->arg(i), (TopDUContext::Features)features); } m_allFilesAdded = 1; if ( m_total ) { std::cout << "Added " << m_total << " files to the background parser" << std::endl; const int threads = ICore::self()->languageController()->backgroundParser()->threadCount(); std::cout << "parsing with " << threads << " threads" << std::endl; ICore::self()->languageController()->backgroundParser()->parseDocuments(); } else { std::cout << "no files added to the background parser" << std::endl; QCoreApplication::exit(0); return; } } void Manager::updateReady(IndexedString url, ReferencedTopDUContext topContext) { kDebug() << "finished" << url.toUrl().toLocalFile() << "success: " << (bool)topContext; m_waiting.remove(url.toUrl()); std::cout << "processed " << (m_total - m_waiting.size()) << " out of " << m_total << std::endl; if (m_args->isSet("dump-errors") && topContext) { DUChainReadLocker lock; if (!topContext->problems().isEmpty()) { std::cout << topContext->problems().size() << " problems encountered in " << qPrintable(topContext->url().str()) << std::endl; foreach(const ProblemPointer& p, topContext->problems()) { std::cout << " " << qPrintable(p->description()) << "\n range: " << "[(" << p->finalLocation().start.line << ", " << p->finalLocation().start.column << ")," << " (" << p->finalLocation().end.line << ", " << p->finalLocation().end.column << ")]" << std::endl; } } } if (m_args->isSet("dump-context") && topContext) { DUChainReadLocker lock; dumpDUContext(topContext); } } void Manager::addToBackgroundParser(QString path, TopDUContext::Features features) { QFileInfo info(path); if(info.isFile()) { kDebug() << "adding file" << path; KUrl pathUrl(info.canonicalFilePath()); m_waiting << pathUrl; ++m_total; KDevelop::DUChain::self()->updateContextForUrl(KDevelop::IndexedString(pathUrl), features, this); }else if(info.isDir()) { QDirIterator contents(path); while(contents.hasNext()) { QString newPath = contents.next(); if(!newPath.endsWith('.')) addToBackgroundParser(newPath, features); } } } QSet< KUrl > Manager::waiting() { return m_waiting; } void Manager::finish() { std::cout << "ready" << std::endl; QApplication::quit(); } using namespace KDevelop; int main(int argc, char** argv) { KAboutData aboutData( "duchainify", 0, ki18n( "duchainify" ), "1", ki18n("Duchain builder application"), KAboutData::License_GPL, ki18n( "(c) 2009 David Nolden" ), KLocalizedString(), "http://www.kdevelop.org" ); KCmdLineArgs::init( argc, argv, &aboutData, KCmdLineArgs::CmdLineArgNone ); KCmdLineOptions options; options.add("+dir", ki18n("directory")); options.add("w").add("warnings", ki18n("Show warnings")); options.add("V").add("verbose", ki18n("Show warnings and debug output")); options.add("u").add("force-update", ki18n("Enforce an update of the top-contexts corresponding to the given files")); options.add("r").add("force-update-recursive", ki18n("Enforce an update of the top-contexts corresponding to the given files and all included files")); options.add("t").add("threads ", ki18n("Number of threads to use")); options.add("f").add("features ", ki18n("Features to build. Options: empty, simplified-visible-declarations, visible-declarations (default), all-declarations, all-declarations-and-uses, all-declarations-and-uses-and-AST")); options.add("dump-context", ki18n("Print complete Definition-Use Chain on successful parse")); options.add("d").add("dump-errors", ki18n("Print problems encountered during parsing")); KCmdLineArgs::addCmdLineOptions( options ); KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); verbose = args->isSet("verbose"); warnings = args->isSet("warnings"); qInstallMsgHandler(messageOutput); KApplication app(false); AutoTestShell::init(); TestCore::initialize(Core::NoUi, "duchainify"); Manager manager(args); QTimer::singleShot(0, &manager, SLOT(init())); int ret = app.exec(); TestCore::shutdown(); return ret; } #include "moc_main.cpp"