Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

This commit is contained in:
hjk
2009-02-20 10:28:41 +01:00
14 changed files with 366 additions and 23 deletions

View File

@@ -37,6 +37,8 @@
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QEventLoop> #include <QtCore/QEventLoop>
#include <QtCore/QTextCodec> #include <QtCore/QTextCodec>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtGui/QApplication> #include <QtGui/QApplication>
@@ -366,5 +368,108 @@ void SynchronousProcess::processStdErr(bool emitSignals)
} }
} }
// Path utilities
enum OS_Type { OS_Mac, OS_Windows, OS_Unix };
#ifdef Q_OS_WIN
static const OS_Type pathOS = OS_Windows;
#else
# ifdef Q_OS_MAC
static const OS_Type pathOS = OS_Mac;
# else
static const OS_Type pathOS = OS_Unix;
# endif
#endif
// Locate a binary in a directory, applying all kinds of
// extensions the operating system supports.
static QString checkBinary(const QDir &dir, const QString &binary)
{
// naive UNIX approach
const QFileInfo info(dir.filePath(binary));
if (info.isFile() && info.isExecutable())
return info.absoluteFilePath();
// Does the OS have some weird extension concept or does the
// binary have a 3 letter extension?
if (pathOS == OS_Unix)
return QString();
const int dotIndex = binary.lastIndexOf(QLatin1Char('.'));
if (dotIndex != -1 && dotIndex == binary.size() - 4)
return QString();
switch (pathOS) {
case OS_Unix:
break;
case OS_Windows: {
static const char *windowsExtensions[] = {".cmd", ".bat", ".exe", ".com" };
// Check the Windows extensions using the order
const int windowsExtensionCount = sizeof(windowsExtensions)/sizeof(const char*);
for (int e = 0; e < windowsExtensionCount; e ++) {
const QFileInfo windowsBinary(dir.filePath(binary + QLatin1String(windowsExtensions[e])));
if (windowsBinary.isFile() && windowsBinary.isExecutable())
return windowsBinary.absoluteFilePath();
}
}
break;
case OS_Mac: {
// Check for Mac app folders
const QFileInfo appFolder(dir.filePath(binary + QLatin1String(".app")));
if (appFolder.isDir()) {
QString macBinaryPath = appFolder.absoluteFilePath();
macBinaryPath += QLatin1String("/Contents/MacOS/");
macBinaryPath += binary;
const QFileInfo macBinary(macBinaryPath);
if (macBinary.isFile() && macBinary.isExecutable())
return macBinary.absoluteFilePath();
}
}
break;
}
return QString();
}
QString SynchronousProcess::locateBinary(const QString &path, const QString &binary)
{
// Absolute file?
const QFileInfo absInfo(binary);
if (absInfo.isAbsolute())
return checkBinary(absInfo.dir(), absInfo.fileName());
// Windows finds binaries in the current directory
if (pathOS == OS_Windows) {
const QString currentDirBinary = checkBinary(QDir::current(), binary);
if (!currentDirBinary.isEmpty())
return currentDirBinary;
}
const QStringList paths = path.split(pathSeparator());
if (paths.empty())
return QString();
const QStringList::const_iterator cend = paths.constEnd();
for (QStringList::const_iterator it = paths.constBegin(); it != cend; ++it) {
const QDir dir(*it);
const QString rc = checkBinary(dir, binary);
if (!rc.isEmpty())
return rc;
}
return QString();
}
QString SynchronousProcess::locateBinary(const QString &binary)
{
const QByteArray path = qgetenv("PATH");
return locateBinary(QString::fromLocal8Bit(path), binary);
}
QChar SynchronousProcess::pathSeparator()
{
if (pathOS == OS_Windows)
return QLatin1Char(';');
return QLatin1Char(':');
}
} // namespace Utils } // namespace Utils
} // namespace Core } // namespace Core

View File

@@ -114,6 +114,12 @@ public:
SynchronousProcessResponse run(const QString &binary, const QStringList &args); SynchronousProcessResponse run(const QString &binary, const QStringList &args);
// Helpers to find binaries. Do not use it for other path variables
// and file types.
static QString locateBinary(const QString &binary);
static QString locateBinary(const QString &path, const QString &binary);
static QChar pathSeparator();
signals: signals:
void stdOut(const QByteArray &data, bool firstTime); void stdOut(const QByteArray &data, bool firstTime);
void stdErr(const QByteArray &data, bool firstTime); void stdErr(const QByteArray &data, bool firstTime);

