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

This commit is contained in:
hjk
2009-02-23 16:07:28 +01:00
42 changed files with 4641 additions and 577 deletions

View File

@@ -117,6 +117,13 @@ Macro *Environment::bind(const Macro &__macro)
return m;
}
void Environment::addMacros(const QList<Macro> &macros)
{
foreach (const Macro &macro, macros) {
bind(macro);
}
}
Macro *Environment::remove(const QByteArray &name)
{
Macro macro;
@@ -127,6 +134,23 @@ Macro *Environment::remove(const QByteArray &name)
return bind(macro);
}
void Environment::reset()
{
if (_macros) {
qDeleteAll(firstMacro(), lastMacro());
free(_macros);
}
if (_hash)
free(_hash);
_macros = 0;
_allocated_macros = 0;
_macro_count = -1;
_hash = 0;
_hash_count = 401;
}
bool Environment::isBuiltinMacro(const QByteArray &s) const
{
if (s.length() != 8)

View File

@@ -56,6 +56,7 @@
#include "CPlusPlusForwardDeclarations.h"
#include <QVector>
#include <QList>
#include <QByteArray>
namespace CPlusPlus {
@@ -89,6 +90,9 @@ public:
Macro **lastMacro()
{ return _macros + _macro_count + 1; }
void reset();
void addMacros(const QList<Macro> &macros);
private:
static unsigned hashCode(const QByteArray &s);
void rehash();

View File

@@ -54,6 +54,11 @@ bool SimpleToken::isKeyword() const
return _kind >= T_FIRST_KEYWORD && _kind < T_FIRST_QT_KEYWORD;
}
bool SimpleToken::isComment() const
{
return _kind == T_COMMENT || _kind == T_DOXY_COMMENT;
}
SimpleLexer::SimpleLexer()
: _lastState(0),
_skipComments(false),

View File

@@ -69,6 +69,7 @@ public:
bool isLiteral() const;
bool isOperator() const;
bool isKeyword() const;
bool isComment() const;
public:
int _kind;

View File

@@ -49,6 +49,9 @@ TokenUnderCursor::~TokenUnderCursor()
SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor) const
{
SimpleLexer tokenize;
tokenize.setObjCEnabled(true);
tokenize.setSkipComments(false);
QTextBlock block = cursor.block();
int column = cursor.columnNumber();

View File

@@ -43,6 +43,7 @@
<glob pattern="*.c++"/>
<glob pattern="*.C"/>
<glob pattern="*.inl"/>
<glob pattern="*.qdoc"/>
</mime-type>
<mime-type type="text/x-objcsrc">

View File

@@ -740,7 +740,9 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs)
<< QLatin1String(TextEditor::Constants::C_OPERATOR)
<< QLatin1String(TextEditor::Constants::C_PREPROCESSOR)
<< QLatin1String(TextEditor::Constants::C_LABEL)
<< QLatin1String(TextEditor::Constants::C_COMMENT);
<< QLatin1String(TextEditor::Constants::C_COMMENT)
<< QLatin1String(TextEditor::Constants::C_DOXYGEN_COMMENT)
<< QLatin1String(TextEditor::Constants::C_DOXYGEN_TAG);
}
const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);

View File

@@ -16,6 +16,7 @@ HEADERS += cppplugin.h \
cppeditorenums.h \
cppeditor_global.h \
cppclasswizard.h
SOURCES += cppplugin.cpp \
cppeditoractionhandler.cpp \
cppeditor.cpp \
@@ -23,4 +24,5 @@ SOURCES += cppplugin.cpp \
cpphoverhandler.cpp \
cppfilewizard.cpp \
cppclasswizard.cpp
RESOURCES += cppeditor.qrc

View File

@@ -51,6 +51,8 @@ enum CppFormats {
CppPreprocessorFormat,
CppLabelFormat,
CppCommentFormat,
CppDoxygenCommentFormat,
CppDoxygenTagFormat,
NumCppFormats
};

View File

@@ -32,6 +32,7 @@
***************************************************************************/
#include "cpphighlighter.h"
#include <cpptools/cppdoxygen.h>
#include <Token.h>
#include <cplusplus/SimpleLexer.h>
@@ -115,23 +116,35 @@ void CppHighlighter::highlightBlock(const QString &text)
}
bool highlightCurrentWordAsPreprocessor = highlightAsPreprocessor;
if (highlightAsPreprocessor)
highlightAsPreprocessor = false;
if (i == 0 && tk.is(T_POUND)) {
setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
highlightAsPreprocessor = true;
} else if (highlightCurrentWordAsPreprocessor &&
(tk.isKeyword() || tk.is(T_IDENTIFIER)) && isPPKeyword(tk.text()))
setFormat(tk.position(), tk.length(), m_formats[CppPreprocessorFormat]);
else if (tk.is(T_INT_LITERAL) || tk.is(T_FLOAT_LITERAL))
setFormat(tk.position(), tk.length(), m_formats[CppNumberFormat]);
else if (tk.is(T_STRING_LITERAL) || tk.is(T_CHAR_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))
setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
else if (tk.is(T_WIDE_STRING_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL))
setFormat(tk.position(), tk.length(), m_formats[CppStringFormat]);
else if (tk.is(T_COMMENT)) {
setFormat(tk.position(), tk.length(), m_formats[CppCommentFormat]);
else if (tk.isComment()) {
if (tk.is(T_COMMENT))
setFormat(tk.position(), tk.length(), m_formats[CppCommentFormat]);
else // a doxygen comment
highlightDoxygenComment(text, tk.position(), tk.length());
// we need to insert a close comment parenthesis, if
// - the line starts in a C Comment (initalState != 0)
// - the first token of the line is a T_COMMENT (i == 0 && tk.is(T_COMMENT))
@@ -145,12 +158,16 @@ void CppHighlighter::highlightBlock(const QString &text)
// clear the initial state.
initialState = 0;
}
} else if (tk.isKeyword() || isQtKeyword(tk.text()))
setFormat(tk.position(), tk.length(), m_formats[CppKeywordFormat]);
else if (tk.isOperator())
setFormat(tk.position(), tk.length(), m_formats[CppOperatorFormat]);
else if (i == 0 && tokens.size() > 1 && tk.is(T_IDENTIFIER) && tokens.at(1).is(T_COLON))
setFormat(tk.position(), tk.length(), m_formats[CppLabelFormat]);
else if (tk.is(T_IDENTIFIER))
highlightWord(tk.text(), tk.position(), tk.length());
}
@@ -304,3 +321,36 @@ void CppHighlighter::highlightWord(QStringRef word, int position, int length)
setFormat(position, length, m_formats[CppTypeFormat]);
}
}
void CppHighlighter::highlightDoxygenComment(const QString &text, int position, int)
{
int initial = position;
const QChar *uc = text.unicode();
const QChar *it = uc + position;
const QTextCharFormat &format = m_formats[CppDoxygenCommentFormat];
const QTextCharFormat &kwFormat = m_formats[CppDoxygenTagFormat];
while (! it->isNull()) {
if (it->unicode() == QLatin1Char('\\') ||
it->unicode() == QLatin1Char('@')) {
++it;
const QChar *start = it;
while (it->isLetterOrNumber() || it->unicode() == '_')
++it;
int k = CppTools::classifyDoxygenTag(start, it - start);
if (k != CppTools::T_DOXY_IDENTIFIER) {
setFormat(initial, start - uc - initial, format);
setFormat(start - uc - 1, it - start + 1, kwFormat);
initial = it - uc;
}
} else
++it;
}
setFormat(initial, it - uc - initial, format);
}

View File

@@ -61,6 +61,10 @@ public:
private:
void highlightWord(QStringRef word, int position, int length);
void highlightDoxygenComment(const QString &text, int position,
int length);
bool isPPKeyword(const QStringRef &text) const;
bool isQtKeyword(const QStringRef &text) const;

View File

