Commit 3cfea5bb authored by hjk's avatar hjk
Browse files

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

parents 4931eecd 4a259547
......@@ -37,6 +37,8 @@
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>
#include <QtCore/QTextCodec>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#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 Core
......@@ -114,6 +114,12 @@ public:
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:
void stdOut(const QByteArray &data, bool firstTime);
void stdErr(const QByteArray &data, bool firstTime);
......
......@@ -102,8 +102,10 @@ GitClient::GitClient(GitPlugin* plugin)
m_plugin(plugin),
m_core(Core::ICore::instance())
{
if (QSettings *s = m_core->settings())
if (QSettings *s = m_core->settings()) {
m_settings.fromSettings(s);
m_binaryPath = m_settings.gitBinaryPath();
}
}
GitClient::~GitClient()
......@@ -478,7 +480,7 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
if (m_settings.adoptPath)
environment.set(QLatin1String("PATH"), m_settings.path);
GitCommand* command = new GitCommand(workingDirectory, environment);
GitCommand* command = new GitCommand(m_binaryPath, workingDirectory, environment);
if (outputToWindow) {
if (!editor) { // assume that the commands output is the important thing
connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(appendDataAndPopup(QByteArray)));
......@@ -527,10 +529,9 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
{
if (Git::Constants::debug)
qDebug() << "synchronousGit" << workingDirectory << arguments;
const QString binary = QLatin1String(Constants::GIT_BINARY);
if (logCommandToWindow)
m_plugin->outputWindow()->append(formatCommand(binary, arguments));
m_plugin->outputWindow()->append(formatCommand(m_binaryPath, arguments));
QProcess process;
process.setWorkingDirectory(workingDirectory);
......@@ -540,7 +541,7 @@ bool GitClient::synchronousGit(const QString &workingDirectory,
environment.set(QLatin1String("PATH"), m_settings.path);
process.setEnvironment(environment.toStringList());
process.start(binary, arguments);
process.start(m_binaryPath, arguments);
if (!process.waitForFinished()) {
if (errorText)
*errorText = "Error: Git timed out";
......@@ -1000,6 +1001,6 @@ void GitClient::setSettings(const GitSettings &s)
m_settings = s;
if (QSettings *s = m_core->settings())
m_settings.toSettings(s);
m_binaryPath = m_settings.gitBinaryPath();
}
}
......@@ -176,6 +176,7 @@ private:
GitPlugin *m_plugin;
Core::ICore *m_core;
GitSettings m_settings;
QString m_binaryPath;
};
......
......@@ -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) :
m_binaryPath(binaryPath),
m_workingDirectory(workingDirectory),
m_environment(environmentToList(environment))
{
......@@ -109,7 +111,7 @@ void GitCommand::run()
if (Git::Constants::debug)
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)) {
ok = false;
error += QLatin1String("Error: Git timed out");
......
......@@ -43,9 +43,11 @@ namespace Internal {
class GitCommand : public QObject
{
Q_DISABLE_COPY(GitCommand)
Q_OBJECT
public:
explicit GitCommand(const QString &workingDirectory,
explicit GitCommand(const QString &binaryPath,
const QString &workingDirectory,
ProjectExplorer::Environment &environment);
......@@ -67,8 +69,7 @@ private:
int timeout;
};
QStringList environment() const;
const QString m_binaryPath;
const QString m_workingDirectory;
const QStringList m_environment;
......
......@@ -32,9 +32,13 @@
***************************************************************************/
#include "gitsettings.h"
#include "gitconstants.h"
#include <utils/synchronousprocess.h>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>
#include <QtCore/QCoreApplication>
static const char *groupC = "Git";
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;
}
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;
}
}
}
......@@ -51,6 +51,8 @@ struct GitSettings
void fromSettings(QSettings *);
void toSettings(QSettings *) const;
QString gitBinaryPath(bool *ok = 0, QString *errorMessage = 0) const;
bool equals(const GitSettings &s) const;
bool adoptPath;
......
......@@ -36,8 +36,10 @@
#include "gitplugin.h"
#include <QtCore/QDebug>
#include <QtGui/QMessageBox>
using namespace Git::Internal;
namespace Git {
namespace Internal {
SettingsPageWidget::SettingsPageWidget(QWidget *parent) :
QWidget(parent)
......@@ -101,6 +103,17 @@ void SettingsPage::apply()
{
if (!m_widget)
return;
const GitSettings newSettings = 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(m_widget->settings());
GitPlugin::instance()->setSettings(newSettings);
}
}
}
......@@ -77,12 +77,7 @@ int ASTVisitor::tokenKind(unsigned index) const
{ return translationUnit()->tokenKind(index); }
const char *ASTVisitor::spell(unsigned index) const
{
if (! index)
return 0;
return translationUnit()->tokenAt(index).spell();
}
{ return translationUnit()->spell(index); }
Identifier *ASTVisitor::identifier(unsigned index) const
{ return translationUnit()->identifier(index); }
......
......@@ -389,6 +389,11 @@ bool CheckDeclaration::visit(UsingDirectiveAST *ast)
UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(ast->firstToken(), name);
ast->symbol = u;
_scope->enterSymbol(u);
if (! (_scope->isBlockScope() || _scope->isNamespaceScope()))
translationUnit()->error(ast->firstToken(),
"using-directive not within namespace or block scope");
return false;
}
......
......@@ -134,6 +134,14 @@ const Token &TranslationUnit::tokenAt(unsigned index) const
int TranslationUnit::tokenKind(unsigned index) const
{ 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
{ return _tokens->at(index).identifier; }
......
......@@ -87,6 +87,7 @@ public:
unsigned tokenCount() const;
const Token &tokenAt(unsigned index) const;
int tokenKind(unsigned index) const;
const char *spell(unsigned index) const;
unsigned matchingBrace(unsigned index) const;
Identifier *identifier(unsigned index) const;
......
......@@ -43,6 +43,8 @@
#include <Symbols.h>
#include <Literals.h>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cassert>
......@@ -55,6 +57,40 @@
// 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
{
public:
......@@ -79,6 +115,10 @@ public:
/// Returns the binding associated with the given symbol.
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc,
Name *name,
bool lookAtParent = true);
/// Helpers.
std::string qualifiedId() const;
void dump();
......@@ -96,6 +136,9 @@ public: // attributes
/// This binding's connections.
Array<NamespaceBinding *> children;
/// This binding's list of using namespaces.
Array<NamespaceBinding *> usings;
/// This binding's namespace symbols.
Array<Namespace *> symbols;
};
......@@ -211,6 +254,104 @@ NamespaceBinding *NamespaceBinding::findOrCreateNamespaceBinding(Namespace *symb
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
std::string NamespaceBinding::qualifiedId() const
{
......@@ -255,28 +396,38 @@ public:
Binder();
virtual ~Binder();
NamespaceBinding *operator()(Symbol *symbol)
{ return bind(symbol, 0); }
NamespaceBinding *operator()(TranslationUnit *u, Namespace *globals)
{
TranslationUnit *previousUnit = unit;
unit = u;
NamespaceBinding *binding = bind(globals, 0);
unit = previousUnit;
return binding;
}
protected:
NamespaceBinding *bind(Symbol *symbol, NamespaceBinding *binding);
NamespaceBinding *findOrCreateNamespaceBinding(Namespace *symbol);
NamespaceBinding *resolveNamespace(const Location &loc, Name *name);
NamespaceBinding *switchNamespaceBinding(NamespaceBinding *binding);
using SymbolVisitor::visit;
virtual bool visit(Namespace *);
virtual bool visit(UsingNamespaceDirective *);
virtual bool visit(Class *);
virtual bool visit(Function *);
virtual bool visit(Block *);
private:
NamespaceBinding *namespaceBinding;
TranslationUnit *unit;
};
Binder::Binder()
: namespaceBinding(0)
: namespaceBinding(0),
unit(0)
{ }
Binder::~Binder()
......@@ -299,6 +450,15 @@ NamespaceBinding *Binder::findOrCreateNamespaceBinding(Namespace *symbol)
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 *previousBinding = namespaceBinding;
......@@ -319,6 +479,20 @@ bool Binder::visit(Namespace *symbol)
return false;
}
bool Binder::visit(UsingNamespaceDirective *u)
{