View File

@@ -102,8 +102,10 @@ GitClient::GitClient(GitPlugin* plugin)
m_plugin(plugin), m_plugin(plugin),
m_core(Core::ICore::instance()) m_core(Core::ICore::instance())
{ {
if (QSettings *s = m_core->settings()) if (QSettings *s = m_core->settings()) {
m_settings.fromSettings(s); m_settings.fromSettings(s);
m_binaryPath = m_settings.gitBinaryPath();
}
} }
GitClient::~GitClient() GitClient::~GitClient()
@@ -478,7 +480,7 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
if (m_settings.adoptPath) if (m_settings.adoptPath)
environment.set(QLatin1String("PATH"), m_settings.path); environment.set(QLatin1String("PATH"), m_settings.path);
GitCommand* command = new GitCommand(workingDirectory, environment); GitCommand* command = new GitCommand(m_binaryPath, workingDirectory, environment);
if (outputToWindow) { if (outputToWindow) {
if (!editor) { // assume that the commands output is the important thing if (!editor) { // assume that the commands output is the important thing
connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(appendDataAndPopup(QByteArray))); connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(appendDataAndPopup(QByteArray)));
@@ -527,10 +529,9 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
{ {
if (Git::Constants::debug) if (Git::Constants::debug)
qDebug() << "synchronousGit" << workingDirectory << arguments; qDebug() << "synchronousGit" << workingDirectory << arguments;
const QString binary = QLatin1String(Constants::GIT_BINARY);
if (logCommandToWindow) if (logCommandToWindow)
m_plugin->outputWindow()->append(formatCommand(binary, arguments)); m_plugin->outputWindow()->append(formatCommand(m_binaryPath, arguments));
QProcess process; QProcess process;
process.setWorkingDirectory(workingDirectory); process.setWorkingDirectory(workingDirectory);
@@ -540,7 +541,7 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
environment.set(QLatin1String("PATH"), m_settings.path); environment.set(QLatin1String("PATH"), m_settings.path);
process.setEnvironment(environment.toStringList()); process.setEnvironment(environment.toStringList());
process.start(binary, arguments); process.start(m_binaryPath, arguments);
if (!process.waitForFinished()) { if (!process.waitForFinished()) {
if (errorText) if (errorText)
*errorText = "Error: Git timed out"; *errorText = "Error: Git timed out";
@@ -1000,6 +1001,6 @@ void GitClient::setSettings(const GitSettings &s)
m_settings = s; m_settings = s;
if (QSettings *s = m_core->settings()) if (QSettings *s = m_core->settings())
m_settings.toSettings(s); m_settings.toSettings(s);
m_binaryPath = m_settings.gitBinaryPath();
} }
} }

View File

@@ -176,6 +176,7 @@ private:
GitPlugin *m_plugin; GitPlugin *m_plugin;
Core::ICore *m_core; Core::ICore *m_core;
GitSettings m_settings; GitSettings m_settings;
QString m_binaryPath;
}; };

View File