@@ -32,8 +32,8 @@
***************************************************************************/
#include "cppcodecompletion.h"
#include "cppmodelmanager.h"
#include "cppdoxygen.h"
#include <Control.h>
#include <AST.h>
@@ -371,46 +371,54 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
const QChar ch3 = pos > 1 ? editor->characterAt(pos - 3) : QChar();
int start = pos;
int k = T_EOF_SYMBOL;
if (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) {
if (kind)
*kind = T_DOT;
k = T_DOT;
--start;
} else if (wantFunctionCall && ch == QLatin1Char('(')) {
if (kind)
*kind = T_LPAREN;
k = T_LPAREN;
--start;
} else if (ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) {
if (kind)
*kind = T_COLON_COLON;
k = T_COLON_COLON;
start -= 2;
} else if (ch2 == QLatin1Char('-') && ch == QLatin1Char('>')) {
if (kind)
*kind = T_ARROW;
k = T_ARROW;
start -= 2;
} else if (ch2 == QLatin1Char('.') && ch == QLatin1Char('*')) {
if (kind)
*kind = T_DOT_STAR;
k = T_DOT_STAR;
start -= 2;
} else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>') && ch == QLatin1Char('*')) {
if (kind)
*kind = T_ARROW_STAR;
k = T_ARROW_STAR;
start -= 3;
} else if (ch == QLatin1Char('@') || ch == QLatin1Char('\\')) {
k = T_DOXY_COMMENT;
--start;
}
if (start != pos) {
TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
QTextCursor tc(edit->textCursor());
tc.setPosition(pos);
static CPlusPlus::TokenUnderCursor tokenUnderCursor;
const SimpleToken tk = tokenUnderCursor(tc);
if (tk.is(T_COMMENT) || tk.isLiteral()) {
if (kind)
*kind = T_EOF_SYMBOL;
return pos;
}
if (start == pos)
return start;
TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
QTextCursor tc(edit->textCursor());
tc.setPosition(pos);
static CPlusPlus::TokenUnderCursor tokenUnderCursor;
const SimpleToken tk = tokenUnderCursor(tc);
if (k == T_DOXY_COMMENT && tk.isNot(T_DOXY_COMMENT)) {
k = T_EOF_SYMBOL;
start = pos;
}
else if (tk.is(T_COMMENT) || tk.isLiteral()) {
k = T_EOF_SYMBOL;
start = pos;
}
if (kind)
*kind = k;
return start;
}
@@ -457,15 +465,32 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
ExpressionUnderCursor expressionUnderCursor;
QString expression;
if (m_completionOperator == T_DOXY_COMMENT) {
for (int i = 1; i < T_DOXY_LAST_TAG; ++i) {
TextEditor::CompletionItem item(this);
item.m_text.append(QString::fromLatin1(doxygenTagSpell(i)));
item.m_icon = m_icons.keywordIcon();
m_completions.append(item);
}
return m_startPosition;
}
if (m_completionOperator) {
QTextCursor tc(edit->document());
tc.setPosition(endOfExpression);
expression = expressionUnderCursor(tc);
if (m_completionOperator == T_LPAREN) {
if (expression.endsWith(QLatin1String("SIGNAL")))
m_completionOperator = T_SIGNAL;
else if (expression.endsWith(QLatin1String("SLOT")))
m_completionOperator = T_SLOT;
else if (editor->position() != endOfOperator) {
// We don't want a function completion when the cursor isn't at the opening brace
expression.clear();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,264 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#include "cpptools_global.h"
namespace CppTools {
enum DoxygenReservedWord {
T_DOXY_IDENTIFIER,
T_DOXY_ARG,
T_DOXY_ATTENTION,
T_DOXY_AUTHOR,
T_DOXY_CALLGRAPH,
T_DOXY_CODE,
T_DOXY_DOT,
T_DOXY_ELSE,
T_DOXY_ENDCODE,
T_DOXY_ENDCOND,
T_DOXY_ENDDOT,
T_DOXY_ENDHTMLONLY,
T_DOXY_ENDIF,
T_DOXY_ENDLATEXONLY,
T_DOXY_ENDLINK,
T_DOXY_ENDMANONLY,
T_DOXY_ENDVERBATIM,
T_DOXY_ENDXMLONLY,
T_DOXY_HIDEINITIALIZER,
T_DOXY_HTMLONLY,
T_DOXY_INTERFACE,
T_DOXY_INTERNAL,
T_DOXY_INVARIANT,
T_DOXY_LATEXONLY,
T_DOXY_LI,
T_DOXY_MANONLY,
T_DOXY_N,
T_DOXY_NOSUBGROUPING,
T_DOXY_NOTE,
T_DOXY_ONLY,
T_DOXY_POST,
T_DOXY_PRE,
T_DOXY_REMARKS,
T_DOXY_RETURN,
T_DOXY_RETURNS,
T_DOXY_SA,
T_DOXY_SEE,
T_DOXY_SHOWINITIALIZER,
T_DOXY_SINCE,
T_DOXY_TEST,
T_DOXY_TODO,
T_DOXY_VERBATIM,
T_DOXY_WARNING,
T_DOXY_XMLONLY,
T_DOXY_A,
T_DOXY_ADDTOGROUP,
T_DOXY_ANCHOR,
T_DOXY_B,
T_DOXY_C,
T_DOXY_CLASS,
T_DOXY_COND,
T_DOXY_COPYDOC,
T_DOXY_DEF,
T_DOXY_DONTINCLUDE,
T_DOXY_DOTFILE,
T_DOXY_E,
T_DOXY_ELSEIF,
T_DOXY_EM,
T_DOXY_ENUM,
T_DOXY_EXAMPLE,
T_DOXY_EXCEPTION,
T_DOXY_EXCEPTIONS,
T_DOXY_FILE,
T_DOXY_HTMLINCLUDE,
T_DOXY_IF,
T_DOXY_IFNOT,
T_DOXY_INCLUDE,
T_DOXY_LINK,
T_DOXY_NAMESPACE,
T_DOXY_P,
T_DOXY_PACKAGE,
T_DOXY_REF,
T_DOXY_RELATES,
T_DOXY_RELATESALSO,
T_DOXY_RETVAL,
T_DOXY_THROW,
T_DOXY_THROWS,
T_DOXY_VERBINCLUDE,
T_DOXY_VERSION,
T_DOXY_XREFITEM,
T_DOXY_PARAM,
T_DOXY_IMAGE,
T_DOXY_DEFGROUP,
T_DOXY_PAGE,
T_DOXY_PARAGRAPH,
T_DOXY_SECTION,
T_DOXY_STRUCT,
T_DOXY_SUBSECTION,
T_DOXY_SUBSUBSECTION,
T_DOXY_UNION,
T_DOXY_WEAKGROUP,
T_DOXY_ADDINDEX,
T_DOXY_BRIEF,
T_DOXY_BUG,
T_DOXY_DATE,
T_DOXY_DEPRECATED,
T_DOXY_FN,
T_DOXY_INGROUP,
T_DOXY_LINE,
T_DOXY_MAINPAGE,
T_DOXY_NAME,
T_DOXY_OVERLOAD,
T_DOXY_PAR,
T_DOXY_SHORT,
T_DOXY_SKIP,
T_DOXY_SKIPLINE,
T_DOXY_TYPEDEF,
T_DOXY_UNTIL,
T_DOXY_VAR,
T_FIRST_QDOC_TAG,
T_DOXY_ABSTRACT = T_FIRST_QDOC_TAG,
T_DOXY_BADCODE,
T_DOXY_BASENAME,
T_DOXY_BOLD,
T_DOXY_CAPTION,
T_DOXY_CHAPTER,
T_DOXY_CODELINE,
T_DOXY_DOTS,
T_DOXY_ENDABSTRACT,
T_DOXY_ENDCHAPTER,
T_DOXY_ENDFOOTNOTE,
T_DOXY_ENDLEGALESE,
T_DOXY_ENDLIST,
T_DOXY_ENDOMIT,
T_DOXY_ENDPART,
T_DOXY_ENDQUOTATION,
T_DOXY_ENDRAW,
T_DOXY_ENDSECTION1,
T_DOXY_ENDSECTION2,
T_DOXY_ENDSECTION3,
T_DOXY_ENDSECTION4,
T_DOXY_ENDSIDEBAR,
T_DOXY_ENDTABLE,
T_DOXY_EXPIRE,
T_DOXY_FOOTNOTE,
T_DOXY_GENERATELIST,
T_DOXY_GRANULARITY,
T_DOXY_HEADER,
T_DOXY_I,
T_DOXY_INDEX,
T_DOXY_INLINEIMAGE,
T_DOXY_KEYWORD,
T_DOXY_L,
T_DOXY_LEGALESE,
T_DOXY_LIST,
T_DOXY_META,
T_DOXY_NEWCODE,
T_DOXY_O,
T_DOXY_OLDCODE,
T_DOXY_OMIT,
T_DOXY_OMITVALUE,
T_DOXY_PART,
T_DOXY_PRINTLINE,
T_DOXY_PRINTTO,
T_DOXY_PRINTUNTIL,
T_DOXY_QUOTATION,
T_DOXY_QUOTEFILE,
T_DOXY_QUOTEFROMFILE,
T_DOXY_QUOTEFUNCTION,
T_DOXY_RAW,
T_DOXY_ROW,
T_DOXY_SECTION1,
T_DOXY_SECTION2,
T_DOXY_SECTION3,
T_DOXY_SECTION4,
T_DOXY_SIDEBAR,
T_DOXY_SKIPTO,
T_DOXY_SKIPUNTIL,
T_DOXY_SNIPPET,
T_DOXY_SUB,
T_DOXY_SUP,
T_DOXY_TABLE,
T_DOXY_TABLEOFCONTENTS,
T_DOXY_TARGET,
T_DOXY_TT,
T_DOXY_UNDERLINE,
T_DOXY_UNICODE,
T_DOXY_VALUE,
T_DOXY_CONTENTSPAGE,
T_DOXY_EXTERNALPAGE,
T_DOXY_GROUP,
T_DOXY_HEADERFILE,
T_DOXY_INDEXPAGE,
T_DOXY_INHEADERFILE,
T_DOXY_MACRO,
T_DOXY_MODULE,
T_DOXY_NEXTPAGE,
T_DOXY_PREVIOUSPAGE,
T_DOXY_PROPERTY,
T_DOXY_REIMP,
T_DOXY_SERVICE,
T_DOXY_STARTPAGE,
T_DOXY_VARIABLE,
T_DOXY_COMPAT,
T_DOXY_INMODULE,
T_DOXY_MAINCLASS,
T_DOXY_NONREENTRANT,
T_DOXY_OBSOLETE,
T_DOXY_PRELIMINARY,
T_DOXY_INPUBLICGROUP,
T_DOXY_REENTRANT,
T_DOXY_SUBTITLE,
T_DOXY_THREADSAFE,
T_DOXY_TITLE,
T_DOXY_CORELIB,
T_DOXY_UITOOLS,
T_DOXY_GUI,
T_DOXY_NETWORK,
T_DOXY_OPENGL,
T_DOXY_QT3SUPPORT,
T_DOXY_SVG,
T_DOXY_SQL,
T_DOXY_QTESTLIB,
T_DOXY_WEBKIT,
T_DOXY_XML,
T_DOXY_LAST_TAG
};
CPPTOOLS_EXPORT int classifyDoxygenTag(const QChar *s, int n);
CPPTOOLS_EXPORT const char *doxygenTagSpell(int index);
} // namespace ::CppTools

View File

@@ -48,6 +48,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
@@ -140,6 +141,10 @@ static const char pp_configuration[] =
"#define restrict\n"
"#define __restrict\n"
"#define __complex__\n"
"#define __imag__\n"
"#define __real__\n"
// ### add macros for win32
"#define __cdecl\n"
"#define QT_WA(x) x\n"
@@ -164,9 +169,16 @@ public:
void setIncludePaths(const QStringList &includePaths);
void setFrameworkPaths(const QStringList &frameworkPaths);
void setProjectFiles(const QStringList &files);
void setTodo(const QStringList &files);
void run(QString &fileName);
void operator()(QString &fileName);
void resetEnvironment();
const QSet<QString> &todo() const
{ return m_todo; }
public: // attributes
Snapshot snapshot;
@@ -200,6 +212,7 @@ private:
QStringList m_frameworkPaths;
QSet<QString> m_included;
CPlusPlus::Document::Ptr m_currentDoc;
QSet<QString> m_todo;
};
} // namespace Internal
@@ -223,9 +236,15 @@ void CppPreprocessor::setFrameworkPaths(const QStringList &frameworkPaths)
void CppPreprocessor::setProjectFiles(const QStringList &files)
{ m_projectFiles = files; }
void CppPreprocessor::setTodo(const QStringList &files)
{ m_todo = QSet<QString>::fromList(files); }
void CppPreprocessor::run(QString &fileName)
{ sourceNeeded(fileName, IncludeGlobal, /*line = */ 0); }
void CppPreprocessor::resetEnvironment()
{ env.reset(); }
void CppPreprocessor::operator()(QString &fileName)
{ run(fileName); }
@@ -386,7 +405,7 @@ void CppPreprocessor::mergeEnvironment(Document::Ptr doc, QSet<QString> *process
processed->insert(fn);
foreach (Document::Include incl, doc->includes()) {
foreach (const Document::Include &incl, doc->includes()) {
QString includedFile = incl.fileName();
if (Document::Ptr includedDoc = snapshot.value(includedFile))
@@ -395,9 +414,7 @@ void CppPreprocessor::mergeEnvironment(Document::Ptr doc, QSet<QString> *process
run(includedFile);
}
foreach (const Macro macro, doc->definedMacros()) {
env.bind(macro);
}
env.addMacros(doc->definedMacros());
}
void CppPreprocessor::startSkippingBlocks(unsigned offset)
@@ -424,55 +441,59 @@ void CppPreprocessor::sourceNeeded(QString &fileName, IncludeType type,
if (m_currentDoc) {
m_currentDoc->addIncludeFile(fileName, line);
if (contents.isEmpty() && ! QFileInfo(fileName).isAbsolute()) {
QString msg;
msg += fileName;
msg += QLatin1String(": No such file or directory");
Document::DiagnosticMessage d(Document::DiagnosticMessage::Warning,
m_currentDoc->fileName(),
env.currentLine, /*column = */ 0,
msg);
m_currentDoc->addDiagnosticMessage(d);
//qWarning() << "file not found:" << fileName << m_currentDoc->fileName() << env.current_line;
return;
}
}
if (! contents.isEmpty()) {
Document::Ptr cachedDoc = snapshot.value(fileName);
if (cachedDoc && m_currentDoc) {
mergeEnvironment(cachedDoc);
} else {
Document::Ptr previousDoc = switchDocument(Document::create(fileName));
//qDebug() << "parse file:" << fileName << "contents:" << contents.size();
const QByteArray previousFile = env.currentFile;
const unsigned previousLine = env.currentLine;
Document::Ptr doc = snapshot.value(fileName);
if (doc) {
mergeEnvironment(doc);
return;
}
TranslationUnit *unit = m_currentDoc->translationUnit();
env.currentFile = QByteArray(unit->fileName(), unit->fileNameLength());
doc = Document::create(fileName);
QByteArray preprocessedCode;
m_proc(contents, &preprocessedCode);
//qDebug() << preprocessedCode;
Document::Ptr previousDoc = switchDocument(doc);
env.currentFile = previousFile;
env.currentLine = previousLine;
QByteArray preprocessedCode;
m_proc(fileName.toUtf8(), contents, &preprocessedCode);
m_currentDoc->setSource(preprocessedCode);
m_currentDoc->parse();
doc->setSource(preprocessedCode);
doc->parse();
doc->check();
#if defined(QTCREATOR_WITH_DUMP_AST) && defined(Q_CC_GNU)
DumpAST dump(m_currentDoc->control());
dump(m_currentDoc->translationUnit()->ast());
#endif
m_currentDoc->check();
m_currentDoc->releaseTranslationUnit(); // release the AST and the token stream.
doc->releaseTranslationUnit();
if (m_modelManager)
m_modelManager->emitDocumentUpdated(m_currentDoc);
(void) switchDocument(previousDoc);
}
}
snapshot[fileName] = doc;
if (m_modelManager)
m_modelManager->emitDocumentUpdated(m_currentDoc); // ### TODO: compress
(void) switchDocument(previousDoc);
m_todo.remove(fileName);
}
Document::Ptr CppPreprocessor::switchDocument(Document::Ptr doc)
@@ -737,7 +758,7 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
QList<TextEditor::BaseTextEditor::BlockRange> blockRanges;
foreach (const Document::Block block, doc->skippedBlocks()) {
foreach (const Document::Block &block, doc->skippedBlocks()) {
blockRanges.append(TextEditor::BaseTextEditor::BlockRange(block.begin(), block.end()));
}
ed->setIfdefedOutBlocks(blockRanges);
@@ -750,7 +771,7 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
macroFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
QTextCursor c = ed->textCursor();
foreach (const Document::Block block, doc->macroUses()) {
foreach (const Document::MacroUse &block, doc->macroUses()) {
QTextEdit::ExtraSelection sel;
sel.cursor = c;
sel.cursor.setPosition(block.begin());
@@ -771,7 +792,7 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
warningFormat.setUnderlineColor(Qt::darkYellow);
QSet<int> lines;
foreach (const Document::DiagnosticMessage m, doc->diagnosticMessages()) {
foreach (const Document::DiagnosticMessage &m, doc->diagnosticMessages()) {
if (m.fileName() != fileName)
continue;
else if (lines.contains(m.line()))
@@ -799,7 +820,7 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc)
}
QList<Editor> todo;
foreach (Editor e, todo) {
foreach (const Editor &e, todo) {
if (e.widget != ed)
todo.append(e);
}
@@ -822,7 +843,7 @@ void CppModelManager::postEditorUpdate()
void CppModelManager::updateEditorSelections()
{
foreach (Editor ed, m_todo) {
foreach (const Editor &ed, m_todo) {
if (! ed.widget)
continue;
@@ -872,20 +893,40 @@ void CppModelManager::parse(QFutureInterface<void> &future,
if (files.isEmpty())
return;
foreach (QString file, files) {
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
QStringList headers, sources;
Core::MimeType cSourceTy = db->findByType(QLatin1String("text/x-csrc"));
Core::MimeType cppSourceTy = db->findByType(QLatin1String("text/x-c++src"));
foreach (const QString &file, files) {
const QFileInfo fileInfo(file);
if (cSourceTy.matchesFile(fileInfo) || cppSourceTy.matchesFile(fileInfo))
sources.append(file);
else
headers.append(file);
}
foreach (const QString &file, files) {
preproc->snapshot.remove(file);
}
files = sources;
files += headers;
preproc->setTodo(files);
// Change the priority of the background parser thread to idle.
QThread::currentThread()->setPriority(QThread::IdlePriority);
future.setProgressRange(0, files.size());
QString conf = QLatin1String(pp_configuration_file);
(void) preproc->run(conf);
const int STEP = 10;
bool processingHeaders = false;
for (int i = 0; i < files.size(); ++i) {
if (future.isPaused())
future.waitForResume();
@@ -893,16 +934,33 @@ void CppModelManager::parse(QFutureInterface<void> &future,
if (future.isCanceled())
break;
future.setProgressValue(i);
#ifdef CPPTOOLS_DEBUG_PARSING_TIME
QTime tm;
tm.start();
#endif
QString fileName = files.at(i);
bool isSourceFile = false;
if (cppSourceTy.matchesFile(fileName) || cSourceTy.matchesFile(fileName))
isSourceFile = true;
if (isSourceFile)
(void) preproc->run(conf);
else if (! processingHeaders) {
(void) preproc->run(conf);
processingHeaders = true;
}
preproc->run(fileName);
future.setProgressValue(files.size() - preproc->todo().size());
if (isSourceFile)
preproc->resetEnvironment();
if (! (i % STEP)) // Yields execution of the current thread.
QThread::yieldCurrentThread();

View File

@@ -8,27 +8,29 @@ include(cpptools_dependencies.pri)
DEFINES += QT_NO_CAST_TO_ASCII
INCLUDEPATH += .
DEFINES += CPPTOOLS_LIBRARY
HEADERS += cpptools_global.h \
cppquickopenfilter.h \
HEADERS += completionsettingspage.h \
cppclassesfilter.h \
searchsymbols.h \
cppfunctionsfilter.h \
completionsettingspage.h
SOURCES += cppquickopenfilter.cpp \
cpptoolseditorsupport.cpp \
cppclassesfilter.cpp \
searchsymbols.cpp \
cppfunctionsfilter.cpp \
completionsettingspage.cpp
# Input
SOURCES += cpptoolsplugin.cpp \
cppmodelmanager.cpp \
cppcodecompletion.cpp
HEADERS += cpptoolsplugin.h \
cppmodelmanager.h \
cppcodecompletion.h \
cppfunctionsfilter.h \
cppmodelmanager.h \
cppmodelmanagerinterface.h \
cppquickopenfilter.h \
cpptools_global.h \
cpptoolsconstants.h \
cpptoolseditorsupport.h \
cpptoolsconstants.h
cpptoolsplugin.h \
searchsymbols.h \
cppdoxygen.h
SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \
cppcodecompletion.cpp \
cppfunctionsfilter.cpp \
cppmodelmanager.cpp \
cppquickopenfilter.cpp \
cpptoolseditorsupport.cpp \
cpptoolsplugin.cpp \
searchsymbols.cpp \
cppdoxygen.cpp
FORMS += completionsettingspage.ui

View File

@@ -34,10 +34,12 @@
#ifndef CPPTOOLS_GLOBAL_H
#define CPPTOOLS_GLOBAL_H
#include <QtGlobal>
#if defined(CPPTOOLS_LIBRARY)
# define CPPTOOLS_EXPORT Q_DECL_EXPORT
#else
# define CPPTOOLS_EXPORT Q_DECL_IMPORT
#endif
#endif // CPPTOOLS_GLOBAL_H

View File

@@ -0,0 +1,34 @@
win32 {
# ---- Detect Debugging Tools For Windows
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
exists ($$CDB_PATH) {
message("Experimental: Adding support for $$CDB_PATH")
DEFINES+=CDB_ENABLED
CDB_PLATFORM=i386
INCLUDEPATH*=$$CDB_PATH
INCLUDEPATH*=$$PWD
CDB_LIBPATH=$$CDB_PATH/lib/$$CDB_PLATFORM
HEADERS += \
$$PWD/cdbdebugengine.h \
$$PWD/cdbdebugengine_p.h \
$$PWD/cdbdebugeventcallback.h \
$$PWD/cdbdebugoutput.h
SOURCES += \
$$PWD/cdbdebugengine.cpp \
$$PWD/cdbdebugeventcallback.cpp \
$$PWD/cdbdebugoutput.cpp
LIBS += -L$$CDB_LIBPATH Dbghelp.lib dbgeng.lib
} else {
error("Debugging Tools for Windows could not be found in $$CDB_PATH")
}
}

View File

@@ -1,4 +1,38 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "debuggermanager.h"
#include "breakhandler.h"
@@ -6,30 +40,28 @@
#include <utils/qtcassert.h>
#include <QDebug>
#include <QTimerEvent>
#include <QFileInfo>
#include <QtCore/QDebug>
#include <QtCore/QTimerEvent>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#define DBGHELP_TRANSLATE_TCHAR
#include <Dbghelp.h>
#include <inc/Dbghelp.h>
using namespace Debugger;
using namespace Debugger::Internal;
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent)
: IDebuggerEngine(parent),
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine) :
m_hDebuggeeProcess(0),
m_hDebuggeeThread(0),
//m_hDebuggeeImage(0),
m_bIgnoreNextDebugEvent(false),
m_watchTimer(-1),
m_debugEventCallBack(this),
m_debugOutputCallBack(this)
m_debugEventCallBack(engine),
m_debugOutputCallBack(engine),
m_engine(engine),
m_debuggerManager(parent),
m_debuggerManagerAccess(parent->engineInterface())
{
q = parent;
qq = parent->engineInterface();
HRESULT hr;
hr = DebugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_pDebugClient));
if (FAILED(hr)) m_pDebugClient = 0;
@@ -51,7 +83,7 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent)
}
}
CdbDebugEngine::~CdbDebugEngine()
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
{
if (m_pDebugClient)
m_pDebugClient->Release();
@@ -65,17 +97,28 @@ CdbDebugEngine::~CdbDebugEngine()
m_pDebugRegisters->Release();
}
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent)
: IDebuggerEngine(parent),
m_d(new CdbDebugEnginePrivate(parent, this))
{
}
CdbDebugEngine::~CdbDebugEngine()
{
delete m_d;
}
void CdbDebugEngine::startWatchTimer()
{
if (m_watchTimer == -1)
m_watchTimer = startTimer(0);
if (m_d->m_watchTimer == -1)
m_d->m_watchTimer = startTimer(0);
}
void CdbDebugEngine::killWatchTimer()
{
if (m_watchTimer != -1) {
killTimer(m_watchTimer);
m_watchTimer = -1;
if (m_d->m_watchTimer != -1) {
killTimer(m_d->m_watchTimer);
m_d->m_watchTimer = -1;
}
}
@@ -84,13 +127,13 @@ void CdbDebugEngine::shutdown()
exitDebugger();
}
void CdbDebugEngine::setToolTipExpression(const QPoint &pos, const QString &exp)
void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString & /*exp*/)
{
}
bool CdbDebugEngine::startDebugger()
{
q->showStatusMessage("Starting Debugger", -1);
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
//if (!q->m_workingDir.isEmpty())
// m_gdbProc.setWorkingDirectory(q->m_workingDir);
@@ -101,19 +144,21 @@ bool CdbDebugEngine::startDebugger()
memset(&dbgopts, 0, sizeof(dbgopts));
dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
HRESULT hr;
const QString filename(m_d->m_debuggerManager->m_executable);
if (debugCDB)
qDebug() << Q_FUNC_INFO <<filename;
QString filename(q->m_executable);
QFileInfo fi(filename);
m_pDebugSymbols->AppendImagePathWide(fi.absolutePath().replace('/','\\').utf16());
const QFileInfo fi(filename);
m_d->m_pDebugSymbols->AppendImagePathWide(QDir::toNativeSeparators(fi.absolutePath()).utf16());
//m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
m_d->m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
//m_pDebugSymbols->AddSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH);
if (q->startMode() == q->attachExternal) {
if (m_d->m_debuggerManager->startMode() == DebuggerManager::AttachExternal) {
qWarning("CdbDebugEngine: attach to process not yet implemented!");
return false;
} else {
hr = m_pDebugClient->CreateProcess2Wide(NULL,
HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
const_cast<PWSTR>(filename.utf16()),
&dbgopts,
sizeof(dbgopts),
@@ -121,19 +166,22 @@ bool CdbDebugEngine::startDebugger()
NULL); // TODO: think about setting the environment
if (FAILED(hr)) {
//qWarning("CreateProcess2Wide failed");
qq->notifyInferiorExited();
m_d->m_debuggerManagerAccess->notifyInferiorExited();
return false;
}
}
q->showStatusMessage(tr("Debugger Running"), -1);
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
startWatchTimer();
return true;
}
void CdbDebugEngine::exitDebugger()
{
m_pDebugClient->TerminateCurrentProcess();
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_d->m_pDebugClient->TerminateCurrentProcess();
killWatchTimer();
}
@@ -143,18 +191,22 @@ void CdbDebugEngine::updateWatchModel()
void CdbDebugEngine::stepExec()
{
//qDebug() << "CdbDebugEngine::stepExec()";
if (debugCDB)
qDebug() << Q_FUNC_INFO;
//m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
HRESULT hr;
hr = m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
m_bIgnoreNextDebugEvent = true;
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
m_d->m_bIgnoreNextDebugEvent = true;
startWatchTimer();
}
void CdbDebugEngine::stepOutExec()
{
//qDebug() << "CdbDebugEngine::stepOutExec()";
StackHandler* sh = qq->stackHandler();
if (debugCDB)
qDebug() << Q_FUNC_INFO;
StackHandler* sh = m_d->m_debuggerManagerAccess->stackHandler();
const int idx = sh->currentIndex() + 1;
QList<StackFrame> stackframes = sh->frames();
if (idx < 0 || idx >= stackframes.size()) {
@@ -171,7 +223,7 @@ void CdbDebugEngine::stepOutExec()
}
IDebugBreakpoint2* pBP;
HRESULT hr = m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
HRESULT hr = m_d->m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
if (FAILED(hr) || !pBP) {
qWarning("stepOutExec: cannot create temporary breakpoint");
return;
@@ -194,9 +246,11 @@ void CdbDebugEngine::stepOutExec()
void CdbDebugEngine::nextExec()
{
//qDebug() << "CdbDebugEngine::nextExec()";
if (debugCDB)
qDebug() << Q_FUNC_INFO;
HRESULT hr;
hr = m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
startWatchTimer();
}
@@ -207,68 +261,85 @@ void CdbDebugEngine::stepIExec()
void CdbDebugEngine::nextIExec()
{
m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
startWatchTimer();
}
void CdbDebugEngine::continueInferior()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
killWatchTimer();
q->resetLocation();
m_d->m_debuggerManager->resetLocation();
ULONG executionStatus;
HRESULT hr = m_pDebugControl->GetExecutionStatus(&executionStatus);
HRESULT hr = m_d->m_pDebugControl->GetExecutionStatus(&executionStatus);
if (SUCCEEDED(hr) && executionStatus != DEBUG_STATUS_GO)
m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO);
startWatchTimer();
qq->notifyInferiorRunning();
}
void CdbDebugEngine::runInferior()
{
continueInferior();
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
}
void CdbDebugEngine::interruptInferior()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
//TODO: better use IDebugControl::SetInterrupt?
if (!m_hDebuggeeProcess)
if (!m_d->m_hDebuggeeProcess)
return;
if (!DebugBreakProcess(m_hDebuggeeProcess)) {
if (!DebugBreakProcess(m_d->m_hDebuggeeProcess)) {
qWarning("DebugBreakProcess failed.");
return;
}
qq->notifyInferiorStopped();
m_d->m_debuggerManagerAccess->notifyInferiorStopped();
}
void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
}
void CdbDebugEngine::runToFunctionExec(const QString &functionName)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << functionName;
}
void CdbDebugEngine::jumpToLineExec(const QString &fileName, int lineNumber)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << fileName << lineNumber;
}
void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &value)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << expr << value;
}
void CdbDebugEngine::executeDebuggerCommand(const QString &/*command*/)
void CdbDebugEngine::executeDebuggerCommand(const QString &command)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << command;
}
void CdbDebugEngine::activateFrame(int frameIndex)
{
if (q->status() != DebuggerInferiorStopped)
if (debugCDB)
qDebug() << Q_FUNC_INFO << frameIndex;
if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped)
return;
StackHandler *stackHandler = qq->stackHandler();
int oldIndex = stackHandler->currentIndex();
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
const int oldIndex = stackHandler->currentIndex();
//qDebug() << "ACTIVATE FRAME: " << frameIndex << oldIndex
// << stackHandler->currentIndex();
@@ -281,42 +352,63 @@ void CdbDebugEngine::activateFrame(int frameIndex)
const StackFrame &frame = stackHandler->currentFrame();
bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
if (usable)
q->gotoLocation(frame.file, frame.line, true);
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
else
qDebug() << "FULL NAME NOT USABLE: " << frame.file;
}
void CdbDebugEngine::selectThread(int index)
{
//reset location arrow
q->resetLocation();
if (debugCDB)
qDebug() << Q_FUNC_INFO << index;
ThreadsHandler *threadsHandler = qq->threadsHandler();
//reset location arrow
m_d->m_debuggerManager->resetLocation();
ThreadsHandler *threadsHandler = m_d->m_debuggerManagerAccess->threadsHandler();
threadsHandler->setCurrentThread(index);
m_currentThreadId = index;
updateStackTrace();
m_d->m_currentThreadId = index;
m_d->updateStackTrace();
}
static inline QString breakPointExpression(const QString &fileName, const QString &lineNumber)
{
QString str;
str += QLatin1Char('`');
str += QDir::toNativeSeparators(fileName);
str += QLatin1Char(':');
str += lineNumber;
str += QLatin1Char('`');
return str;
}
void CdbDebugEngine::attemptBreakpointSynchronization()
{
BreakHandler *handler = qq->breakHandler();
//qDebug() << "attemptBreakpointSynchronization";
if (debugCDB)
qDebug() << Q_FUNC_INFO;
if (!m_d->m_hDebuggeeProcess) {
qWarning("attemptBreakpointSynchronization() called while debugger is not running");
return;
}
BreakHandler *handler = m_d->m_debuggerManagerAccess->breakHandler();
for (int i=0; i < handler->size(); ++i) {
BreakpointData* breakpoint = handler->at(i);
if (breakpoint->pending) {
const QString expr = breakPointExpression(breakpoint->fileName, breakpoint->lineNumber);
IDebugBreakpoint2* pBP = 0;
HRESULT hr = m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
HRESULT hr = m_d->m_pDebugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &pBP);
if (FAILED(hr) || !pBP) {
qWarning("m_pDebugControl->AddBreakpoint2 failed");
qWarning("m_pDebugControl->AddBreakpoint2 %s failed.", qPrintable(expr));
continue;
}
QString str = '`' + breakpoint->fileName + ':' + breakpoint->lineNumber + '`';
hr = pBP->SetOffsetExpressionWide(str.utf16());
hr = pBP->SetOffsetExpressionWide(expr.utf16());
if (FAILED(hr)) {
qWarning("SetOffsetExpressionWide failed");
qWarning("SetOffsetExpressionWide %s failed", qPrintable(expr));
continue;
}
@@ -352,10 +444,14 @@ void CdbDebugEngine::reloadModules()
void CdbDebugEngine::loadSymbols(const QString &moduleName)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << moduleName;
}
void CdbDebugEngine::loadAllSymbols()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
}
void CdbDebugEngine::reloadRegisters()
@@ -363,42 +459,53 @@ void CdbDebugEngine::reloadRegisters()
}
void CdbDebugEngine::timerEvent(QTimerEvent* te)
{
if (te->timerId() != m_watchTimer)
{
if (te->timerId() != m_d->m_watchTimer)
return;
if (debugCDB > 1)
qDebug() << Q_FUNC_INFO;
HRESULT hr;
hr = m_pDebugControl->WaitForEvent(0, 1);
hr = m_d->m_pDebugControl->WaitForEvent(0, 1);
switch (hr) {
case S_OK:
//qDebug() << "WaitForEvent S_OK";
if (debugCDB > 1)
qDebug() << "WaitForEvent S_OK";
killWatchTimer();
handleDebugEvent();
m_d->handleDebugEvent();
break;
case S_FALSE:
//qDebug() << "S_FALSE";
if (debugCDB > 1)
qDebug() << "WaitForEvent S_FALSE";
break;
case E_PENDING:
qDebug() << "S_PENDING";
if (debugCDB > 1)
qDebug() << "WaitForEvent E_PENDING";
break;
case E_UNEXPECTED:
if (debugCDB > 1)
qDebug() << "WaitForEvent E_UNEXPECTED";
killWatchTimer();
break;
case E_FAIL:
qDebug() << "E_FAIL";
if (debugCDB > 1)
qDebug() << "WaitForEvent E_FAIL";
break;
//default:
// qDebug() << "asser welljuh, schuddnt heppn";
}
}
void CdbDebugEngine::handleDebugEvent()
void CdbDebugEnginePrivate::handleDebugEvent()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
if (m_bIgnoreNextDebugEvent) {
startWatchTimer();
m_engine->startWatchTimer();
m_bIgnoreNextDebugEvent = false;
} else {
qq->notifyInferiorStopped();
m_debuggerManagerAccess->notifyInferiorStopped();
updateThreadList();
updateStackTrace();
}
@@ -415,9 +522,12 @@ void CdbDebugEngine::handleDebugEvent()
//}
}
void CdbDebugEngine::updateThreadList()
void CdbDebugEnginePrivate::updateThreadList()
{
ThreadsHandler* th = qq->threadsHandler();
if (debugCDB)
qDebug() << Q_FUNC_INFO;
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
QList<ThreadData> threads;
HRESULT hr;
@@ -436,11 +546,13 @@ void CdbDebugEngine::updateThreadList()
th->setThreads(threads);
}
void CdbDebugEngine::updateStackTrace()
void CdbDebugEnginePrivate::updateStackTrace()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
//qDebug() << "updateStackTrace()";
HRESULT hr;
hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
//ULONG64 frameOffset, instructionOffset, stackOffset;
//if (FAILED(m_pDebugRegisters->GetFrameOffset2(DEBUG_REGSRC_DEBUGGEE, &frameOffset)) ||
@@ -466,7 +578,7 @@ void CdbDebugEngine::updateStackTrace()
StackFrame frame;
frame.line = 0;
frame.level = i;
frame.address = QString("0x%1").arg(frames[i].InstructionOffset, 0, 16);
frame.address = QString::fromLatin1("0x%1").arg(frames[i].InstructionOffset, 0, 16);
m_pDebugSymbols->GetNameByOffsetWide(frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
frame.function = QString::fromUtf16(wszBuf);
@@ -482,15 +594,15 @@ void CdbDebugEngine::updateStackTrace()
stackFrames.append(frame);
}
qq->stackHandler()->setFrames(stackFrames);
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
// find the first usable frame and select it
for (int i=0; i < stackFrames.count(); ++i) {
const StackFrame &frame = stackFrames.at(i);
bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
if (usable) {
qq->stackHandler()->setCurrentIndex(i);
q->gotoLocation(frame.file, frame.line, true);
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(i);
m_debuggerManager->gotoLocation(frame.file, frame.line, true);
break;
}
}
@@ -504,17 +616,33 @@ void CdbDebugEngine::updateStackTrace()
//m_pDebugControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, frames, numFramesFilled, DEBUG_STACK_SOURCE_LINE);
}
void CdbDebugEngine::handleDebugOutput(const char* szOutputString)
void CdbDebugEnginePrivate::handleDebugOutput(const char* szOutputString)
{
qq->showApplicationOutput("app-dbgoutput", QString::fromLocal8Bit(szOutputString));
m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString));
}
void CdbDebugEngine::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)
{
qDebug() << "CdbDebugEngine::handleBreakpointEvent()";
Q_UNUSED(pBP)
if (debugCDB)
qDebug() << Q_FUNC_INFO;
}
IDebuggerEngine *createWinEngine(DebuggerManager *parent)
{
return new CdbDebugEngine(parent);
}
void CdbDebugEngine::setDebugDumpers(bool on)
{
Q_UNUSED(on)
}
void CdbDebugEngine::setUseCustomDumpers(bool on)
{
Q_UNUSED(on)
}
void CdbDebugEngine::reloadSourceFiles()
{
}

