kde-extraapps/kdevplatform/util/duchainify/main.cpp
2015-07-26 14:23:17 +03:00

267 lines
9.5 KiB
C++

/***************************************************************************
* Copyright 2009 David Nolden <david.nolden.kdevelop@art-master.de> *
* *
* 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 <shell/core.h>
#include <shell/shellextension.h>
#include <language/backgroundparser/parsejob.h>
#include <language/backgroundparser/backgroundparser.h>
#include <language/duchain/duchain.h>
#include <language/duchain/duchainlock.h>
#include <language/duchain/dumpchain.h>
#include <language/duchain/problem.h>
#include <interfaces/ilanguage.h>
#include <interfaces/iplugincontroller.h>
#include <interfaces/ilanguagecontroller.h>
#include <tests/autotestshell.h>
#include <tests/testcore.h>
#include <KDE/KApplication>
#include <KDE/KCmdLineArgs>
#include <KDE/KAboutData>
#include <KDE/KDebug>
#include <QtCore/QStringList>
#include <QtCore/QFile>
#include <QtCore/QTimer>
#include <QtCore/QDirIterator>
#include <stdio.h>
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; i<m_args->count(); 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 <count>", ki18n("Number of threads to use"));
options.add("f").add("features <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"