@@ -61,8 +61,10 @@ GitCommand::Job::Job(const QStringList &a, int t) :
{ {
} }
GitCommand::GitCommand(const QString &workingDirectory, GitCommand::GitCommand(const QString &binaryPath,
const QString &workingDirectory,
ProjectExplorer::Environment &environment) : ProjectExplorer::Environment &environment) :
m_binaryPath(binaryPath),
m_workingDirectory(workingDirectory), m_workingDirectory(workingDirectory),
m_environment(environmentToList(environment)) m_environment(environmentToList(environment))
{ {
@@ -109,7 +111,7 @@ void GitCommand::run()
if (Git::Constants::debug) if (Git::Constants::debug)
qDebug() << "GitCommand::run" << j << '/' << count << m_jobs.at(j).arguments; qDebug() << "GitCommand::run" << j << '/' << count << m_jobs.at(j).arguments;
process.start(QLatin1String(Constants::GIT_BINARY), m_jobs.at(j).arguments); process.start(m_binaryPath, m_jobs.at(j).arguments);
if (!process.waitForFinished(m_jobs.at(j).timeout * 1000)) { if (!process.waitForFinished(m_jobs.at(j).timeout * 1000)) {
ok = false; ok = false;
error += QLatin1String("Error: Git timed out"); error += QLatin1String("Error: Git timed out");

View File

@@ -43,9 +43,11 @@ namespace Internal {
class GitCommand : public QObject class GitCommand : public QObject
{ {
Q_DISABLE_COPY(GitCommand)
Q_OBJECT Q_OBJECT
public: public:
explicit GitCommand(const QString &workingDirectory, explicit GitCommand(const QString &binaryPath,
const QString &workingDirectory,
ProjectExplorer::Environment &environment); ProjectExplorer::Environment &environment);
@@ -67,8 +69,7 @@ private:
int timeout; int timeout;
}; };
QStringList environment() const; const QString m_binaryPath;
const QString m_workingDirectory; const QString m_workingDirectory;
const QStringList m_environment; const QStringList m_environment;

View File

@@ -32,9 +32,13 @@
***************************************************************************/ ***************************************************************************/
#include "gitsettings.h" #include "gitsettings.h"
#include "gitconstants.h"
#include <utils/synchronousprocess.h>
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QCoreApplication>
static const char *groupC = "Git"; static const char *groupC = "Git";
static const char *sysEnvKeyC = "SysEnv"; static const char *sysEnvKeyC = "SysEnv";
@@ -79,5 +83,30 @@ bool GitSettings::equals(const GitSettings &s) const
return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount && timeout == s.timeout; return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount && timeout == s.timeout;
} }
QString GitSettings::gitBinaryPath(bool *ok, QString *errorMessage) const
{
// Locate binary in path if one is specified, otherwise default
// to pathless binary
if (ok)
*ok = true;
if (errorMessage)
errorMessage->clear();
const QString binary = QLatin1String(Constants::GIT_BINARY);
// Easy, git is assumed to be elsewhere accessible
if (!adoptPath)
return binary;
// Search in path?
const QString pathBinary = Core::Utils::SynchronousProcess::locateBinary(path, binary);
if (pathBinary.isEmpty()) {
if (ok)
*ok = false;
if (errorMessage)
*errorMessage = QCoreApplication::translate("GitSettings",
"The binary '%1' could not be located in the path '%2'").arg(binary, path);
return binary;
}
return pathBinary;
}
} }
} }

View File

@@ -51,6 +51,8 @@ struct GitSettings
void fromSettings(QSettings *); void fromSettings(QSettings *);
void toSettings(QSettings *) const; void toSettings(QSettings *) const;
QString gitBinaryPath(bool *ok = 0, QString *errorMessage = 0) const;
bool equals(const GitSettings &s) const; bool equals(const GitSettings &s) const;
bool adoptPath; bool adoptPath;

View File

@@ -36,8 +36,10 @@
#include "gitplugin.h" #include "gitplugin.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtGui/QMessageBox>
using namespace Git::Internal; namespace Git {
namespace Internal {
SettingsPageWidget::SettingsPageWidget(QWidget *parent) : SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
QWidget(parent) QWidget(parent)
@@ -101,6 +103,17 @@ void SettingsPage::apply()
{ {
if (!m_widget) if (!m_widget)
return; return;
const GitSettings newSettings = m_widget->settings();
GitPlugin::instance()->setSettings(m_widget->settings()); // Warn if git cannot be found in path if the widget is on top
if (m_widget->isVisible()) {
bool gitFoundOk;
QString errorMessage;
newSettings.gitBinaryPath(&gitFoundOk, &errorMessage);
if (!gitFoundOk)
QMessageBox::warning(m_widget, tr("Git Settings"), errorMessage);
}
GitPlugin::instance()->setSettings(newSettings);
}
}
} }

View File

@@ -77,12 +77,7 @@ int ASTVisitor::tokenKind(unsigned index) const
{ return translationUnit()->tokenKind(index); } { return translationUnit()->tokenKind(index); }
const char *ASTVisitor::spell(unsigned index) const const char *ASTVisitor::spell(unsigned index) const
{ { return translationUnit()->spell(index); }
if (! index)
return 0;
return translationUnit()->tokenAt(index).spell();
}
Identifier *ASTVisitor::identifier(unsigned index) const Identifier *ASTVisitor::identifier(unsigned index) const
{ return translationUnit()->identifier(index); } { return translationUnit()->identifier(index); }

View File