View File

@@ -1,17 +1,48 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#ifndef DEBUGGER_CDBENGINE_H
#define DEBUGGER_CDBENGINE_H
#include "idebuggerengine.h"
#include "cdbdebugeventcallback.h"
#include "cdbdebugoutput.h"
#include <windows.h>
namespace Debugger {
namespace Internal {
class DebuggerManager;
class IDebuggerManagerAccessForEngines;
class CdbDebugEventCallback;
class CdbDebugOutput;
struct CdbDebugEnginePrivate;
class CdbDebugEngine : public IDebuggerEngine
{
@@ -32,8 +63,7 @@ public:
virtual void stepIExec();
virtual void nextIExec();
virtual void continueInferior();
virtual void runInferior();
virtual void continueInferior();
virtual void interruptInferior();
virtual void runToLineExec(const QString &fileName, int lineNumber);
@@ -58,37 +88,21 @@ public:
virtual void reloadRegisters();
virtual void setDebugDumpers(bool on);
virtual void setUseCustomDumpers(bool on);
virtual void reloadSourceFiles();
protected:
void timerEvent(QTimerEvent*);
private:
void startWatchTimer();
void killWatchTimer();
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
void handleDebugEvent();
void updateThreadList();
void updateStackTrace();
void handleDebugOutput(const char* szOutputString);
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
private:
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
int m_currentThreadId;
bool m_bIgnoreNextDebugEvent;
int m_watchTimer;
IDebugClient5* m_pDebugClient;
IDebugControl4* m_pDebugControl;
IDebugSystemObjects4* m_pDebugSystemObjects;
IDebugSymbols3* m_pDebugSymbols;
IDebugRegisters2* m_pDebugRegisters;
CdbDebugEventCallback m_debugEventCallBack;
CdbDebugOutput m_debugOutputCallBack;
DebuggerManager *q;
IDebuggerManagerAccessForEngines *qq;
CdbDebugEnginePrivate *m_d;
friend struct CdbDebugEnginePrivate;
friend class CdbDebugEventCallback;
friend class CdbDebugOutput;
};

View File

@@ -0,0 +1,82 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#ifndef DEBUGGER_CDBENGINEPRIVATE_H
#define DEBUGGER_CDBENGINEPRIVATE_H
#include "cdbdebugeventcallback.h"
#include "cdbdebugoutput.h"
namespace Debugger {
namespace Internal {
class DebuggerManager;
class IDebuggerManagerAccessForEngines;
struct CdbDebugEnginePrivate
{
explicit CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine);
~CdbDebugEnginePrivate();
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
void handleDebugEvent();
void updateThreadList();
void updateStackTrace();
void handleDebugOutput(const char* szOutputString);
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
int m_currentThreadId;
bool m_bIgnoreNextDebugEvent;
int m_watchTimer;
IDebugClient5* m_pDebugClient;
IDebugControl4* m_pDebugControl;
IDebugSystemObjects4* m_pDebugSystemObjects;
IDebugSymbols3* m_pDebugSymbols;
IDebugRegisters2* m_pDebugRegisters;
CdbDebugEventCallback m_debugEventCallBack;
CdbDebugOutput m_debugOutputCallBack;
CdbDebugEngine* m_engine;
DebuggerManager *m_debuggerManager;
IDebuggerManagerAccessForEngines *m_debuggerManagerAccess;
};
enum { debugCDB = 0 };
} // namespace Internal
} // namespace Debugger
#endif // DEBUGGER_CDBENGINEPRIVATE_H

View File

@@ -0,0 +1,288 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#include "cdbdebugeventcallback.h"
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "debuggermanager.h"
#include <QtCore/QDebug>
namespace Debugger {
namespace Internal {
CdbDebugEventCallback::CdbDebugEventCallback(CdbDebugEngine* dbg) :
m_pEngine(dbg)
{
}
STDMETHODIMP CdbDebugEventCallback::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) {
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
} else {
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) CdbDebugEventCallback::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG) CdbDebugEventCallback::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
{
*mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
//| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
| DEBUG_EVENT_BREAKPOINT
| DEBUG_EVENT_EXCEPTION
;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT Bp)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_pEngine->m_d->handleBreakpointEvent(Bp);
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::Exception(
THIS_
__in PEXCEPTION_RECORD64 Exception,
__in ULONG FirstChance
)
{
Q_UNUSED(Exception)
if (debugCDB)
qDebug() << Q_FUNC_INFO << FirstChance;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::CreateThread(
THIS_
__in ULONG64 Handle,
__in ULONG64 DataOffset,
__in ULONG64 StartOffset
)
{
Q_UNUSED(Handle)
Q_UNUSED(DataOffset)
Q_UNUSED(StartOffset)
if (debugCDB)
qDebug() << Q_FUNC_INFO;
//Debugger::ThreadInfo ti;
//ti.handle = Handle;
//ti.dataOffset = DataOffset;
//ti.startOffset = StartOffset;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::ExitThread(
THIS_
__in ULONG ExitCode
)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << ExitCode;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::CreateProcess(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 Handle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp,
__in ULONG64 InitialThreadHandle,
__in ULONG64 ThreadDataOffset,
__in ULONG64 StartOffset
)
{
Q_UNUSED(ImageFileHandle)
Q_UNUSED(BaseOffset)
Q_UNUSED(ModuleSize)
Q_UNUSED(ModuleName)
Q_UNUSED(ImageName)
Q_UNUSED(CheckSum)
Q_UNUSED(TimeDateStamp)
Q_UNUSED(ThreadDataOffset)
Q_UNUSED(StartOffset)
if (debugCDB)
qDebug() << Q_FUNC_INFO << ModuleName;
m_pEngine->m_d->m_hDebuggeeProcess = (HANDLE)Handle;
m_pEngine->m_d->m_hDebuggeeThread = (HANDLE)InitialThreadHandle;
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorRunning();
ULONG currentThreadId;
if (SUCCEEDED(m_pEngine->m_d->m_pDebugSystemObjects->GetThreadIdByHandle(InitialThreadHandle, &currentThreadId)))
m_pEngine->m_d->m_currentThreadId = currentThreadId;
else
m_pEngine->m_d->m_currentThreadId = 0;
m_pEngine->attemptBreakpointSynchronization();
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::ExitProcess(
THIS_
__in ULONG ExitCode
)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << ExitCode;
m_pEngine->m_d->m_hDebuggeeProcess = 0;
m_pEngine->m_d->m_hDebuggeeThread = 0;
m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorExited();
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::LoadModule(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
)
{
Q_UNUSED(ImageFileHandle)
Q_UNUSED(BaseOffset)
Q_UNUSED(ModuleSize)
Q_UNUSED(ModuleName)
Q_UNUSED(ImageName)
Q_UNUSED(CheckSum)
Q_UNUSED(TimeDateStamp)
if (debugCDB)
qDebug() << Q_FUNC_INFO << ModuleName;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::UnloadModule(
THIS_
__in_opt PCSTR ImageBaseName,
__in ULONG64 BaseOffset
)
{
Q_UNUSED(ImageBaseName)
Q_UNUSED(BaseOffset)
if (debugCDB)
qDebug() << Q_FUNC_INFO << ImageBaseName;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::SystemError(
THIS_
__in ULONG Error,
__in ULONG Level
)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << Error << Level;
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::SessionStatus(
THIS_
__in ULONG Status
)
{
Q_UNUSED(Status)
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::ChangeDebuggeeState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
Q_UNUSED(Flags)
Q_UNUSED(Argument)
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::ChangeEngineState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
Q_UNUSED(Flags)
Q_UNUSED(Argument)
return S_OK;
}
STDMETHODIMP CdbDebugEventCallback::ChangeSymbolState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
Q_UNUSED(Flags)
Q_UNUSED(Argument)
return S_OK;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -1,8 +1,41 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#ifndef DEBUGGER_CDBDEBUGEVENTCALLBACK_H
#define DEBUGGER_CDBDEBUGEVENTCALLBACK_H
#include <windows.h>
#include <dbgeng.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
@@ -12,9 +45,7 @@ class CdbDebugEngine;
class CdbDebugEventCallback : public IDebugEventCallbacks
{
public:
CdbDebugEventCallback(CdbDebugEngine* dbg)
: m_pEngine(dbg)
{}
explicit CdbDebugEventCallback(CdbDebugEngine* dbg);
// IUnknown.
STDMETHOD(QueryInterface)(
@@ -125,7 +156,7 @@ public:
);
private:
CdbDebugEngine* m_pEngine;
CdbDebugEngine *m_pEngine;
};
} // namespace Internal

View File

@@ -0,0 +1,95 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#include "cdbdebugoutput.h"
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
CdbDebugOutput::CdbDebugOutput(CdbDebugEngine* engine) :
m_pEngine(engine)
{
}
STDMETHODIMP CdbDebugOutput::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
{
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
} else {
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) CdbDebugOutput::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG) CdbDebugOutput::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP CdbDebugOutput::Output(
THIS_
IN ULONG mask,
IN PCSTR text
)
{
UNREFERENCED_PARAMETER(mask);
m_pEngine->m_d->handleDebugOutput(text);
return S_OK;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -0,0 +1,77 @@
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#ifndef DEBUGGER_CDBOUTPUT_H
#define DEBUGGER_CDBOUTPUT_H
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
class CdbDebugEngine;
class CdbDebugOutput : public IDebugOutputCallbacks
{
public:
explicit CdbDebugOutput(CdbDebugEngine* engine);
// IUnknown.
STDMETHOD(QueryInterface)(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
);
STDMETHOD_(ULONG, AddRef)(
THIS
);
STDMETHOD_(ULONG, Release)(
THIS
);
// IDebugOutputCallbacks.
STDMETHOD(Output)(
THIS_
IN ULONG mask,
IN PCSTR text
);
private:
CdbDebugEngine* m_pEngine;
};
} // namespace Internal
} // namespace Debugger
#endif // DEBUGGER_CDBOUTPUT_H

View File

@@ -1,203 +0,0 @@
#include "cdbdebugeventcallback.h"
#include "cdbcdebugengine.h"
#include "debuggermanager.h"
#include <QtCore/QDebug>
namespace Debugger {
namespace Internal {
STDMETHODIMP MSVCDebugEventCallback::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
{
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) MSVCDebugEventCallback::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG) MSVCDebugEventCallback::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP MSVCDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
{
*mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
//| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
| DEBUG_EVENT_BREAKPOINT
| DEBUG_EVENT_EXCEPTION
;
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT Bp)
{
qDebug() << "MSVCDebugEventCallback::Breakpoint";
m_pEngine->handleBreakpointEvent(Bp);
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::Exception(
THIS_
__in PEXCEPTION_RECORD64 Exception,
__in ULONG FirstChance
)
{
qDebug() << "MSVCDebugEventCallback::Exception";
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::CreateThread(
THIS_
__in ULONG64 Handle,
__in ULONG64 DataOffset,
__in ULONG64 StartOffset
)
{
//Debugger::ThreadInfo ti;
//ti.handle = Handle;
//ti.dataOffset = DataOffset;
//ti.startOffset = StartOffset;
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::ExitThread(
THIS_
__in ULONG ExitCode
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::CreateProcess(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 Handle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp,
__in ULONG64 InitialThreadHandle,
__in ULONG64 ThreadDataOffset,
__in ULONG64 StartOffset
)
{
m_pEngine->m_hDebuggeeProcess = (HANDLE)Handle;
m_pEngine->m_hDebuggeeThread = (HANDLE)InitialThreadHandle;
//m_pEngine->qq->notifyStartupFinished();
m_pEngine->qq->notifyInferiorRunning();
ULONG currentThreadId;
if (SUCCEEDED(m_pEngine->m_pDebugSystemObjects->GetThreadIdByHandle(InitialThreadHandle, &currentThreadId)))
m_pEngine->m_currentThreadId = currentThreadId;
else
m_pEngine->m_currentThreadId = 0;
m_pEngine->attemptBreakpointSynchronization();
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::ExitProcess(
THIS_
__in ULONG ExitCode
)
{
UNREFERENCED_PARAMETER(ExitCode);
m_pEngine->m_hDebuggeeProcess = 0;
m_pEngine->m_hDebuggeeThread = 0;
m_pEngine->qq->notifyInferiorExited();
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::LoadModule(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::UnloadModule(
THIS_
__in_opt PCSTR ImageBaseName,
__in ULONG64 BaseOffset
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::SystemError(
THIS_
__in ULONG Error,
__in ULONG Level
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::SessionStatus(
THIS_
__in ULONG Status
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::ChangeDebuggeeState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::ChangeEngineState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
STDMETHODIMP MSVCDebugEventCallback::ChangeSymbolState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -1,57 +0,0 @@
#include <windows.h>
#include <dbgeng.h>
#include "cdbdebugoutput.h"
#include "cdbdebugengine.h"
namespace Debugger {
namespace Internal {
STDMETHODIMP MSVCDebugOutput::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
{
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) MSVCDebugOutput::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG) MSVCDebugOutput::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP MSVCDebugOutput::Output(
THIS_
IN ULONG mask,
IN PCSTR text
)
{
UNREFERENCED_PARAMETER(mask);
m_pEngine->handleDebugOutput(text);
return S_OK;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -1,43 +0,0 @@
#ifndef DEBUGGER_CDBOUTPUT_H
#define DEBUGGER_CDBOUTPUT_H
namespace Debugger {
namespace Internal {
class CdbDebugEngine;
class CdbDebugOutput : public IDebugOutputCallbacks
{
public:
CdbDebugOutput(CdbDebugEngine* engine)
: m_pEngine(engine)
{}
// IUnknown.
STDMETHOD(QueryInterface)(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
);
STDMETHOD_(ULONG, AddRef)(
THIS
);
STDMETHOD_(ULONG, Release)(
THIS
);
// IDebugOutputCallbacks.
STDMETHOD(Output)(
THIS_
IN ULONG mask,
IN PCSTR text
);
private:
CdbDebugEngine* m_pEngine;
};
} // namespace Internal
} // namespace Debugger
#endif // DEBUGGER_CDBOUTPUT_H

View File

@@ -85,19 +85,4 @@ HEADERS += $$PWD/modeltest.h
DEFINES += USE_MODEL_TEST=1
}
false {
HEADERS += \
cdbdebugengine.h \
cdbdebugeventcallback.h \
cdbdebugoutput.h
SOURCES += \
cdbdebugengine.cpp \
cdbdebugeventcallback.cpp \
cdbdebugoutput.cpp
LIBS += dbgeng.lib
}
CONFIG(cdbdebugger):include(cdb\cdb.pri)

View File

@@ -132,7 +132,12 @@ static IDebuggerEngine *winEngine = 0;
static IDebuggerEngine *scriptEngine = 0;
extern IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
extern IDebuggerEngine *createWinEngine(DebuggerManager *) { return 0; }
extern IDebuggerEngine *createWinEngine(DebuggerManager *)
#ifdef CDB_ENABLED
;
#else
{ return 0; }
#endif
extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
DebuggerManager::DebuggerManager()

View File

@@ -106,11 +106,11 @@ enum DebuggerStatus
DebuggerInferiorStopped, // Debuggee stopped
};
class IDebuggerEngine;
class GdbEngine;
class ScriptEngine;
class WinEngine;
class CdbDebugEngine;
struct CdbDebugEnginePrivate;
// The construct below is not nice but enforces a bit of order. The
// DebuggerManager interfaces a lots of thing: The DebuggerPlugin,
@@ -131,10 +131,12 @@ public:
private:
// This is the part of the interface that's exclusively seen by the
// debugger engines.
// debugger engines
friend class GdbEngine;
friend class CdbDebugEngine;
friend class CdbDebugEventCallback;
friend class ScriptEngine;
friend class WinEngine;
friend struct CdbDebugEnginePrivate;
// called from the engines after successful startup
virtual void notifyInferiorStopRequested() = 0;

View File

@@ -234,15 +234,6 @@ static bool isLeavableFunction(const QString &funcName, const QString &fileName)
return false;
}
static QString startSymbolName()
{
#ifdef Q_OS_WIN
return "WinMainCRTStartup";
#else
return "_start";
#endif
}
///////////////////////////////////////////////////////////////////////
//
@@ -1555,9 +1546,7 @@ bool GdbEngine::startDebugger()
qDebug() << "ExeFile: " << q->m_executable;
#endif
q->showStatusMessage(tr("Starting Debugger"));
emit gdbInputAvailable(QString(), q->settings()->m_gdbCmd + ' ' + gdbArgs.join(" "));
q->showStatusMessage(tr("Starting Debugger: ") + q->settings()->m_gdbCmd + ' ' + gdbArgs.join(" "));
m_gdbProc.start(q->settings()->m_gdbCmd, gdbArgs);
m_gdbProc.waitForStarted();
@@ -1655,7 +1644,7 @@ bool GdbEngine::startDebugger()
if (!q->m_processArgs.isEmpty())
sendCommand("-exec-arguments " + q->m_processArgs.join(" "));
sendCommand("set auto-solib-add off");
sendCommand("x/2i " + startSymbolName(), GdbStart);
sendCommand("info target", GdbStart);
}
// set all to "pending"
@@ -1678,14 +1667,14 @@ void GdbEngine::continueInferior()
void GdbEngine::handleStart(const GdbResultRecord &response)
{
if (response.resultClass == GdbResultDone) {
// stdout:&"x/2i _start\n"
// stdout:~"0x404540 <_start>:\txor %ebp,%ebp\n"
// stdout:~"0x404542 <_start+2>:\tmov %rdx,%r9\n"
// [some leading stdout here]
// stdout:&" Entry point: 0x80831f0 0x08048134 - 0x08048147 is .interp\n"
// [some trailing stdout here]
QString msg = response.data.findChild("consolestreamoutput").data();
QRegExp needle("0x([0-9a-f]+) <" + startSymbolName() + "\\+.*>:");
QRegExp needle("\\bEntry point: (0x[0-9a-f]+)\\b");
if (needle.indexIn(msg) != -1) {
//debugMessage("STREAM: " + msg + " " + needle.cap(1));
sendCommand("tbreak *0x" + needle.cap(1));
sendCommand("tbreak *" + needle.cap(1));
m_waitingForFirstBreakpointToBeHit = true;
qq->notifyInferiorRunningRequested();
sendCommand("-exec-run");
@@ -1693,7 +1682,7 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
debugMessage("PARSING START ADDRESS FAILED: " + msg);
}
} else if (response.resultClass == GdbResultError) {
debugMessage("PARSING START ADDRESS FAILED: " + response.toString());
debugMessage("FETCHING START ADDRESS FAILED: " + response.toString());
}
}

View File

@@ -39,6 +39,8 @@
#include <QtNetwork/QLocalSocket>
#include <QtCore/QCoreApplication>
#include <stdlib.h>
#else
#include <QtCore/QFile>
@@ -80,7 +82,9 @@ bool OutputCollector::listen()
return m_server->isListening();
m_server = new QLocalServer(this);
connect(m_server, SIGNAL(newConnection()), SLOT(newConnectionAvailable()));
return m_server->listen(QString::fromLatin1("creator-%1").arg(QCoreApplication::applicationPid())); // XXX how to make that secure?
return m_server->listen(QString::fromLatin1("creator-%1-%2")
.arg(QCoreApplication::applicationPid())
.arg(rand()));
#else
if (!m_serverPath.isEmpty())
return true;
@@ -156,7 +160,7 @@ void OutputCollector::newConnectionAvailable()
if (m_socket)
return;
m_socket = m_server->nextPendingConnection();
connect(m_socket, SIGNAL(bytesAvailable()), SLOT(bytesAvailable()));
connect(m_socket, SIGNAL(readyRead()), SLOT(bytesAvailable()));
}
#endif

View File

@@ -111,7 +111,7 @@ QWidget *ApplicationRunConfigurationRunner::configurationWidget(QSharedPointer<R
// ApplicationRunControl
ApplicationRunControl::ApplicationRunControl(QSharedPointer<ApplicationRunConfiguration> runConfiguration)
: RunControl(runConfiguration), m_applicationLauncher()
: RunControl(runConfiguration)
{
connect(&m_applicationLauncher, SIGNAL(applicationError(QString)),
this, SLOT(slotError(QString)));

View File

@@ -84,6 +84,9 @@ const char * const C_OPERATOR = "Operator";
const char * const C_PREPROCESSOR = "Preprocessor";
const char * const C_LABEL = "Label";
const char * const C_COMMENT = "Comment";
const char * const C_DOXYGEN_COMMENT = "Doxygen.Comment";
const char * const C_DOXYGEN_TAG = "Doxygen.Tag";
const char * const C_DISABLED_CODE = "DisabledCode";
const char * const C_ADDED_LINE = "AddedLine";

View File

@@ -84,6 +84,8 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
formatDescriptions.push_back(FormatDescription(QLatin1String(C_PREPROCESSOR), tr("Preprocessor"), Qt::darkBlue));
formatDescriptions.push_back(FormatDescription(QLatin1String(C_LABEL), tr("Label"), Qt::darkRed));
formatDescriptions.push_back(FormatDescription(QLatin1String(C_COMMENT), tr("Comment"), Qt::darkGreen));
formatDescriptions.push_back(FormatDescription(QLatin1String(C_DOXYGEN_COMMENT), tr("Doxygen Comment"), Qt::darkBlue));
formatDescriptions.push_back(FormatDescription(QLatin1String(C_DOXYGEN_TAG), tr("Doxygen Tag"), Qt::blue));
formatDescriptions.push_back(FormatDescription(QLatin1String(C_DISABLED_CODE), tr("Disabled Code"), Qt::gray));
// Diff categories

View File

@@ -60,7 +60,7 @@ CPLUSPLUS_BEGIN_NAMESPACE
Lexer::Lexer(TranslationUnit *unit)
: _translationUnit(unit),
_state(Lexer::DefaultState),
_state(State_Default),
_flags(0),
_currentLine(1)
{
@@ -71,7 +71,7 @@ Lexer::Lexer(TranslationUnit *unit)
Lexer::Lexer(const char *firstChar, const char *lastChar)
: _translationUnit(0),
_state(Lexer::DefaultState),
_state(State_Default),
_flags(0),
_currentLine(1)
{
@@ -196,7 +196,9 @@ void Lexer::scan_helper(Token *tok)
_tokenStart = _currentChar;
tok->offset = _currentChar - _firstChar;
if (_state == MultiLineCommentState) {
if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) {
const int originalState = _state;
if (! _yychar) {
tok->kind = T_EOF_SYMBOL;
return;
@@ -209,7 +211,7 @@ void Lexer::scan_helper(Token *tok)
yyinp();
if (_yychar == '/') {
yyinp();
_state = DefaultState;
_state = State_Default;
break;
}
}
@@ -218,7 +220,10 @@ void Lexer::scan_helper(Token *tok)
if (! _scanCommentTokens)
goto _Lagain;
tok->kind = T_COMMENT;
else if (originalState == State_MultiLineComment)
tok->kind = T_COMMENT;
else
tok->kind = T_DOXY_COMMENT;
return; // done
}
@@ -402,14 +407,30 @@ void Lexer::scan_helper(Token *tok)
case '/':
if (_yychar == '/') {
do {
yyinp();
bool doxy = false;
if (_yychar == '/' || _yychar == '!') {
yyinp();
} while (_yychar && _yychar != '\n');
if (_yychar != '\n' && std::isspace(_yychar))
doxy = true;
}
while (_yychar && _yychar != '\n')
yyinp();
if (! _scanCommentTokens)
goto _Lagain;
tok->kind = T_COMMENT;
tok->kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
} else if (_yychar == '*') {
yyinp();
const bool doxy = _yychar == '*' || _yychar == '!';
while (_yychar) {
if (_yychar != '*') {
yyinp();
@@ -423,11 +444,13 @@ void Lexer::scan_helper(Token *tok)
if (_yychar)
yyinp();
else
_state = MultiLineCommentState;
_state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment;
if (! _scanCommentTokens)
goto _Lagain;
tok->kind = T_COMMENT;
tok->kind = doxy ? T_DOXY_COMMENT : T_COMMENT;
} else if (_yychar == '=') {
yyinp();
tok->kind = T_SLASH_EQUAL;

View File

@@ -66,8 +66,9 @@ class CPLUSPLUS_EXPORT Lexer
public:
enum State {
DefaultState,
MultiLineCommentState
State_Default,
State_MultiLineComment,
State_MultiLineDoxyComment
};
Lexer(TranslationUnit *unit);

View File

@@ -58,7 +58,7 @@ CPLUSPLUS_BEGIN_NAMESPACE
static const char *token_names[] = {
(""), ("<error>"),
("<comment>"),
("<comment>"), ("<doxy comment>"),
("<identifier>"), ("<int literal>"), ("<float literal>"), ("<char literal>"),
("<wide char literal>"), ("<string literal>"), ("<wide char literal>"),

View File

@@ -64,6 +64,7 @@ enum Kind {
T_ERROR,
T_COMMENT,
T_DOXY_COMMENT,
T_IDENTIFIER,
T_FIRST_LITERAL,
@@ -297,6 +298,9 @@ public:
inline bool isKeyword() const
{ return kind >= T_FIRST_KEYWORD && kind < T_FIRST_QT_KEYWORD; }
inline bool isComment() const
{ return kind == T_COMMENT || kind == T_DOXY_COMMENT; }
inline bool isObjCAtKeyword() const
{ return kind >= T_FIRST_OBJC_AT_KEYWORD && kind < T_LAST_OBJC_AT_KEYWORD; }

View File

@@ -5,4 +5,3 @@ echo "Generating $t"
${CPP-gcc} -xc++ -E -include $me/conf.c++ $* > $t
echo "Parsing $t"
$me/cplusplus0 $t

View File

@@ -6,3 +6,6 @@
#define restrict
#define __restrict
#define __weak
#define __complex__
#define __imag__
#define __real__