diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index b3a80a5d24d..c1227b79c0a 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -3572,15 +3573,15 @@ template { QMapNode *mn = 0; const int valueOffset = (char *)&(mn->value) - (char*)mn; - d.put("(size_t)&(('"NS"QMapNode<"); + d.put("[\"(size_t)&(('"NS"QMapNode<"); d.put(keyType); d.put(','); d.put(valueType); if (valueType[qstrlen(valueType) - 1] == '>') d.put(' '); - d.put(">'*)0)->value=\""); + d.put(">'*)0)->value\",\""); d.put(valueOffset); - d.put('"'); + d.put("\"]"); return d; } @@ -3595,20 +3596,86 @@ template { std::pair *p = 0; const int valueOffset = (char *)&(p->second) - (char*)p; - d.put("(size_t)&(('std::pair<"); + d.put("[\"(size_t)&(('std::pair<"); d.put(keyType); d.put(" const ,"); d.put(valueType); if (valueType[qstrlen(valueType) - 1] == '>') d.put(' '); - d.put(">'*)0)->second=\""); + d.put(">'*)0)->second\",\""); d.put(valueOffset); - d.put('"'); + d.put("\"]"); return d; } #endif // Q_CC_MSVC +// Dump out sizes for CDB +static inline void dumpSizes(QDumper &d) +{ + // Sort by sizes + typedef QMultiMap SizeMap; + SizeMap sizeMap; + + sizeMap.insert(sizeof(int), "int"); + sizeMap.insert(sizeof(char*), "char*"); + sizeMap.insert(sizeof(QString), NS"QString"); + sizeMap.insert(sizeof(QStringList), NS"QStringList"); +#ifndef QT_BOOTSTRAPPED + sizeMap.insert(sizeof(QObject), NS"QObject"); + sizeMap.insert(sizeof(QList), NS"QList"); + sizeMap.insert(sizeof(QLinkedList), NS"QLinkedList"); + sizeMap.insert(sizeof(QVector), NS"QVector"); + sizeMap.insert(sizeof(QQueue), NS"QQueue"); +#endif +#if USE_QT_GUI + sizeMap.insert(sizeof(QWidget), NS"QWidget"); +#endif +#ifdef Q_OS_WIN + sizeMap.insert(sizeof(std::string), "string"); + sizeMap.insert(sizeof(std::wstring), "wstring"); +#endif + sizeMap.insert(sizeof(std::string), "std::string"); + sizeMap.insert(sizeof(std::wstring), "std::wstring"); + sizeMap.insert(sizeof(std::allocator), "std::allocator"); + sizeMap.insert(sizeof(std::char_traits), "std::char_traits"); + sizeMap.insert(sizeof(std::char_traits), "std::char_traits"); +#ifndef QT_BOOTSTRAPPED +#if QT_VERSION >= 0x040500 + sizeMap.insert(sizeof(QSharedPointer), NS"QSharedPointer"); + sizeMap.insert(sizeof(QSharedDataPointer), NS"QSharedDataPointer"); + sizeMap.insert(sizeof(QWeakPointer), NS"QWeakPointer"); +#endif +#endif // QT_BOOTSTRAPPED + sizeMap.insert(sizeof(QPointer), "QPointer"); + // Common map node types + sizeMap.insert(sizeof(QMapNode), NS"QMapNode"); + sizeMap.insert(sizeof(QMapNode), NS"QMapNode"); + sizeMap.insert(sizeof(QMapNode), NS"QMapNode"); + sizeMap.insert(sizeof(QMapNode), NS"QMapNode<"NS"QString,int>"); + sizeMap.insert(sizeof(QMapNode), NS"QMapNode<"NS"QString,"NS"QString>"); + sizeMap.insert(sizeof(QMapNode), NS"QMapNode<"NS"QString,"NS"QVariant>"); + // Dump as lists of types preceded by size + size_t lastSize = 0; + d.put("sizes=["); + const SizeMap::const_iterator cend = sizeMap.constEnd(); + for (SizeMap::const_iterator it = sizeMap.constBegin(); it != cend; ++it) { + // new size list + if (it.key() != lastSize) { + if (lastSize) + d.put("],"); + d.put("[\""); + d.put(it.key()); + lastSize = it.key(); + d.put('"'); + } + d.put(",\""); + d.put(it.value()); + d.put('"'); + } + d.put("]]"); +} + extern "C" Q_DECL_EXPORT void *qDumpObjectData440( int protocolVersion, @@ -3702,45 +3769,10 @@ void *qDumpObjectData440( d.put(",namespace=\""NS"\","); d.put("dumperversion=\"1.3\","); // Dump out size information - d.put("sizes={"); - d.put("int=\"").put(sizeof(int)).put("\",") - .put("char*=\"").put(sizeof(char*)).put("\",") - .put(""NS"QString=\"").put(sizeof(QString)).put("\",") - .put(""NS"QStringList=\"").put(sizeof(QStringList)).put("\",") -#ifndef QT_BOOTSTRAPPED - .put(""NS"QObject=\"").put(sizeof(QObject)).put("\",") -#endif -#if USE_QT_GUI - .put(""NS"QWidget=\"").put(sizeof(QWidget)).put("\",") -#endif -#ifdef Q_OS_WIN - .put("string=\"").put(sizeof(std::string)).put("\",") - .put("wstring=\"").put(sizeof(std::wstring)).put("\",") -#endif - .put("std::string=\"").put(sizeof(std::string)).put("\",") - .put("std::wstring=\"").put(sizeof(std::wstring)).put("\",") - .put("std::allocator=\"").put(sizeof(std::allocator)).put("\",") - .put("std::char_traits=\"").put(sizeof(std::char_traits)).put("\",") - .put("std::char_traits=\"").put(sizeof(std::char_traits)).put("\",") -#ifndef QT_BOOTSTRAPPED -#if QT_VERSION >= 0x040500 - .put(NS"QSharedPointer=\"").put(sizeof(QSharedPointer)).put("\",") - .put(NS"QSharedDataPointer=\"").put(sizeof(QSharedDataPointer)).put("\",") - .put(NS"QWeakPointer=\"").put(sizeof(QWeakPointer)).put("\",") -#endif -#endif // QT_BOOTSTRAPPED - .put("QPointer=\"").put(sizeof(QPointer)).put("\",") - // Common map node types - .put(NS"QMapNode=\"").put(sizeof(QMapNode)).put("\",") - .put(NS"QMapNode=\"").put(sizeof(QMapNode)).put("\",") - .put(NS"QMapNode=\"").put(sizeof(QMapNode)).put("\",") - .put(NS"QMapNode<"NS"QString,int>=\"").put(sizeof(QMapNode)).put("\",") - .put(NS"QMapNode<"NS"QString,"NS"QString>=\"").put(sizeof(QMapNode)).put("\",") - .put(NS"QMapNode<"NS"QString,"NS"QVariant>=\"").put(sizeof(QMapNode)) - .put("\"}"); + dumpSizes(d); // Write out common expression values for CDB #ifdef Q_CC_MSVC - d.put(",expressions={"); + d.put(",expressions=["); putQMapNodeOffsetExpression("int", "int", d).put(','); putQMapNodeOffsetExpression("int", NS"QString", d).put(','); putQMapNodeOffsetExpression("int", NS"QVariant", d).put(','); @@ -3754,11 +3786,11 @@ void *qDumpObjectData440( putStdPairValueOffsetExpression(NS"QString", "int", d).put(','); putStdPairValueOffsetExpression(stdStringTypeC, stdStringTypeC, d).put(','); putStdPairValueOffsetExpression("int", stdStringTypeC, d).put(','); - putStdPairValueOffsetExpression(stdStringTypeC, "int", d.put(',')); + putStdPairValueOffsetExpression(stdStringTypeC, "int", d).put(','); putStdPairValueOffsetExpression(stdWideStringTypeUShortC, stdWideStringTypeUShortC, d).put(','); putStdPairValueOffsetExpression("int", stdWideStringTypeUShortC, d).put(','); putStdPairValueOffsetExpression(stdWideStringTypeUShortC, "int", d); - d.put('}'); + d.put(']'); #endif // Q_CC_MSVC d.disarm(); } diff --git a/share/qtcreator/gdbmacros/gdbmacros_p.h b/share/qtcreator/gdbmacros/gdbmacros_p.h index 0aed16d3781..7914e04aa44 100644 --- a/share/qtcreator/gdbmacros/gdbmacros_p.h +++ b/share/qtcreator/gdbmacros/gdbmacros_p.h @@ -152,8 +152,6 @@ public: QList pendingChildInsertedEvents; QList > eventFilters; void *currentChildBeingDeleted; - void *declarativeData; - void *objectGuards; QAtomicPointer sharedRefcount; int *deleteWatch; #endif diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index 39956dcb0fb..b6be579ab38 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -28,10 +28,12 @@ **************************************************************************/ #include +#include #include #include #include #include +#include #include #include @@ -138,6 +140,16 @@ static int dumpQIntList() return 0; } +static int dumpQIntLinkedList() +{ + QLinkedList test = QLinkedList() << 1 << 2; + prepareInBuffer("QLinkedList", "local.qintlinkedlist", "local.qlinkedintlist", "int"); + qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), 0, 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + static int dumpQIntVector() { QVector test = QVector() << 42 << 43; @@ -148,6 +160,16 @@ static int dumpQIntVector() return 0; } +static int dumpQQStringVector() +{ + QVector test = QVector() << "42s" << "43s"; + prepareInBuffer("QVector", "local.qstringvector", "local.qstringvector", "QString"); + qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), 0, 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + static int dumpQMapIntInt() { QMap test; @@ -176,6 +198,33 @@ static int dumpQMapIntString() return 0; } +static int dumpQSetInt() +{ + QSet test; + test.insert(42); + test.insert(43); + prepareInBuffer("QSet", "local.qsetint", "local.qsetint", "int"); + qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), 0, 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + + +static int dumpQMapQStringString() +{ + QMap test; + QMapNode mapNode; + const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; + test.insert(QLatin1String("42s"), QLatin1String("fortytwo")); + test.insert(QLatin1String("423"), QLatin1String("fortytree")); + prepareInBuffer("QMap", "local.qmapqstringqstring", "local.qmapqstringqstring", "QString@QString"); + qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), sizeof(QString), sizeof(mapNode), valueOffset); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + static int dumpQVariant() { QVariant test(QLatin1String("item")); @@ -417,10 +466,14 @@ static TypeDumpFunctionMap registerTypes() rc.insert("QSharedPointer", dumpQSharedPointerQString); rc.insert("QStringList", dumpQStringList); rc.insert("QList", dumpQIntList); + rc.insert("QLinkedList", dumpQIntLinkedList); rc.insert("QList", dumpStdStringQList); rc.insert("QVector", dumpQIntVector); + rc.insert("QVector", dumpQQStringVector); rc.insert("QMap", dumpQMapIntString); + rc.insert("QMap", dumpQMapQStringString); rc.insert("QMap", dumpQMapIntInt); + rc.insert("QSet", dumpQSetInt); rc.insert("string", dumpStdString); rc.insert("wstring", dumpStdWString); rc.insert("list", dumpStdIntList); diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp index b0b71ffecdf..da12f3e599a 100644 --- a/src/libs/cplusplus/BackwardsScanner.cpp +++ b/src/libs/cplusplus/BackwardsScanner.cpp @@ -38,6 +38,7 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suf , _block(cursor.block()) , _maxBlockCount(maxBlockCount) { + _tokenize.setQtMocRunEnabled(true); _tokenize.setSkipComments(true); _text = _block.text().left(cursor.position() - cursor.block().position()); @@ -52,13 +53,10 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, const QString &suf int BackwardsScanner::state() const { return _tokenize.state(); } -const QList &BackwardsScanner::tokens() const -{ return _tokens; } - -const SimpleToken &BackwardsScanner::LA(int index) const +SimpleToken BackwardsScanner::LA(int index) const { return const_cast(this)->fetchToken(_startToken - index); } -const SimpleToken &BackwardsScanner::operator[](int index) const +SimpleToken BackwardsScanner::operator[](int index) const { return const_cast(this)->fetchToken(index); } const SimpleToken &BackwardsScanner::fetchToken(int i) @@ -72,16 +70,15 @@ const SimpleToken &BackwardsScanner::fetchToken(int i) } else { ++_blocksTokenized; - QString blockText = _block.text(); + const QString blockText = _block.text(); _text.prepend(blockText); + QList adaptedTokens; for (int i = 0; i < _tokens.size(); ++i) { - const SimpleToken &t = _tokens.at(i); - const int position = t.position() + blockText.length(); - adaptedTokens.append(SimpleToken(t.kind(), - position, - t.length(), - _text.midRef(position, t.length()))); + SimpleToken t = _tokens.at(i); + t.setPosition(t.position() + blockText.length()); + t.setText(_text.midRef(t.position(), t.length())); + adaptedTokens.append(t); } _tokens = _tokenize(blockText, previousBlockState(_block)); @@ -102,18 +99,22 @@ int BackwardsScanner::startPosition() const QString BackwardsScanner::text() const { return _text; } -QString BackwardsScanner::text(int begin, int end) const +QString BackwardsScanner::mid(int index) const { - const SimpleToken &firstToken = _tokens.at(begin + _offset); - const SimpleToken &lastToken = _tokens.at(end + _offset - 1); - return _text.mid(firstToken.begin(), lastToken.end() - firstToken.begin()); + const SimpleToken &firstToken = _tokens.at(index + _offset); + return _text.mid(firstToken.begin()); } -QStringRef BackwardsScanner::textRef(int begin, int end) const +QString BackwardsScanner::text(int index) const { - const SimpleToken &firstToken = _tokens.at(begin + _offset); - const SimpleToken &lastToken = _tokens.at(end + _offset - 1); - return _text.midRef(firstToken.begin(), lastToken.end() - firstToken.begin()); + const SimpleToken &firstToken = _tokens.at(index + _offset); + return _text.mid(firstToken.begin(), firstToken.length()); +} + +QStringRef BackwardsScanner::textRef(int index) const +{ + const SimpleToken &firstToken = _tokens.at(index + _offset); + return _text.midRef(firstToken.begin(), firstToken.length()); } int BackwardsScanner::previousBlockState(const QTextBlock &block) const @@ -156,6 +157,17 @@ int BackwardsScanner::startOfMatchingBrace(int index) const --count; --i; } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); + } else if (tk[index - 1].is(T_RBRACE)) { + int i = index - 1; + int count = 0; + do { + if (tk[i].is(T_LBRACE)) { + if (! ++count) + return i; + } else if (tk[i].is(T_RBRACE)) + --count; + --i; + } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); } else if (tk[index - 1].is(T_GREATER)) { int i = index - 1; int count = 0; @@ -167,7 +179,71 @@ int BackwardsScanner::startOfMatchingBrace(int index) const --count; --i; } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); + } else { + Q_ASSERT(0); } return index; } + +int BackwardsScanner::startOfLine(int index) const +{ + const BackwardsScanner tk(*this); + + forever { + const SimpleToken &tok = tk[index - 1]; + + if (tok.is(T_EOF_SYMBOL)) + break; + else if (tok.followsNewline()) + return index - 1; + + --index; + } + + return index; +} + +int BackwardsScanner::startOfBlock(int index) const +{ + const BackwardsScanner tk(*this); + + const int start = index; + + forever { + SimpleToken token = tk[index - 1]; + + if (token.is(T_EOF_SYMBOL)) { + break; + + } else if (token.is(T_GREATER)) { + const int matchingBrace = startOfMatchingBrace(index); + + if (matchingBrace != index && tk[matchingBrace - 1].is(T_TEMPLATE)) + index = matchingBrace; + + } else if (token.is(T_RPAREN) || token.is(T_RBRACKET) || token.is(T_RBRACE)) { + const int matchingBrace = startOfMatchingBrace(index); + + if (matchingBrace != index) + index = matchingBrace; + + } else if (token.is(T_LPAREN) || token.is(T_LBRACKET)) { + break; // unmatched brace + + } else if (token.is(T_LBRACE)) { + return index - 1; + + } + + --index; + } + + return start; +} + +int BackwardsScanner::indentation(int index) const +{ + SimpleToken newline = operator[](startOfLine(index + 1)); + return newline.position(); +} diff --git a/src/libs/cplusplus/BackwardsScanner.h b/src/libs/cplusplus/BackwardsScanner.h index 68d1f047878..b2e7414951e 100644 --- a/src/libs/cplusplus/BackwardsScanner.h +++ b/src/libs/cplusplus/BackwardsScanner.h @@ -51,21 +51,26 @@ public: int startPosition() const; QString text() const; - QString text(int begin, int end) const; - QStringRef textRef(int begin, int end) const; + QString mid(int index) const; + QString text(int index) const; + QStringRef textRef(int index) const; // 1-based - const SimpleToken &LA(int index) const; + SimpleToken LA(int index) const; // n-la token is [startToken - n] - const SimpleToken &operator[](int index) const; // ### deprecate + SimpleToken operator[](int index) const; // ### deprecate + int indentation(int index) const; + + int startOfLine(int index) const; int startOfMatchingBrace(int index) const; + int startOfBlock(int index) const; + int previousBlockState(const QTextBlock &block) const; private: const SimpleToken &fetchToken(int i); - const QList &tokens() const; private: QList _tokens; diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 106e3040b1b..8016f537bb2 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -150,7 +150,7 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) if (i == initialSize) return QString(); - return scanner.text(i, initialSize); + return scanner.mid(i); } int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index 8813e890bee..bbbb06b8311 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -49,9 +49,9 @@ static bool shouldOverrideChar(const QChar &ch) } } -static bool isCompleteStringLiteral(const BackwardsScanner &tk, int index, int startToken) +static bool isCompleteStringLiteral(const BackwardsScanner &tk, int index) { - const QStringRef text = tk.textRef(index, startToken); + const QStringRef text = tk.textRef(index); if (text.length() < 2) return false; @@ -62,9 +62,9 @@ static bool isCompleteStringLiteral(const BackwardsScanner &tk, int index, int s return false; } -static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index, int startToken) +static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index) { - const QStringRef text = tk.textRef(index, startToken); + const QStringRef text = tk.textRef(index); if (text.length() < 2) return false; @@ -75,7 +75,16 @@ static bool isCompleteCharLiteral(const BackwardsScanner &tk, int index, int sta return false; } -static bool shouldInsertMatchingText(const QChar &lookAhead) +MatchingText::MatchingText() +{ } + +bool MatchingText::shouldInsertMatchingText(const QTextCursor &tc) +{ + QTextDocument *doc = tc.document(); + return shouldInsertMatchingText(doc->characterAt(tc.selectionEnd())); +} + +bool MatchingText::shouldInsertMatchingText(const QChar &lookAhead) { switch (lookAhead.unicode()) { case '{': case '}': @@ -91,9 +100,6 @@ static bool shouldInsertMatchingText(const QChar &lookAhead) } // switch } -MatchingText::MatchingText() -{ } - QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QString &textToProcess, const QChar &la, int *skippedChars) const { @@ -133,7 +139,7 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri if (text.length() != 1) qWarning() << Q_FUNC_INFO << "handle event compression"; - if (isCompleteStringLiteral(tk, index - 1, startToken)) + if (isCompleteStringLiteral(tk, index - 1)) return QLatin1String("\""); return QString(); @@ -141,7 +147,7 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri if (text.length() != 1) qWarning() << Q_FUNC_INFO << "handle event compression"; - if (isCompleteCharLiteral(tk, index - 1, startToken)) + if (isCompleteCharLiteral(tk, index - 1)) return QLatin1String("'"); return QString(); diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index cd3d59c5c16..26af99a8bea 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -41,6 +41,9 @@ class CPLUSPLUS_EXPORT MatchingText public: MatchingText(); + static bool shouldInsertMatchingText(const QTextCursor &tc); + static bool shouldInsertMatchingText(const QChar &lookAhead); + QString insertMatchingBrace(const QTextCursor &tc, const QString &text, const QChar &la, int *skippedChars) const; QString insertParagraphSeparator(const QTextCursor &tc) const; diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp index 7e60f76115b..59475bc4a4e 100644 --- a/src/libs/cplusplus/SimpleLexer.cpp +++ b/src/libs/cplusplus/SimpleLexer.cpp @@ -35,6 +35,17 @@ using namespace CPlusPlus; +SimpleToken::SimpleToken(const Token &token, const QStringRef &text) + : _kind(token.f.kind) + , _flags(0) + , _position(token.begin()) + , _length(token.f.length) + , _text(text) +{ + f._whitespace = token.f.whitespace; + f._newline = token.f.newline; +} + bool SimpleToken::isLiteral() const { return _kind >= T_FIRST_LITERAL && _kind <= T_LAST_LITERAL; @@ -60,6 +71,11 @@ bool SimpleToken::isObjCAtKeyword() const return _kind >= T_FIRST_OBJC_AT_KEYWORD && _kind <= T_LAST_OBJC_AT_KEYWORD; } +const char *SimpleToken::name() const +{ + return Token::name(_kind); +} + SimpleLexer::SimpleLexer() : _lastState(0), _skipComments(false), @@ -113,6 +129,7 @@ QList SimpleLexer::operator()(const QString &text, int state) Lexer lex(firstChar, lastChar); lex.setQtMocRunEnabled(_qtMocRunEnabled); lex.setObjCEnabled(_objCEnabled); + lex.setStartWithNewline(true); if (! _skipComments) lex.setScanCommentTokens(true); @@ -128,12 +145,8 @@ QList SimpleLexer::operator()(const QString &text, int state) if (tk.is(T_EOF_SYMBOL)) break; - SimpleToken simpleTk; - simpleTk._kind = int(tk.f.kind); - simpleTk._position = int(lex.tokenOffset()); - simpleTk._length = int(lex.tokenLength()); - simpleTk._text = text.midRef(simpleTk._position, simpleTk._length); - + QStringRef spell = text.midRef(lex.tokenOffset(), lex.tokenLength()); + SimpleToken simpleTk(tk, spell); lex.setScanAngleStringLiteralTokens(false); if (tk.f.newline && tk.is(T_POUND)) diff --git a/src/libs/cplusplus/SimpleLexer.h b/src/libs/cplusplus/SimpleLexer.h index 3f15193ee03..0775eccb1c9 100644 --- a/src/libs/cplusplus/SimpleLexer.h +++ b/src/libs/cplusplus/SimpleLexer.h @@ -37,21 +37,18 @@ namespace CPlusPlus { class SimpleLexer; +class Token; class CPLUSPLUS_EXPORT SimpleToken { public: - SimpleToken(int kind, int position, int length, const QStringRef &text) - : _kind(kind) - , _position(position) - , _length(length) - , _text(text) - { } + SimpleToken(const Token &token, const QStringRef &text); SimpleToken() - : _kind(0), - _position(0), - _length(0) + : _kind(0) + , _flags(0) + , _position(0) + , _length(0) { } inline int kind() const @@ -72,6 +69,12 @@ public: inline QStringRef text() const { return _text; } + inline bool followsNewline() const + { return f._newline; } + + inline bool followsWhitespace() const + { return f._whitespace; } + inline bool is(int k) const { return _kind == k; } inline bool isNot(int k) const { return _kind != k; } @@ -81,8 +84,27 @@ public: bool isComment() const; bool isObjCAtKeyword() const; + const char *name() const; + + // internal + inline void setPosition(int position) + { _position = position; } + + // internal + inline void setText(const QStringRef &text) + { _text = text; } + public: - int _kind; + short _kind; + union { + short _flags; + + struct { + short _newline: 1; + short _whitespace: 1; + } f; + }; + int _position; int _length; QStringRef _text; diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index 741486e89f6..22ffa7e248e 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -176,10 +176,11 @@ void StyleHelper::horizontalGradient(QPainter *painter, const QRect &spanRect, c QColor base = StyleHelper::baseColor(); QLinearGradient grad(rect.topLeft(), rect.bottomLeft()); - grad.setColorAt(0, highlightColor().lighter(120)); - grad.setColorAt(0.4, highlightColor()); - grad.setColorAt(0.401, base); + if (rect.height() == navigationWidgetHeight()) { + grad.setColorAt(0.4, highlightColor()); + grad.setColorAt(0.401, base); + } grad.setColorAt(1, shadowColor()); p->fillRect(rect, grad); diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 2a681e858c5..c6b860234e3 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -1263,17 +1264,17 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const { if (ch == QLatin1Char('{') || ch == QLatin1Char('}') || + ch == QLatin1Char(':') || ch == QLatin1Char('#')) { return true; } return false; } -#if 1 QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &textToInsert) const { - bool checkBlockEnd = m_allowSkippingOfBlockEnd; - m_allowSkippingOfBlockEnd = false; + const bool checkBlockEnd = m_allowSkippingOfBlockEnd; + m_allowSkippingOfBlockEnd = false; // consume blockEnd. if (!contextAllowsAutoParentheses(cursor)) return QString(); @@ -1281,16 +1282,21 @@ QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &textToInsert QString text = textToInsert; const QChar lookAhead = characterAt(cursor.selectionEnd()); - QString autoText; - int skippedChars = 0; - - if (checkBlockEnd && (lookAhead == QChar::ParagraphSeparator && (! text.isEmpty() && text.at(0) == QLatin1Char('}')))) { - skippedChars = 2; - text = text.mid(1); - } - MatchingText matchingText; - autoText = matchingText.insertMatchingBrace(cursor, text, lookAhead, &skippedChars); + int skippedChars = 0; + const QString autoText = matchingText.insertMatchingBrace(cursor, text, lookAhead, &skippedChars); + + if (checkBlockEnd && textToInsert.at(0) == QLatin1Char('}')) { + if (textToInsert.length() > 1) + qWarning() << "*** handle event compression"; + + int startPos = cursor.selectionEnd(), pos = startPos; + while (characterAt(pos).isSpace()) + ++pos; + + if (characterAt(pos) == QLatin1Char('}')) + skippedChars += (pos - startPos) + 1; + } if (skippedChars) { const int pos = cursor.position(); @@ -1300,67 +1306,6 @@ QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &textToInsert return autoText; } -#else -QString CPPEditor::autoComplete(QTextCursor &cursor, const QString &text) const -{ - bool checkBlockEnd = m_allowSkippingOfBlockEnd; - m_allowSkippingOfBlockEnd = false; - - if (!contextAllowsAutoParentheses(cursor)) - return QString(); - - QString autoText; - QChar lookAhead = characterAt(cursor.selectionEnd()); - if (lookAhead.isSpace() // Only auto-insert when the text right of the cursor seems unrelated - || lookAhead == QLatin1Char('{') - || lookAhead == QLatin1Char('}') - || lookAhead == QLatin1Char(']') - || lookAhead == QLatin1Char(')') - || lookAhead == QLatin1Char(';') - || lookAhead == QLatin1Char(',') - ) { - foreach (QChar c, text) { - QChar close; - if (c == QLatin1Char('(')) { - close = QLatin1Char(')'); - } else if (c == QLatin1Char('[')) - close = QLatin1Char(']'); - else if (c == QLatin1Char('\"')) - close = c; - else if (c == QLatin1Char('\'')) - close = c; - if (!close.isNull()) - autoText += close; - } - } - - bool skip = false; - QChar first = text.at(0); - if (first == QLatin1Char(')') - || first == QLatin1Char(']') - || first == QLatin1Char(';') - ) { - skip = (first == lookAhead); - } else if (first == QLatin1Char('\"') || first == QLatin1Char('\'')) { - if (first == lookAhead) { - QChar lookBehind = characterAt(cursor.position()-1); - skip = (lookBehind != '\\'); - } - } else if (checkBlockEnd && first == QLatin1Char('}') - && lookAhead == QChar::ParagraphSeparator) { - skip = (first == characterAt(cursor.position() + 1)); - cursor.movePosition(QTextCursor::Right); - } - - if (skip) { - int pos = cursor.position(); - cursor.setPosition(pos+1); - cursor.setPosition(pos, QTextCursor::KeepAnchor); - } - - return autoText; -} -#endif bool CPPEditor::autoBackspace(QTextCursor &cursor) { @@ -1398,7 +1343,6 @@ int CPPEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) if (!contextAllowsAutoParentheses(cursor)) return 0; - // verify that we indeed do have an extra opening brace in the document int braceDepth = document()->lastBlock().userState(); if (braceDepth >= 0) @@ -1432,6 +1376,9 @@ int CPPEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor) const { + if (! MatchingText::shouldInsertMatchingText(cursor)) + return false; + CPlusPlus::TokenUnderCursor tokenUnderCursor; const SimpleToken tk = tokenUnderCursor(cursor); @@ -1470,9 +1417,60 @@ static void indentCPPBlock(const CPPEditor::TabSettings &ts, void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar) { + QTextCursor tc(block); + tc.movePosition(QTextCursor::EndOfBlock); + + BackwardsScanner tk(tc, QString(), 400); + const int tokenCount = tk.startToken(); + const int indentSize = tabSettings().m_indentSize; + + if (tokenCount != 0) { + const SimpleToken firstToken = tk[0]; + + if (firstToken.is(T_COLON)) { + const int indent = tk.indentation(-1) + // indentation of the previous newline + indentSize; + tabSettings().indentLine(block, indent); + return; + } else if ((firstToken.is(T_PUBLIC) || firstToken.is(T_PROTECTED) || firstToken.is(T_PRIVATE) || + firstToken.is(T_Q_SIGNALS) || firstToken.is(T_Q_SLOTS)) && tk[1].is(T_COLON)) { + const int startOfBlock = tk.startOfBlock(0); + if (startOfBlock != 0) { + const int indent = tk.indentation(startOfBlock); + tabSettings().indentLine(block, indent); + return; + } + } else if (firstToken.is(T_CASE) || firstToken.is(T_DEFAULT)) { + const int startOfBlock = tk.startOfBlock(0); + if (startOfBlock != 0) { + const int indent = tk.indentation(startOfBlock); + tabSettings().indentLine(block, indent); + return; + } + return; + } + } + + if ((tokenCount == 0 || tk[0].isNot(T_POUND)) && typedChar.isNull() && (tk[-1].is(T_IDENTIFIER) || tk[-1].is(T_RPAREN))) { + int tokenIndex = -1; + if (tk[-1].is(T_RPAREN)) { + const int matchingBrace = tk.startOfMatchingBrace(0); + if (matchingBrace != 0 && tk[matchingBrace - 1].is(T_IDENTIFIER)) { + tokenIndex = matchingBrace - 1; + } + } + + const QString spell = tk.text(tokenIndex); + if (tk[tokenIndex].followsNewline() && (spell.startsWith(QLatin1String("QT_")) || + spell.startsWith(QLatin1String("Q_")))) { + const int indent = tk.indentation(tokenIndex); + tabSettings().indentLine(block, indent); + return; + } + } + const TextEditor::TextBlockIterator begin(doc->begin()); const TextEditor::TextBlockIterator end(block.next()); - indentCPPBlock(tabSettings(), block, begin, end, typedChar); } diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 3e66d27d500..de6f3d1cd16 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -554,7 +554,7 @@ static inline QString msgNotHandled(const QString &type) return QString::fromLatin1("The type '%1' is not handled.").arg(type); } -CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source, +CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, QList *result, QString *errorMessage) { // Check failure cache and supported types @@ -593,7 +593,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool arg(wd.name, wd.exp, wd.type); m_access->showDebuggerOutput(LogMisc, message); - const DumpExecuteResult der = executeDump(wd, td, dumpChildren, source, result, errorMessage); + const DumpExecuteResult der = executeDump(wd, td, dumpChildren, result, errorMessage); if (der == DumpExecuteOk) return DumpOk; // Cache types that fail due to complicated template size expressions. @@ -610,7 +610,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool CdbDumperHelper::DumpExecuteResult CdbDumperHelper::executeDump(const WatchData &wd, - const QtDumperHelper::TypeData& td, bool dumpChildren, int source, + const QtDumperHelper::TypeData& td, bool dumpChildren, QList *result, QString *errorMessage) { QByteArray inBuffer; @@ -658,12 +658,10 @@ CdbDumperHelper::DumpExecuteResult } if (!callDumper(callCmd, inBuffer, &outputData, true, errorMessage)) return DumpExecuteCallFailed; - QtDumperResult dumpResult; - if (!QtDumperHelper::parseValue(outputData, &dumpResult)) { + if (!QtDumperHelper::parseValue(outputData, result)) { *errorMessage = QLatin1String("Parsing of value query output failed."); return DumpExecuteCallFailed; } - *result = dumpResult.toWatchData(source); return DumpExecuteOk; } diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h index 5c7530a7a7b..c9895e08d96 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.h +++ b/src/plugins/debugger/cdb/cdbdumperhelper.h @@ -89,7 +89,7 @@ public: // Dump a WatchData item. enum DumpResult { DumpNotHandled, DumpOk, DumpError }; - DumpResult dumpType(const WatchData &d, bool dumpChildren, int source, + DumpResult dumpType(const WatchData &d, bool dumpChildren, QList *result, QString *errorMessage); inline CdbComInterfaces *comInterfaces() const { return m_cif; } @@ -113,7 +113,7 @@ private: DumpComplexExpressionEncountered, DumpExecuteCallFailed }; DumpExecuteResult executeDump(const WatchData &wd, - const QtDumperHelper::TypeData& td, bool dumpChildren, int source, + const QtDumperHelper::TypeData& td, bool dumpChildren, QList *result, QString *errorMessage); static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage); diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 8938f93e48a..1b9b18a04f0 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -156,7 +156,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt derefedWd.name = QString(QLatin1Char('*')); derefedWd.iname = wd.iname + QLatin1String(".*"); derefedWd.source = OwnerDumper | CdbStackFrameContext::ChildrenKnownBit; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, OwnerDumper, &m_dumperResult, errorMessage); + const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage); if (dr != CdbDumperHelper::DumpOk) break; // Insert the pointer item with 1 additional child + its dumper results @@ -166,8 +166,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt ptrWd.setHasChildren(true); ptrWd.setChildrenUnneeded(); m_wh->insertData(ptrWd); - foreach(const WatchData &dwd, m_dumperResult) - m_wh->insertData(dwd); + m_wh->insertBulkData(m_dumperResult); handled = true; } while (false); if (debugCDBWatchHandling) @@ -184,7 +183,8 @@ static inline void fixDumperResult(const WatchData &source, const int size = result->size(); if (!size) return; - // debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult"); + if (debugCDBWatchHandling) + debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult"); WatchData &returned = result->front(); if (returned.iname != source.iname) return; @@ -198,6 +198,10 @@ static inline void fixDumperResult(const WatchData &source, returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "")); } } + // Indicate owner and known children + returned.source = OwnerDumper; + if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren) + returned.source |= CdbStackFrameContext::ChildrenKnownBit; if (size == 1) return; // If the model queries the expanding item by pretending childrenNeeded=1, @@ -208,6 +212,10 @@ static inline void fixDumperResult(const WatchData &source, QList::iterator it = result->begin(); for (++it; it != wend; ++it) { WatchData &wd = *it; + // Indicate owner and known children + it->source = OwnerDumper; + if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren) + it->source |= CdbStackFrameContext::ChildrenKnownBit; if (wd.addr.isEmpty() && wd.isSomethingNeeded()) { wd.setHasChildren(false); wd.setAllUnneeded(); @@ -218,7 +226,8 @@ static inline void fixDumperResult(const WatchData &source, wd.setHasChildren(false); } } - // debugWatchDataList(*result, "dumpType(wd, true, OwnerDumper, &m_dumperResult, &errorMessage)) { + switch (m_dumper->dumpType(wd, true, &m_dumperResult, &errorMessage)) { case CdbDumperHelper::DumpOk: if (debugCDBWatchHandling) qDebug() << "dumper triggered"; // Dumpers omit types for complicated templates fixDumperResult(wd, &m_dumperResult, false); // Discard the original item and insert the dumper results - foreach(const WatchData &dwd, m_dumperResult) - m_wh->insertData(dwd); + m_wh->insertBulkData(m_dumperResult); // Nasty side effect: Modify owner for the ignore predicate wd.source = OwnerDumper; break; @@ -325,13 +333,12 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal, return true; } QList dumperResult; - const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, OwnerDumper, &dumperResult, errorMessage); + const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, &dumperResult, errorMessage); if (dr == CdbDumperHelper::DumpOk) { // Hack to stop endless model recursion const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname); fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren); - foreach(const WatchData &dwd, dumperResult) - wh->insertData(dwd); + wh->insertBulkData(dumperResult); } else { const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage); qWarning("%s", qPrintable(msg)); @@ -372,7 +379,7 @@ bool CdbStackFrameContext::editorToolTip(const QString &iname, // Check dumpers. Should actually be just one item. if (m_useDumpers && m_dumper->state() != CdbDumperHelper::Disabled) { QList result; - if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, OwnerDumper, &result, errorMessage)) { + if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage)) { foreach (const WatchData &dwd, result) { if (!value->isEmpty()) value->append(QLatin1Char('\n')); diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index ee941972cb0..f58f1f74527 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -595,9 +595,9 @@ bool CdbSymbolGroupContext::debugValueToInteger(const DEBUG_VALUE &dv, qint64 *v * To add further types, have a look at the toString() output of the * symbol group. */ -static QString msgStructuralError(const QString &type, int code) +static QString msgStructuralError(const QString &name, const QString &type, int code) { - return QString::fromLatin1("Warning: Internal dumper for '%1' failed with %2.").arg(type).arg(code); + return QString::fromLatin1("Warning: Internal dumper for '%1' (%2) failed with %3.").arg(name, type).arg(code); } static inline bool isStdStringOrPointer(const QString &type) @@ -631,7 +631,7 @@ CdbSymbolGroupContext::DumperResult rc = DumperError; break; default: - qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc))); + qWarning("%s\n", qPrintable(msgStructuralError(wd->iname, wd->type, drc))); rc = DumperNotHandled; break; } @@ -647,7 +647,7 @@ CdbSymbolGroupContext::DumperResult rc = DumperError; break; default: - qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc))); + qWarning("%s\n", qPrintable(msgStructuralError(wd->iname, wd->type, drc))); rc = DumperNotHandled; break; } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index faa860a1467..3844f0af683 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3305,36 +3305,12 @@ static void parseSizeCache(const GdbMi &contents, QtDumperHelper *dumperHelper) void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const QVariant &) { const double dumperVersionRequired = 1.0; - m_dumperHelper.clear(); //qDebug() << "DATA DUMPER TRIAL:" << record.toString(); GdbMi contents; QTC_ASSERT(parseConsoleStream(record, &contents), /**/); - GdbMi simple = contents.findChild("dumpers"); - - m_dumperHelper.setQtNamespace(_(contents.findChild("namespace").data())); - GdbMi qtversion = contents.findChild("qtversion"); - int qtv = 0; - if (qtversion.children().size() == 3) { - qtv = (qtversion.childAt(0).data().toInt() << 16) - + (qtversion.childAt(1).data().toInt() << 8) - + qtversion.childAt(2).data().toInt(); - //qDebug() << "FOUND QT VERSION:" << qtversion.toString() << m_qtVersion; - } - m_dumperHelper.setQtVersion(qtv); - //qDebug() << "CONTENTS:" << contents.toString(); - //qDebug() << "SIMPLE DUMPERS:" << simple.toString(); - - QStringList availableSimpleDebuggingHelpers; - foreach (const GdbMi &item, simple.children()) - availableSimpleDebuggingHelpers.append(_(item.data())); - m_dumperHelper.parseQueryTypes(availableSimpleDebuggingHelpers, QtDumperHelper::GdbDebugger); - - if (availableSimpleDebuggingHelpers.isEmpty()) { - if (!m_dumperInjectionLoad) // Retry if thread has not terminated yet. - m_debuggingHelperState = DebuggingHelperUnavailable; - showStatusMessage(tr("Debugging helpers not found.")); - } else { + const bool ok = m_dumperHelper.parseQuery(contents, QtDumperHelper::GdbDebugger) && m_dumperHelper.typeCount(); + if (ok) { // Get version and sizes from dumpers. Expression cache // currently causes errors. const double dumperVersion = getDumperVersion(contents); @@ -3347,6 +3323,10 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const m_debuggingHelperState = DebuggingHelperAvailable; const QString successMsg = tr("Dumper version %1, %n custom dumpers found.", 0, m_dumperHelper.typeCount()).arg(dumperVersion); showStatusMessage(successMsg); + } else { + if (!m_dumperInjectionLoad) // Retry if thread has not terminated yet. + m_debuggingHelperState = DebuggingHelperUnavailable; + showStatusMessage(tr("Debugging helpers not found.")); } //qDebug() << m_dumperHelper.toString(true); //qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE"; @@ -4318,7 +4298,8 @@ IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, QSharedPointer options(new TrkOptions); options->fromSettings(Core::ICore::instance()->settings()); - opts->push_back(new TrkOptionsPage(options)); + if (!qgetenv("QTCREATOR_WITH_S60").isEmpty()) + opts->push_back(new TrkOptionsPage(options)); TrkGdbAdapter *adapter = new TrkGdbAdapter(options); GdbEngine *engine = new GdbEngine(parent, adapter); QObject::connect(adapter, SIGNAL(output(QString)), diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 8e71dae9610..ac52e47baa3 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -227,6 +227,8 @@ QString WatchData::toString() const str << QLatin1Char('{'); if (!iname.isEmpty()) str << "iname=\"" << iname << doubleQuoteComma; + if (!name.isEmpty() && name != iname) + str << "name=\"" << name << doubleQuoteComma; if (!addr.isEmpty()) str << "addr=\"" << addr << doubleQuoteComma; if (!exp.isEmpty()) diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 7b70b5845d3..d09544fcab3 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -29,6 +29,7 @@ #include "watchutils.h" #include "watchhandler.h" +#include "gdb/gdbmi.h" #include #include @@ -491,172 +492,6 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, return expr; } -// --------------- QtDumperResult - -QtDumperResult::Child::Child() : - keyEncoded(0), - valueEncoded(0), - childCount(-1), - valueEnabled(true), - valueEncountered(false) -{ -} - -QtDumperResult::QtDumperResult() : - valueEncountered(false), - valueEncoded(0), - valueEnabled(true), - childCount(-1), - internal(false), - childChildCount(-1) -{ -} - -void QtDumperResult::clear() -{ - iname.clear(); - value.clear(); - address.clear(); - addressInfo.clear(); - type.clear(); - extra.clear(); - displayedType.clear(); - valueEncoded = 0; - valueEncountered = false; - valueEnabled = false; - childCount = -1; - internal = false; - childType.clear(); - children.clear(); - childChildCount = -1; -} - -QList QtDumperResult::toWatchData(int source) const -{ - QList rc; - rc.push_back(WatchData()); - WatchData &root = rc.front(); - root.iname = iname; - const QChar dot = QLatin1Char('.'); - const int lastDotIndex = root.iname.lastIndexOf(dot); - root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1); - if (valueEncountered) { - root.setValue(decodeData(value, valueEncoded)); - root.valueEnabled = valueEnabled; - } - root.setType(type); - if (!displayedType.isEmpty()) - root.displayedType = displayedType; - root.setAddress(address); - root.source = source; - if (childCount >= 0) - root.setHasChildren(childCount > 0); - // Children. Sanity check after parsing sets childcount to list size - // if list is not empty - if (children.empty()) { - if (childCount > 0) - root.setChildrenNeeded(); - } else { - root.setChildrenUnneeded(); - for (int c = 0; c < childCount; c++) { - const Child &dchild = children.at(c); - rc.push_back(WatchData()); - WatchData &wchild = rc.back(); - wchild.source = source; - wchild.iname = iname; - // Name can be empty for array-like things - const QString iname = dchild.name.isEmpty() ? QString::number(c) : dchild.name; - // Use key entry as name (which is used for map nodes) - if (dchild.key.isEmpty()) { - wchild.name = iname; - } else { - // Do not use map keys as iname since they might contain quotes. - wchild.name = decodeData(dchild.key, dchild.keyEncoded); - if (wchild.name.size() > 13) { - wchild.name.truncate(12); - wchild.name += QLatin1String("..."); - } - } - // Append iname to total iname. - wchild.iname += dot; - wchild.iname += iname; - wchild.exp = dchild.exp; - if (dchild.valueEncountered) { - wchild.valueEnabled = dchild.valueEnabled; - wchild.setValue(decodeData(dchild.value, dchild.valueEncoded)); - } - wchild.setAddress(dchild.address); - // The type setter sets hasChildren for known types. - wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); - if (!dchild.displayedType.isEmpty()) - wchild.displayedType = dchild.displayedType; - // Child overrides. - const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; - switch (effectiveChildChildCount) { - case -1: // In this case, trust WatchData::setType(). - break; - case 0: - wchild.setHasChildren(false); - break; - default: - wchild.setHasChildren(true); - wchild.setChildrenNeeded(); - break; - } - } - } - if (debug) { - QDebug nospace = qDebug().nospace(); - nospace << "QtDumperResult::toWatchData" << *this << '\n'; - foreach(const WatchData &wd, rc) - nospace << " " << wd.toString() << '\n'; - } - - return rc; -} - -QDebug operator<<(QDebug in, const QtDumperResult &d) -{ - QDebug nospace = in.nospace(); - nospace << " iname=" << d.iname << " type=" << d.type - << " displayed=" << d.displayedType - << " address=" << d.address; - if (!d.addressInfo.isEmpty()) - nospace << " addressInfo=" << d.addressInfo; - if (d.valueEncountered) { - nospace << " encoded=" << d.valueEncoded - << " value=" << d.value - << " enabled=" << d.valueEnabled; - } else { - nospace << " "; - } - nospace << " childnumchild=" << d.childChildCount - << " internal=" << d.internal - << " extra='" << d.extra << "'\n"; - - const int realChildCount = d.children.size(); - if (d.childCount || realChildCount) { - nospace << "childCount=" << d.childCount << '/' << realChildCount - << " childType=" << d.childType << '\n'; - for (int i = 0; i < realChildCount; i++) { - const QtDumperResult::Child &c = d.children.at(i); - nospace << " #" << i << " addr=" << c.address - << " enabled=" << c.valueEnabled - << " type=" << c.type << " exp=" << c.exp - << " name=" << c.name; - if (!c.key.isEmpty()) - nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key; - if (c.valueEncountered) { - nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value; - } else { - nospace << " "; - } - nospace << "childcount=" << c.childCount << '\n'; - } - } - return in; -} - // ----------------- QtDumperHelper::TypeData QtDumperHelper::TypeData::TypeData() : type(UnknownType), @@ -725,6 +560,10 @@ QString QtDumperHelper::toString(bool debug) const for (SizeCache::const_iterator it = m_sizeCache.constBegin(); it != scend; ++it) { str << ' ' << it.key() << '=' << it.value(); } + str << "\nExpression cache: (" << m_expressionCache.size() << ")\n"; + const QMap::const_iterator excend = m_expressionCache.constEnd(); + for (QMap::const_iterator it = m_expressionCache.constBegin(); it != excend; ++it) + str << " " << it.key() << ' ' << it.value() << '\n'; return rc; } const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("QtDumperHelper", "") : m_qtNamespace; @@ -749,11 +588,6 @@ QString QtDumperHelper::qtNamespace() const return m_qtNamespace; } -void QtDumperHelper::setQtNamespace(const QString &qtNamespace) -{ - m_qtNamespace = qtNamespace; -} - int QtDumperHelper::typeCount() const { return m_nameTypeMap.size(); @@ -842,23 +676,6 @@ QString QtDumperHelper::qtVersionString() const return rc; } -void QtDumperHelper::setQtVersion(int v) -{ - m_qtVersion = v; -} - -void QtDumperHelper::setQtVersion(const QString &v) -{ - m_qtVersion = 0; - const QStringList vl = v.split(QLatin1Char('.')); - if (vl.size() == 3) { - const int major = vl.at(0).toInt(); - const int minor = vl.at(1).toInt(); - const int patch = vl.at(2).toInt(); - m_qtVersion = (major << 16) | (minor << 8) | patch; - } -} - // Parse a list of types. void QtDumperHelper::parseQueryTypes(const QStringList &l, Debugger debugger) { @@ -1049,134 +866,6 @@ bool DumperParser::handleValue(const char *k, int size) return true; } -/* Parse 'query' (1) protocol response of the custom dumpers: - * "'dumpers=["QByteArray","QDateTime",..."std::basic_string",], - * qtversion=["4","5","1"],namespace="""' */ - -class QueryDumperParser : public DumperParser { -public: - typedef QPair SizeEntry; - explicit QueryDumperParser(const char *s); - - struct Data { - QString qtNameSpace; - QString qtVersion; - QString dumperVersion; - QStringList types; - QList sizes; - QMap expressionCache; - }; - - inline Data data() const { return m_data; } - -protected: - virtual bool handleKeyword(const char *k, int size); - virtual bool handleListStart(); - virtual bool handleListEnd(); - virtual bool handleHashEnd(); - virtual bool handleValue(const char *k, int size); - -private: - enum Mode { None, ExpectingDumpers, ExpectingQtVersion, ExpectingDumperVersion, - ExpectingNameSpace, ExpectingSizes, ExpectingExpressionCache }; - Mode m_mode; - Data m_data; - QString m_lastSizeType; - QString m_lastExpression; -}; - -QueryDumperParser::QueryDumperParser(const char *s) : - DumperParser(s), - m_mode(None) -{ -} - -bool QueryDumperParser::handleKeyword(const char *k, int size) -{ - switch (m_mode) { - case ExpectingSizes: - m_lastSizeType = QString::fromLatin1(k, size); - return true; - case ExpectingExpressionCache: - m_lastExpression = QString::fromLatin1(k, size); - return true; - default: - break; - } - if (!qstrncmp(k, "dumpers", size)) { - m_mode = ExpectingDumpers; - return true; - } - if (!qstrncmp(k, "qtversion", size)) { - m_mode = ExpectingQtVersion; - return true; - } - if (!qstrncmp(k, "dumperversion", size)) { - m_mode = ExpectingDumperVersion; - return true; - } - if (!qstrncmp(k, "namespace", size)) { - m_mode = ExpectingNameSpace; - return true; - } - if (!qstrncmp(k, "sizes", size)) { - m_mode = ExpectingSizes; - return true; - } - if (!qstrncmp(k, "expressions", size)) { - m_mode = ExpectingExpressionCache; - return true; - } - qWarning("%s Unexpected keyword %s.\n", Q_FUNC_INFO, QByteArray(k, size).constData()); - return false; -} - -bool QueryDumperParser::handleListStart() -{ - return m_mode == ExpectingDumpers || m_mode == ExpectingQtVersion; -} - -bool QueryDumperParser::handleListEnd() -{ - m_mode = None; - return true; -} - -bool QueryDumperParser::handleHashEnd() -{ - m_mode = None; // Size hash - return true; -} - -bool QueryDumperParser::handleValue(const char *k, int size) -{ - switch (m_mode) { - case None: - return false; - case ExpectingDumpers: - m_data.types.push_back(QString::fromLatin1(k, size)); - break; - case ExpectingNameSpace: - m_data.qtNameSpace = QString::fromLatin1(k, size); - break; - case ExpectingDumperVersion: - m_data.dumperVersion = QString::fromLatin1(k, size); - break; - case ExpectingQtVersion: // ["4","1","5"] - if (!m_data.qtVersion.isEmpty()) - m_data.qtVersion += QLatin1Char('.'); - m_data.qtVersion += QString::fromLatin1(k, size); - break; - case ExpectingSizes: - m_data.sizes.push_back(SizeEntry(m_lastSizeType, QString::fromLatin1(k, size).toInt())); - break; - case ExpectingExpressionCache: - m_data.expressionCache.insert(m_lastExpression, QString::fromLatin1(k, size)); - break; - } - return true; -} - static inline QString qClassName(const QString &qtNamespace, const char *className) { if (qtNamespace.isEmpty()) @@ -1194,36 +883,73 @@ void QtDumperHelper::setQClassPrefixes(const QString &qNamespace) m_qSharedPointerPrefix = qClassName(qNamespace, "QSharedPointer"); m_qSharedDataPointerPrefix = qClassName(qNamespace, "QSharedDataPointer"); m_qWeakPointerPrefix = qClassName(qNamespace, "QWeakPointer"); + m_qListPrefix = qClassName(qNamespace, "QList"); + m_qLinkedListPrefix = qClassName(qNamespace, "QLinkedList"); + m_qVectorPrefix = qClassName(qNamespace, "QVector"); +} + +static inline double getDumperVersion(const GdbMi &contents) +{ + const GdbMi dumperVersionG = contents.findChild("dumperversion"); + if (dumperVersionG.type() != GdbMi::Invalid) { + bool ok; + const double v = QString::fromAscii(dumperVersionG.data()).toDouble(&ok); + if (ok) + return v; + } + return 1.0; +} + +bool QtDumperHelper::parseQuery(const GdbMi &contents, Debugger debugger) +{ + clear(); + if (debug > 1) + qDebug() << "parseQuery" << contents.toString(true, 2); + + // Common info, dumper version, etc + m_qtNamespace = QLatin1String(contents.findChild("namespace").data()); + int qtv = 0; + const GdbMi qtversion = contents.findChild("qtversion"); + if (qtversion.children().size() == 3) { + qtv = (qtversion.childAt(0).data().toInt() << 16) + + (qtversion.childAt(1).data().toInt() << 8) + + qtversion.childAt(2).data().toInt(); + } + m_qtVersion = qtv; + // Get list of helpers + QStringList availableSimpleDebuggingHelpers; + foreach (const GdbMi &item, contents.findChild("dumpers").children()) + availableSimpleDebuggingHelpers.append(QLatin1String(item.data())); + parseQueryTypes(availableSimpleDebuggingHelpers, debugger); + m_dumperVersion = getDumperVersion(contents); + // Parse sizes + foreach (const GdbMi &sizesList, contents.findChild("sizes").children()) { + const int childCount = sizesList.childCount(); + if (childCount > 1) { + const int size = sizesList.childAt(0).data().toInt(); + for (int c = 1; c < childCount; c++) + addSize(QLatin1String(sizesList.childAt(c).data()), size); + } + } + // Parse expressions + foreach (const GdbMi &exprList, contents.findChild("expressions").children()) + if (exprList.childCount() == 2) + m_expressionCache.insert(QLatin1String(exprList.childAt(0).data()), + QLatin1String(exprList.childAt(1).data())); + return true; } // parse a query bool QtDumperHelper::parseQuery(const char *data, Debugger debugger) { - QueryDumperParser parser(data); - if (!parser.run()) + QByteArray fullData = data; + fullData.insert(0, '{'); + fullData.append(data); + fullData.append('}'); + GdbMi root(fullData); + if (!root.isValid()) return false; - clear(); - m_qtNamespace = parser.data().qtNameSpace; - setQtVersion(parser.data().qtVersion); - setQClassPrefixes(m_qtNamespace); - parseQueryTypes(parser.data().types, debugger); - foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes) - addSize(se.first, se.second); - m_expressionCache = parser.data().expressionCache; - // Version - if (!parser.data().dumperVersion.isEmpty()) { - double dumperVersion; - bool ok; - dumperVersion = parser.data().dumperVersion.toDouble(&ok); - if (ok) - m_dumperVersion = dumperVersion; - } - return true; -} - -void QtDumperHelper::addExpression(const QString &expression, const QString &value) -{ - m_expressionCache.insert(expression, value); + return parseQuery(root, debugger); } void QtDumperHelper::addSize(const QString &name, int size) @@ -1316,6 +1042,14 @@ QtDumperHelper::SpecialSizeType QtDumperHelper::specialSizeType(const QString &t return QSharedDataPointerSize; if (typeName.startsWith(m_qWeakPointerPrefix)) return QWeakPointerSize; + if (typeName.startsWith(m_qListPrefix)) + return QListSize; + if (typeName.startsWith(m_qLinkedListPrefix)) + return QLinkedListSize; + if (typeName.startsWith(m_qVectorPrefix)) + return QVectorSize; + if (typeName.startsWith(m_qQueuePrefix)) + return QQueueSize; return SpecialSizeCount; } @@ -1504,233 +1238,173 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, qDebug() << '\n' << Q_FUNC_INFO << '\n' << data.toString() << "\n-->" << outertype << td.type << extraArgs; } -/* Parse value: - * "iname="local.sl",addr="0x0012BA84",value="<3 items>",valuedisabled="true", - * numchild="3",childtype="QString",childnumchild="0", - * children=[{name="0",value="",valueencoded="2"}, - * {name="1",value="dAB3AG8A",valueencoded="2"}, - * {name="2",value="dABoAHIAZQBlAA==",valueencoded="2"}]" */ +// GdbMi parsing helpers for parsing dumper value results -class ValueDumperParser : public DumperParser +static bool gdbMiGetIntValue(int *target, + const GdbMi &node, + const char *child) { -public: - explicit ValueDumperParser(const char *s); + *target = -1; + const GdbMi childNode = node.findChild(child); + if (!childNode.isValid()) + return false; + bool ok; + *target = childNode.data().toInt(&ok); + return ok; +} - inline QtDumperResult result() const { return m_result; } +// Find a string child node and assign value if it exists. +// Optionally decode. +static bool gdbMiGetStringValue(QString *target, + const GdbMi &node, + const char *child, + const char *encodingChild = 0) +{ + target->clear(); + const GdbMi childNode = node.findChild(child); + if (!childNode.isValid()) + return false; + // Encoded data + if (encodingChild) { + int encoding; + if (!gdbMiGetIntValue(&encoding, node, encodingChild)) + encoding = 0; + *target = decodeData(childNode.data(), encoding); + return true; + } + // Plain data + *target = QLatin1String(childNode.data()); + return true; +} -protected: - virtual bool handleKeyword(const char *k, int size); - virtual bool handleHashStart(); - virtual bool handleValue(const char *k, int size); +static bool gdbMiGetBoolValue(bool *target, + const GdbMi &node, + const char *child) +{ + *target = false; + const GdbMi childNode = node.findChild(child); + if (!childNode.isValid()) + return false; + *target = childNode.data() == "true"; + return true; +} -private: - enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue, - ExpectingType, ExpectingDisplayedType, ExpectingInternal, - ExpectingValueEnabled, ExpectingValueEncoded, - ExpectingCommonChildType, ExpectingChildCount, - ExpectingChildChildOverrideCount, - ExpectingExtra, - IgnoreNext, - ChildModeStart, - ExpectingChildren,ExpectingChildName, ExpectingChildAddress, - ExpectingChildExpression, ExpectingChildType, - ExpectingChildDisplayedType, - ExpectingChildKey, ExpectingChildKeyEncoded, - ExpectingChildValue, ExpectingChildValueEncoded, - ExpectingChildValueEnabled, ExpectingChildChildCount, - IgnoreNextChildMode - }; +/* Context to store parameters that influence the next level children. + * (next level only, it is not further inherited). For example, the root item + * can provide a "childtype" node that specifies the type of the children. */ - static inline Mode nextMode(Mode in, const char *keyword, int size); +struct GdbMiRecursionContext { + GdbMiRecursionContext(int recursionLevelIn = 0) : + recursionLevel(recursionLevelIn), childNumChild(-1), childIndex(0) {} - Mode m_mode; - QtDumperResult m_result; + int recursionLevel; + int childNumChild; + int childIndex; + QString childType; + QString parentIName; }; -ValueDumperParser::ValueDumperParser(const char *s) : - DumperParser(s), - m_mode(None) +static void gbdMiToWatchData(const GdbMi &root, + const GdbMiRecursionContext &ctx, + QList *wl) { -} - -// Check key words -ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword, int size) -{ - // Careful with same prefix - switch (size) { - case 3: - if (!qstrncmp(keyword, "exp", size)) - return ExpectingChildExpression; - if (!qstrncmp(keyword, "key", size)) - return ExpectingChildKey; - break; - case 4: - if (!qstrncmp(keyword, "addr", size)) - return in > ChildModeStart ? ExpectingChildAddress : ExpectingAddress; - if (!qstrncmp(keyword, "type", size)) - return in > ChildModeStart ? ExpectingChildType : ExpectingType; - if (!qstrncmp(keyword, "name", size)) - return ExpectingChildName; - break; - case 5: - if (!qstrncmp(keyword, "iname", size)) - return ExpectingIName; - if (!qstrncmp(keyword, "value", size)) - return in > ChildModeStart ? ExpectingChildValue : ExpectingValue; - if (!qstrncmp(keyword, "extra", size)) - return ExpectingExtra; - break; - case 8: - if (!qstrncmp(keyword, "children", size)) - return ExpectingChildren; - if (!qstrncmp(keyword, "numchild", size)) - return in > ChildModeStart ? ExpectingChildChildCount : ExpectingChildCount; - if (!qstrncmp(keyword, "internal", size)) - return ExpectingInternal; - break; - case 9: - if (!qstrncmp(keyword, "childtype", size)) - return ExpectingCommonChildType; - break; - case 10: - if (!qstrncmp(keyword, "keyencoded", size)) - return ExpectingChildKeyEncoded; - break; - case 12: - if (!qstrncmp(keyword, "valueencoded", size)) - return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded; - break; - case 13: - if (!qstrncmp(keyword, "valueenabled", size)) - return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled; - if (!qstrncmp(keyword, "displayedtype", size)) - return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType; - if (!qstrncmp(keyword, "childnumchild", size)) - return ExpectingChildChildOverrideCount; - break; - } - return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext; -} - -bool ValueDumperParser::handleKeyword(const char *k, int size) -{ - const Mode newMode = nextMode(m_mode, k, size); - if (debug && newMode == IgnoreNext) - qWarning("%s Unexpected keyword %s.\n", Q_FUNC_INFO, QByteArray(k, size).constData()); - m_mode = newMode; - return true; -} - -bool ValueDumperParser::handleHashStart() -{ - m_result.children.push_back(QtDumperResult::Child()); - return true; -} - -bool ValueDumperParser::handleValue(const char *k, int size) -{ - const QByteArray valueBA(k, size); - switch (m_mode) { - case None: - case ChildModeStart: - return false; - case ExpectingIName: - m_result.iname = QString::fromLatin1(valueBA); - break; - case ExpectingAddress: { - const QString address = QString::fromLatin1(valueBA); - if (address.startsWith(QLatin1String("0x"))) { - m_result.address = address; - } else { - m_result.addressInfo = address; - } - } - break; - case ExpectingValue: - m_result.valueEncountered = true; - m_result.value = valueBA; - break; - case ExpectingValueEnabled: - m_result.valueEnabled = valueBA == "true"; - break; - case ExpectingValueEncoded: - m_result.valueEncoded = QString::fromLatin1(valueBA).toInt(); - break; - case ExpectingType: - m_result.type = QString::fromLatin1(valueBA); - break; - case ExpectingDisplayedType: - m_result.displayedType = QString::fromLatin1(valueBA); - break; - case ExpectingExtra: - m_result.extra = valueBA; - break; - case ExpectingInternal: - m_result.internal = valueBA == "true"; - break; - case ExpectingCommonChildType: - m_result.childType = QString::fromLatin1(valueBA); - break; - case ExpectingChildCount: - m_result.childCount = QString::fromLatin1(valueBA).toInt(); - break; - case ExpectingChildChildOverrideCount: - m_result.childChildCount = QString::fromLatin1(valueBA).toInt(); - break; - case ExpectingChildren: - case IgnoreNextChildMode: - case IgnoreNext: - break; - case ExpectingChildName: - m_result.children.back().name = QString::fromLatin1(valueBA); - break; - case ExpectingChildAddress: - m_result.children.back().address = QString::fromLatin1(valueBA); - break; - case ExpectingChildKeyEncoded: - m_result.children.back().keyEncoded = QString::fromLatin1(valueBA).toInt(); - break; - case ExpectingChildKey: - m_result.children.back().key = valueBA; - break; - case ExpectingChildValue: - m_result.children.back().valueEncountered = true; - m_result.children.back().value = valueBA; - break; - case ExpectingChildExpression: - m_result.children.back().exp = QString::fromLatin1(valueBA); - break; - case ExpectingChildValueEncoded: - m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt(); - break; - case ExpectingChildValueEnabled: - m_result.children.back().valueEnabled = valueBA == "true"; - break; - case ExpectingChildType: - m_result.children.back().type = QString::fromLatin1(valueBA); - break; - case ExpectingChildDisplayedType: - m_result.children.back().displayedType = QString::fromLatin1(valueBA); - break; - case ExpectingChildChildCount: - m_result.children.back().childCount = QString::fromLatin1(valueBA).toInt(); - break; - } - return true; -} - -bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) -{ - ValueDumperParser parser(data); - - if (!parser.run()) - return false; - *r = parser.result(); - // Sanity - if (!r->children.empty() && r->childCount != r->children.size()) - r->childCount = r->children.size(); if (debug > 1) - qDebug() << '\n' << data << '\n' << *r; + qDebug() << Q_FUNC_INFO << '\n' << root.toString(false, 0); + WatchData w; + QString v; + // Check for name/iname and use as expression default + if (ctx.recursionLevel == 0) { + // parents have only iname, from which name is derived + if (!gdbMiGetStringValue(&w.iname, root, "iname")) + qWarning("Internal error: iname missing"); + w.name = w.iname; + const int lastDotPos = w.name.lastIndexOf(QLatin1Char('.')); + if (lastDotPos != -1) + w.name.remove(0, lastDotPos + 1); + w.exp = w.name; + } else { + // Children can have a 'name' attribute. If missing, assume array index + // For display purposes, it can be overridden by "key" + if (!gdbMiGetStringValue(&w.name, root, "name")) { + w.name = QString::number(ctx.childIndex); + } + // Set iname + w.iname = ctx.parentIName; + w.iname += QLatin1Char('.'); + w.iname += w.name; + // Key? + QString key; + if (gdbMiGetStringValue(&key, root, "key", "keyencoded")) { + w.name = key.size() > 13 ? key.mid(0, 13) + QLatin1String("...") : key; + } + } + if (w.name.isEmpty()) { + const QString msg = QString::fromLatin1("Internal error: Unable to determine name at level %1/%2 for %3").arg(ctx.recursionLevel).arg(w.iname, QLatin1String(root.toString(true, 2))); + qWarning("%s\n", qPrintable(msg)); + } + gdbMiGetStringValue(&w.displayedType, root, "displayedtype"); + if (gdbMiGetStringValue(&v, root, "editvalue")) + w.editvalue = v.toLatin1(); + if (gdbMiGetStringValue(&v, root, "exp")) + w.exp = v; + gdbMiGetStringValue(&w.addr, root, "addr"); + gdbMiGetStringValue(&w.saddr, root, "saddr"); + gdbMiGetBoolValue(&w.valueEnabled, root, "valueenabled"); + gdbMiGetBoolValue(&w.valueEditable, root, "valueeditable"); + if (gdbMiGetStringValue(&v, root, "valuetooltip", "valuetooltipencoded")) + w.setValue(v); + if (gdbMiGetStringValue(&v, root, "value", "valueencoded")) + w.setValue(v); + // Type from context or self + if (ctx.childType.isEmpty()) { + if (gdbMiGetStringValue(&v, root, "type")) + w.setType(v); + } else { + w.setType(ctx.childType); + } + // child count? + int numChild = -1; + if (ctx.childNumChild >= 0) { + numChild = ctx.childNumChild; + } else { + gdbMiGetIntValue(&numChild, root, "numchild"); + } + if (numChild >= 0) + w.setHasChildren(numChild > 0); + wl->push_back(w); + // Parse children with a new context + if (numChild == 0) + return; + const GdbMi childrenNode = root.findChild("children"); + if (!childrenNode.isValid()) + return; + const QList children =childrenNode.children(); + if (children.empty()) + return; + wl->back().setChildrenUnneeded(); + GdbMiRecursionContext nextLevelContext(ctx.recursionLevel + 1); + nextLevelContext.parentIName = w.iname; + gdbMiGetStringValue(&nextLevelContext.childType, root, "childtype"); + if (!gdbMiGetIntValue(&nextLevelContext.childNumChild, root, "childnumchild")) + nextLevelContext.childNumChild = -1; + foreach(const GdbMi &child, children) { + gbdMiToWatchData(child, nextLevelContext, wl); + nextLevelContext.childIndex++; + } +} + +bool QtDumperHelper::parseValue(const char *data, + QList *l) +{ + l->clear(); + QByteArray fullData = data; + fullData.insert(0, '{'); + fullData.append(data); + fullData.append('}'); + GdbMi root(fullData); + if (!root.isValid()) + return false; + gbdMiToWatchData(root, GdbMiRecursionContext(), l); return true; } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 395ba5f5eac..9c4280b0dfe 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -49,6 +49,7 @@ namespace Debugger { namespace Internal { class WatchData; +class GdbMi; QString dotEscape(QString str); QString currentTime(); @@ -89,49 +90,6 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, // Decode string data as returned by the dumper helpers. QString decodeData(const QByteArray &baIn, int encoding); -// Result of a dumper call. -struct QtDumperResult -{ - struct Child { - Child(); - - int keyEncoded; - int valueEncoded; - int childCount; - bool valueEnabled; - QString name; - QString address; - QString exp; - QString type; - QString displayedType; - QByteArray key; - bool valueEncountered; - QByteArray value; - }; - - QtDumperResult(); - void clear(); - QList toWatchData(int source = 0) const; - - QString iname; - QString address; - QString addressInfo; // "" or such, in the 2nd adress field. - QString type; - QString extra; - QString displayedType; - bool valueEncountered; - QByteArray value; - int valueEncoded; - bool valueEnabled; - int childCount; - bool internal; - QString childType; - int childChildCount; - QList children; -}; - -QDebug operator<<(QDebug in, const QtDumperResult &d); - /* Attempt to put common code of the dumper handling into a helper * class. * "Custom dumper" is a library compiled against the current @@ -181,7 +139,6 @@ public: void clear(); double dumperVersion() const { return m_dumperVersion; } - void setDumperVersion(double v) { m_dumperVersion = v; } int typeCount() const; // Look up a simple, non-template type @@ -192,17 +149,14 @@ public: int qtVersion() const; QString qtVersionString() const; - void setQtVersion(int v); - void setQtVersion(const QString &v); - QString qtNamespace() const; - void setQtNamespace(const QString &qtNamespace); // Complete parse of "query" (protocol 1) response from debuggee buffer. // 'data' excludes the leading indicator character. bool parseQuery(const char *data, Debugger debugger); - // Set up from pre-parsed type list - void parseQueryTypes(const QStringList &l, Debugger debugger); + bool parseQuery(const GdbMi &data, Debugger debugger); + // Sizes can be added as the debugger determines them + void addSize(const QString &name, int size); // Determine the parameters required for an "evaluate" (protocol 2) call void evaluationParameters(const WatchData &data, @@ -213,7 +167,7 @@ public: // Parse the value response (protocol 2) from debuggee buffer. // 'data' excludes the leading indicator character. - static bool parseValue(const char *data, QtDumperResult *r); + static bool parseValue(const char *data, QList *l); // What kind of debugger expressions are required to dump that type. // A debugger with restricted expression syntax can handle @@ -228,9 +182,6 @@ public: QString toString(bool debug = false) const; - // Helpers for debuggers that use a different dumper parser. - void addSize(const QString &name, int size); - void addExpression(const QString &expression, const QString &value); static QString msgDumperOutdated(double requiredVersion, double currentVersion); @@ -241,6 +192,7 @@ private: // Look up a simple (namespace) type static Type specialType(QString s); QString evaluationSizeofTypeExpression(const QString &typeName, Debugger d) const; + void parseQueryTypes(const QStringList &l, Debugger debugger); NameTypeMap m_nameTypeMap; SizeCache m_sizeCache; @@ -250,7 +202,9 @@ private: // They are not complete (std::allocator). enum SpecialSizeType { IntSize, PointerSize, StdAllocatorSize, QSharedPointerSize, QSharedDataPointerSize, - QWeakPointerSize, QPointerSize, SpecialSizeCount }; + QWeakPointerSize, QPointerSize, + QListSize, QLinkedListSize, QVectorSize, QQueueSize, + SpecialSizeCount }; // Resolve name to enumeration or SpecialSizeCount (invalid) SpecialSizeType specialSizeType(const QString &t) const; @@ -268,6 +222,10 @@ private: QString m_qSharedPointerPrefix; QString m_qSharedDataPointerPrefix; QString m_qWeakPointerPrefix; + QString m_qListPrefix; + QString m_qLinkedListPrefix; + QString m_qVectorPrefix; + QString m_qQueuePrefix; }; QDebug operator<<(QDebug in, const QtDumperHelper::TypeData &d); diff --git a/src/plugins/projectexplorer/debugginghelper.cpp b/src/plugins/projectexplorer/debugginghelper.cpp index 6c39e7376d8..61c5b4538d1 100644 --- a/src/plugins/projectexplorer/debugginghelper.cpp +++ b/src/plugins/projectexplorer/debugginghelper.cpp @@ -106,7 +106,7 @@ QString DebuggingHelperLibrary::debuggingHelperLibraryByInstallData(const QStrin foreach(const QString &directory, debuggingHelperLibraryDirectories(qtInstallData)) { const QFileInfo fi(helperFilePath(directory)); - if (fi.exists() && fi.lastModified() > lastModified) + if (fi.exists() && fi.lastModified() >= lastModified) return fi.filePath(); } return QString(); diff --git a/src/plugins/projectexplorer/outputwindow.cpp b/src/plugins/projectexplorer/outputwindow.cpp index d886584db07..d2f7ec7ac27 100644 --- a/src/plugins/projectexplorer/outputwindow.cpp +++ b/src/plugins/projectexplorer/outputwindow.cpp @@ -341,6 +341,7 @@ OutputWindow::OutputWindow(QWidget *parent) : QPlainTextEdit(parent) { m_enforceNewline = false; + m_scrollToBottom = false; setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); //setCenterOnScroll(false); @@ -392,8 +393,18 @@ OutputWindow::~OutputWindow() Core::ICore::instance()->removeContextObject(m_outputWindowContext); } +void OutputWindow::showEvent(QShowEvent *e) +{ + QPlainTextEdit::showEvent(e); + if (m_scrollToBottom) { + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); + } + m_scrollToBottom = false; +} + void OutputWindow::appendOutput(const QString &out) { + m_scrollToBottom = true; QString s = out; m_enforceNewline = true; // make appendOutputInline put in a newline next time if (s.endsWith(QLatin1Char('\n'))) { @@ -407,6 +418,7 @@ void OutputWindow::appendOutput(const QString &out) void OutputWindow::appendOutputInline(const QString &out) { + m_scrollToBottom = true; setMaximumBlockCount(MaxBlockCount); int newline = -1; @@ -439,6 +451,7 @@ void OutputWindow::appendOutputInline(const QString &out) void OutputWindow::insertLine() { + m_scrollToBottom = true; setMaximumBlockCount(MaxBlockCount); appendPlainText(QString()); enableUndoRedo(); diff --git a/src/plugins/projectexplorer/outputwindow.h b/src/plugins/projectexplorer/outputwindow.h index 6820f5076e0..ce81025bdbd 100644 --- a/src/plugins/projectexplorer/outputwindow.h +++ b/src/plugins/projectexplorer/outputwindow.h @@ -126,10 +126,13 @@ public: void appendOutputInline(const QString &out); void insertLine(); + void showEvent(QShowEvent *); + private: Core::BaseContext *m_outputWindowContext; void enableUndoRedo(); bool m_enforceNewline; + bool m_scrollToBottom; }; #if 0 diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index f8fba415b42..b256b5e3ed1 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -367,8 +367,7 @@ QByteArray MSVCToolChain::predefinedMacros() QByteArray key = split.at(0).mid(1); QByteArray value = split.at(1); if (!value.isEmpty()) { - value = value.mid(1); - value.chop(1); + value.chop(1); //remove '\n' } QByteArray newDefine = "#define " + key + " " + value + '\n'; m_predefinedMacros.append(newDefine); diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri index 279447ce4b7..d421fe16c29 100644 --- a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri +++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri @@ -22,5 +22,5 @@ SUPPORT_QT_S60 = $$(QTCREATOR_WITH_S60) $$PWD/rvcttoolchain.h FORMS += $$PWD/s60devicespreferencepane.ui OTHER_FILES += $$PWD/qt-s60-todo.txt - include(../../shared/trk/trk.pri)||error("could not include trk.pri") + include(../../../shared/trk/trk.pri)||error("could not include trk.pri") } diff --git a/src/plugins/qtscripteditor/parser/javascript.g b/src/plugins/qtscripteditor/parser/javascript.g index ceb2aeb726b..e75ee1cf7ed 100644 --- a/src/plugins/qtscripteditor/parser/javascript.g +++ b/src/plugins/qtscripteditor/parser/javascript.g @@ -2118,7 +2118,7 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ; token_buffer[1].dval = yylval = lexer->dval(); token_buffer[1].loc = yylloc = location(lexer); - if (t_action(errorState, yytoken)) { + if (token_buffer[0].token != -1 && t_action(errorState, yytoken)) { QString msg = QString::fromUtf8("Removed token"); if (const char *tokenSpell = spell[token_buffer[0].token]) { msg += QLatin1String(": `"); diff --git a/src/shared/trk/launcher.cpp b/src/shared/trk/launcher.cpp index 5535cb1a62e..a984cee40d5 100644 --- a/src/shared/trk/launcher.cpp +++ b/src/shared/trk/launcher.cpp @@ -397,13 +397,14 @@ void Launcher::handleWaitForFinished(const TrkResult &result) void Launcher::handleSupportMask(const TrkResult &result) { - const char *data = result.data.data(); + const char *data = result.data.data() + 1; + QByteArray str; for (int i = 0; i < 32; ++i) { //str.append(" [" + formatByte(data[i]) + "]: "); for (int j = 0; j < 8; ++j) if (data[i] & (1 << j)) - str.append(QByteArray::number(i * 8 + j, 16)); + str.append(QByteArray::number(i * 8 + j, 16) + " "); } logMessage("SUPPORTED: " + str); } diff --git a/tests/auto/aggregation/aggregation.pro b/tests/auto/aggregation/aggregation.pro index c35c696239e..ca1d1205a35 100644 --- a/tests/auto/aggregation/aggregation.pro +++ b/tests/auto/aggregation/aggregation.pro @@ -12,3 +12,4 @@ SOURCES += tst_aggregate.cpp \ HEADERS += $$AGGREGATION_PATH/aggregate.h \ $$AGGREGATION_PATH/aggregation_global.h +TARGET=tst_$$TARGET diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 826e842ef9c..193c1156ecb 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -3,7 +3,6 @@ TEMPLATE = subdirs SUBDIRS += \ cplusplus \ debugger \ - extensionsystem \ fakevim \ # profilereader \ aggregation diff --git a/tests/auto/cplusplus/ast/ast.pro b/tests/auto/cplusplus/ast/ast.pro index 84733f97e6f..2f5a0a33eae 100644 --- a/tests/auto/cplusplus/ast/ast.pro +++ b/tests/auto/cplusplus/ast/ast.pro @@ -3,3 +3,5 @@ CONFIG += qt warn_on console depend_includepath QT = core testlib include(../shared/shared.pri) SOURCES += tst_ast.cpp +TARGET=tst_$$TARGET + diff --git a/tests/auto/cplusplus/lookup/lookup.pro b/tests/auto/cplusplus/lookup/lookup.pro index cd02b709575..b80aa2f2b7b 100644 --- a/tests/auto/cplusplus/lookup/lookup.pro +++ b/tests/auto/cplusplus/lookup/lookup.pro @@ -5,3 +5,4 @@ QT = core testlib include(../../../../src/libs/cplusplus/cplusplus-lib.pri) SOURCES += tst_lookup.cpp +TARGET=tst_$$TARGET diff --git a/tests/auto/cplusplus/semantic/semantic.pro b/tests/auto/cplusplus/semantic/semantic.pro index 37c013685f7..09f80ab27ab 100644 --- a/tests/auto/cplusplus/semantic/semantic.pro +++ b/tests/auto/cplusplus/semantic/semantic.pro @@ -4,3 +4,4 @@ QT = core testlib include(../shared/shared.pri) SOURCES += tst_semantic.cpp +TARGET=tst_$$TARGET diff --git a/tests/auto/debugger/dumpers.pro b/tests/auto/debugger/dumpers.pro index ca5338af380..201c36cb436 100644 --- a/tests/auto/debugger/dumpers.pro +++ b/tests/auto/debugger/dumpers.pro @@ -14,3 +14,5 @@ DEFINES += MACROSDEBUG INCLUDEPATH += $$DEBUGGERDIR $$UTILSDIR $$MACROSDIR +TARGET = tst_$$TARGET + diff --git a/tests/auto/debugger/plugin.pro b/tests/auto/debugger/plugin.pro index fae675b38f8..7cc42dac750 100644 --- a/tests/auto/debugger/plugin.pro +++ b/tests/auto/debugger/plugin.pro @@ -12,3 +12,5 @@ DEFINES += MACROSDEBUG INCLUDEPATH += $$DEBUGGERDIR $$UTILSDIR $$MACROSDIR +TARGET = tst_$$TARGET + diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index d7d39452123..3f84e5cb6fe 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1501,7 +1501,7 @@ template append(" isSimpleValue: ").append(N(simpleVal)). append(" keyOffset: ").append(N(transKeyOffset)).append(" valueOffset: "). append(N(transValOffset)).append(" mapnodesize: "). - append(N(nodeSize)).append("',children=["); + append(N(qulonglong(nodeSize))).append("',children=["); // 64bit Linux hack typedef typename QMap::iterator mapIter; for (mapIter it = map.begin(); it != map.end(); ++it) { if (it != map.begin()) @@ -2368,7 +2368,9 @@ void tst_Debugger::initTestCase() d.weakref = d.strongref = 0; // That's what the destructor expects. QVERIFY(sizeof(int) == sizeof(d.weakref)); QVERIFY(sizeof(int) == sizeof(d.strongref)); - QVERIFY(sizeof(QObjectPrivate) == sizeof(ObjectPrivate)); + const size_t qObjectPrivateSize = sizeof(QObjectPrivate); + const size_t objectPrivateSize = sizeof(ObjectPrivate); + QVERIFY2(qObjectPrivateSize == objectPrivateSize, QString::fromLatin1("QObjectPrivate=%1 ObjectPrivate=%2").arg(qObjectPrivateSize).arg(objectPrivateSize).toLatin1().constData()); VERIFY_OFFSETOF(threadData); VERIFY_OFFSETOF(extraData); VERIFY_OFFSETOF(objectName); @@ -2379,11 +2381,12 @@ void tst_Debugger::initTestCase() VERIFY_OFFSETOF(currentChildBeingDeleted); VERIFY_OFFSETOF(connectedSignals); VERIFY_OFFSETOF(deleteWatch); +#ifdef QT3_SUPPORT #if QT_VERSION < 0x040600 VERIFY_OFFSETOF(pendingChildInsertedEvents); -#else - VERIFY_OFFSETOF(declarativeData); - VERIFY_OFFSETOF(objectGuards); +#endif +#endif +#if QT_VERSION >= 0x040600 VERIFY_OFFSETOF(sharedRefcount); #endif } diff --git a/tests/auto/fakevim/fakevim.pro b/tests/auto/fakevim/fakevim.pro index 04fefc12d30..a4aaea078ed 100644 --- a/tests/auto/fakevim/fakevim.pro +++ b/tests/auto/fakevim/fakevim.pro @@ -21,3 +21,4 @@ HEADERS += \ INCLUDEPATH += $$FAKEVIMDIR $$UTILSDIR +TARGET=tst_$$TARGET diff --git a/tests/auto/profilereader/profilereader.pro b/tests/auto/profilereader/profilereader.pro index b80ce8e4954..486ddd547d0 100644 --- a/tests/auto/profilereader/profilereader.pro +++ b/tests/auto/profilereader/profilereader.pro @@ -14,3 +14,4 @@ HEADERS += \ profilereader.h \ profilecache.h \ qtversionmanager.h +TARGET=tst_$$TARGET