@@ -389,6 +389,11 @@ bool CheckDeclaration::visit(UsingDirectiveAST *ast)
UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name); UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name);
ast->symbol = u; ast->symbol = u;
_scope->enterSymbol(u); _scope->enterSymbol(u);
if (! (_scope->isBlockScope() || _scope->isNamespaceScope()))
translationUnit()->error(ast->firstToken(),
"using-directive not within namespace or block scope");
return false; return false;
} }

View File

@@ -134,6 +134,14 @@ const Token &TranslationUnit::tokenAt(unsigned index) const
int TranslationUnit::tokenKind(unsigned index) const int TranslationUnit::tokenKind(unsigned index) const
{ return _tokens->at(index).kind; } { return _tokens->at(index).kind; }
const char *TranslationUnit::spell(unsigned index) const
{
if (! index)
return 0;
return _tokens->at(index).spell();
}
Identifier *TranslationUnit::identifier(unsigned index) const Identifier *TranslationUnit::identifier(unsigned index) const
{ return _tokens->at(index).identifier; } { return _tokens->at(index).identifier; }

View File

@@ -87,6 +87,7 @@ public:
unsigned tokenCount() const; unsigned tokenCount() const;
const Token &tokenAt(unsigned index) const; const Token &tokenAt(unsigned index) const;
int tokenKind(unsigned index) const; int tokenKind(unsigned index) const;
const char *spell(unsigned index) const;
unsigned matchingBrace(unsigned index) const; unsigned matchingBrace(unsigned index) const;
Identifier *identifier(unsigned index) const; Identifier *identifier(unsigned index) const;

View File

