Commit 2bbc261f authored by mae's avatar mae
Browse files

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

parents 2ef4a169 222b4fab
......@@ -34,6 +34,7 @@
#include "Macro.h"
#include <QByteArray>
#include <QFileInfo>
#include <QList>
#include <QMap>
#include <QSharedPointer>
......@@ -199,6 +200,9 @@ public:
unsigned line() const
{ return _line; }
bool resolved() const
{ return QFileInfo(_fileName).isAbsolute(); }
};
class MacroUse: public Block {
......
......@@ -67,9 +67,13 @@ CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
: m_manager(manager),
m_fileName(fileName),
m_rootNode(new CMakeProjectNode(m_fileName)),
m_toolChain(0)
m_toolChain(0),
m_insideFileChanged(false)
{
m_file = new CMakeFile(this, fileName);
m_watcher = new ProjectExplorer::FileWatcher(this);
connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
m_watcher->addFile(fileName);
}
CMakeProject::~CMakeProject()
......@@ -78,53 +82,94 @@ CMakeProject::~CMakeProject()
delete m_toolChain;
}
// TODO also call this method if the CMakeLists.txt file changed, which is also called if the CMakeList.txt is updated
// TODO make this function work even if it is reparsing
void CMakeProject::fileChanged(const QString &fileName)
{
if (m_insideFileChanged== true)
return;
m_insideFileChanged = true;
if (fileName == m_fileName) {
// Oh we have changed...
// Pop up a dialog asking the user to rerun cmake
QFileInfo sourceFileInfo(m_fileName);
QStringList needToCreate;
QStringList needToUpdate;
foreach(const QString &buildConfiguration, buildConfigurations()) {
QString buildDirectory = value(buildConfiguration, "buildDirectory").toString();
QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory));
QFileInfo cbpFileFi(cbpFile);
if (!cbpFileFi.exists())
needToCreate << buildDirectory;
else if (cbpFileFi.lastModified() < sourceFileInfo.lastModified())
needToUpdate << buildDirectory;
}
if (!needToCreate.isEmpty() || !needToUpdate.isEmpty()) {
CMakeOpenProjectWizard copw(m_manager, sourceFileInfo.absolutePath(), needToCreate, needToUpdate);
copw.exec();
}
// reparse
parseCMakeLists();
}
m_insideFileChanged = false;
}
void CMakeProject::updateToolChain(const QString &compiler)
{
//qDebug()<<"CodeBlocks Compilername"<<compiler
ProjectExplorer::ToolChain *newToolChain = 0;
if (compiler == "gcc") {
newToolChain = ProjectExplorer::ToolChain::createGccToolChain("gcc");
} else if (compiler == "msvc8") {
// TODO hmm
//newToolChain = ProjectExplorer::ToolChain::createMSVCToolChain("//TODO");
Q_ASSERT(false);
} else {
// TODO hmm?
qDebug()<<"Not implemented yet!!! Qt Creator doesn't know which toolchain to use for"<<compiler;
}
if (ProjectExplorer::ToolChain::equals(newToolChain, m_toolChain)) {
delete newToolChain;
newToolChain = 0;
} else {
delete m_toolChain;
m_toolChain = newToolChain;
}
}
void CMakeProject::parseCMakeLists()
{
// Find cbp file
QString sourceDirectory = QFileInfo(m_fileName).absolutePath();
QString cbpFile = CMakeManager::findCbpFile(buildDirectory(activeBuildConfiguration()));
// setFolderName
m_rootNode->setFolderName(QFileInfo(cbpFile).completeBaseName());
CMakeCbpParser cbpparser;
qDebug()<<"Parsing file "<<cbpFile;
if (cbpparser.parseCbpFile(cbpFile)) {
qDebug()<<"CodeBlocks Compilername"<<cbpparser.compilerName();
ProjectExplorer::ToolChain *newToolChain = 0;
if (cbpparser.compilerName() == "gcc") {
newToolChain = ProjectExplorer::ToolChain::createGccToolChain("gcc");
} else if (cbpparser.compilerName() == "msvc8") {
// TODO hmm
//newToolChain = ProjectExplorer::ToolChain::createMSVCToolChain("//TODO");
Q_ASSERT(false);
} else {
// TODO hmm?
qDebug()<<"Not implemented yet!!! Qt Creator doesn't know which toolchain to use for"<<cbpparser.compilerName();
}
if (ProjectExplorer::ToolChain::equals(newToolChain, m_toolChain)) {
delete newToolChain;
newToolChain = 0;
} else {
delete m_toolChain;
m_toolChain = newToolChain;
}
// Parsing
//qDebug()<<"Parsing file "<<cbpFile;
if (cbpparser.parseCbpFile(cbpFile)) {
// ToolChain
updateToolChain(cbpparser.compilerName());
m_projectName = cbpparser.projectName();
m_rootNode->setFolderName(cbpparser.projectName());
qDebug()<<"Building Tree";
// TODO do a intelligent updating of the tree
//qDebug()<<"Building Tree";
QList<ProjectExplorer::FileNode *> fileList = cbpparser.fileList();
// Manually add the CMakeLists.txt file
fileList.append(new ProjectExplorer::FileNode(sourceDirectory + "/CMakeLists.txt", ProjectExplorer::ProjectFileType, false));
buildTree(m_rootNode, fileList);
m_files.clear();
foreach (ProjectExplorer::FileNode *fn, fileList)
m_files.append(fn->path());
m_files.sort();
qDebug()<<"Adding Targets";
buildTree(m_rootNode, fileList);
//qDebug()<<"Adding Targets";
m_targets = cbpparser.targets();
// qDebug()<<"Printing targets";
// foreach(CMakeTarget ct, m_targets) {
......@@ -134,7 +179,7 @@ void CMakeProject::parseCMakeLists()
// qDebug()<<"";
// }
qDebug()<<"Updating CodeModel";
//qDebug()<<"Updating CodeModel";
QStringList allIncludePaths;
QStringList allFrameworkPaths;
......@@ -158,7 +203,7 @@ void CMakeProject::parseCMakeLists()
}
// Create run configurations for m_targets
qDebug()<<"Create run configurations of m_targets";
//qDebug()<<"Create run configurations of m_targets";
QMap<QString, QSharedPointer<CMakeRunConfiguration> > existingRunConfigurations;
foreach(QSharedPointer<ProjectExplorer::RunConfiguration> cmakeRunConfiguration, runConfigurations()) {
if (QSharedPointer<CMakeRunConfiguration> rc = cmakeRunConfiguration.dynamicCast<CMakeRunConfiguration>()) {
......@@ -177,16 +222,16 @@ void CMakeProject::parseCMakeLists()
if (it != existingRunConfigurations.end()) {
// Already exists, so override the settings...
QSharedPointer<CMakeRunConfiguration> rc = it.value();
qDebug()<<"Updating Run Configuration with title"<<ct.title;
qDebug()<<" Executable new:"<<ct.executable<< "old:"<<rc->executable();
qDebug()<<" WD new:"<<ct.workingDirectory<<"old:"<<rc->workingDirectory();
//qDebug()<<"Updating Run Configuration with title"<<ct.title;
//qDebug()<<" Executable new:"<<ct.executable<< "old:"<<rc->executable();
//qDebug()<<" WD new:"<<ct.workingDirectory<<"old:"<<rc->workingDirectory();
rc->setExecutable(ct.executable);
rc->setWorkingDirectory(ct.workingDirectory);
existingRunConfigurations.erase(it);
} else {
// Does not exist yet
qDebug()<<"Adding new run configuration with title"<<ct.title;
qDebug()<<" Executable:"<<ct.executable<<"WD:"<<ct.workingDirectory;
//qDebug()<<"Adding new run configuration with title"<<ct.title;
//qDebug()<<" Executable:"<<ct.executable<<"WD:"<<ct.workingDirectory;
QSharedPointer<ProjectExplorer::RunConfiguration> rc(new CMakeRunConfiguration(this, ct.executable, ct.workingDirectory, ct.title));
addRunConfiguration(rc);
// The first one gets the honour of beeing the active one
......@@ -200,11 +245,11 @@ void CMakeProject::parseCMakeLists()
existingRunConfigurations.constBegin();
for( ; it != existingRunConfigurations.constEnd(); ++it) {
QSharedPointer<CMakeRunConfiguration> rc = it.value();
qDebug()<<"Removing old RunConfiguration with title:"<<rc->title();
qDebug()<<" Executable:"<<rc->executable()<<rc->workingDirectory();
//qDebug()<<"Removing old RunConfiguration with title:"<<rc->title();
//qDebug()<<" Executable:"<<rc->executable()<<rc->workingDirectory();
removeRunConfiguration(rc);
}
qDebug()<<"\n";
//qDebug()<<"\n";
} else {
// TODO report error
qDebug()<<"Parsing failed";
......@@ -239,17 +284,79 @@ QStringList CMakeProject::targets() const
return results;
}
void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list)
void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list)
{
foreach(ProjectExplorer::FolderNode *folder, parent->subFolderNodes())
gatherFileNodes(folder, list);
foreach(ProjectExplorer::FileNode *file, parent->fileNodes())
list.append(file);
}
void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList)
{
//m_rootNode->addFileNodes(fileList, m_rootNode);
qSort(list.begin(), list.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
foreach (ProjectExplorer::FileNode *fn, list) {
// Gather old list
QList<ProjectExplorer::FileNode *> oldList;
gatherFileNodes(rootNode, oldList);
qSort(oldList.begin(), oldList.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
qSort(newList.begin(), newList.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
// generate added and deleted list
QList<ProjectExplorer::FileNode *>::const_iterator oldIt = oldList.constBegin();
QList<ProjectExplorer::FileNode *>::const_iterator oldEnd = oldList.constEnd();
QList<ProjectExplorer::FileNode *>::const_iterator newIt = newList.constBegin();
QList<ProjectExplorer::FileNode *>::const_iterator newEnd = newList.constEnd();
QList<ProjectExplorer::FileNode *> added;
QList<ProjectExplorer::FileNode *> deleted;
while(oldIt != oldEnd && newIt != newEnd) {
if ( (*oldIt)->path() == (*newIt)->path()) {
delete *newIt;
++oldIt;
++newIt;
} else if ((*oldIt)->path() < (*newIt)->path()) {
deleted.append(*oldIt);
++oldIt;
} else {
added.append(*newIt);
++newIt;
}
}
while (oldIt != oldEnd) {
deleted.append(*oldIt);
++oldIt;
}
while (newIt != newEnd) {
added.append(*newIt);
++newIt;
}
// add added nodes
foreach (ProjectExplorer::FileNode *fn, added) {
// qDebug()<<"added"<<fn->path();
// Get relative path to rootNode
QString parentDir = QFileInfo(fn->path()).absolutePath();
ProjectExplorer::FolderNode *folder = findOrCreateFolder(rootNode, parentDir);
rootNode->addFileNodes(QList<ProjectExplorer::FileNode *>()<< fn, folder);
}
//m_rootNode->addFileNodes(list, rootNode);
// remove old file nodes and check wheter folder nodes can be removed
foreach (ProjectExplorer::FileNode *fn, deleted) {
ProjectExplorer::FolderNode *parent = fn->parentFolderNode();
// qDebug()<<"removed"<<fn->path();
rootNode->removeFileNodes(QList<ProjectExplorer::FileNode *>() << fn, parent);
// Check for empty parent
while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
rootNode->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent, grandparent);
parent = grandparent;
if (parent == rootNode)
break;
}
}
}
ProjectExplorer::FolderNode *CMakeProject::findOrCreateFolder(CMakeProjectNode *rootNode, QString directory)
......@@ -347,13 +454,11 @@ ProjectExplorer::ProjectNode *CMakeProject::rootProjectNode() const
QStringList CMakeProject::files(FilesMode fileMode) const
{
Q_UNUSED(fileMode);
// TODO
return m_files;
}
void CMakeProject::saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer)
{
// TODO
Project::saveSettingsImpl(writer);
}
......
......@@ -38,6 +38,7 @@
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/buildstep.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/filewatcher.h>
#include <coreplugin/ifile.h>
#include <utils/pathchooser.h>
......@@ -101,13 +102,21 @@ public:
QStringList targets() const;
QString buildParser(const QString &buildConfiguration) const;
protected:
virtual void saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer);
virtual void restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &reader);
private slots:
void fileChanged(const QString &fileName);
private:
void parseCMakeLists();
void updateToolChain(const QString &compiler);
void buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list);
void gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list);
ProjectExplorer::FolderNode *findOrCreateFolder(CMakeProjectNode *rootNode, QString directory);
CMakeManager *m_manager;
QString m_fileName;
CMakeFile *m_file;
......@@ -118,11 +127,8 @@ private:
QStringList m_files;
QList<CMakeTarget> m_targets;
ProjectExplorer::ToolChain *m_toolChain;
protected:
virtual void saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer);
virtual void restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &reader);
ProjectExplorer::FileWatcher *m_watcher;
bool m_insideFileChanged;
};
class CMakeCbpParser : public QXmlStreamReader
......
......@@ -605,7 +605,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
// Handle include directives
const unsigned lineno = cursor.blockNumber() + 1;
foreach (const Document::Include &incl, doc->includes()) {
if (incl.line() == lineno) {
if (incl.line() == lineno && incl.resolved()) {
link.fileName = incl.fileName();
link.pos = cursor.block().position();
link.length = cursor.block().length();
......
......@@ -1209,10 +1209,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (Function *function = symbol->type()->asFunctionType()) {
// If the member is a function, automatically place the opening parenthesis,
// except when it might take template parameters.
const bool hasReturnType = function->returnType().isValid() ||
function->returnType().isSigned() ||
function->returnType().isUnsigned();
if (! hasReturnType && (function->identity() && !function->identity()->isDestructorNameId())) {
if (! function->hasReturnType() && (function->identity() && !function->identity()->isDestructorNameId())) {
// Don't insert any magic, since the user might have just wanted to select the class
} else if (function->templateParameterCount() != 0) {
......@@ -1224,9 +1221,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
extraChars += QLatin1Char('(');
// If the function takes no arguments, automatically place the closing parenthesis
if (item.m_duplicateCount == 0 && (function->argumentCount() == 0 ||
(function->argumentCount() == 1 &&
function->argumentAt(0)->type()->isVoidType()))) {
if (item.m_duplicateCount == 0 && ! function->hasArguments()) {
extraChars += QLatin1Char(')');
// If the function doesn't return anything, automatically place the semicolon,
......
......@@ -22,12 +22,16 @@ HEADERS += \
$$PWD/cdbdebugengine.h \
$$PWD/cdbdebugengine_p.h \
$$PWD/cdbdebugeventcallback.h \
$$PWD/cdbdebugoutput.h
$$PWD/cdbdebugoutput.h \
$$PWD/cdbsymbolgroupcontext.h \
$$PWD/cdbstacktracecontext.h
SOURCES += \
$$PWD/cdbdebugengine.cpp \
$$PWD/cdbdebugeventcallback.cpp \
$$PWD/cdbdebugoutput.cpp
$$PWD/cdbdebugoutput.cpp \
$$PWD/cdbsymbolgroupcontext.cpp \
$$PWD/cdbstacktracecontext.cpp
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
}
......
......@@ -29,6 +29,8 @@
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "cdbsymbolgroupcontext.h"
#include "cdbstacktracecontext.h"
#include "debuggermanager.h"
#include "breakhandler.h"
......@@ -55,7 +57,12 @@
static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate";
static QString msgDebugEngineComResult(HRESULT hr)
static const char *localSymbolRootC = "local";
namespace Debugger {
namespace Internal {
QString msgDebugEngineComResult(HRESULT hr)
{
switch (hr) {
case S_OK:
......@@ -87,13 +94,12 @@ static QString msgStackIndexOutOfRange(int idx, int size)
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}
static QString msgComFailed(const char *func, HRESULT hr)
QString msgComFailed(const char *func, HRESULT hr)
{
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
}
namespace Debugger {
namespace Internal {
static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
DebuggerEngineLibrary::DebuggerEngineLibrary() :
m_debugCreate(0)
......@@ -138,6 +144,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
m_engine(engine),
m_debuggerManager(parent),
m_debuggerManagerAccess(parent->engineInterface()),
m_currentStackTrace(0),
m_mode(AttachCore)
{
}
......@@ -205,6 +212,7 @@ IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
{
cleanStackTrace();
if (m_pDebugClient)
m_pDebugClient->Release();
if (m_pDebugControl)
......@@ -217,6 +225,17 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
m_pDebugRegisters->Release();
}
void CdbDebugEnginePrivate::cleanStackTrace()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
if (m_currentStackTrace) {
delete m_currentStackTrace;
m_currentStackTrace = 0;
}
}
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
IDebuggerEngine(parent),
m_d(new CdbDebugEnginePrivate(parent, this))
......@@ -366,6 +385,7 @@ void CdbDebugEngine::processTerminated(unsigned long exitCode)
if (debugCDB)
qDebug() << Q_FUNC_INFO << exitCode;
m_d->cleanStackTrace();
m_d->setDebuggeeHandles(0, 0);
m_d->m_debuggerManagerAccess->notifyInferiorExited();
m_d->m_debuggerManager->exitDebugger();
......@@ -377,6 +397,7 @@ void CdbDebugEngine::exitDebugger()
qDebug() << Q_FUNC_INFO;
if (m_d->m_hDebuggeeProcess) {
m_d->cleanStackTrace();
// Terminate or detach if we are running
HRESULT hr;
switch (m_d->m_mode) {
......@@ -407,47 +428,22 @@ void CdbDebugEngine::exitDebugger()
killWatchTimer();
}
// Retrieve a symbol
static WatchData symbolToWatchData(ULONG index, const QString &namePrefix,
IDebugSymbolGroup2 *pDbgSymGroup)
class ModelBuildIterator {
public:
explicit ModelBuildIterator(WatchHandler *wh) : m_wh(wh) {}
ModelBuildIterator & operator*() { return *this; }
ModelBuildIterator &operator=(const WatchData &wd);
ModelBuildIterator &operator++() { return *this; }
private:
WatchHandler *m_wh;
};
ModelBuildIterator &ModelBuildIterator::operator=(const WatchData &wd)
{
// retrieve symbol names and value strings
ULONG nameLength;
static WCHAR nameBuffer[MAX_PATH + 1];
// Name
pDbgSymGroup->GetSymbolNameWide(index, nameBuffer, MAX_PATH, &nameLength);
nameBuffer[nameLength] = 0;
const QString name = QString::fromUtf16(nameBuffer);
// Type name
pDbgSymGroup->GetSymbolTypeNameWide(index, nameBuffer, MAX_PATH, &nameLength);
nameBuffer[nameLength] = 0;
const QString type = QString::fromUtf16(nameBuffer);
// Value
QString value;
const HRESULT hr = pDbgSymGroup->GetSymbolValueTextWide(index, nameBuffer, MAX_PATH, &nameLength);
if (SUCCEEDED(hr)) {
nameBuffer[nameLength] = 0;
value = QString::fromUtf16(nameBuffer);
} else {
value = QLatin1String("<unknown>");
}
WatchData wd;
wd.iname =namePrefix + name;
wd.name = name;
wd.value = value;
wd.type = type;
if (isPointerType(type)) {
wd.setTypeUnneeded();
wd.setValueUnneeded();
} else {
wd.setAllUnneeded();
}
if (debugCDB) {
qDebug() << Q_FUNC_INFO << index << "state=0x" << QString::number(wd.state, 16)
<< wd.name << " type=" << wd.type << " (" << type << ')'
<< " value " << wd.value << " (" << value << ')';
}
return wd;
m_wh->insertData(wd);
return *this;
}
bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
......@@ -456,82 +452,36 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << frameIndex;
CdbStackTrace cdbStackTrace;
if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
return false;
if ((unsigned)frameIndex >= cdbStackTrace.frameCount) {
*errorMessage = msgStackIndexOutOfRange(frameIndex, cdbStackTrace.frameCount);
return false;
}
IDebugSymbolGroup2 *pDbgSymGroup = 0;
DEBUG_SYMBOL_PARAMETERS *symParams = 0;
bool success = false;
wh->cleanup();
do {
HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &pDbgSymGroup);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
break;
}
hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0);
if (FAILED(hr)) {
*errorMessage = msgComFailed("SetScope", hr);
break;
}
// refresh with current frame
hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
break;
}
ULONG symbolCount;
hr = pDbgSymGroup->GetNumberSymbols(&symbolCount);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetNumberSymbols", hr);
if (!m_currentStackTrace) {
*errorMessage = QLatin1String(msgNoStackTraceC);
break;