@@ -43,6 +43,8 @@
#include <Symbols.h> #include <Symbols.h>
#include <Literals.h> #include <Literals.h>
#include <vector>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <cassert>
@@ -55,6 +57,40 @@
// NamespaceBinding // NamespaceBinding
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class Location
{
public:
Location()
: _fileId(0),
_sourceLocation(0)
{ }
Location(Symbol *symbol)
: _fileId(symbol->fileId()),
_sourceLocation(symbol->sourceLocation())
{ }
Location(StringLiteral *fileId, unsigned sourceLocation)
: _fileId(fileId), _sourceLocation(sourceLocation)
{ }
inline bool isValid() const
{ return _fileId != 0; }
inline operator bool() const
{ return _fileId != 0; }
inline StringLiteral *fileId() const
{ return _fileId; }
inline unsigned sourceLocation() const
{ return _sourceLocation; }
private:
StringLiteral *_fileId;
unsigned _sourceLocation;
};
class NamespaceBinding class NamespaceBinding
{ {
public: public:
@@ -79,6 +115,10 @@ public:
/// Returns the binding associated with the given symbol. /// Returns the binding associated with the given symbol.
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc,
Name *name,
bool lookAtParent = true);
/// Helpers. /// Helpers.
std::string qualifiedId() const; std::string qualifiedId() const;
void dump(); void dump();
@@ -96,6 +136,9 @@ public: // attributes
/// This binding's connections. /// This binding's connections.
Array<NamespaceBinding *> children; Array<NamespaceBinding *> children;
/// This binding's list of using namespaces.
Array<NamespaceBinding *> usings;
/// This binding's namespace symbols. /// This binding's namespace symbols.
Array<Namespace *> symbols; Array<Namespace *> symbols;
}; };
@@ -211,6 +254,104 @@ NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symb
return binding; return binding;
} }
static void closure(const Location &loc,
NamespaceBinding *binding, Name *name,
Array<NamespaceBinding *> *bindings)
{
for (unsigned i = 0; i < bindings->size(); ++i) {
NamespaceBinding *b = bindings->at(i);
if (b == binding)
return;
}
bindings->push_back(binding);
assert(name->isNameId());
Identifier *id = name->asNameId()->identifier();
bool ignoreUsingDirectives = false;
for (unsigned i = 0; i < binding->symbols.size(); ++i) {
Namespace *symbol = binding->symbols.at(i);
Scope *scope = symbol->members();
for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
if (symbol->name() != name || ! symbol->isNamespace())
continue;
const Location l(symbol);
if (l.fileId() == loc.fileId() && l.sourceLocation() < loc.sourceLocation()) {
ignoreUsingDirectives = true;
break;
}
}
}
if (ignoreUsingDirectives)
return;
for (unsigned i = 0; i < binding->usings.size(); ++i) {
NamespaceBinding *u = binding->usings.at(i);
closure(loc, u, name, bindings);
}
}
NamespaceBinding *NamespaceBinding::resolveNamespace(const Location &loc,
Name *name,
bool lookAtParent)
{
if (! name)
return 0;
else if (NameId *nameId = name->asNameId()) {
Array<NamespaceBinding *> bindings;
closure(loc, this, nameId, &bindings);
Array<NamespaceBinding *> results;
for (unsigned i = 0; i < bindings.size(); ++i) {
NamespaceBinding *binding = bindings.at(i);
if (NamespaceBinding *b = binding->findNamespaceBinding(nameId))
results.push_back(b);
}
if (results.size() == 1)
return results.at(0);
else if (results.size() > 1) {
// ### FIXME: return 0;
return results.at(0);
}
else if (parent && lookAtParent)
return parent->resolveNamespace(loc, name);
} else if (QualifiedNameId *q = name->asQualifiedNameId()) {
if (q->nameCount() == 1) {
assert(q->isGlobal());
return globalNamespaceBinding()->resolveNamespace(loc, q->nameAt(0));
}
NamespaceBinding *current = this;
if (q->isGlobal())
current = globalNamespaceBinding();
current = current->resolveNamespace(loc, q->nameAt(0));
for (unsigned i = 1; current && i < q->nameCount(); ++i)
current = current->resolveNamespace(loc, q->nameAt(i), false);
return current;
}
return 0;
}
// ### rewrite me // ### rewrite me
std::string NamespaceBinding::qualifiedId() const std::string NamespaceBinding::qualifiedId() const
{ {
@@ -255,28 +396,38 @@ public:
Binder(); Binder();
virtual ~Binder(); virtual ~Binder();
NamespaceBinding *operator()(Symbol *symbol) NamespaceBinding *operator()(TranslationUnit *u, Namespace *globals)
{ return bind(symbol, 0); } {
TranslationUnit *previousUnit = unit;
unit = u;
NamespaceBinding *binding = bind(globals, 0);
unit = previousUnit;
return binding;
}
protected: protected:
NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding); NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding);
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol); NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc, Name *name);
NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding); NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding);
using SymbolVisitor::visit; using SymbolVisitor::visit;
virtual bool visit(Namespace *); virtual bool visit(Namespace *);
virtual bool visit(UsingNamespaceDirective *);
virtual bool visit(Class *); virtual bool visit(Class *);
virtual bool visit(Function *); virtual bool visit(Function *);
virtual bool visit(Block *); virtual bool visit(Block *);
private: private:
NamespaceBinding *namespaceBinding; NamespaceBinding *namespaceBinding;
TranslationUnit *unit;
}; };
Binder::Binder() Binder::Binder()
: namespaceBinding(0) : namespaceBinding(0),
unit(0)
{ } { }
Binder::~Binder() Binder::~Binder()
@@ -299,6 +450,15 @@ NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol)
return namespaceBinding; return namespaceBinding;
} }
NamespaceBinding *Binder::resolveNamespace(const Location &loc, Name *name)
{
if (! namespaceBinding)
return 0;
return namespaceBinding->resolveNamespace(loc, name);
}
NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding) NamespaceBinding *Binder::switchNamespaceBinding(NamespaceBinding *binding)
{ {
NamespaceBinding *previousBinding = namespaceBinding; NamespaceBinding *previousBinding = namespaceBinding;
@@ -319,6 +479,20 @@ bool Binder::visit(Namespace *symbol)
return false; return false;
} }
bool Binder::visit(UsingNamespaceDirective *u)
{
NamespaceBinding *resolved = resolveNamespace(Location(u), u->name());
if (! resolved) {
unit->error(u->sourceLocation(), "expected namespace-name");
return false;
}
namespaceBinding->usings.push_back(resolved);
return false;
}
bool Binder::visit(Class *) bool Binder::visit(Class *)
{ return false; } { return false; }
@@ -376,7 +550,7 @@ int main(int argc, char *argv[])
// bind // bind
Binder bind; Binder bind;
NamespaceBinding *binding = bind(globalNamespace); NamespaceBinding *binding = bind(&unit, globalNamespace);
binding->dump(); binding->dump();
delete binding; delete binding;