diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 5ad19cadec943dbe49a73ff049646a938f967557..b5283d42e3fb5d973351d9d70ec1efcd1f0ad3bd 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -2929,7 +2929,7 @@ static void qDumpQVector(QDumper &d) d.putItemCount("value", n); d.putItem("valueeditable", "false"); - d.putItem("numchild", n); + d.putItem("numchild", nn); if (d.dumpChildren) { QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = innerIsPointerType ? strippedInnerType.data() : 0; @@ -2998,10 +2998,26 @@ static void qDumpQWeakPointer(QDumper &d) #endif // QT_VERSION >= 0x040500 #endif // QT_BOOTSTRAPPED +#ifdef Q_CC_MSVC +// A friendly list that grants access to its head. +template <class T> class FriendlyList : public std::list<T> { +public: + typedef _Node Node; + static const Node *head(const std::list<T> *list) { + return static_cast<const FriendlyList *>(list)->_Myhead; + } +}; +#endif + static void qDumpStdList(QDumper &d) { const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data); #ifdef Q_CC_MSVC + /* Extensive checks to avoid _HAS_ITERATOR_DEBUGGING asserts at all cost. + * Examine the head element which is present in empty lists as well. + * It could be even further checked if the type was known. */ + const void *head = FriendlyList<int>::head(&list); + qCheckAccess(head); const int size = static_cast<int>(list.size()); if (size < 0) return; @@ -3052,6 +3068,43 @@ static void qDumpStdList(QDumper &d) d.disarm(); } +#ifdef Q_CC_MSVC +// A friendly red-black tree that is able to access the node type and head +// pointer. The class _Tree is used for the std::map/std::set implementations in +// MS VS CC. It has a head element pointer (with left and right) that exists +// even if it is empty. Provides a check() function to perform extensive checks +// to avoid _HAS_ITERATOR_DEBUGGING asserts at all cost. +template <class RedBlackTreeTraits> class FriendlyRedBlackTree : public std::_Tree<RedBlackTreeTraits> { +public: + static inline void check(const std::_Tree<RedBlackTreeTraits> *fs, bool *ok); +}; + +template <class RedBlackTreeTraits> +void FriendlyRedBlackTree<RedBlackTreeTraits>::check(const std::_Tree<RedBlackTreeTraits> *fs, bool *ok) +{ + *ok = false; + const FriendlyRedBlackTree *friendlyTree = static_cast<const FriendlyRedBlackTree*>(fs); + // Check the red/black tree + const _Node *head = friendlyTree->_Myhead; + qCheckAccess(head); + if (head->_Color != _Red && head->_Color != _Black) + return; + const _Node *left = head->_Left; + if (left && left != head) { + qCheckAccess(left); + if (left->_Color != _Red && left->_Color != _Black) + return; + } + const _Node *right= head->_Right; + if (right && right != left) { + qCheckAccess(right); + if (right->_Color != _Red && right->_Color != _Black) + return; + } + *ok = true; +} +#endif + /* Dump out an arbitrary map. To iterate the map, * it is cast to a map of <KeyType,Value>. 'int' can be used for both * for all types if the implementation does not depend on the types @@ -3072,6 +3125,16 @@ static void qDumpStdMapHelper(QDumper &d) const int nn = map.size(); if (nn < 0) return; +#ifdef Q_CC_MSVC + // Additional checks to avoid _HAS_ITERATOR_DEBUGGING asserts + typedef std::pair<const KeyType, ValueType> RedBlackTreeEntryType; + typedef std::_Tmap_traits<KeyType, ValueType, std::less<KeyType>, std::allocator<RedBlackTreeEntryType>, false> + MapRedBlackTreeTraits; + bool ok; + FriendlyRedBlackTree<MapRedBlackTreeTraits>::check(&map, &ok); + if (!ok) + return; +#endif Q_TYPENAME DummyType::const_iterator it = map.begin(); const Q_TYPENAME DummyType::const_iterator cend = map.end(); for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) @@ -3178,6 +3241,15 @@ static void qDumpStdSetHelper(QDumper &d) const int nn = set.size(); if (nn < 0) return; +#ifdef Q_CC_MSVC + // Additional checks to avoid _HAS_ITERATOR_DEBUGGING asserts + typedef std::_Tset_traits<KeyType, std::less<KeyType> , std::allocator<KeyType>, false> + SetRedBlackTreeTraits; + bool ok; + FriendlyRedBlackTree<SetRedBlackTreeTraits>::check(&set, &ok); + if (!ok) + return; +#endif Q_TYPENAME DummyType::const_iterator it = set.begin(); const Q_TYPENAME DummyType::const_iterator cend = set.end(); for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index 28dea56f762336fe7d82f60e03b1507998e75f1f..60e0989294b9055bb13baf75b424c76723b450b5 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -48,13 +48,32 @@ // Test uninitialized variables allocing memory bool optTestUninitialized = false; +bool optTestAll = false; +bool optEmptyContainers = false; +unsigned optVerbose = 0; +// Provide address of type of be tested. +// When testing unitialized memory, allocate at random. template <class T> inline T* testAddress(T* in) { - return optTestUninitialized ? - (reinterpret_cast<T*>(new char[sizeof(T)])) - : in; + unsigned char *mem = 0; + if (optTestUninitialized) { + mem = new unsigned char[sizeof(T)]; + for (unsigned int i = 0; i < sizeof(T); i++) { + mem[i] = char(rand() % 255u); + } + } else { + mem = reinterpret_cast<unsigned char*>(in); + } + if (optVerbose) { + for (unsigned int i = 0; i < sizeof(T); i++) { + unsigned int b = mem[i]; + printf("%2d %2x %3d\n", i, b, b); + } + fflush(stdout); + } + return reinterpret_cast<T*>(mem); } /* Test program for Dumper development/porting. @@ -175,8 +194,10 @@ static int dumpQMapIntInt() QMap<int,int> test; QMapNode<int,int> mapNode; const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; - test.insert(42, 43); - test.insert(43, 44); + if (!optEmptyContainers) { + test.insert(42, 43); + test.insert(43, 44); + } prepareInBuffer("QMap", "local.qmapintint", "local.qmapintint", "int@int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(int), sizeof(mapNode), valueOffset); fputs(qDumpOutBuffer, stdout); @@ -189,8 +210,10 @@ static int dumpQMapIntString() QMap<int,QString> test; QMapNode<int,QString> mapNode; const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode; - test.insert(42, QLatin1String("fortytwo")); - test.insert(43, QLatin1String("fortytree")); + if (!optEmptyContainers) { + test.insert(42, QLatin1String("fortytwo")); + test.insert(43, QLatin1String("fortytree")); + } prepareInBuffer("QMap", "local.qmapintqstring", "local.qmapintqstring", "int@QString"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(QString), sizeof(mapNode), valueOffset); fputs(qDumpOutBuffer, stdout); @@ -201,8 +224,10 @@ static int dumpQMapIntString() static int dumpQSetInt() { QSet<int> test; - test.insert(42); - test.insert(43); + if (!optEmptyContainers) { + 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); @@ -216,9 +241,11 @@ static int dumpQMapQStringString() QMap<QString,QString> test; QMapNode<QString,QString> 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"); + if (!optEmptyContainers) { + 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); @@ -278,8 +305,10 @@ static int dumpStdWString() static int dumpStdStringList() { std::list<std::string> test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("std::list", "local.stringlist", "local.stringlist", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list<std::string>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -290,8 +319,10 @@ static int dumpStdStringList() static int dumpStdStringQList() { QList<std::string> test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("QList", "local.stringqlist", "local.stringqlist", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), 0, 0, 0); fputs(qDumpOutBuffer, stdout); @@ -302,8 +333,10 @@ static int dumpStdStringQList() static int dumpStdIntList() { std::list<int> test; - test.push_back(1); - test.push_back(2); + if (!optEmptyContainers) { + test.push_back(1); + test.push_back(2); + } prepareInBuffer("std::list", "local.intlist", "local.intlist", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -314,8 +347,10 @@ static int dumpStdIntList() static int dumpStdIntVector() { std::vector<int> test; - test.push_back(1); - test.push_back(2); + if (!optEmptyContainers) { + test.push_back(1); + test.push_back(2); + } prepareInBuffer("std::vector", "local.intvector", "local.intvector", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -326,8 +361,10 @@ static int dumpStdIntVector() static int dumpStdStringVector() { std::vector<std::string> test; - test.push_back("item1"); - test.push_back("item2"); + if (!optEmptyContainers) { + test.push_back("item1"); + test.push_back("item2"); + } prepareInBuffer("std::vector", "local.stringvector", "local.stringvector", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -338,8 +375,10 @@ static int dumpStdStringVector() static int dumpStdWStringVector() { std::vector<std::wstring> test; - test.push_back(L"item1"); - test.push_back(L"item2"); + if (!optEmptyContainers) { + test.push_back(L"item1"); + test.push_back(L"item2"); + } prepareInBuffer("std::vector", "local.wstringvector", "local.wstringvector", "std::wstring"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::wstring), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -350,8 +389,10 @@ static int dumpStdWStringVector() static int dumpStdIntSet() { std::set<int> test; - test.insert(1); - test.insert(2); + if (!optEmptyContainers) { + test.insert(1); + test.insert(2); + } prepareInBuffer("std::set", "local.intset", "local.intset", "int"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -362,8 +403,10 @@ static int dumpStdIntSet() static int dumpStdStringSet() { std::set<std::string> test; - test.insert("item1"); - test.insert("item2"); + if (!optEmptyContainers) { + test.insert("item1"); + test.insert("item2"); + } prepareInBuffer("std::set", "local.stringset", "local.stringset", "std::string"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::string), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -374,8 +417,10 @@ static int dumpStdStringSet() static int dumpStdQStringSet() { std::set<QString> test; - test.insert(QLatin1String("item1")); - test.insert(QLatin1String("item2")); + if (!optEmptyContainers) { + test.insert(QLatin1String("item1")); + test.insert(QLatin1String("item2")); + } prepareInBuffer("std::set", "local.stringset", "local.stringset", "QString"); qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), sizeof(std::list<int>::allocator_type), 0, 0); fputs(qDumpOutBuffer, stdout); @@ -385,9 +430,11 @@ static int dumpStdQStringSet() static int dumpStdMapIntString() { - std::map<int,std::string> test; + std::map<int,std::string> test; std::map<int,std::string>::value_type entry(42, std::string("fortytwo")); - test.insert(entry); + if (!optEmptyContainers) { + test.insert(entry); + } const int valueOffset = (char*)&(entry.second) - (char*)&entry; prepareInBuffer("std::map", "local.stdmapintstring", "local.stdmapintstring", "int@std::basic_string<char,std::char_traits<char>,std::allocator<char> >@std::less<int>@std::allocator<std::pair<const int,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >"); @@ -402,7 +449,9 @@ static int dumpStdMapStringString() typedef std::map<std::string,std::string> TestType; TestType test; const TestType::value_type entry("K", "V"); - test.insert(entry); + if (!optEmptyContainers) { + test.insert(entry); + } const int valueOffset = (char*)&(entry.second) - (char*)&entry; prepareInBuffer("std::map", "local.stdmapstringstring", "local.stdmapstringstring", "std::basic_string<char,std::char_traits<char>,std::allocator<char> >@std::basic_string<char,std::char_traits<char>,std::allocator<char> >@std::less<int>@std::allocator<std::pair<const std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >"); @@ -502,6 +551,23 @@ static TypeDumpFunctionMap registerTypes() return rc; } +static void usage(const char *b, const TypeDumpFunctionMap &tdm) +{ + printf("Usage: %s [-v][-u][-e] <type1> <type2..>\n", b); + printf("Usage: %s [-v][-u][-e] -a excluded_type1 <excluded_type2...>\n", b); + printf("Options: -u Test uninitialized memory\n"); + printf(" -e Empty containers\n"); + printf(" -v Verbose\n"); + printf(" -a Test all available types\n"); + printf("Supported types: "); + const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd(); + for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { + fputs(qPrintable(it.key()), stdout); + fputc(' ', stdout); + } + fputc('\n', stdout); +} + int main(int argc, char *argv[]) { printf("\nQt Creator Debugging Helper testing tool\n\n"); @@ -515,30 +581,57 @@ int main(int argc, char *argv[]) const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd(); if (argc < 2) { - printf("Usage: %s [-a]|<type1> <type2..>\n", argv[0]); - printf("Supported types: "); - for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { - fputs(qPrintable(it.key()), stdout); - fputc(' ', stdout); - } - fputc('\n', stdout); + usage(argv[0], tdm); return 0; } - + // Parse args + QStringList tests; + for (int a = 1; a < argc; a++) { + const char *arg = argv[a]; + if (arg[0] == '-') { + switch (arg[1]) { + case 'a': + optTestAll = true; + break; + case 'u': + optTestUninitialized = true; + break; + case 'v': + optVerbose++; + break; + case 'e': + optEmptyContainers = true; + break; + default: + fprintf(stderr, "Invalid option %s\n", arg); + usage(argv[0], tdm); + return -1; + } + } else { + tests.push_back(QLatin1String(arg)); + } + } + // Go int rc = 0; - if (argc == 2 && !qstrcmp(argv[1], "-a")) { + if (optTestAll) { for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) { - printf("\nTesting: %s\n", qPrintable(it.key())); - rc += (*it.value())(); + const QString test = it.key(); + if (tests.contains(test)) { + printf("\nSkipping: %s\n", qPrintable(test)); + } else { + printf("\nTesting: %s\n", qPrintable(test)); + rc += (*it.value())(); + if (optTestUninitialized) + printf("Survived: %s\n", qPrintable(test)); + } } } else { - for (int i = 1; i < argc; i++) { - const char *arg = argv[i]; - printf("\nTesting: %s\n", arg); - const TypeDumpFunctionMap::const_iterator it = tdm.constFind(QLatin1String(arg)); + foreach(const QString &test, tests) { + printf("\nTesting: %s\n", qPrintable(test)); + const TypeDumpFunctionMap::const_iterator it = tdm.constFind(test); if (it == cend) { rc = -1; - fprintf(stderr, "\nUnhandled type: %s\n", argv[i]); + fprintf(stderr, "\nUnhandled type: %s\n", qPrintable(test)); } else { rc = (*it.value())(); } diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index ec58883712fb1338a61fe4d926b651680476f900..edaafcc890fe4e8a500edd7c863e600704a0c715 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -565,63 +565,63 @@ static int startOfOperator(TextEditor::ITextEditable *editor, const QChar ch3 = pos > 1 ? editor->characterAt(pos - 3) : QChar(); int start = pos; - int k = T_EOF_SYMBOL; + int completionKind = T_EOF_SYMBOL; switch (ch.toLatin1()) { case '.': if (ch2 != QLatin1Char('.')) { - k = T_DOT; + completionKind = T_DOT; --start; } break; case ',': - k = T_COMMA; + completionKind = T_COMMA; --start; break; case '(': if (wantFunctionCall) { - k = T_LPAREN; + completionKind = T_LPAREN; --start; } break; case ':': if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) { - k = T_COLON_COLON; + completionKind = T_COLON_COLON; start -= 2; } break; case '>': if (ch2 == QLatin1Char('-')) { - k = T_ARROW; + completionKind = T_ARROW; start -= 2; } break; case '*': if (ch2 == QLatin1Char('.')) { - k = T_DOT_STAR; + completionKind = T_DOT_STAR; start -= 2; } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) { - k = T_ARROW_STAR; + completionKind = T_ARROW_STAR; start -= 3; } break; case '\\': case '@': if (ch2.isNull() || ch2.isSpace()) { - k = T_DOXY_COMMENT; + completionKind = T_DOXY_COMMENT; --start; } break; case '<': - k = T_ANGLE_STRING_LITERAL; + completionKind = T_ANGLE_STRING_LITERAL; --start; break; case '"': - k = T_STRING_LITERAL; + completionKind = T_STRING_LITERAL; --start; break; case '/': - k = T_SLASH; + completionKind = T_SLASH; --start; break; } @@ -634,20 +634,20 @@ static int startOfOperator(TextEditor::ITextEditable *editor, tc.setPosition(pos); // Include completion: make sure the quote character is the first one on the line - if (k == T_STRING_LITERAL) { + if (completionKind == T_STRING_LITERAL) { QTextCursor s = tc; s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); QString sel = s.selectedText(); if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) { - k = T_EOF_SYMBOL; + completionKind = T_EOF_SYMBOL; start = pos; } } - if (k == T_COMMA) { + if (completionKind == T_COMMA) { ExpressionUnderCursor expressionUnderCursor; if (expressionUnderCursor.startOfFunctionCall(tc) == -1) { - k = T_EOF_SYMBOL; + completionKind = T_EOF_SYMBOL; start = pos; } } @@ -655,24 +655,24 @@ static int startOfOperator(TextEditor::ITextEditable *editor, static CPlusPlus::TokenUnderCursor tokenUnderCursor; const SimpleToken tk = tokenUnderCursor(tc); - if (k == T_DOXY_COMMENT && tk.isNot(T_DOXY_COMMENT)) { - k = T_EOF_SYMBOL; + if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { + completionKind = T_EOF_SYMBOL; start = pos; } // Don't complete in comments or strings, but still check for include completion - else if (tk.is(T_COMMENT) || (tk.isLiteral() && - (k != T_STRING_LITERAL - && k != T_ANGLE_STRING_LITERAL - && k != T_SLASH))) { - k = T_EOF_SYMBOL; + else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) || + (tk.isLiteral() && (completionKind != T_STRING_LITERAL + && completionKind != T_ANGLE_STRING_LITERAL + && completionKind != T_SLASH))) { + completionKind = T_EOF_SYMBOL; start = pos; } // Include completion: can be triggered by slash, but only in a string - else if (k == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) { - k = T_EOF_SYMBOL; + else if (completionKind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) { + completionKind = T_EOF_SYMBOL; start = pos; } - else if (k == T_LPAREN) { + else if (completionKind == T_LPAREN) { const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); int i = 0; for (; i < tokens.size(); ++i) { @@ -688,12 +688,12 @@ static int startOfOperator(TextEditor::ITextEditable *editor, } if (i == tokens.size()) { - k = T_EOF_SYMBOL; + completionKind = T_EOF_SYMBOL; start = pos; } } // Check for include preprocessor directive - else if (k == T_STRING_LITERAL || k == T_ANGLE_STRING_LITERAL || k == T_SLASH) { + else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) { bool include = false; const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); if (tokens.size() >= 3) { @@ -709,13 +709,13 @@ static int startOfOperator(TextEditor::ITextEditable *editor, } if (!include) { - k = T_EOF_SYMBOL; + completionKind = T_EOF_SYMBOL; start = pos; } } if (kind) - *kind = k; + *kind = completionKind; return start; } @@ -1022,8 +1022,13 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi // find a scope that encloses the current location, starting from the lastVisibileSymbol // and moving outwards - Scope *sc = context.symbol()->scope(); - while (sc->enclosingScope()) { + Scope *sc = 0; + if (context.symbol()) + sc = context.symbol()->scope(); + else if (context.thisDocument()) + sc = context.thisDocument()->globalSymbols(); + + while (sc && sc->enclosingScope()) { unsigned startLine, startColumn; context.thisDocument()->translationUnit()->getPosition(sc->owner()->startOffset(), &startLine, &startColumn); unsigned endLine, endColumn; @@ -1037,7 +1042,7 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi sc = sc->enclosingScope(); } - if (sc->isClassScope() || sc->isNamespaceScope()) + if (sc && (sc->isClassScope() || sc->isNamespaceScope())) { // It may still be a function call. If the whole line parses as a function // declaration, we should be certain that it isn't. @@ -1066,10 +1071,18 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi Overview overview; overview.setShowArgumentNames(true); - TextEditor::CompletionItem item(this); - item.text = overview(f->type()); - item.text = item.text.mid(1, item.text.size()-2); - m_completions.append(item); + // get rid of parentheses and cv-qualifiers + QString completion = overview(f->type()); + if (f->isVolatile() || f->isConst()) + completion = completion.mid(1, completion.lastIndexOf(')') - 1); + else + completion = completion.mid(1, completion.size() - 2); + + if (completion.size()) { + TextEditor::CompletionItem item(this); + item.text = completion; + m_completions.append(item); + } } return true; } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index e9f4967b39749b4b776f5781c1a77c27dea46863..6c307af0c5a16c7860d75c717c92929f5832aa0f 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -707,10 +707,17 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QStri { // Need to attrach invasively, otherwise, no notification signals // for for CreateProcess/ExitProcess occur. - // As of version 6.11, the initial breakpoint suppression has no effect (see notifyException). - // when attaching to a console process starting up. However, there is no initial breakpoint - // (and no startup trap), when attaching to a running GUI process. - const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS|DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; + // Initial breakpoint occur: + // 1) Desired: When attaching to a crashed process + // 2) Undesired: When starting up a console process, in conjunction + // with the 32bit Wow-engine + // As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed + // by lookup at the state of the application (startup trap). However, + // there is no startup trap when attaching to a process that has been + // running for a while. (see notifyException). + ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS; + if (manager()->startParameters()->startMode != AttachCrashedExternal) + flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags); if (debugCDB) qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl); @@ -817,6 +824,9 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 void CdbDebugEngine::processTerminated(unsigned long exitCode) { manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode)); + if (state() != InferiorStopping) + setState(InferiorStopping, Q_FUNC_INFO, __LINE__); + setState(InferiorStopped, Q_FUNC_INFO, __LINE__); setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__); m_d->setDebuggeeHandles(0, 0); m_d->clearForRun(); @@ -912,14 +922,11 @@ void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em) errorMessage.clear(); } // Clean up resources (open files, etc.) - m_engine->setState(AdapterShuttingDown, Q_FUNC_INFO, __LINE__); + m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__); clearForRun(); const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE); - if (SUCCEEDED(hr)) { - m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__); - } else { - m_engine->setState(AdapterShutdownFailed, Q_FUNC_INFO, __LINE__); - m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__); + m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__); + if (!SUCCEEDED(hr)) { errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr)); manager()->showDebuggerOutput(LogError, errorMessage); } diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 77f3f798594bda2e6a60e521ea95c0bd70a430b1..2269aab42cdcd906244ebb1db94727f52ef6cec0 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -341,6 +341,8 @@ void CdbDumperInitThread ::run() CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager, CdbComInterfaces *cif) : m_tryInjectLoad(true), + m_msgDisabled(QLatin1String("Dumpers are disabled")), + m_msgNotInScope(QLatin1String("Data not in scope")), m_state(NotLoaded), m_manager(manager), m_cif(cif), @@ -561,8 +563,14 @@ CdbDumperHelper::CallResult if (!writeToDebuggee(m_cif->debugDataSpaces, inBuffer, m_inBufferAddress, errorMessage)) return CallFailed; } - if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage)) + if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage)) { + // Clear the outstanding call in case we triggered a debug library assert with a message box + QString clearError; + if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, QLatin1String(".call /c"), &clearError)) { + *errorMessage += QString::fromLatin1("/Unable to clear call %1").arg(clearError); + } return CallSyntaxError; + } // Set up call and a temporary breakpoint after it. // Try to skip debuggee crash exceptions and dumper exceptions // by using 'gN' (go not handled -> pass handling to dumper __try/__catch block) @@ -648,8 +656,12 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool { errorMessage->clear(); // Check failure cache and supported types - if (m_state == Disabled) { - *errorMessage = QLatin1String("Dumpers are disabled"); + if (m_state == Disabled) { + *errorMessage =m_msgDisabled; + return DumpNotHandled; + } + if (wd.error) { + *errorMessage =m_msgNotInScope; return DumpNotHandled; } if (m_failedTypes.contains(wd.type)) { diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h index 4035d03ee282aecf2a0271f11471778e33fa5edc..be326768df63f5faffa89bd0630cdac3192acd83 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.h +++ b/src/plugins/debugger/cdb/cdbdumperhelper.h @@ -134,6 +134,8 @@ private: static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage); const bool m_tryInjectLoad; + const QString m_msgDisabled; + const QString m_msgNotInScope; State m_state; DebuggerManager *m_manager; CdbComInterfaces *m_cif; diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index d97a968768c2cf2c6fa29285256e1780339244e8..f64f0366a1d7efe2f44f8645e95983da7c2a3fa9 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -217,7 +217,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt bool handled = false; do { - if (!isPointerType(wd.type)) + if (wd.error || !isPointerType(wd.type)) break; const int classPos = wd.value.indexOf(" class "); if (classPos == -1) @@ -396,9 +396,9 @@ bool CdbStackFrameContext::editorToolTip(const QString &iname, *errorMessage = QString::fromLatin1("%1 not found.").arg(iname); return false; } - const WatchData wd = m_symbolContext->symbolAt(index); // Check dumpers. Should actually be just one item. - if (m_useDumpers && m_dumper->state() != CdbDumperHelper::Disabled) { + const WatchData wd = m_symbolContext->watchDataAt(index); + if (m_useDumpers && !wd.error && m_dumper->state() != CdbDumperHelper::Disabled) { QList<WatchData> result; if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage)) { foreach (const WatchData &dwd, result) { diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 0a338f9fdcc79a0bf46de4e2b53ec4cfc016aa1b..90329dfe04fbfbc34bf5b41d0fbe5b672353851b 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -33,8 +33,11 @@ #include "cdbsymbolgroupcontext.h" #include "cdbdebugengine_p.h" #include "cdbdumperhelper.h" +#include "debuggeractions.h" +#include "debuggermanager.h" #include <QtCore/QDir> +#include <QtCore/QDebug> #include <QtCore/QTextStream> namespace Debugger { @@ -85,6 +88,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa if (debugCDB) qDebug() << Q_FUNC_INFO << frameCount; + const QChar exclamationMark = QLatin1Char('!'); m_frameContexts.resize(frameCount); qFill(m_frameContexts, static_cast<CdbStackFrameContext*>(0)); @@ -99,7 +103,11 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16); m_cif->debugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0); + // Determine function and module, if available frame.function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + const int moduleSepPos = frame.function.indexOf(exclamationMark); + if (moduleSepPos != -1) + frame.from = frame.function.mid(0, moduleSepPos); ULONG ulLine; ULONG64 ul64Displacement; @@ -160,7 +168,13 @@ CdbStackFrameContext *CdbStackTraceContext::frameContextAt(int index, QString *e *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); return 0; } - CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(QLatin1String("local"), sg, errorMessage); + // Exclude unitialized variables if desired + QStringList uninitializedVariables; + if (theDebuggerAction(UseCodeModel)->isChecked()) { + const StackFrame &frame = m_frames.at(index); + getUninitializedVariables(DebuggerManager::instance()->cppCodeModelSnapshot(), frame.function, frame.file, frame.line, &uninitializedVariables); + } + CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(QLatin1String("local"), sg, uninitializedVariables, errorMessage); if (!sc) { *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); return 0; diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index f58f1f745272a9912e89d72b23cf473b4e2e997f..2efd3672b963f8be4442a64ede88c494781d0683 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -39,6 +39,9 @@ enum { debug = 0 }; enum { debugInternalDumpers = 0 }; +// name separator for shadowed variables +static const char iNameShadowDelimiter = '#'; + static inline QString msgSymbolNotFound(const QString &s) { return QString::fromLatin1("The symbol '%1' could not be found.").arg(s); @@ -83,6 +86,14 @@ QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p) return str; } +static inline QString hexSymbolOffset(CIDebugSymbolGroup *sg, unsigned long index) +{ + ULONG64 rc = 0; + if (FAILED(sg->GetSymbolOffset(index, &rc))) + rc = 0; + return QLatin1String("0x") + QString::number(rc, 16); +} + // A helper function to extract a string value from a member function of // IDebugSymbolGroup2 taking the symbol index and a character buffer. // Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide' @@ -129,12 +140,15 @@ static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMB } CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup) : + CIDebugSymbolGroup *symbolGroup, + const QStringList &uninitializedVariables) : m_prefix(prefix), m_nameDelimiter(QLatin1Char('.')), + m_uninitializedVariables(uninitializedVariables.toSet()), m_symbolGroup(symbolGroup), m_unnamedSymbolNumber(1) { + } CdbSymbolGroupContext::~CdbSymbolGroupContext() @@ -144,9 +158,10 @@ CdbSymbolGroupContext::~CdbSymbolGroupContext() CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix, CIDebugSymbolGroup *symbolGroup, + const QStringList &uninitializedVariables, QString *errorMessage) { - CdbSymbolGroupContext *rc = new CdbSymbolGroupContext(prefix, symbolGroup); + CdbSymbolGroupContext *rc = new CdbSymbolGroupContext(prefix, symbolGroup, uninitializedVariables); if (!rc->init(errorMessage)) { delete rc; return 0; @@ -173,28 +188,36 @@ bool CdbSymbolGroupContext::init(QString *errorMessage) *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO), msgComFailed("GetSymbolParameters", hr)).arg(count); return false; } - populateINameIndexMap(m_prefix, DEBUG_ANY_ID, 0, count); + populateINameIndexMap(m_prefix, DEBUG_ANY_ID, count); } if (debug) - qDebug() << Q_FUNC_INFO << '\n'<< toString(); + qDebug() << Q_FUNC_INFO << '\n'<< toString(true); return true; } +/* Make the entries for iname->index mapping. We might encounter + * already expanded subitems when doing it for top-level ('this'-pointers), + * recurse in that case, (skip over expanded children). + * Loop backwards to detect shadowed variables in the order the +/* debugger expects them: +\code +int x; // Occurrence (1), should be reported as "x <shadowed 1>" +if (true) { + int x = 5; (2) // Occurrence (2), should be reported as "x" +} +\endcode + * The order in the symbol group is (1),(2). Give them an iname of + * <root>#<shadowed-nr>, which will be split apart for display. */ + void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long parentId, - unsigned long start, unsigned long count) + unsigned long end) { - // Make the entries for iname->index mapping. We might encounter - // already expanded subitems when doing it for top-level, recurse in that case. const QString symbolPrefix = prefix + m_nameDelimiter; if (debug) - qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << start << count; - const unsigned long end = m_symbolParameters.size(); - unsigned long seenChildren = 0; - // Skip over expanded children - for (unsigned long i = start; i < end && seenChildren < count; i++) { + qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << parentId << end; + for (unsigned long i = end - 1; ; i--) { const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); if (parentId == p.ParentSymbol) { - seenChildren++; // "__formal" occurs when someone writes "void foo(int /* x */)..." static const QString unnamedFormalParameter = QLatin1String("__formal"); QString symbolName = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); @@ -203,11 +226,21 @@ void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigne symbolName += QString::number(m_unnamedSymbolNumber++); symbolName += QLatin1Char('>'); } - const QString name = symbolPrefix + symbolName; + // Find a unique name in case the variable is shadowed by + // an existing one + const QString namePrefix = symbolPrefix + symbolName; + QString name = namePrefix; + for (int n = 1; m_inameIndexMap.contains(name); n++) { + name.truncate(namePrefix.size()); + name += QLatin1Char(iNameShadowDelimiter); + name += QString::number(n); + } m_inameIndexMap.insert(name, i); if (getSymbolState(p) == ExpandedSymbol) - populateINameIndexMap(name, i, i + 1, p.SubElements); + populateINameIndexMap(name, i, i + 1 + p.SubElements); } + if (i == 0 || i == parentId) + break; } } @@ -223,7 +256,10 @@ QString CdbSymbolGroupContext::toString(bool verbose) const str << " "; str << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); if (p.Flags & DEBUG_SYMBOL_IS_LOCAL) - str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i); + str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i) << '\''; + str << " Address: " << hexSymbolOffset(m_symbolGroup, i); + if (verbose) + str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, i) << '\''; str << p << '\n'; } if (verbose) { @@ -348,7 +384,7 @@ bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long in if (it.value() > index) it.value() += newSymbolCount; // insert the new symbols - populateINameIndexMap(prefix, index, index + 1, newSymbolCount); + populateINameIndexMap(prefix, index, index + 1 + newSymbolCount); if (debug > 1) qDebug() << '<' << Q_FUNC_INFO << '\n' << prefix << index << '\n' << toString(); return true; @@ -365,14 +401,6 @@ QString CdbSymbolGroupContext::symbolINameAt(unsigned long index) const return m_inameIndexMap.key(index); } -static inline QString hexSymbolOffset(CIDebugSymbolGroup *sg, unsigned long index) -{ - ULONG64 rc = 0; - if (FAILED(sg->GetSymbolOffset(index, &rc))) - rc = 0; - return QLatin1String("0x") + QString::number(rc, 16); -} - // check for "0x000", "0x000 class X" static inline bool isNullPointer(const WatchData &wd) { @@ -409,19 +437,35 @@ static inline QString fixValue(const QString &value) return removeInnerTemplateType(value); } -WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const +WatchData CdbSymbolGroupContext::watchDataAt(unsigned long index) const { WatchData wd; wd.iname = symbolINameAt(index); wd.exp = wd.iname; + // Determine name from iname and format shadowed variables correctly + // as "<shadowed X>, see populateINameIndexMap(). const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter); + QString name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1); + int shadowedNumber = 0; + const int shadowedPos = name.lastIndexOf(QLatin1Char(iNameShadowDelimiter)); + if (shadowedPos != -1) { + shadowedNumber = name.mid(shadowedPos + 1).toInt(); + name.truncate(shadowedPos); + } // For class hierarchies, we get sometimes complicated std::template types here. - // Remove them for display - wd.name = removeInnerTemplateType(lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1)); + // (std::map extends std::tree<>... Remove them for display only. + const QString fullShadowedName = WatchData::shadowedName(name, shadowedNumber); + wd.name = WatchData::shadowedName(removeInnerTemplateType(name), shadowedNumber); wd.addr = hexSymbolOffset(m_symbolGroup, index); - const QString type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); + const QString type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); + wd.setType(type); + // Check for unitialized variables at level 0 only. + const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(index); + if (p.ParentSymbol == DEBUG_ANY_ID && m_uninitializedVariables.contains(fullShadowedName)) { + wd.setError(WatchData::msgNotInScope()); + return wd; + } const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); - wd.setType(type); wd.setValue(fixValue(value)); wd.setChildrenNeeded(); // compensate side effects of above setters // Figure out children. The SubElement is only a guess unless the symbol, @@ -429,7 +473,7 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const // If the symbol has children (expanded or not), we leave the 'Children' flag // in 'needed' state. Suppress 0-pointers right ("0x000 class X") // here as they only lead to children with memory access errors. - const bool hasChildren = m_symbolParameters.at(index).SubElements && !isNullPointer(wd); + const bool hasChildren = p.SubElements && !isNullPointer(wd); wd.setHasChildren(hasChildren); if (debug > 1) qDebug() << Q_FUNC_INFO << index << '\n' << wd.toString(); @@ -438,7 +482,7 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const WatchData CdbSymbolGroupContext::dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index) { - WatchData rc = symbolAt(index); + WatchData rc = watchDataAt(index); dump(ds, &rc); return rc; } diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index c2770fb20399bfdceff311259ce4636e8c751bf5..2db042423f07f7b170af324ad1876a358f09a790 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -69,12 +69,14 @@ class CdbSymbolGroupContext { Q_DISABLE_COPY(CdbSymbolGroupContext); explicit CdbSymbolGroupContext(const QString &prefix, - CIDebugSymbolGroup *symbolGroup); + CIDebugSymbolGroup *symbolGroup, + const QStringList &uninitializedVariables = QStringList()); public: ~CdbSymbolGroupContext(); - static CdbSymbolGroupContext *create(const QString &prefix, + static CdbSymbolGroupContext *create(const QString &prefix, CIDebugSymbolGroup *symbolGroup, + const QStringList &uninitializedVariables, QString *errorMessage); QString prefix() const { return m_prefix; } @@ -118,7 +120,7 @@ public: int dumpedOwner, OutputIterator it, QString *errorMessage); - WatchData symbolAt(unsigned long index) const; + WatchData watchDataAt(unsigned long index) const; // Run the internal dumpers on the symbol WatchData dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index); @@ -155,7 +157,7 @@ private: unsigned long *parentId, QString *errorMessage); bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage); - void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count); + void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long end); QString symbolINameAt(unsigned long index) const; int dumpQString(CIDebugDataSpaces *ds, WatchData *wd); @@ -166,6 +168,7 @@ private: const QString m_prefix; const QChar m_nameDelimiter; + const QSet<QString> m_uninitializedVariables; CIDebugSymbolGroup *m_symbolGroup; NameIndexMap m_inameIndexMap; diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h index 0b143207952b450a54daf983db45cce3aa58e5e2..fe33e802b6cedc6e8a46c5fcb04e510a40cc04fb 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h @@ -61,7 +61,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(CIDebugDataSpaces *ds, const QSt for (int s = start; s < m_symbolParameters.size(); ++s) { const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s); if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { - WatchData wd = symbolAt(s); + WatchData wd = watchDataAt(s); // Run internal dumper, mark ownership if (ds) { switch (dump(ds, &wd)) { diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index a2c1da01721b361222cfad6383486374127f8f96..4a0b0f783eb10e5657e569e53282d6876efc49ba 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -229,6 +229,13 @@ DebuggerSettings *DebuggerSettings::instance() item->setValue(false); instance->insertItem(DebugDebuggingHelpers, item); + item = new SavedAction(instance); + item->setSettingsKey(debugModeGroup, QLatin1String("UseCodeModel")); + item->setText(tr("Use code model")); + item->setCheckable(true); + item->setDefaultValue(false); + item->setValue(false); + instance->insertItem(UseCodeModel, item); item = new SavedAction(instance); item->setText(tr("Recheck debugging helper availability")); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index ffc334b268fce0ca9e1045caeea03ebd8ac1d567..234cf21731ccd3eb20b79c75742ba903a534733f 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -85,6 +85,8 @@ enum DebuggerActionCode UseCustomDebuggingHelperLocation, CustomDebuggingHelperLocation, DebugDebuggingHelpers, + + UseCodeModel, UseToolTipsInMainEditor, UseToolTipsInLocalsView, diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 2100aa873fee419730c47b966f204a08beb1e3e3..d3bc9d20f4027734d1561338de98b7f26939ef3b 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -79,15 +79,13 @@ enum DebuggerState InferiorStopping, // Debuggee running, stop requested InferiorStopped, // Debuggee stopped - InferiorStopFailed, // Debuggee stopped + InferiorStopFailed, // Debuggee not stopped, will kill debugger InferiorShuttingDown, InferiorShutDown, InferiorShutdownFailed, - AdapterShuttingDown, - //AdapterShutDown, // Use DebuggerNotReady instead - AdapterShutdownFailed, + EngineShuttingDown }; enum DebuggerStartMode diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 918ddc49692685e2b88efc451c7a275a04a8420a..c6d00f0112e32c5ad68a50e35c594305168ca7ec 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -61,6 +61,8 @@ #include <utils/qtcassert.h> #include <utils/fancymainwindow.h> #include <projectexplorer/toolchain.h> +#include <cplusplus/CppDocument.h> +#include <cpptools/cppmodelmanagerinterface.h> #include <QtCore/QDebug> #include <QtCore/QDir> @@ -99,43 +101,35 @@ // gdbserver, the trk client etc are referred to as 'Adapter', // whereas the debugged process is referred to as 'Inferior'. // -// 0 == DebuggerNotReady +// 0 == DebuggerNotReady // | -// EngineStarting +// EngineStarting // | -// AdapterStarting --> AdapterStartFailed --> 0 +// AdapterStarting --> AdapterStartFailed --> 0 // | -// AdapterStarted -// | -// InferiorStarting --> InferiorStartFailed --> 0 -// | -// (core) | (attach) (remote) -// .-----------------<-|->--------------------. -// | v | -// InferiorUnrunnable | | -// | | v -// | | (plain) -// | | (trk) -// | | -// | | .------------------------------------. -// | | v | -// | InferiorRunningRequested v | -// | | | | -// | .---- InferiorRunning | | -// | | | | | -// | | InferiorStopping | | -// | | | | | -// | v v | | -// | |<--- InferiorStopped <-----------' | -// | | | | -// | | `---------------------------------------' -// | | -// | '---> InferiorShuttingDown -> InferiorShutdownFailed -// | | -// | InferiorShutDown -// | | -// | v -// '------------> AdapterShuttingDown -> AdapterShutdownFailed --> 0 +// AdapterStarted ------------------------------------. +// | v +// InferiorStarting ----> InferiorStartFailed -------->| +// | | +// (core) | (attach) (term) (remote) | +// .-----------------<-|->------------------. | +// | v | | +// InferiorUnrunnable | (plain) | | +// | | (trk) | | +// | | | | +// | .--> InferiorRunningRequested | | +// | | | | | +// | | InferiorRunning | | +// | | | | | +// | | InferiorStopping | | +// | | | | | +// | '------ InferiorStopped <-----------' | +// | | v +// | InferiorShuttingDown -> InferiorShutdownFailed ---->| +// | | | +// | InferiorShutDown | +// | | | +// '--------> EngineShuttingDown <--------------------------------' // | // 0 // @@ -206,8 +200,7 @@ static const char *stateName(int s) SN(InferiorShuttingDown) SN(InferiorShutDown) SN(InferiorShutdownFailed) - SN(AdapterShuttingDown) - SN(AdapterShutdownFailed) + SN(EngineShuttingDown) } return "<unknown>"; #undef SN @@ -290,6 +283,8 @@ struct DebuggerManagerPrivate IDebuggerEngine *m_engine; DebuggerState m_state; + + CPlusPlus::Snapshot m_codeModelSnapshot; }; DebuggerManager *DebuggerManagerPrivate::instance = 0; @@ -610,6 +605,18 @@ WatchHandler *DebuggerManager::watchHandler() const return d->m_watchHandler; } +const CPlusPlus::Snapshot &DebuggerManager::cppCodeModelSnapshot() const +{ + if (d->m_codeModelSnapshot.isEmpty() && theDebuggerAction(UseCodeModel)->isChecked()) + d->m_codeModelSnapshot = CppTools::CppModelManagerInterface::instance()->snapshot(); + return d->m_codeModelSnapshot; +} + +void DebuggerManager::clearCppCodeModelSnapshot() +{ + d->m_codeModelSnapshot.clear(); +} + SourceFilesWindow *DebuggerManager::sourceFileWindow() const { return d->m_sourceFilesWindow; @@ -1013,6 +1020,7 @@ void DebuggerManager::exitDebugger() // in turn will handle the cleanup. if (d->m_engine && state() != DebuggerNotReady) d->m_engine->exitDebugger(); + d->m_codeModelSnapshot.clear(); } DebuggerStartParametersPtr DebuggerManager::startParameters() const @@ -1544,7 +1552,7 @@ static bool isAllowedTransition(int from, int to) case AdapterStarting: return to == AdapterStarted || to == AdapterStartFailed; case AdapterStarted: - return to == InferiorStarting; + return to == InferiorStarting || to == EngineShuttingDown; case AdapterStartFailed: return to == DebuggerNotReady; @@ -1552,37 +1560,38 @@ static bool isAllowedTransition(int from, int to) return to == InferiorRunningRequested || to == InferiorStopped || to == InferiorStartFailed || to == InferiorUnrunnable; case InferiorStartFailed: - return to == DebuggerNotReady; + return to == EngineShuttingDown; case InferiorRunningRequested: - return to == InferiorRunning; + return to == InferiorRunning || to == InferiorStopped; case InferiorRunning: - return to == InferiorStopping || to == InferiorShuttingDown; + return to == InferiorStopping; case InferiorStopping: return to == InferiorStopped || to == InferiorStopFailed; case InferiorStopped: return to == InferiorRunningRequested || to == InferiorShuttingDown; case InferiorStopFailed: - return to == DebuggerNotReady; + return to == EngineShuttingDown; case InferiorUnrunnable: - return to == AdapterShuttingDown; + return to == EngineShuttingDown; case InferiorShuttingDown: return to == InferiorShutDown || to == InferiorShutdownFailed; case InferiorShutDown: - return to == AdapterShuttingDown; + return to == EngineShuttingDown; + case InferiorShutdownFailed: + return to == EngineShuttingDown; - case AdapterShuttingDown: + case EngineShuttingDown: return to == DebuggerNotReady; - - default: - qDebug() << "UNKNOWN STATE: " << from; } + + qDebug() << "UNKNOWN STATE:" << from; return false; } -void DebuggerManager::setState(DebuggerState state) +void DebuggerManager::setState(DebuggerState state, bool forced) { //STATE_DEBUG("STATUS CHANGE: FROM " << stateName(d->m_state) // << " TO " << stateName(state)); @@ -1591,7 +1600,7 @@ void DebuggerManager::setState(DebuggerState state) .arg(stateName(d->m_state)).arg(d->m_state).arg(stateName(state)).arg(state); //if (!((d->m_state == -1 && state == 0) || (d->m_state == 0 && state == 0))) // qDebug() << msg; - if (!isAllowedTransition(d->m_state, state)) + if (!forced && !isAllowedTransition(d->m_state, state)) qDebug() << "UNEXPECTED STATE TRANSITION: " << msg; showDebuggerOutput(LogDebug, msg); @@ -1685,8 +1694,7 @@ bool DebuggerManager::debuggerActionsEnabled() const case InferiorShuttingDown: case InferiorShutDown: case InferiorShutdownFailed: - case AdapterShuttingDown: - case AdapterShutdownFailed: + case EngineShuttingDown: break; } return false; @@ -1763,9 +1771,9 @@ DebuggerState IDebuggerEngine::state() const return m_manager->state(); } -void IDebuggerEngine::setState(DebuggerState state) +void IDebuggerEngine::setState(DebuggerState state, bool forced) { - m_manager->setState(state); + m_manager->setState(state, forced); } ////////////////////////////////////////////////////////////////////// diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index ba1feb77f96fb0be5e266e6496b5a167d4da246a..7272584754a7b373d5a8749b54bee01092095d47 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -59,6 +59,10 @@ namespace TextEditor { class ITextEditor; } +namespace CPlusPlus { + class Snapshot; +} + namespace Debugger { namespace Internal { @@ -183,6 +187,8 @@ public: QString *settingsCategory = 0, QString *settingsPage = 0) const; + const CPlusPlus::Snapshot &cppCodeModelSnapshot() const; + static DebuggerManager *instance(); public slots: @@ -235,6 +241,7 @@ public slots: void setRegisterValue(int nr, const QString &value); void showStatusMessage(const QString &msg, int timeout = -1); // -1 forever + void clearCppCodeModelSnapshot(); public slots: // FIXME void showDebuggerOutput(const QString &msg) @@ -270,7 +277,8 @@ private: Internal::ThreadsHandler *threadsHandler() const; Internal::WatchHandler *watchHandler() const; Internal::SourceFilesWindow *sourceFileWindow() const; - QWidget *threadsWindow() const; + QWidget *threadsWindow() const; + Internal::DebuggerManagerActions debuggerManagerActions() const; void notifyInferiorStopped(); @@ -280,7 +288,7 @@ private: void cleanupViews(); - void setState(DebuggerState state); + void setState(DebuggerState state, bool forced = false); // // internal implementation diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 9ce3c0ef81a646866b1158f4e5a886c9407d8801..ebcd04404b4067af02a4a5929f51ec72b00027b1 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -373,6 +373,9 @@ QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent) m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation), m_ui.dumperLocationChooser); + m_group.insert(theDebuggerAction(UseCodeModel), + m_ui.checkBoxUseCodeModel); + #ifdef QT_DEBUG m_group.insert(theDebuggerAction(DebugDebuggingHelpers), m_ui.checkBoxDebugDebuggingHelpers); diff --git a/src/plugins/debugger/dumperoptionpage.ui b/src/plugins/debugger/dumperoptionpage.ui index 1b6bb8ed5054b28fd3e58ada4c78c885a403c0d2..e63355068dea82821d54522740a0f052e897456c 100644 --- a/src/plugins/debugger/dumperoptionpage.ui +++ b/src/plugins/debugger/dumperoptionpage.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>403</width> + <width>432</width> <height>434</height> </rect> </property> @@ -83,10 +83,20 @@ </widget> </item> <item> - <widget class="Utils::PathChooser" name="dumperLocationChooser" native="true"/> + <widget class="Utils::PathChooser" name="dumperLocationChooser"/> </item> </layout> </item> + <item> + <widget class="QCheckBox" name="checkBoxUseCodeModel"> + <property name="toolTip"> + <string>Makes use of Qt Creator's code model to find out if a variable has already been assigned a value at the point the debugger interrupts.</string> + </property> + <property name="text"> + <string>Use code model</string> + </property> + </widget> + </item> <item> <widget class="QCheckBox" name="checkBoxDebugDebuggingHelpers"> <property name="toolTip"> diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.cpp b/src/plugins/debugger/gdb/abstractgdbadapter.cpp index 52c76107606ece581a43ca7a3f820c8745445620..e9f67b9a48b8e99123ec97f9e4a60053a4dadf93 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.cpp +++ b/src/plugins/debugger/gdb/abstractgdbadapter.cpp @@ -31,7 +31,6 @@ #include <utils/qtcassert.h> -#include <QtCore/QObject> #include <QtCore/QProcess> namespace Debugger { @@ -47,35 +46,22 @@ AbstractGdbAdapter::~AbstractGdbAdapter() disconnect(); } -// This cannot be in the c'tor, as it would not connect the "virtual" slots -void AbstractGdbAdapter::commonInit() +void AbstractGdbAdapter::shutdown() { - QTC_ASSERT(state() == EngineStarting, qDebug() << state()); - connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(handleGdbError(QProcess::ProcessError))); - connect(&m_gdbProc, SIGNAL(started()), - this, SLOT(handleGdbStarted())); - connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(handleGdbFinished(int, QProcess::ExitStatus))); - connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), - this, SIGNAL(readyReadStandardOutput())); - connect(&m_gdbProc, SIGNAL(readyReadStandardError()), - this, SIGNAL(readyReadStandardError())); } -QByteArray AbstractGdbAdapter::readAllStandardOutput() +void AbstractGdbAdapter::startInferiorPhase2() { - return m_gdbProc.readAllStandardOutput(); } -QByteArray AbstractGdbAdapter::readAllStandardError() +const char *AbstractGdbAdapter::inferiorShutdownCommand() const { - return m_gdbProc.readAllStandardError(); + return "kill"; } void AbstractGdbAdapter::write(const QByteArray &data) { - m_gdbProc.write(data); + m_engine->m_gdbProc.write(data); } bool AbstractGdbAdapter::isTrkAdapter() const diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.h b/src/plugins/debugger/gdb/abstractgdbadapter.h index 7765401e1a68b8472207137d073344e98826142c..83a76682b042831c1f639da10cd17bea27b50aa7 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.h +++ b/src/plugins/debugger/gdb/abstractgdbadapter.h @@ -42,7 +42,7 @@ namespace Internal { // debugging and TrkGdbAdapter used for on-device debugging. // In the PlainGdbAdapter case it's just a wrapper around a QProcess running // gdb, in the TrkGdbAdapter case it's the interface to the gdb process in -// the whole rfomm/gdb/gdbserver combo. +// the whole rfcomm/gdb/gdbserver combo. class AbstractGdbAdapter : public QObject { Q_OBJECT @@ -51,34 +51,44 @@ public: AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0); virtual ~AbstractGdbAdapter(); - QByteArray readAllStandardOutput(); - QByteArray readAllStandardError(); virtual void write(const QByteArray &data); virtual bool isTrkAdapter() const; // isUtterlyBrokenAdapter virtual void startAdapter() = 0; virtual void startInferior() = 0; + virtual void startInferiorPhase2(); virtual void interruptInferior() = 0; - virtual void shutdown() = 0; + virtual void shutdown(); + virtual const char *inferiorShutdownCommand() const; virtual bool dumpersAvailable() const = 0; + static QString msgGdbStopFailed(const QString &why); + static QString msgInferiorStopFailed(const QString &why); + static QString msgAttachedToStoppedInferior(); + static QString msgInferiorStarted(); + static QString msgInferiorRunning(); + static QString msgConnectRemoteServerFailed(const QString &why); + signals: void adapterStarted(); + + // Something went wrong with the adapter *before* adapterStarted() was emitted. + // Make sure to clean up everything before emitting this signal. void adapterStartFailed(const QString &msg, const QString &settingsIdHint); - void adapterShutDown(); - void adapterShutdownFailed(const QString &msg); + + // Something went wrong with the adapter *after* adapterStarted() was emitted. + // Make sure to clean up everything before emitting this signal. void adapterCrashed(const QString &msg); + // This triggers the initial breakpoint synchronization and causes + // startInferiorPhase2() being called once done. + void inferiorPrepared(); + + // The adapter is still running just fine, but it failed to acquire a debuggee. void inferiorStartFailed(const QString &msg); - void inferiorShutDown(); - void inferiorShutdownFailed(const QString &msg); - void readyReadStandardOutput(); - void readyReadStandardError(); - protected: - void commonInit(); DebuggerState state() const { return m_engine->state(); } void setState(DebuggerState state) @@ -89,17 +99,10 @@ protected: { m_engine->debugMessage(msg); } void showStatusMessage(const QString &msg) const { m_engine->showStatusMessage(msg); } - - static QString msgGdbStopFailed(const QString &why); - static QString msgInferiorStopFailed(const QString &why); - static QString msgAttachedToStoppedInferior(); - static QString msgInferiorStarted(); - static QString msgInferiorRunning(); - static QString msgConnectRemoteServerFailed(const QString &why); + void showMessageBox(int icon, const QString &title, const QString &text) const + { m_engine->showMessageBox(icon, title, text); } GdbEngine * const m_engine; - - QProcess m_gdbProc; }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index e6325deb61df3edba6f62ecbde97cd33b779d2ee..440c29bbd8ec08f8c0d0a912ba8d09c3077f753f 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -29,7 +29,6 @@ #include "attachgdbadapter.h" -#include "debuggeractions.h" #include "gdbengine.h" #include "procinterrupt.h" #include "debuggerstringutils.h" @@ -53,7 +52,6 @@ namespace Internal { AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent) : AbstractGdbAdapter(engine, parent) { - commonInit(); } void AttachGdbAdapter::startAdapter() @@ -62,28 +60,12 @@ void AttachGdbAdapter::startAdapter() setState(AdapterStarting); debugMessage(_("TRYING TO START ADAPTER")); - QStringList gdbArgs; - gdbArgs.prepend(_("mi")); - gdbArgs.prepend(_("-i")); - - QString location = theDebuggerStringSetting(GdbLocation); - m_gdbProc.start(location, gdbArgs); -} + if (!m_engine->startGdb()) + return; -void AttachGdbAdapter::handleGdbStarted() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - setState(AdapterStarted); emit adapterStarted(); } -void AttachGdbAdapter::handleGdbError(QProcess::ProcessError error) -{ - debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR")); - emit adapterCrashed(m_engine->errorMessage(error)); - shutdown(); -} - void AttachGdbAdapter::startInferior() { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); @@ -99,6 +81,7 @@ void AttachGdbAdapter::handleAttach(const GdbResponse &response) QTC_ASSERT(state() == InferiorStopped, qDebug() << state()); debugMessage(_("INFERIOR ATTACHED")); showStatusMessage(msgAttachedToStoppedInferior()); + emit inferiorPrepared(); m_engine->updateAll(); } else { QString msg = __(response.data.findChild("msg").data()); @@ -114,59 +97,5 @@ void AttachGdbAdapter::interruptInferior() debugMessage(_("CANNOT INTERRUPT %1").arg(pid)); } -void AttachGdbAdapter::shutdown() -{ - switch (state()) { - - case InferiorStartFailed: - m_engine->postCommand(_("-gdb-exit")); - setState(DebuggerNotReady); - return; - - case InferiorStopped: - setState(InferiorShuttingDown); - m_engine->postCommand(_("detach"), CB(handleDetach)); - return; - - case InferiorShutDown: - setState(AdapterShuttingDown); - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; - - default: - QTC_ASSERT(false, qDebug() << state()); - } -} - -void AttachGdbAdapter::handleDetach(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - setState(InferiorShutDown); - emit inferiorShutDown(); - shutdown(); // re-iterate... - } else { - const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); - setState(InferiorShutdownFailed); - emit inferiorShutdownFailed(msg); - } -} - -void AttachGdbAdapter::handleExit(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - // don't set state here, this will be handled in handleGdbFinished() - } else { - const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); - emit adapterShutdownFailed(msg); - } -} - -void AttachGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) -{ - debugMessage(_("GDB PROESS FINISHED")); - setState(DebuggerNotReady); - emit adapterShutDown(); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/attachgdbadapter.h b/src/plugins/debugger/gdb/attachgdbadapter.h index 34196725417216c918c1a58eefda6fb829822ce1..006b49b1a5b6b37c854087e0a0c62e2d97f0aeb3 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.h +++ b/src/plugins/debugger/gdb/attachgdbadapter.h @@ -31,10 +31,6 @@ #define DEBUGGER_ATTACHGDBADAPTER_H #include "abstractgdbadapter.h" -#include "gdbengine.h" - -#include <QtCore/QDebug> -#include <QtCore/QProcess> namespace Debugger { namespace Internal { @@ -57,16 +53,10 @@ public: void startAdapter(); void startInferior(); void interruptInferior(); - void shutdown(); + const char *inferiorShutdownCommand() const { return "detach"; } private: void handleAttach(const GdbResponse &response); - void handleDetach(const GdbResponse &response); - void handleExit(const GdbResponse &response); - - Q_SLOT void handleGdbStarted(); - Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus); - Q_SLOT void handleGdbError(QProcess::ProcessError error); }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index b0ddd2d7b52b9930fb726e20a170c51b2221570d..ee0304208be70654ea66aca1b4afe67075af3cbe 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -35,7 +35,9 @@ #include <utils/qtcassert.h> +#include <QtCore/QDir> #include <QtCore/QFileInfo> +#include <QtGui/QMessageBox> namespace Debugger { namespace Internal { @@ -53,7 +55,6 @@ namespace Internal { CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent) : AbstractGdbAdapter(engine, parent) { - commonInit(); } void CoreGdbAdapter::startAdapter() @@ -62,85 +63,42 @@ void CoreGdbAdapter::startAdapter() setState(AdapterStarting); debugMessage(_("TRYING TO START ADAPTER")); - QStringList gdbArgs; - gdbArgs.prepend(_("mi")); - gdbArgs.prepend(_("-i")); - - QString location = theDebuggerStringSetting(GdbLocation); - m_gdbProc.start(location, gdbArgs); -} + if (!m_engine->startGdb()) + return; -void CoreGdbAdapter::handleGdbStarted() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - setState(AdapterStarted); emit adapterStarted(); } -void CoreGdbAdapter::handleGdbError(QProcess::ProcessError error) -{ - debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR")); - emit adapterCrashed(m_engine->errorMessage(error)); - shutdown(); -} - void CoreGdbAdapter::startInferior() { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); - QFileInfo fi(startParameters().coreFile); m_executable = startParameters().executable; if (m_executable.isEmpty()) { +#ifdef EXE_FROM_CORE // Extra round trip to get executable name from core file. // This is sometimes not the full name, so it can't be used // as the generic solution. - // Quoting core name below fails in gdb 6.8-debian. - QString coreName = fi.absoluteFilePath(); - m_engine->postCommand(_("target core ") + coreName, CB(handleTargetCore1)); - } else { - // Directly load symbols. - QFileInfo fi(m_executable); - m_engine->postCommand(_("-file-exec-and-symbols \"%1\"") - .arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); - } -} -void CoreGdbAdapter::handleTargetCore1(const GdbResponse &response) -{ - QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); - if (response.resultClass == GdbResultDone) { - showStatusMessage(tr("Attached to core temporarily.")); - GdbMi console = response.data.findChild("consolestreamoutput"); - int pos1 = console.data().indexOf('`'); - int pos2 = console.data().indexOf('\''); - if (pos1 == -1 || pos2 == -1) { - emit inferiorStartFailed(tr("No binary found.")); - } else { - m_executable = console.data().mid(pos1 + 1, pos2 - pos1 - 1); - // Strip off command line arguments. FIXME: make robust. - if (m_executable.contains(' ')) - m_executable = m_executable.section(' ', 0, 0); - QTC_ASSERT(!m_executable.isEmpty(), /**/); - // Finish extra round. - m_engine->postCommand(_("detach"), CB(handleDetach1)); - } - } else { - const QByteArray msg = response.data.findChild("msg").data(); - emit inferiorStartFailed(msg); + m_round = 1; + loadCoreFile(); +#else + showMessageBox(QMessageBox::Warning, tr("Error Loading Symbols"), + tr("No executable to load symbols from specified.")); +#endif + return; } +#ifdef EXE_FROM_CORE + m_round = 2; +#endif + loadExeAndSyms(); } -void CoreGdbAdapter::handleDetach1(const GdbResponse &response) +void CoreGdbAdapter::loadExeAndSyms() { - QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); - if (response.resultClass == GdbResultDone) { - // Load symbols. - QFileInfo fi(m_executable); - m_engine->postCommand(_("-file-exec-and-symbols \"%1\"") - .arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); - } else { - const QByteArray msg = response.data.findChild("msg").data(); - emit inferiorStartFailed(msg); - } + // Do that first, otherwise no symbols are loaded. + QFileInfo fi(m_executable); + m_engine->postCommand(_("-file-exec-and-symbols \"%1\"") + .arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); } void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) @@ -148,74 +106,70 @@ void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); if (response.resultClass == GdbResultDone) { showStatusMessage(tr("Symbols found.")); - // Quoting core name below fails in gdb 6.8-debian. - QFileInfo fi(startParameters().coreFile); - QString coreName = fi.absoluteFilePath(); - m_engine->postCommand(_("target core ") + coreName, CB(handleTargetCore2)); } else { - QString msg = tr("Symbols not found in \"%1\" failed:\n%2") - .arg(__(response.data.findChild("msg").data())); - setState(InferiorUnrunnable); - m_engine->updateAll(); - // emit inferiorStartFailed(msg); + QString msg = tr("Loading symbols from \"%1\" failed:\n").arg(m_executable) + + __(response.data.findChild("msg").data()); + showMessageBox(QMessageBox::Warning, tr("Error Loading Symbols"), msg); } + loadCoreFile(); +} + +void CoreGdbAdapter::loadCoreFile() +{ + // Quoting core name below fails in gdb 6.8-debian. + QFileInfo fi(startParameters().coreFile); + QString coreName = fi.absoluteFilePath(); + m_engine->postCommand(_("target core ") + coreName, CB(handleTargetCore)); } -void CoreGdbAdapter::handleTargetCore2(const GdbResponse &response) +void CoreGdbAdapter::handleTargetCore(const GdbResponse &response) { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); if (response.resultClass == GdbResultDone) { +#ifdef EXE_FROM_CORE + if (m_round == 1) { + m_round = 2; + GdbMi console = response.data.findChild("consolestreamoutput"); + int pos1 = console.data().indexOf('`'); + int pos2 = console.data().indexOf('\''); + if (pos1 != -1 && pos2 != -1) { + m_executable = console.data().mid(pos1 + 1, pos2 - pos1 - 1); + // Strip off command line arguments. FIXME: make robust. + int idx = m_executable.indexOf(_c(' ')); + if (idx >= 0) + m_executable.truncate(idx); + if (!m_executable.isEmpty()) { + m_executable = QFileInfo(startParameters().coreFile).absoluteDir() + .absoluteFilePath(m_executable); + if (QFile::exists(m_executable)) { + // Finish extra round ... + showStatusMessage(tr("Attached to core temporarily.")); + m_engine->postCommand(_("detach")); + // ... and retry. + loadExeAndSyms(); + return; + } + } + } + showMessageBox(QMessageBox::Warning, tr("Error Loading Symbols"), + tr("Unable to determine executable from core file.")); + } +#endif showStatusMessage(tr("Attached to core.")); setState(InferiorUnrunnable); m_engine->updateAll(); } else { - QString msg = tr("Attach to core \"%1\" failed:\n%2") - .arg(__(response.data.findChild("msg").data())); - setState(InferiorUnrunnable); - m_engine->updateAll(); - // emit inferiorStartFailed(msg); + QString msg = tr("Attach to core \"%1\" failed:\n").arg(startParameters().coreFile) + + __(response.data.findChild("msg").data()); + emit inferiorStartFailed(msg); } } + void CoreGdbAdapter::interruptInferior() { // A core should never 'run' QTC_ASSERT(false, /**/); } -void CoreGdbAdapter::shutdown() -{ - switch (state()) { - - case DebuggerNotReady: - return; - - case InferiorUnrunnable: - case InferiorShutDown: - setState(AdapterShuttingDown); - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; - - default: - QTC_ASSERT(false, qDebug() << state()); - } -} - -void CoreGdbAdapter::handleExit(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - // don't set state here, this will be handled in handleGdbFinished() - } else { - const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); - emit adapterShutdownFailed(msg); - } -} - -void CoreGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) -{ - debugMessage(_("GDB PROESS FINISHED")); - setState(DebuggerNotReady); - emit adapterShutDown(); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h index 4a3fe67799dfe53dca4bd73e971c8b4aa26497a0..e0bc387c055a8eb4d4dbdda713454a5290b66ca2 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.h +++ b/src/plugins/debugger/gdb/coregdbadapter.h @@ -31,10 +31,10 @@ #define DEBUGGER_COREGDBADAPTER_H #include "abstractgdbadapter.h" -#include "gdbengine.h" -#include <QtCore/QDebug> -#include <QtCore/QProcess> +#ifdef Q_OS_LINUX +# define EXE_FROM_CORE +#endif namespace Debugger { namespace Internal { @@ -57,19 +57,16 @@ public: void startAdapter(); void startInferior(); void interruptInferior(); - void shutdown(); private: - void handleTargetCore1(const GdbResponse &response); - void handleDetach1(const GdbResponse &response); + void loadExeAndSyms(); + void loadCoreFile(); void handleFileExecAndSymbols(const GdbResponse &response); - void handleTargetCore2(const GdbResponse &response); - void handleExit(const GdbResponse &response); - - Q_SLOT void handleGdbStarted(); - Q_SLOT void handleGdbError(QProcess::ProcessError error); - Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus); + void handleTargetCore(const GdbResponse &response); +#ifdef EXE_FROM_CORE + int m_round; +#endif QString m_executable; }; diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri index ddd47c88b13e120e395683b0f632e02266f105a8..e7763cecb6f939efe2862d7bb3cc3adada4438d7 100644 --- a/src/plugins/debugger/gdb/gdb.pri +++ b/src/plugins/debugger/gdb/gdb.pri @@ -16,6 +16,7 @@ HEADERS += \ $$PWD/attachgdbadapter.h \ $$PWD/coregdbadapter.h \ $$PWD/plaingdbadapter.h \ + $$PWD/termgdbadapter.h \ $$PWD/remotegdbadapter.h \ $$PWD/trkgdbadapter.h \ @@ -30,6 +31,7 @@ SOURCES += \ $$PWD/attachgdbadapter.cpp \ $$PWD/coregdbadapter.cpp \ $$PWD/plaingdbadapter.cpp \ + $$PWD/termgdbadapter.cpp \ $$PWD/remotegdbadapter.cpp \ $$PWD/trkgdbadapter.cpp \ diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 343066a71e772f962d9f58aa9f0bc400888d55cf..c1881fb2982da75ada3f4d500a794f7ece66441a 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -37,6 +37,7 @@ #include "attachgdbadapter.h" #include "coregdbadapter.h" #include "plaingdbadapter.h" +#include "termgdbadapter.h" #include "remotegdbadapter.h" #include "trkgdbadapter.h" @@ -89,10 +90,6 @@ #endif #include <ctype.h> -// FIXME: temporary hack to evalaute tbreak based step-over behaviour -static QString lastFile; -static int lastLine; - namespace Debugger { namespace Internal { @@ -109,17 +106,29 @@ namespace Internal { static bool stateAcceptsGdbCommands(DebuggerState state) { - return state == AdapterStarted - || state == InferiorUnrunnable - || state == InferiorStarting - || state == InferiorRunningRequested - || state == InferiorRunning - || state == InferiorStopping - || state == InferiorStopped - || state == InferiorShuttingDown - || state == InferiorShutDown - || state == AdapterShuttingDown; -}; + switch (state) { + case AdapterStarting: + case AdapterStarted: + case AdapterStartFailed: + case InferiorUnrunnable: + case InferiorStarting: + case InferiorStartFailed: + case InferiorRunningRequested: + case InferiorRunning: + case InferiorStopping: + case InferiorStopped: + case InferiorShuttingDown: + case InferiorShutDown: + case InferiorShutdownFailed: + return true; + case DebuggerNotReady: + case EngineStarting: + case InferiorStopFailed: + case EngineShuttingDown: + break; + } + return false; +} static int ¤tToken() { @@ -221,27 +230,16 @@ GdbEngine::~GdbEngine() void GdbEngine::connectAdapter() { - // Gdb Process interaction - connect(m_gdbAdapter, SIGNAL(readyReadStandardOutput()), - this, SLOT(readGdbStandardOutput())); - connect(m_gdbAdapter, SIGNAL(readyReadStandardError()), - this, SLOT(readGdbStandardError())); - connect(m_gdbAdapter, SIGNAL(adapterStarted()), this, SLOT(handleAdapterStarted())); connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString,QString)), this, SLOT(handleAdapterStartFailed(QString,QString))); - connect(m_gdbAdapter, SIGNAL(adapterShutDown()), - this, SLOT(handleAdapterShutDown())); - connect(m_gdbAdapter, SIGNAL(adapterShutdownFailed(QString)), - this, SLOT(handleAdapterShutdownFailed(QString))); + + connect(m_gdbAdapter, SIGNAL(inferiorPrepared()), + this, SLOT(handleInferiorPrepared())); connect(m_gdbAdapter, SIGNAL(inferiorStartFailed(QString)), this, SLOT(handleInferiorStartFailed(QString))); - connect(m_gdbAdapter, SIGNAL(inferiorShutDown()), - this, SLOT(handleInferiorShutDown())); - connect(m_gdbAdapter, SIGNAL(inferiorShutdownFailed(QString)), - this, SLOT(handleInferiorShutdownFailed(QString))); connect(m_gdbAdapter, SIGNAL(adapterCrashed(QString)), this, SLOT(handleAdapterCrashed(QString))); @@ -265,7 +263,6 @@ void GdbEngine::initializeVariables() m_commandsDoneCallback = 0; m_commandsToRunOnTemporaryBreak.clear(); m_cookieForToken.clear(); - m_customOutputForToken.clear(); m_pendingConsoleStreamOutput.clear(); m_pendingLogStreamOutput.clear(); @@ -561,11 +558,6 @@ void GdbEngine::handleResponse(const QByteArray &buff) m_pendingLogStreamOutput); response.data.setStreamOutput("consolestreamoutput", m_pendingConsoleStreamOutput); - QByteArray custom = m_customOutputForToken[token]; - if (!custom.isEmpty()) - response.data.setStreamOutput("customvaluecontents", - '{' + custom + '}'); - //m_customOutputForToken.remove(token); m_pendingLogStreamOutput.clear(); m_pendingConsoleStreamOutput.clear(); @@ -581,7 +573,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) void GdbEngine::readGdbStandardError() { - qWarning() << "Unexpected gdb stderr:" << m_gdbAdapter->readAllStandardError(); + qWarning() << "Unexpected gdb stderr:" << m_gdbProc.readAllStandardError(); } void GdbEngine::readGdbStandardOutput() @@ -589,7 +581,7 @@ void GdbEngine::readGdbStandardOutput() int newstart = 0; int scan = m_inbuffer.size(); - m_inbuffer.append(m_gdbAdapter->readAllStandardOutput()); + m_inbuffer.append(m_gdbProc.readAllStandardOutput()); while (newstart < m_inbuffer.size()) { int start = newstart; @@ -704,13 +696,13 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd) } if (cmd.flags & NeedsStop) { - if (state() == InferiorStopped || state() == AdapterStarted) { + if (state() == InferiorStopped + || state() == InferiorStarting || state() == AdapterStarted) { // Can be safely sent now. flushCommand(cmd); } else { // Queue the commands that we cannot send at once. showStatusMessage(tr("Stopping temporarily."), 1000); - qDebug() << _("QUEUING COMMAND ") + cmd.command; debugMessage(_("QUEUING COMMAND ") + cmd.command); m_commandsToRunOnTemporaryBreak.append(cmd); interruptInferior(); @@ -896,14 +888,6 @@ void GdbEngine::handleQuerySources(const GdbResponse &response) } } -void GdbEngine::handleInfoShared(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - // let the modules handler do the parsing - handleModulesList(response); - } -} - #if 0 void GdbEngine::handleExecJumpToLine(const GdbResponse &response) { @@ -1078,7 +1062,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) QString pat = theDebuggerStringSetting(SelectedPluginBreakpointsPattern); debugMessage(_("PATTERN: ") + pat); postCommand(_("sharedlibrary ") + pat); - continueInferior(); + continueInferiorInternal(); showStatusMessage(tr("Loading %1...").arg(dataStr)); return; } @@ -1093,7 +1077,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) // args=[],from="C:\\WINDOWS\\system32\\ntdll.dll"} //if (reason == "signal-received" // && data.findChild("signal-name").data() == "SIGTRAP") { - // continueInferior(); + // continueInferiorInternal(); // return; //} @@ -1194,7 +1178,7 @@ void GdbEngine::handleStop1(const GdbMi &data) reloadSourceFiles(); postCommand(_("-break-list"), CB(handleBreakList)); QVariant var = QVariant::fromValue<GdbMi>(data); - postCommand(_("p 0"), CB(handleStop2), var); // dummy + postCommand(_("p 2"), CB(handleStop2), var); // dummy } else { #ifdef Q_OS_LINUX // For some reason, attaching to a stopped process causes *two* stops @@ -1205,8 +1189,7 @@ void GdbEngine::handleStop1(const GdbMi &data) GdbMi frameData = data.findChild("frame"); if (frameData.findChild("func").data() == "_start" && frameData.findChild("from").data() == "/lib/ld-linux.so.2") { - setState(InferiorRunningRequested); - postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); + continueInferiorInternal(); return; } } @@ -1247,9 +1230,9 @@ void GdbEngine::handleStop2(const GdbResponse &response) void GdbEngine::handleStop2(const GdbMi &data) { // Sometimes we get some interesting extra information. Grab it. - GdbMi frame = data.findChild("frame"); - GdbMi shortName = frame.findChild("file"); - GdbMi fullName = frame.findChild("fullname"); + const GdbMi gdbmiFrame = data.findChild("frame"); + GdbMi shortName = gdbmiFrame.findChild("file"); + GdbMi fullName = gdbmiFrame.findChild("fullname"); if (shortName.isValid() && fullName.isValid()) { QString file = QFile::decodeName(shortName.data()); QString full = QFile::decodeName(fullName.data()); @@ -1260,16 +1243,17 @@ void GdbEngine::handleStop2(const GdbMi &data) } // Quick shot: Jump to stack frame #0. - if (frame.isValid()) { - const StackFrame f = parseStackFrame(frame, 0); - gotoLocation(f, true); + StackFrame frame; + if (gdbmiFrame.isValid()) { + frame = parseStackFrame(gdbmiFrame, 0); + gotoLocation(frame, true); } // // Stack // manager()->stackHandler()->setCurrentIndex(0); - updateLocals(); // Quick shot + updateLocals(qVariantFromValue(frame)); // Quick shot reloadStack(false); @@ -1342,17 +1326,16 @@ void GdbEngine::handleExecContinue(const GdbResponse &response) QTC_ASSERT(state() == InferiorRunning, /**/); } else { QTC_ASSERT(state() == InferiorRunningRequested, /**/); + setState(InferiorStopped); QByteArray msg = response.data.findChild("msg").data(); if (msg.startsWith("Cannot find bounds of current function")) { - setState(InferiorStopped); showStatusMessage(tr("Stopped."), 5000); //showStatusMessage(tr("No debug information available. " // "Leaving function...")); //stepOutExec(); } else { - showMessageBox(QMessageBox::Critical, tr("Error"), - tr("Starting executable failed:\n") + QString::fromLocal8Bit(msg)); - QTC_ASSERT(state() == InferiorRunning, /**/); + showMessageBox(QMessageBox::Critical, tr("Execution Error"), + tr("Cannot continue debugged process:\n") + QString::fromLocal8Bit(msg)); shutdown(); } } @@ -1397,8 +1380,73 @@ QString GdbEngine::fullName(const QStringList &candidates) void GdbEngine::shutdown() { debugMessage(_("INITIATE GDBENGINE SHUTDOWN")); - initializeVariables(); - m_gdbAdapter->shutdown(); + switch (state()) { + case DebuggerNotReady: // Nothing to do! :) + case EngineStarting: // We can't get here, really + case InferiorShuttingDown: // Will auto-trigger further shutdown steps + case EngineShuttingDown: // Do not disturb! :) + break; + case AdapterStarting: // GDB is up, adapter is "doing something" + setState(AdapterStartFailed); + m_gdbAdapter->shutdown(); + // fall-through + case AdapterStartFailed: // Adapter "did something", but it did not help + // FIXME set some timeout? + postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit)); + break; + case InferiorRunningRequested: + case InferiorRunning: + case InferiorStopping: + case InferiorStopped: + // FIXME set some timeout? + postCommand(_(m_gdbAdapter->inferiorShutdownCommand()), + NeedsStop, CB(handleInferiorShutdown)); + setState(InferiorShuttingDown); // Do it after posting the command! + break; + case AdapterStarted: // We can't get here, really + case InferiorStartFailed: + case InferiorShutDown: + case InferiorShutdownFailed: // Whatever + case InferiorUnrunnable: + // FIXME set some timeout? + postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit)); + setState(EngineShuttingDown); // Do it after posting the command! + break; + case InferiorStarting: // This may take some time, so just short-circuit it + setState(InferiorStartFailed); + // fall-through + case InferiorStopFailed: // Tough luck, I guess. But unreachable as of now anyway. + setState(EngineShuttingDown); + m_gdbProc.terminate(); + break; + } +} + +void GdbEngine::handleInferiorShutdown(const GdbResponse &response) +{ + QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state()); + if (response.resultClass == GdbResultDone) { + debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN")); + setState(InferiorShutDown); + } else { + debugMessage(_("INFERIOR SHUTDOWN FAILED")); + setState(InferiorShutdownFailed); + QString msg = m_gdbAdapter->msgInferiorStopFailed(_(response.data.findChild("msg").data())); + showMessageBox(QMessageBox::Critical, tr("Inferior shutdown failed"), msg); + } + shutdown(); // re-iterate... +} + +void GdbEngine::handleGdbExit(const GdbResponse &response) +{ + if (response.resultClass == GdbResultExit) { + debugMessage(_("GDB CLAIMS EXIT; WAITING")); + // don't set state here, this will be handled in handleGdbFinished() + } else { + QString msg = m_gdbAdapter->msgGdbStopFailed(_(response.data.findChild("msg").data())); + debugMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg)); + m_gdbProc.terminate(); + } } void GdbEngine::detachDebugger() @@ -1414,8 +1462,7 @@ void GdbEngine::detachDebugger() void GdbEngine::exitDebugger() // called from the manager { disconnectDebuggingHelperActions(); - initializeVariables(); - m_gdbAdapter->shutdown(); + shutdown(); } int GdbEngine::currentFrame() const @@ -1463,6 +1510,8 @@ AbstractGdbAdapter *GdbEngine::createAdapter(const DebuggerStartParametersPtr &s case AttachExternal: return new AttachGdbAdapter(this); default: + if (sp->useTerminal) + return new TermGdbAdapter(this); return new PlainGdbAdapter(this); } } @@ -1476,25 +1525,23 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp) // initializeVariables()); //QTC_ASSERT(m_gdbAdapter == 0, delete m_gdbAdapter; m_gdbAdapter = 0); + initializeVariables(); + m_startParameters = sp; delete m_gdbAdapter; m_gdbAdapter = createAdapter(sp); + connectAdapter(); if (startModeAllowsDumpers()) connectDebuggingHelperActions(); - initializeVariables(); - connectAdapter(); - m_gdbAdapter->startAdapter(); } void GdbEngine::continueInferiorInternal() { QTC_ASSERT(state() == InferiorStopped, qDebug() << state()); - m_manager->resetLocation(); - setTokenBarrier(); setState(InferiorRunningRequested); postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); } @@ -1507,6 +1554,8 @@ void GdbEngine::autoContinueInferior() void GdbEngine::continueInferior() { + m_manager->resetLocation(); + setTokenBarrier(); continueInferiorInternal(); showStatusMessage(tr("Running requested..."), 5000); } @@ -1589,12 +1638,10 @@ void GdbEngine::runToFunctionExec(const QString &functionName) QTC_ASSERT(state() == InferiorStopped, qDebug() << state()); setTokenBarrier(); postCommand(_("-break-insert -t ") + functionName); - setState(InferiorRunningRequested); - showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000); - // that should be "^running". We need to handle the resulting - // "Stopped" - postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); + continueInferiorInternal(); + //setState(InferiorRunningRequested); //postCommand(_("-exec-continue"), handleExecRunToFunction); + showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000); } void GdbEngine::jumpToLineExec(const QString &fileName, int lineNumber) @@ -1903,11 +1950,7 @@ void GdbEngine::handleBreakInsert(const GdbResponse &response) const BreakpointData *data = handler->at(index); // Note that it is perfectly correct that the file name is put // in quotes but not escaped. GDB simply is like that. -#if defined(Q_OS_WIN) - QFileInfo fi(data->fileName); - QString where = _c('"') + fi.fileName() + _("\":") - + data->lineNumber; -#elif defined(Q_OS_MAC) +#if defined(Q_OS_WIN) || defined(Q_OS_MAC) QFileInfo fi(data->fileName); QString where = _c('"') + fi.fileName() + _("\":") + data->lineNumber; @@ -2597,11 +2640,6 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos, // ////////////////////////////////////////////////////////////////////// -//: Variable -static const QString strNotInScope = - QCoreApplication::translate("Debugger::Internal::GdbEngine", "<not in scope>"); - - static void setWatchDataValue(WatchData &data, const GdbMi &mi, int encoding = 0) { @@ -2818,8 +2856,8 @@ void GdbEngine::updateSubItem(const WatchData &data0) qDebug() << "FIXME: GdbEngine::updateSubItem:" << data.toString() << "should not happen"; #else - data.setType(strNotInScope); - data.setValue(strNotInScope); + data.setType(WatchData::msgNotInScope()); + data.setValue(WatchData::msgNotInScope()); data.setHasChildren(false); insertData(data); return; @@ -2964,7 +3002,7 @@ void GdbEngine::updateWatchData(const WatchData &data) if (isSynchroneous()) { // This should only be called for fresh expanded items, not for // items that had their children retrieved earlier. - qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n"; + //qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n"; #if 0 WatchData data1 = data; data1.setAllUnneeded(); @@ -3153,7 +3191,7 @@ void GdbEngine::handleVarCreate(const GdbResponse &response) } else { data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); if (data.isWatcher()) { - data.value = strNotInScope; + data.value = WatchData::msgNotInScope(); data.type = _(" "); data.setAllUnneeded(); data.setHasChildren(false); @@ -3206,7 +3244,7 @@ void GdbEngine::handleDebuggingHelperValue1(const GdbResponse &response) && msg.startsWith(__("The program being debugged stopped while")) && msg.contains(__("qDumpObjectData440"))) { // Fake full stop - postCommand(_("p 0"), CB(handleStop2)); // dummy + postCommand(_("p 3"), CB(handleStop2)); // dummy return; } #endif @@ -3227,7 +3265,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResponse &response) GdbMi contents; if (!parseConsoleStream(response, &contents)) { - data.setError(strNotInScope); + data.setError(WatchData::msgNotInScope()); insertData(data); return; } @@ -3320,7 +3358,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response) // << " STREAM:" << out; if (list.isEmpty()) { //: Value for variable - data.setError(strNotInScope); + data.setError(WatchData::msgNotInScope()); data.setAllUnneeded(); insertData(data); } else if (data.type == __("QString") @@ -3365,19 +3403,19 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response) } } else { //: Value for variable - data.setError(strNotInScope); + data.setError(WatchData::msgNotInScope()); data.setAllUnneeded(); insertData(data); } } else { WatchData data = response.cookie.value<WatchData>(); - data.setError(strNotInScope); + data.setError(WatchData::msgNotInScope()); data.setAllUnneeded(); insertData(data); } } -void GdbEngine::updateLocals() +void GdbEngine::updateLocals(const QVariant &cookie) { m_pendingRequests = 0; m_processedNames.clear(); @@ -3398,8 +3436,8 @@ void GdbEngine::updateLocals() postCommand(_("bb %1 %2") .arg(int(theDebuggerBoolSetting(UseDebuggingHelpers))) .arg(expanded.join(_(","))), - WatchUpdate, CB(handleStackFrame1)); - postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2)); + CB(handleStackFrame1)); + postCommand(_("p 1"), CB(handleStackFrame2)); } else { QString level = QString::number(currentFrame()); // '2' is 'list with type and value' @@ -3407,7 +3445,7 @@ void GdbEngine::updateLocals() postCommand(cmd, WatchUpdate, CB(handleStackListArguments)); // '2' is 'list with type and value' postCommand(_("-stack-list-locals 2"), WatchUpdate, - CB(handleStackListLocals)); // stage 2/2 + CB(handleStackListLocals), cookie); // stage 2/2 } } @@ -3434,7 +3472,7 @@ void GdbEngine::handleStackFrame2(const GdbResponse &response) out = m_firstChunk + out; int pos = out.indexOf("locals="); if (pos != 0) { - qDebug() << "DICARDING JUNK AT BEGIN OF RESPONSE: " + qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: " << out.left(pos); out = out.mid(pos); } @@ -3455,7 +3493,9 @@ void GdbEngine::handleStackFrame2(const GdbResponse &response) // qDebug() << "READ: " << list.at(i).toString(); manager()->watchHandler()->insertBulkData(list); - manager()->watchHandler()->updateWatchers(); + // FIXME: + //manager()->watchHandler()->updateWatchers(); + rebuildModel(); } else { QTC_ASSERT(false, /**/); } @@ -3503,91 +3543,105 @@ void GdbEngine::handleStackListLocals(const GdbResponse &response) // There could be shadowed variables QList<GdbMi> locals = response.data.findChild("locals").children(); locals += m_currentFunctionArgs; - - setLocals(locals); + QMap<QByteArray, int> seen; + // If desired, retrieve list of uninitialized variables looking at + // the current frame. This is invoked first time after a stop from + // handleStop2, which passes on the frame as cookie. The whole stack + // is not known at this point. + QStringList uninitializedVariables; + if (theDebuggerAction(UseCodeModel)->isChecked()) { + const StackFrame frame = qVariantCanConvert<Debugger::Internal::StackFrame>(response.cookie) ? + qVariantValue<Debugger::Internal::StackFrame>(response.cookie) : + m_manager->stackHandler()->currentFrame(); + if (frame.isUsable()) + getUninitializedVariables(m_manager->cppCodeModelSnapshot(), + frame.function, frame.file, frame.line, + &uninitializedVariables); + } + QList<WatchData> list; + foreach (const GdbMi &item, locals) { + const WatchData data = localVariable(item, uninitializedVariables, &seen); + if (data.isValid()) + list.push_back(data); + } + manager()->watchHandler()->insertBulkData(list); manager()->watchHandler()->updateWatchers(); } -void GdbEngine::setLocals(const QList<GdbMi> &locals) +// Parse a local variable from GdbMi +WatchData GdbEngine::localVariable(const GdbMi &item, + const QStringList &uninitializedVariables, + QMap<QByteArray, int> *seen) { - //qDebug() << m_varToType; - QMap<QByteArray, int> seen; - - QList<WatchData> list; - foreach (const GdbMi &item, locals) { - // Local variables of inlined code are reported as - // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this", - // numchild="1",type="const QtSharedPointer::Basic<CPlusPlus::..." - // We do not want these at all. Current hypotheses is that those - // "spurious" locals have _two_ "exp" field. Try to filter them: - #ifdef Q_OS_MAC - int numExps = 0; - foreach (const GdbMi &child, item.children()) - numExps += int(child.name() == "exp"); - if (numExps > 1) - continue; - QByteArray name = item.findChild("exp").data(); - #else - QByteArray name = item.findChild("name").data(); - #endif - int n = seen.value(name); - if (n) { - seen[name] = n + 1; - WatchData data; - QString nam = _(name); - data.iname = _("local.") + nam + QString::number(n + 1); - //: Variable %1 is the variable name, %2 is a simple count - data.name = tr("%1 <shadowed %2>").arg(nam).arg(n); + // Local variables of inlined code are reported as + // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this", + // numchild="1",type="const QtSharedPointer::Basic<CPlusPlus::..."}} + // We do not want these at all. Current hypotheses is that those + // "spurious" locals have _two_ "exp" field. Try to filter them: +#ifdef Q_OS_MAC + int numExps = 0; + foreach (const GdbMi &child, item.children()) + numExps += int(child.name() == "exp"); + if (numExps > 1) + return WatchData(); + QByteArray name = item.findChild("exp").data(); +#else + QByteArray name = item.findChild("name").data(); +#endif + const QMap<QByteArray, int>::iterator it = seen->find(name); + if (it != seen->end()) { + const int n = it.value(); + ++(it.value()); + WatchData data; + QString nam = _(name); + data.iname = _("local.") + nam + QString::number(n + 1); + //: Variable %1 is the variable name, %2 is a simple count + data.name = WatchData::shadowedName(nam, n); + if (uninitializedVariables.contains(data.name)) { + data.setError(WatchData::msgNotInScope()); + return data; + } + //: Type of local variable or parameter shadowed by another + //: variable of the same name in a nested block. + setWatchDataValue(data, item.findChild("value")); + data.setType(GdbEngine::tr("<shadowed>")); + data.setHasChildren(false); + return data; + } + seen->insert(name, 1); + WatchData data; + QString nam = _(name); + data.iname = _("local.") + nam; + data.name = nam; + data.exp = nam; + data.framekey = m_currentFrame + data.name; + setWatchDataType(data, item.findChild("type")); + if (uninitializedVariables.contains(data.name)) { + data.setError(WatchData::msgNotInScope()); + return data; + } + if (isSynchroneous()) { + setWatchDataValue(data, item.findChild("value"), + item.findChild("valueencoded").data().toInt()); + // We know that the complete list of children is + // somewhere in the response. + data.setChildrenUnneeded(); + } else { + // set value only directly if it is simple enough, otherwise + // pass through the insertData() machinery + if (isIntOrFloatType(data.type) || isPointerType(data.type)) + setWatchDataValue(data, item.findChild("value")); + if (isSymbianIntType(data.type)) { setWatchDataValue(data, item.findChild("value")); - //: Type of local variable or parameter shadowed by another - //variable of the same name in a nested block - data.setType(tr("<shadowed>")); data.setHasChildren(false); - list.append(data); - } else { - seen[name] = 1; - WatchData data; - QString nam = _(name); - data.iname = _("local.") + nam; - data.name = nam; - data.exp = nam; - data.framekey = m_currentFrame + data.name; - setWatchDataType(data, item.findChild("type")); - if (isSynchroneous()) { - setWatchDataValue(data, item.findChild("value"), - item.findChild("valueencoded").data().toInt()); - // We know that the complete list of children is - // somewhere in the response. - data.setChildrenUnneeded(); - } else { - // set value only directly if it is simple enough, otherwise - // pass through the insertData() machinery - if (isIntOrFloatType(data.type) || isPointerType(data.type)) - setWatchDataValue(data, item.findChild("value")); - if (isSymbianIntType(data.type)) { - setWatchDataValue(data, item.findChild("value")); - data.setHasChildren(false); - } - } - - // Let's be a bit more bold: - //if (!hasDebuggingHelperForType(data.type)) { - // QByteArray value = item.findChild("value").data(); - // if (!value.isEmpty() && value != "{...}") - // data.setValue(decodeData(value, 0)); - //} - if (!manager()->watchHandler()->isExpandedIName(data.iname)) - data.setChildrenUnneeded(); - if (isPointerType(data.type) || data.name == __("this")) - data.setHasChildren(true); - if (0 && m_varToType.contains(data.framekey)) { - qDebug() << "RE-USING" << m_varToType.value(data.framekey); - data.setType(m_varToType.value(data.framekey)); - } - list.append(data); } } - manager()->watchHandler()->insertBulkData(list); + + if (!m_manager->watchHandler()->isExpandedIName(data.iname)) + data.setChildrenUnneeded(); + if (isPointerType(data.type) || data.name == __("this")) + data.setHasChildren(true); + return data; } void GdbEngine::insertData(const WatchData &data0) @@ -4112,9 +4166,7 @@ void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResponse &response) void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker) { - lastFile = frame.file; - lastLine = frame.line; - //qDebug() << "GOTO " << frame.toString() << setMarker; + // qDebug() << "GOTO " << frame << setMarker; m_manager->gotoLocation(frame, setMarker); } @@ -4122,18 +4174,37 @@ void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker) // Starting up & shutting down // -void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint) +bool GdbEngine::startGdb(const QStringList &args, const QString &gdb) { - setState(AdapterStartFailed); - debugMessage(_("ADAPTER START FAILED")); - Core::ICore::instance()->showWarningWithOptions(tr("Adapter start failed"), msg, QString(), - QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint); - shutdown(); -} + debugMessage(_("STARTING GDB ") + gdb); -void GdbEngine::handleAdapterStarted() -{ - debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING GDB")); + m_gdbProc.disconnect(); // From any previous runs + + QString location = gdb; + if (location.isEmpty()) + location = theDebuggerStringSetting(GdbLocation); + QStringList gdbArgs; + gdbArgs << _("-i"); + gdbArgs << _("mi"); + gdbArgs += args; + m_gdbProc.start(location, gdbArgs); + + if (!m_gdbProc.waitForStarted()) { + handleAdapterStartFailed(m_gdbProc.errorString()); + return false; + } + + // Do this only after the process is running, so we get no needless error notifications + connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), + SLOT(handleGdbError(QProcess::ProcessError))); + connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(handleGdbFinished(int, QProcess::ExitStatus))); + connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + SLOT(readGdbStandardOutput())); + connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + SLOT(readGdbStandardError())); + + debugMessage(_("GDB STARTED, INITIALIZING IT")); postCommand(_("show version"), CB(handleShowVersion)); postCommand(_("help bb"), CB(handleIsSynchroneous)); @@ -4217,70 +4288,108 @@ void GdbEngine::handleAdapterStarted() } } - // Initial attempt to set breakpoints - showStatusMessage(tr("Setting breakpoints...")); - attemptBreakpointSynchronization(); + return true; +} - QTC_ASSERT(m_commandsDoneCallback == 0, /**/); - m_commandsDoneCallback = &GdbEngine::startInferior; +void GdbEngine::handleGdbError(QProcess::ProcessError error) +{ + debugMessage(_("HANDLE GDB ERROR")); + switch (error) { + case QProcess::Crashed: + break; // will get a processExited() as well + // impossible case QProcess::FailedToStart: + case QProcess::ReadError: + case QProcess::WriteError: + case QProcess::Timedout: + default: + m_gdbProc.terminate(); + setState(EngineShuttingDown, true); + showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"), + errorMessage(error)); + break; + } } -void GdbEngine::startInferior() +void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type) { - QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); - showStatusMessage(tr("Starting inferior...")); - setState(InferiorStarting); - m_gdbAdapter->startInferior(); + debugMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code)); + if (state() == EngineShuttingDown) { + m_gdbAdapter->shutdown(); + } else if (state() != AdapterStartFailed) { + showMessageBox(QMessageBox::Critical, tr("Unexpected Gdb Exit"), + tr("The gdb process exited unexpectedly (%1).") + .arg((type == QProcess::CrashExit) + ? tr("crashed") : tr("code %1").arg(code))); + m_gdbAdapter->shutdown(); + } + initializeVariables(); + setState(DebuggerNotReady, true); } -void GdbEngine::handleInferiorStartFailed(const QString &msg) +void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint) { - debugMessage(_("INFERIOR START FAILED")); - showMessageBox(QMessageBox::Critical, tr("Inferior start failed"), msg); - setState(InferiorStartFailed); + setState(AdapterStartFailed); + debugMessage(_("ADAPTER START FAILED")); + Core::ICore::instance()->showWarningWithOptions( + tr("Adapter start failed"), msg, QString(), + _(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint); shutdown(); } -void GdbEngine::handleInferiorShutDown() +void GdbEngine::handleAdapterStarted() { - debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN")); + setState(AdapterStarted); + debugMessage(_("ADAPTER SUCCESSFULLY STARTED")); + + showStatusMessage(tr("Starting inferior...")); + setState(InferiorStarting); + m_gdbAdapter->startInferior(); } -void GdbEngine::handleInferiorShutdownFailed(const QString &msg) +void GdbEngine::handleInferiorPrepared() { - debugMessage(_("INFERIOR SHUTDOWN FAILED")); - showMessageBox(QMessageBox::Critical, tr("Inferior shutdown failed"), msg); - shutdown(); // continue with adapter shutdown + // Initial attempt to set breakpoints + showStatusMessage(tr("Setting breakpoints...")); + attemptBreakpointSynchronization(); + + if (m_cookieForToken.isEmpty()) { + startInferiorPhase2(); + } else { + QTC_ASSERT(m_commandsDoneCallback == 0, /**/); + m_commandsDoneCallback = &GdbEngine::startInferiorPhase2; + } } -void GdbEngine::handleAdapterCrashed(const QString &msg) +void GdbEngine::startInferiorPhase2() { - debugMessage(_("ADAPTER CRASHED")); - switch (state()) { - // All fall-through. - case InferiorRunning: - setState(InferiorShuttingDown); - case InferiorShuttingDown: - setState(InferiorShutDown); - case InferiorShutDown: - setState(AdapterShuttingDown); - default: - setState(DebuggerNotReady); - } - showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg); + debugMessage(_("BREAKPOINTS SET, CONTINUING INFERIOR STARTUP")); + m_gdbAdapter->startInferiorPhase2(); } -void GdbEngine::handleAdapterShutDown() +void GdbEngine::handleInferiorStartFailed(const QString &msg) { - debugMessage(_("ADAPTER SUCCESSFULLY SHUT DOWN")); - setState(DebuggerNotReady); + debugMessage(_("INFERIOR START FAILED")); + showMessageBox(QMessageBox::Critical, tr("Inferior start failed"), msg); + setState(InferiorStartFailed); + shutdown(); } -void GdbEngine::handleAdapterShutdownFailed(const QString &msg) +void GdbEngine::handleAdapterCrashed(const QString &msg) { - debugMessage(_("ADAPTER SHUTDOWN FAILED")); - showMessageBox(QMessageBox::Critical, tr("Adapter shutdown failed"), msg); - setState(DebuggerNotReady); + debugMessage(_("ADAPTER CRASHED")); + + // The adapter is expected to have cleaned up after itself when we get here, + // so the effect is about the same as AdapterStartFailed => use it. + // Don't bother with state transitions - this can happen in any state and + // the end result is always the same, so it makes little sense to find a + // "path" which does not assert. + setState(AdapterStartFailed, true); + + // No point in being friendly here ... + m_gdbProc.terminate(); + + if (!msg.isEmpty()) + showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg); } void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const @@ -4314,4 +4423,3 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *manager) Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgentCookie); Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerAgentCookie); Q_DECLARE_METATYPE(Debugger::Internal::GdbMi); - diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 99f59fb63d179b6549c770005b6a1355fea26643..a891a557472fe80b30fa780b10eec5cbd9f1348f 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -92,84 +92,79 @@ private: friend class AttachGdbAdapter; friend class CoreGdbAdapter; friend class PlainGdbAdapter; + friend class TermGdbAdapter; friend class RemoteGdbAdapter; friend class TrkGdbAdapter; - // - // IDebuggerEngine implementation - // - void stepExec(); - void stepOutExec(); - void nextExec(); - void stepIExec(); - void nextIExec(); - - void shutdown(); - void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); - void startDebugger(const DebuggerStartParametersPtr &sp); - void exitDebugger(); - void detachDebugger(); +private: ////////// General Interface ////////// - void continueInferiorInternal(); - void autoContinueInferior(); - void continueInferior(); - void interruptInferior(); + virtual void addOptionPages(QList<Core::IOptionsPage*> *opts) const; - void runToLineExec(const QString &fileName, int lineNumber); - void runToFunctionExec(const QString &functionName); - void jumpToLineExec(const QString &fileName, int lineNumber); + virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; - void activateFrame(int index); - void selectThread(int index); + virtual bool isGdbEngine() const { return true; } - Q_SLOT void attemptBreakpointSynchronization(); + virtual void startDebugger(const DebuggerStartParametersPtr &sp); + virtual void exitDebugger(); + virtual void detachDebugger(); + virtual void shutdown(); - void assignValueInDebugger(const QString &expr, const QString &value); - void executeDebuggerCommand(const QString & command); - void watchPoint(const QPoint &); + virtual void executeDebuggerCommand(const QString &command); - void loadSymbols(const QString &moduleName); - void loadAllSymbols(); - virtual QList<Symbol> moduleSymbols(const QString &moduleName); +private: ////////// General State ////////// - void fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length); - void handleFetchMemory(const GdbResponse &response); + void initializeVariables(); + DebuggerStartMode startMode() const; + const DebuggerStartParameters &startParameters() const + { return *m_startParameters; } + Q_SLOT void setAutoDerefPointers(const QVariant &on); - void fetchDisassembler(DisassemblerViewAgent *agent, - const StackFrame &frame); - void fetchDisassemblerByAddress(DisassemblerViewAgent *agent, - bool useMixedMode); - void handleFetchDisassemblerByLine(const GdbResponse &response); - void handleFetchDisassemblerByAddress1(const GdbResponse &response); - void handleFetchDisassemblerByAddress0(const GdbResponse &response); + DebuggerStartParametersPtr m_startParameters; + QSharedPointer<TrkOptions> m_trkOptions; - Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); - Q_SLOT void setUseDebuggingHelpers(const QVariant &on); - Q_SLOT void setAutoDerefPointers(const QVariant &on); - bool isGdbEngine() const { return true; } - bool isSynchroneous() const; +private: ////////// Gdb Process Management ////////// - bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; + AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp); + void connectAdapter(); + bool startGdb(const QStringList &args = QStringList(), const QString &gdb = QString()); + void startInferiorPhase2(); - // - // Own stuff - // + void handleInferiorShutdown(const GdbResponse &response); + void handleGdbExit(const GdbResponse &response); - int currentFrame() const; + void gdbInputAvailable(int channel, const QString &msg) + { m_manager->showDebuggerInput(channel, msg); } + void gdbOutputAvailable(int channel, const QString &msg) + { m_manager->showDebuggerOutput(channel, msg); } - bool supportsThreads() const; - void gotoLocation(const StackFrame &frame, bool setLocationMarker); - StackFrame parseStackFrame(const GdbMi &mi, int level); +private slots: + void handleGdbFinished(int, QProcess::ExitStatus status); + void handleGdbError(QProcess::ProcessError error); + void readGdbStandardOutput(); + void readGdbStandardError(); + void readDebugeeOutput(const QByteArray &data); - void connectAdapter(); - void initializeVariables(); - QString fullName(const QString &fileName); - // get one usable name out of these, try full names first - QString fullName(const QStringList &candidates); + void handleAdapterStarted(); + void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString()); + + void handleInferiorPrepared(); + + void handleInferiorStartFailed(const QString &msg); + + void handleAdapterCrashed(const QString &msg); - void handleResult(const GdbResponse &response); +private: + QTextCodec *m_outputCodec; + QTextCodec::ConverterState m_outputCodecState; -public: // otherwise the Qt flag macros are unhappy + QByteArray m_inbuffer; + + QProcess m_gdbProc; + AbstractGdbAdapter *m_gdbAdapter; + +private: ////////// Gdb Command Management ////////// + + public: // otherwise the Qt flag macros are unhappy enum GdbCommandFlag { NoFlags = 0, NeedsStop = 1, // The command needs a stopped inferior @@ -181,9 +176,8 @@ public: // otherwise the Qt flag macros are unhappy ExitRequest = 32 // Callback expect GdbResultExit instead of GdbResultDone }; Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag) + private: - -private: typedef void (GdbEngine::*GdbCommandCallback) (const GdbResponse &response); typedef void (AbstractGdbAdapter::*AdapterCallback) @@ -230,81 +224,78 @@ private: void postCommandHelper(const GdbCommand &cmd); void setTokenBarrier(); - void updateAll(); - void updateLocals(); + QHash<int, GdbCommand> m_cookieForToken; - void gdbInputAvailable(int channel, const QString &msg) - { m_manager->showDebuggerInput(channel, msg); } - void gdbOutputAvailable(int channel, const QString &msg) - { m_manager->showDebuggerOutput(channel, msg); } + QByteArray m_pendingConsoleStreamOutput; + QByteArray m_pendingLogStreamOutput; -private slots: - void readGdbStandardOutput(); - void readGdbStandardError(); - void readDebugeeOutput(const QByteArray &data); + // contains the first token number for the current round + // of evaluation. Responses with older tokens are considers + // out of date and discarded. + int m_oldestAcceptableToken; - void handleAdapterStarted(); - void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString()); + int m_pendingRequests; // Watch updating commands in flight - void handleInferiorStartFailed(const QString &msg); - void handleInferiorShutDown(); - void handleInferiorShutdownFailed(const QString &msg); + typedef void (GdbEngine::*CommandsDoneCallback)(); + // function called after all previous responses have been received + CommandsDoneCallback m_commandsDoneCallback; - void handleAdapterCrashed(const QString &msg); - void handleAdapterShutDown(); - void handleAdapterShutdownFailed(const QString &msg); + QList<GdbCommand> m_commandsToRunOnTemporaryBreak; + +private: ////////// Gdb Output, State & Capability Handling ////////// -private: - int terminationIndex(const QByteArray &buffer, int &length); void handleResponse(const QByteArray &buff); void handleStopResponse(const GdbMi &data); + void handleResultRecord(const GdbResponse &response); void handleStop1(const GdbResponse &response); void handleStop1(const GdbMi &data); void handleStop2(const GdbResponse &response); void handleStop2(const GdbMi &data); - void handleResultRecord(const GdbResponse &response); - void handleExecContinue(const GdbResponse &response); -// void handleExecRunToFunction(const GdbResponse &response); - void handleInfoShared(const GdbResponse &response); + StackFrame parseStackFrame(const GdbMi &mi, int level); + + virtual bool isSynchroneous() const; + bool supportsThreads() const; + + // Gdb initialization sequence void handleShowVersion(const GdbResponse &response); - void handleQuerySources(const GdbResponse &response); - void handleWatchPoint(const GdbResponse &response); void handleIsSynchroneous(const GdbResponse &response); - bool showToolTip(); - // Convenience - QMainWindow *mainWindow() const; - DebuggerStartMode startMode() const; - qint64 inferiorPid() const { return m_manager->inferiorPid(); } - void handleInferiorPidChanged(qint64 pid) { manager()->notifyInferiorPidChanged(pid); } + int m_gdbVersion; // 6.8.0 is 680 + int m_gdbBuildVersion; // MAC only? + bool m_isSynchroneous; // Can act synchroneously? - void handleChildren(const WatchData &parent, const GdbMi &child, - QList<WatchData> *insertions); - const bool m_dumperInjectionLoad; +private: ////////// Inferior Management ////////// - QTextCodec *m_outputCodec; - QTextCodec::ConverterState m_outputCodecState; + Q_SLOT virtual void attemptBreakpointSynchronization(); - QByteArray m_inbuffer; + virtual void stepExec(); + virtual void stepOutExec(); + virtual void nextExec(); + virtual void stepIExec(); + virtual void nextIExec(); - QHash<int, GdbCommand> m_cookieForToken; - QHash<int, QByteArray> m_customOutputForToken; + void continueInferiorInternal(); + void autoContinueInferior(); + virtual void continueInferior(); + virtual void interruptInferior(); - QByteArray m_pendingConsoleStreamOutput; - QByteArray m_pendingLogStreamOutput; + virtual void runToLineExec(const QString &fileName, int lineNumber); + virtual void runToFunctionExec(const QString &functionName); +// void handleExecRunToFunction(const GdbResponse &response); + virtual void jumpToLineExec(const QString &fileName, int lineNumber); - // contains the first token number for the current round - // of evaluation. Responses with older tokens are considers - // out of date and discarded. - int m_oldestAcceptableToken; + void handleExecContinue(const GdbResponse &response); - int m_gdbVersion; // 6.8.0 is 680 - int m_gdbBuildVersion; // MAC only? - bool m_isSynchroneous; // Can act synchroneously? + qint64 inferiorPid() const { return m_manager->inferiorPid(); } + void handleInferiorPidChanged(qint64 pid) { manager()->notifyInferiorPidChanged(pid); } + void maybeHandleInferiorPidChanged(const QString &pid); - // awful hack to keep track of used files - QMap<QString, QString> m_shortToFullName; - QMap<QString, QString> m_fullToShortName; +private: ////////// View & Data Stuff ////////// + + virtual void selectThread(int index); + virtual void activateFrame(int index); + + void gotoLocation(const StackFrame &frame, bool setLocationMarker); // // Breakpoint specific stuff @@ -323,9 +314,13 @@ private: // // Modules specific stuff // + virtual void loadSymbols(const QString &moduleName); + virtual void loadAllSymbols(); + virtual QList<Symbol> moduleSymbols(const QString &moduleName); void reloadModules(); void handleModulesList(const GdbResponse &response); + bool m_modulesListOutdated; // // Register specific stuff @@ -335,54 +330,83 @@ private: void handleRegisterListNames(const GdbResponse &response); void handleRegisterListValues(const GdbResponse &response); + // + // Disassembler specific stuff + // + virtual void fetchDisassembler(DisassemblerViewAgent *agent, + const StackFrame &frame); + void fetchDisassemblerByAddress(DisassemblerViewAgent *agent, + bool useMixedMode); + void handleFetchDisassemblerByLine(const GdbResponse &response); + void handleFetchDisassemblerByAddress1(const GdbResponse &response); + void handleFetchDisassemblerByAddress0(const GdbResponse &response); + QString parseDisassembler(const GdbMi &lines); + // // Source file specific stuff // void reloadSourceFiles(); + void handleQuerySources(const GdbResponse &response); + + QString fullName(const QString &fileName); + // get one usable name out of these, try full names first + QString fullName(const QStringList &candidates); + + // awful hack to keep track of used files + QMap<QString, QString> m_shortToFullName; + QMap<QString, QString> m_fullToShortName; // // Stack specific stuff // + void updateAll(); void handleStackListFrames(const GdbResponse &response); void handleStackSelectThread(const GdbResponse &response); void handleStackListThreads(const GdbResponse &response); void handleStackFrame1(const GdbResponse &response); void handleStackFrame2(const GdbResponse &response); - QByteArray m_firstChunk; Q_SLOT void reloadStack(bool forceGotoLocation); Q_SLOT void reloadFullStack(); + int currentFrame() const; + QList<GdbMi> m_currentFunctionArgs; + QByteArray m_firstChunk; + QString m_currentFrame; // - // Tooltip specific stuff + // Watch specific stuff // - void sendToolTipCommand(const QString &command, const QString &cookie); + virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); + virtual void assignValueInDebugger(const QString &expr, const QString &value); + + virtual void fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length); + void handleFetchMemory(const GdbResponse &response); + + virtual void watchPoint(const QPoint &); + void handleWatchPoint(const GdbResponse &response); - // - // Watch specific stuff - // // FIXME: BaseClass. called to improve situation for a watch item void updateSubItem(const WatchData &data); + void handleChildren(const WatchData &parent, const GdbMi &child, + QList<WatchData> *insertions); void updateWatchData(const WatchData &data); Q_SLOT void updateWatchDataHelper(const WatchData &data); void rebuildModel(); + bool showToolTip(); void insertData(const WatchData &data); void sendWatchParameters(const QByteArray ¶ms0); void createGdbVariable(const WatchData &data); - void maybeHandleInferiorPidChanged(const QString &pid); - - void tryLoadDebuggingHelpers(); - void tryQueryDebuggingHelpers(); - Q_SLOT void recheckDebuggingHelperAvailability(); void runDebuggingHelper(const WatchData &data, bool dumpChildren); void runDirectDebuggingHelper(const WatchData &data, bool dumpChildren); bool hasDebuggingHelperForType(const QString &type) const; void handleVarListChildren(const GdbResponse &response); + void handleVarListChildrenHelper(const GdbMi &child, + const WatchData &parent); void handleVarCreate(const GdbResponse &response); void handleVarAssign(const GdbResponse &response); void handleEvaluateExpression(const GdbResponse &response); @@ -393,53 +417,42 @@ private: void handleDebuggingHelperValue3(const GdbResponse &response); void handleDebuggingHelperEditValue(const GdbResponse &response); void handleDebuggingHelperSetup(const GdbResponse &response); + + void updateLocals(const QVariant &cookie = QVariant()); void handleStackListLocals(const GdbResponse &response); + WatchData localVariable(const GdbMi &item, + const QStringList &uninitializedVariables, + QMap<QByteArray, int> *seen); + void setLocals(const QList<GdbMi> &locals); void handleStackListArguments(const GdbResponse &response); - void handleVarListChildrenHelper(const GdbMi &child, - const WatchData &parent); void setWatchDataType(WatchData &data, const GdbMi &mi); void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi); - void setLocals(const QList<GdbMi> &locals); - void connectDebuggingHelperActions(); - void disconnectDebuggingHelperActions(); - AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp); - - bool startModeAllowsDumpers() const; - QString parseDisassembler(const GdbMi &lines); - int m_pendingRequests; QSet<QString> m_processedNames; - - QtDumperHelper m_dumperHelper; - - DebuggingHelperState m_debuggingHelperState; - QList<GdbMi> m_currentFunctionArgs; - QString m_currentFrame; QMap<QString, QString> m_varToType; - typedef void (GdbEngine::*CommandsDoneCallback)(); - // function called after all previous responses have been received - CommandsDoneCallback m_commandsDoneCallback; - void startInferior(); - - bool m_modulesListOutdated; - - QList<GdbCommand> m_commandsToRunOnTemporaryBreak; +private: ////////// Dumper Management ////////// - DebuggerStartParametersPtr m_startParameters; - // make sure to re-initialize new members in initializeVariables(); + bool startModeAllowsDumpers() const; + void tryLoadDebuggingHelpers(); + void tryQueryDebuggingHelpers(); + Q_SLOT void recheckDebuggingHelperAvailability(); + void connectDebuggingHelperActions(); + void disconnectDebuggingHelperActions(); + Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); + Q_SLOT void setUseDebuggingHelpers(const QVariant &on); - QSharedPointer<TrkOptions> m_trkOptions; + const bool m_dumperInjectionLoad; + DebuggingHelperState m_debuggingHelperState; + QtDumperHelper m_dumperHelper; - AbstractGdbAdapter *m_gdbAdapter; +private: ////////// Convenience Functions ////////// -public: QString errorMessage(QProcess::ProcessError error); void showMessageBox(int icon, const QString &title, const QString &text); void debugMessage(const QString &msg); - void addOptionPages(QList<Core::IOptionsPage*> *opts) const; - const DebuggerStartParameters &startParameters() const - { return *m_startParameters; } + QMainWindow *mainWindow() const; + }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index b1395f6439c2d41b3875be0d7c3784774e4b0e5e..9eb4da18b775e8d72af220eacced7fcce069925b 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -29,18 +29,13 @@ #include "plaingdbadapter.h" -#include "debuggeractions.h" #include "gdbengine.h" #include "procinterrupt.h" #include "debuggerstringutils.h" #include <utils/qtcassert.h> -#include <utils/fancymainwindow.h> -#include <coreplugin/icore.h> #include <QtCore/QFileInfo> -#include <QtCore/QVariant> -#include <QtGui/QMessageBox> namespace Debugger { namespace Internal { @@ -58,8 +53,6 @@ namespace Internal { PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) : AbstractGdbAdapter(engine, parent) { - commonInit(); - // Output connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)), engine, SLOT(readDebugeeOutput(QByteArray))); @@ -72,37 +65,27 @@ void PlainGdbAdapter::startAdapter() debugMessage(_("TRYING TO START ADAPTER")); QStringList gdbArgs; - gdbArgs.prepend(_("mi")); - gdbArgs.prepend(_("-i")); if (!m_outputCollector.listen()) { emit adapterStartFailed(tr("Cannot set up communication with child process: %1") .arg(m_outputCollector.errorString()), QString()); return; } - gdbArgs.prepend(_("--tty=") + m_outputCollector.serverName()); + gdbArgs.append(_("--tty=") + m_outputCollector.serverName()); if (!startParameters().workingDir.isEmpty()) - m_gdbProc.setWorkingDirectory(startParameters().workingDir); + m_engine->m_gdbProc.setWorkingDirectory(startParameters().workingDir); if (!startParameters().environment.isEmpty()) - m_gdbProc.setEnvironment(startParameters().environment); + m_engine->m_gdbProc.setEnvironment(startParameters().environment); - m_gdbProc.start(theDebuggerStringSetting(GdbLocation), gdbArgs); -} + if (!m_engine->startGdb(gdbArgs)) { + m_outputCollector.shutdown(); + return; + } -void PlainGdbAdapter::handleGdbStarted() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - setState(AdapterStarted); emit adapterStarted(); } -void PlainGdbAdapter::handleGdbError(QProcess::ProcessError error) -{ - debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR")); - emit adapterCrashed(m_engine->errorMessage(error)); -} - void PlainGdbAdapter::startInferior() { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); @@ -118,9 +101,7 @@ void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); if (response.resultClass == GdbResultDone) { - //m_breakHandler->clearBreakMarkers(); - setState(InferiorRunningRequested); - m_engine->postCommand(_("-exec-run"), GdbEngine::RunRequest, CB(handleExecRun)); + emit inferiorPrepared(); } else { QString msg = tr("Starting executable failed:\n") + __(response.data.findChild("msg").data()); @@ -128,6 +109,12 @@ void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) } } +void PlainGdbAdapter::startInferiorPhase2() +{ + setState(InferiorRunningRequested); + m_engine->postCommand(_("-exec-run"), GdbEngine::RunRequest, CB(handleExecRun)); +} + void PlainGdbAdapter::handleExecRun(const GdbResponse &response) { if (response.resultClass == GdbResultRunning) { @@ -160,74 +147,6 @@ void PlainGdbAdapter::shutdown() { debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state())); m_outputCollector.shutdown(); - switch (state()) { - - case InferiorRunningRequested: - case InferiorRunning: - case InferiorStopping: - case InferiorStopped: - setState(InferiorShuttingDown); - m_engine->postCommand(_("kill"), CB(handleKill)); - return; - - case InferiorShuttingDown: - // FIXME: How can we end up here? - QTC_ASSERT(false, qDebug() << state()); - // Fall through. - - case InferiorShutDown: - setState(AdapterShuttingDown); - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; - -/* - case InferiorShutdownFailed: - m_gdbProc.terminate(); - // 20s can easily happen when loading webkit debug information - m_gdbProc.waitForFinished(20000); - setState(AdapterShuttingDown); - debugMessage(_("FORCING TERMINATION: %1").arg(state())); - if (state() != QProcess::NotRunning) { - debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1") - .arg(state())); - m_gdbProc.kill(); - } - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; -*/ - default: - QTC_ASSERT(false, qDebug() << state()); - } -} - -void PlainGdbAdapter::handleKill(const GdbResponse &response) -{ - debugMessage(_("PLAIN ADAPTER HANDLE KILL " + response.toString())); - if (response.resultClass == GdbResultDone) { - setState(InferiorShutDown); - emit inferiorShutDown(); - shutdown(); // re-iterate... - } else { - const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); - setState(InferiorShutdownFailed); - emit inferiorShutdownFailed(msg); - } -} - -void PlainGdbAdapter::handleExit(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - // don't set state here, this will be handled in handleGdbFinished() - } else { - const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); - emit adapterShutdownFailed(msg); - } -} - -void PlainGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) -{ - debugMessage(_("GDB PROCESS FINISHED")); - emit adapterShutDown(); } } // namespace Internal diff --git a/src/plugins/debugger/gdb/plaingdbadapter.h b/src/plugins/debugger/gdb/plaingdbadapter.h index 52311b372b44e0a1099fa5a227ad5095308e26d8..41154640223c4bc45384d19b269cb60a903e4eab 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.h +++ b/src/plugins/debugger/gdb/plaingdbadapter.h @@ -31,11 +31,8 @@ #define DEBUGGER_PLAINGDBADAPTER_H #include "abstractgdbadapter.h" -#include "gdbengine.h" -#include "outputcollector.h" -#include <QtCore/QDebug> -#include <QtCore/QProcess> +#include <outputcollector.h> namespace Debugger { namespace Internal { @@ -57,19 +54,15 @@ public: void startAdapter(); void startInferior(); + void startInferiorPhase2(); void interruptInferior(); void shutdown(); + const char *inferiorShutdownCommand() const { return "kill"; } private: void handleFileExecAndSymbols(const GdbResponse &response); - void handleKill(const GdbResponse &response); - void handleExit(const GdbResponse &response); void handleExecRun(const GdbResponse &response); - Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus status); - Q_SLOT void handleGdbError(QProcess::ProcessError error); - Q_SLOT void handleGdbStarted(); - OutputCollector m_outputCollector; }; diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index 6b6e70b9c3585b4ea4d759082fe31db513f61a65..bf255592a6c4f9183ea4f78e206ea4ef8003cf35 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -28,8 +28,8 @@ **************************************************************************/ #include "remotegdbadapter.h" + #include "debuggerstringutils.h" -#include "debuggeractions.h" #include "gdbengine.h" #include <utils/qtcassert.h> @@ -54,8 +54,6 @@ namespace Internal { RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent) : AbstractGdbAdapter(engine, parent) { - commonInit(); - connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(uploadProcError(QProcess::ProcessError))); connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()), @@ -70,14 +68,6 @@ void RemoteGdbAdapter::startAdapter() setState(AdapterStarting); debugMessage(_("TRYING TO START ADAPTER")); - QStringList gdbArgs; - gdbArgs.prepend(_("mi")); - gdbArgs.prepend(_("-i")); - - QString location = startParameters().debuggerCommand; - if (location.isEmpty()) - location = theDebuggerStringSetting(GdbLocation); - // FIXME: make asynchroneous // Start the remote server if (startParameters().serverStartScript.isEmpty()) { @@ -88,33 +78,19 @@ void RemoteGdbAdapter::startAdapter() m_uploadProc.waitForStarted(); } - // Start the debugger - m_gdbProc.start(location, gdbArgs); -} + if (!m_engine->startGdb(QStringList(), startParameters().debuggerCommand)) + // FIXME: cleanup missing + return; -void RemoteGdbAdapter::handleGdbStarted() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - setState(AdapterStarted); emit adapterStarted(); } -void RemoteGdbAdapter::handleGdbError(QProcess::ProcessError error) -{ - debugMessage(_("ADAPTER, HANDLE GDB ERROR")); - emit adapterCrashed(m_engine->errorMessage(error)); - shutdown(); -} - void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error) { QString msg; switch (error) { case QProcess::FailedToStart: - msg = tr("The upload process failed to start. Either the " - "invoked script '%1' is missing, or you may have insufficient " - "permissions to invoke the program.") - .arg(theDebuggerStringSetting(GdbLocation)); + msg = tr("The upload process failed to start. Shell missing?"); break; case QProcess::Crashed: msg = tr("The upload process crashed some time after starting " @@ -140,7 +116,7 @@ void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error) } m_engine->showStatusMessage(msg); - QMessageBox::critical(m_engine->mainWindow(), tr("Error"), msg); + showMessageBox(QMessageBox::Critical, tr("Error"), msg); } void RemoteGdbAdapter::readUploadStandardOutput() @@ -211,7 +187,7 @@ void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record) // gdb server will stop the remote application itself. debugMessage(_("INFERIOR STARTED")); showStatusMessage(msgAttachedToStoppedInferior()); - m_engine->continueInferior(); + emit inferiorPrepared(); } else { // 16^error,msg="hd:5555: Connection timed out." QString msg = msgConnectRemoteServerFailed(__(record.data.findChild("msg").data())); @@ -219,63 +195,19 @@ void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record) } } -void RemoteGdbAdapter::interruptInferior() -{ - m_engine->postCommand(_("-exec-interrupt")); -} - -void RemoteGdbAdapter::shutdown() -{ - switch (state()) { - - case InferiorRunning: - case InferiorStopped: - setState(InferiorShuttingDown); - m_engine->postCommand(_("kill"), CB(handleKill)); - return; - - default: - QTC_ASSERT(false, qDebug() << state()); - // fall through - - case InferiorStartFailed: - case InferiorShutDown: - setState(AdapterShuttingDown); - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; - - } -} - -void RemoteGdbAdapter::handleKill(const GdbResponse &response) +void RemoteGdbAdapter::startInferiorPhase2() { - QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state()); - if (response.resultClass == GdbResultDone) { - setState(InferiorShutDown); - emit inferiorShutDown(); - shutdown(); // re-iterate... - } else { - QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); - setState(InferiorShutdownFailed); - emit inferiorShutdownFailed(msg); - } + m_engine->continueInferiorInternal(); } -void RemoteGdbAdapter::handleExit(const GdbResponse &response) +void RemoteGdbAdapter::interruptInferior() { - if (response.resultClass == GdbResultDone) { - // don't set state here, this will be handled in handleGdbFinished() - } else { - QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); - emit adapterShutdownFailed(msg); - } + m_engine->postCommand(_("-exec-interrupt")); } -void RemoteGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus) +void RemoteGdbAdapter::shutdown() { - debugMessage(_("GDB PROESS FINISHED")); - setState(DebuggerNotReady); - emit adapterShutDown(); + // FIXME: cleanup missing } } // namespace Internal diff --git a/src/plugins/debugger/gdb/remotegdbadapter.h b/src/plugins/debugger/gdb/remotegdbadapter.h index 75305bbd25c5058c8771d7fdac955c1a6e2a829d..fa7fab155f369d4012a237ca91fae85162fcdeba 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.h +++ b/src/plugins/debugger/gdb/remotegdbadapter.h @@ -31,10 +31,6 @@ #define DEBUGGER_REMOTEGDBADAPTER_H #include "abstractgdbadapter.h" -#include "gdbengine.h" - -#include <QtCore/QDebug> -#include <QtCore/QProcess> namespace Debugger { namespace Internal { @@ -56,6 +52,7 @@ public: void startAdapter(); void startInferior(); + void startInferiorPhase2(); void interruptInferior(); void shutdown(); @@ -67,12 +64,6 @@ private: void handleSetTargetAsync(const GdbResponse &response); void handleFileExecAndSymbols(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response); - void handleKill(const GdbResponse &response); - void handleExit(const GdbResponse &response); - - Q_SLOT void handleGdbStarted(); - Q_SLOT void handleGdbError(QProcess::ProcessError error); - Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus); QProcess m_uploadProc; }; diff --git a/src/plugins/debugger/gdb/termgdbadapter.cpp b/src/plugins/debugger/gdb/termgdbadapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c6d070eddc586ac6ea13c2054858bed78af53cd --- /dev/null +++ b/src/plugins/debugger/gdb/termgdbadapter.cpp @@ -0,0 +1,154 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "termgdbadapter.h" + +#include "gdbengine.h" +#include "procinterrupt.h" +#include "debuggerstringutils.h" + +#include <utils/qtcassert.h> +#include <coreplugin/icore.h> + +#include <QtGui/QMessageBox> + +namespace Debugger { +namespace Internal { + +#define CB(callback) \ + static_cast<GdbEngine::AdapterCallback>(&TermGdbAdapter::callback), \ + STRINGIFY(callback) + +/////////////////////////////////////////////////////////////////////// +// +// TermGdbAdapter +// +/////////////////////////////////////////////////////////////////////// + +TermGdbAdapter::TermGdbAdapter(GdbEngine *engine, QObject *parent) + : AbstractGdbAdapter(engine, parent) +{ + m_stubProc.setMode(Utils::ConsoleProcess::Debug); +#ifdef Q_OS_UNIX + m_stubProc.setSettings(Core::ICore::instance()->settings()); +#endif + + connect(&m_stubProc, SIGNAL(processError(QString)), SLOT(stubError(QString))); + connect(&m_stubProc, SIGNAL(processStarted()), SLOT(handleInferiorStarted())); + connect(&m_stubProc, SIGNAL(wrapperStopped()), SLOT(stubExited())); +} + +TermGdbAdapter::~TermGdbAdapter() +{ + m_stubProc.disconnect(); // Avoid spurious state transitions from late exiting stub +} + +void TermGdbAdapter::startAdapter() +{ + QTC_ASSERT(state() == EngineStarting, qDebug() << state()); + setState(AdapterStarting); + debugMessage(_("TRYING TO START ADAPTER")); + +// Currently, adapters are not re-used +// // We leave the console open, so recycle it now. +// m_stubProc.blockSignals(true); +// m_stubProc.stop(); +// m_stubProc.blockSignals(false); + + m_stubProc.setWorkingDirectory(startParameters().workingDir); + m_stubProc.setEnvironment(startParameters().environment); + // FIXME: Starting the stub implies starting the inferior. This is + // fairly unclean as far as the state machine and error reporting go. + if (!m_stubProc.start(startParameters().executable, + startParameters().processArgs)) { + // Error message for user is delivered via a signal. + emit adapterStartFailed(QString(), QString()); + return; + } + + if (!m_engine->startGdb()) { + m_stubProc.stop(); + return; + } +} + +void TermGdbAdapter::handleInferiorStarted() +{ + QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); + emit adapterStarted(); +} + +void TermGdbAdapter::startInferior() +{ + QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); + const qint64 attachedPID = m_stubProc.applicationPID(); + m_engine->handleInferiorPidChanged(attachedPID); + m_engine->postCommand(_("attach %1").arg(attachedPID), CB(handleStubAttached)); +} + +void TermGdbAdapter::handleStubAttached(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + QTC_ASSERT(state() == InferiorStopped, qDebug() << state()); + debugMessage(_("INFERIOR ATTACHED")); + emit inferiorPrepared(); + } else if (response.resultClass == GdbResultError) { + QString msg = _(response.data.findChild("msg").data()); + emit inferiorStartFailed(msg); + } +} + +void TermGdbAdapter::startInferiorPhase2() +{ + m_engine->continueInferiorInternal(); +} + +void TermGdbAdapter::interruptInferior() +{ + debugMessage(_("TRYING TO INTERUPT INFERIOR")); + const qint64 attachedPID = m_engine->inferiorPid(); + if (!interruptProcess(attachedPID)) + debugMessage(_("CANNOT INTERRUPT %1").arg(attachedPID)); +} + +void TermGdbAdapter::stubError(const QString &msg) +{ + showMessageBox(QMessageBox::Critical, tr("Debugger Error"), msg); +} + +void TermGdbAdapter::stubExited() +{ + debugMessage(_("STUB EXITED")); + if (state() != AdapterStarting // From previous instance + && state() != EngineShuttingDown && state() != DebuggerNotReady) + emit adapterCrashed(QString()); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/gdb/termgdbadapter.h b/src/plugins/debugger/gdb/termgdbadapter.h new file mode 100644 index 0000000000000000000000000000000000000000..11fb04a2c4cb03b9918fa934f36094377fc55fa6 --- /dev/null +++ b/src/plugins/debugger/gdb/termgdbadapter.h @@ -0,0 +1,74 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_TERMGDBADAPTER_H +#define DEBUGGER_TERMGDBADAPTER_H + +#include "abstractgdbadapter.h" + +#include <consoleprocess.h> + +namespace Debugger { +namespace Internal { + +/////////////////////////////////////////////////////////////////////// +// +// TermGdbAdapter +// +/////////////////////////////////////////////////////////////////////// + +class TermGdbAdapter : public AbstractGdbAdapter +{ + Q_OBJECT + +public: + TermGdbAdapter(GdbEngine *engine, QObject *parent = 0); + ~TermGdbAdapter(); + + bool dumpersAvailable() const { return true; } + + void startAdapter(); + void startInferior(); + void startInferiorPhase2(); + void interruptInferior(); + +private: + void handleStubAttached(const GdbResponse &response); + + Q_SLOT void handleInferiorStarted(); + Q_SLOT void stubExited(); + Q_SLOT void stubError(const QString &msg); + + Utils::ConsoleProcess m_stubProc; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_TERMGDBADAPTER_H diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index bd32a388104eaa5f54a8f9cdbfef5c424a89a6e0..c62a31b9678dfd0f6872c2553a378cd11e3f82f8 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -30,10 +30,17 @@ #include "trkgdbadapter.h" #include "trkoptions.h" #include "trkoptionspage.h" + #include "debuggerstringutils.h" #ifndef STANDALONE_RUNNER #include "gdbengine.h" #endif + +#include <utils/qtcassert.h> + +#include <QtCore/QTimer> +#include <QtCore/QDir> + #ifdef Q_OS_WIN # include <windows.h> #else @@ -41,11 +48,6 @@ # include <unistd.h> #endif -#include <utils/qtcassert.h> - -#include <QtCore/QTimer> -#include <QtCore/QDir> - #define CB(callback) \ static_cast<GdbEngine::AdapterCallback>(&TrkGdbAdapter::callback), \ STRINGIFY(callback) @@ -204,10 +206,6 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) : #endif m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset); - commonInit(); - connect(&m_gdbProc, SIGNAL(stateChanged(QProcess::ProcessState)), - this, SLOT(handleGdbStateChanged(QProcess::ProcessState))); - connect(&m_rfcommProc, SIGNAL(readyReadStandardError()), this, SLOT(handleRfcommReadyReadStandardError())); connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), @@ -380,17 +378,6 @@ QByteArray TrkGdbAdapter::trkInterruptMessage() return ba; } -void TrkGdbAdapter::emitDelayedAdapterStartFailed(const QString &msg) -{ - m_adapterFailMessage = msg; - QTimer::singleShot(0, this, SLOT(slotEmitDelayedAdapterStartFailed())); -} - -void TrkGdbAdapter::slotEmitDelayedAdapterStartFailed() -{ - emit adapterStartFailed(m_adapterFailMessage, TrkOptionsPage::settingsId()); -} - void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg) { m_adapterFailMessage = msg; @@ -428,6 +415,7 @@ void TrkGdbAdapter::waitForTrkConnect() } m_trkDevice.sendTrkInitialPing(); + sendTrkMessage(0x02); // Disconnect, as trk might be still connected sendTrkMessage(0x01); // Connect sendTrkMessage(0x05, TrkCB(handleSupportMask)); sendTrkMessage(0x06, TrkCB(handleCpuType)); @@ -437,7 +425,7 @@ void TrkGdbAdapter::waitForTrkConnect() // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File - maybeAdapterStarted(); + emit adapterStarted(); } void TrkGdbAdapter::logMessage(const QString &msg) @@ -1527,52 +1515,6 @@ void TrkGdbAdapter::interruptInferior() sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting..."); } -void TrkGdbAdapter::handleGdbError(QProcess::ProcessError error) -{ - if (error == QProcess::FailedToStart) { - const QString msg = QString::fromLatin1("GDB: Cannot start '%1': %2. Please check the settings.").arg(m_options->gdb).arg(m_gdbProc.errorString()); - emitDelayedAdapterStartFailed(msg); // Emitted from QProcess::start() on Windows - } else { - // Others should trigger handleGdbFinished - const QString msg = QString::fromLatin1("GDB: Process error %1: %2").arg(error).arg(m_gdbProc.errorString()); - logMessage(msg); - } -} - -void TrkGdbAdapter::handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - const QString msg = exitStatus == QProcess::NormalExit ? - QString::fromLatin1("GDB: Process finished (exit code: %1).").arg(exitCode) : - QString::fromLatin1("GDB: Process crashed: %1").arg(m_gdbProc.errorString()); - if (state() == AdapterStarting) { - emitDelayedAdapterStartFailed(msg);// Potentially emitted from QProcess::start() on Windows - } else { - logMessage(msg); - setState(DebuggerNotReady); - emit adapterShutDown(); - } -} - -void TrkGdbAdapter::handleGdbStarted() -{ - logMessage(QString("GDB: Process Started")); - maybeAdapterStarted(); -} - -void TrkGdbAdapter::maybeAdapterStarted() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - if (m_gdbProc.state() == QProcess::Running && m_trkDevice.isOpen()) { - setState(AdapterStarted); - emit adapterStarted(); - } -} - -void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState) -{ - logMessage(_("GDB: Process State %1").arg(newState)); -} - void TrkGdbAdapter::startAdapter() { // Retrieve parameters @@ -1634,13 +1576,12 @@ void TrkGdbAdapter::startAdapter() connect(m_gdbServer, SIGNAL(newConnection()), this, SLOT(handleGdbConnection())); - logMessage("STARTING GDB"); - logMessage(_("### Starting gdb %1").arg(m_options->gdb)); QStringList gdbArgs; gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file - gdbArgs.append(QLatin1String("-i")); - gdbArgs.append(QLatin1String("mi")); - m_gdbProc.start(m_options->gdb, gdbArgs); + if (!m_engine->startGdb(gdbArgs, m_options->gdb)) { + cleanup(); + return; + } waitForTrkConnect(); } @@ -1701,8 +1642,7 @@ void TrkGdbAdapter::handleTargetRemote(const GdbResponse &record) { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); if (record.resultClass == GdbResultDone) { - setState(InferiorRunningRequested); - m_engine->postCommand(_("-exec-continue"), GdbEngine::RunRequest, CB(handleFirstContinue)); + emit inferiorPrepared(); } else { QString msg = tr("Connecting to trk server adapter failed:\n") + _(record.data.findChild("msg").data()); @@ -1710,15 +1650,9 @@ void TrkGdbAdapter::handleTargetRemote(const GdbResponse &record) } } -void TrkGdbAdapter::handleFirstContinue(const GdbResponse &record) +void TrkGdbAdapter::startInferiorPhase2() { - QTC_ASSERT(state() == InferiorRunning, qDebug() << state()); - if (record.resultClass == GdbResultDone) { - debugMessage(_("INFERIOR STARTED")); - showStatusMessage(msgInferiorRunning()); - } else { - emit inferiorStartFailed(msgConnectRemoteServerFailed(record.toString())); - } + m_engine->continueInferiorInternal(); } // @@ -1794,7 +1728,7 @@ void TrkGdbAdapter::write(const QByteArray &data) trkReadMemoryMessage(m_session.dataseg, 12)); return; } - m_gdbProc.write(data); + m_engine->m_gdbProc.write(data); } uint oldPC; @@ -1992,79 +1926,7 @@ void TrkGdbAdapter::cleanup() void TrkGdbAdapter::shutdown() { - switch (state()) { - case AdapterStarting: - case AdapterStartFailed: - cleanup(); - setState(DebuggerNotReady); - return; - - case InferiorStopping: - case InferiorRunningRequested: - case InferiorRunning: - //sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting..."); - // Fall through. - - case InferiorStopped: - //sendTrkMessage(0x41, TrkCallback(), trkDeleteProcessMessage(), "Delete process"); - //sendTrkMessage(0x02, TrkCB(handleDisconnect)); - setState(InferiorShuttingDown); - m_engine->postCommand(_("kill"), CB(handleKill)); - return; - - case InferiorShutDown: - setState(AdapterShuttingDown); - cleanup(); - m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit)); - return; - -/* - if (m_options->mode == TrkOptions::BlueTooth - && m_rfcommProc.state() == QProcess::Running) - m_rfcommProc.kill(); - m_rfcommProc.terminate(); - m_rfcommProc.write(ba); - m_rfcommProc.terminate(); - m_rfcommProc.waitForFinished(); - - m_gdbProc.kill(); - m_gdbProc.terminate(); - - QByteArray ba; - ba.append(0x03); - QProcess proc; - proc.start("rfcomm release " + m_options->blueToothDevice); - proc.waitForFinished(); - m_gdbProc.waitForFinished(msecs); -*/ - - default: - QTC_ASSERT(false, qDebug() << state()); - } -} - -void TrkGdbAdapter::handleKill(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - setState(InferiorShutDown); - emit inferiorShutDown(); - shutdown(); // re-iterate... - } else { - const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); - setState(InferiorShutdownFailed); - emit inferiorShutdownFailed(msg); - } -} - -void TrkGdbAdapter::handleExit(const GdbResponse &response) -{ - if (response.resultClass == GdbResultDone) { - qDebug() << "EXITED, NO MESSAGE..."; - // don't set state here, this will be handled in handleGdbFinished() - } else { - const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); - emit adapterShutdownFailed(msg); - } + cleanup(); } } // namespace Internal diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index 5e2e4939a4252927db29ea8d02156f56a459b1ee..9bc68b430981f39ea246d85622b238f4c07b8a80 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -30,10 +30,11 @@ #ifndef DEBUGGER_TRKGDBADAPTER_H #define DEBUGGER_TRKGDBADAPTER_H +#include "abstractgdbadapter.h" + #include "trkutils.h" #include "trkdevice.h" #include "trkoptions.h" -#include "abstractgdbadapter.h" #include <QtCore/QHash> #include <QtCore/QPointer> @@ -163,8 +164,6 @@ public: // void start(const QString &program, const QStringList &args, QIODevice::OpenMode mode = QIODevice::ReadWrite); - QByteArray readAllStandardError(); - QByteArray readAllStandardOutput(); void write(const QByteArray &data); bool isTrkAdapter() const { return true; } bool dumpersAvailable() const { return false; } @@ -172,19 +171,16 @@ public: private: void startAdapter(); void startInferior(); + void startInferiorPhase2(); void interruptInferior(); void shutdown(); + void cleanup(); - void emitDelayedAdapterStartFailed(const QString &msg); - Q_SLOT void slotEmitDelayedAdapterStartFailed(); void emitDelayedInferiorStartFailed(const QString &msg); Q_SLOT void slotEmitDelayedInferiorStartFailed(); Q_SLOT void waitForTrkConnect(); - void handleKill(const GdbResponse &response); - void handleExit(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response); - void handleFirstContinue(const GdbResponse &response); // // TRK @@ -285,13 +281,6 @@ private: bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); void tryAnswerGdbMemoryRequest(bool buffered); - Q_SLOT void handleGdbError(QProcess::ProcessError error); - Q_SLOT void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus); - Q_SLOT void handleGdbStarted(); - Q_SLOT void handleGdbStateChanged(QProcess::ProcessState newState); - - void maybeAdapterStarted(); - void logMessage(const QString &msg); // triggers output() if m_verbose Q_SLOT void trkLogMessage(const QString &msg); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 619ac2bddb9ea596f3978c089d6dfbc91d8cae1e..7766b73b7c276f0a1c01d972d981ca37fee1837b 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -123,7 +123,7 @@ public: protected: void showStatusMessage(const QString &msg, int timeout = -1); DebuggerState state() const; - void setState(DebuggerState state); + void setState(DebuggerState state, bool forced = false); DebuggerManager *manager() const { return m_manager; } DebuggerManager *m_manager; diff --git a/src/plugins/debugger/stackframe.h b/src/plugins/debugger/stackframe.h index 3a0e415e1f21f9b1cd88eb1f32b65c3e428e8f50..8e5771f7060061fedc1266c14f607300045e8ee0 100644 --- a/src/plugins/debugger/stackframe.h +++ b/src/plugins/debugger/stackframe.h @@ -33,12 +33,17 @@ #include <QtCore/QString> #include <QtCore/QMetaType> +QT_BEGIN_NAMESPACE +class QDebug; +QT_END_NAMESPACE + namespace Debugger { namespace Internal { struct StackFrame { StackFrame(); + void clear(); bool isUsable() const; QString toToolTip() const; QString toString() const; @@ -52,6 +57,8 @@ struct StackFrame QString address; }; +QDebug operator<<(QDebug d, const StackFrame &); + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 2d9cbea92d7073b1a015bb819115945a63ff4e19..ec47a02b1591252e8befd053ee784b9e0851d7a7 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -37,12 +37,23 @@ #include <QtCore/QDebug> #include <QtCore/QFileInfo> -using namespace Debugger::Internal; +namespace Debugger { +namespace Internal { StackFrame::StackFrame() : level(0), line(0) {} +void StackFrame::clear() +{ + line = level = 0; + function.clear(); + file.clear(); + from.clear(); + to.clear(); + address.clear(); +} + bool StackFrame::isUsable() const { return !file.isEmpty() && QFileInfo(file).isReadable(); @@ -52,12 +63,12 @@ QString StackFrame::toString() const { QString res; QTextStream str(&res); - str << StackHandler::tr("Address:") << " " << address << " " - << StackHandler::tr("Function:") << " " << function << " " - << StackHandler::tr("File:") << " " << file << " " - << StackHandler::tr("Line:") << " " << line << " " - << StackHandler::tr("From:") << " " << from << " " - << StackHandler::tr("To:") << " " << to; + str << StackHandler::tr("Address:") << ' ' << address << ' ' + << StackHandler::tr("Function:") << ' ' << function << ' ' + << StackHandler::tr("File:") << ' ' << file << ' ' + << StackHandler::tr("Line:") << ' ' << line << ' ' + << StackHandler::tr("From:") << ' ' << from << ' ' + << StackHandler::tr("To:") << ' ' << to; return res; } @@ -76,6 +87,23 @@ QString StackFrame::toToolTip() const return res; } +QDebug operator<<(QDebug d, const StackFrame &f) +{ + QString res; + QTextStream str(&res); + str << "level=" << f.level << " address=" << f.address; + if (!f.function.isEmpty()) + str << ' ' << f.function; + if (!f.file.isEmpty()) + str << ' ' << f.file << ':' << f.line; + if (!f.from.isEmpty()) + str << " from=" << f.from; + if (!f.to.isEmpty()) + str << " to=" << f.to; + d.nospace() << res; + return d; +} + //////////////////////////////////////////////////////////////////////// // // StackHandler @@ -379,3 +407,5 @@ void ThreadsHandler::notifyRunning() it->notifyRunning(); emit dataChanged(index(0, 1), index(m_threads.size()- 1, ColumnCount - 1)); } +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/threadswindow.cpp b/src/plugins/debugger/threadswindow.cpp index 5e19966895336f90e59530de6807b8dc5f1e5f12..a004a9d59acb3557691879991fc4ca8c99a9d02d 100644 --- a/src/plugins/debugger/threadswindow.cpp +++ b/src/plugins/debugger/threadswindow.cpp @@ -30,18 +30,11 @@ #include "threadswindow.h" #include "debuggeractions.h" -#include "stackhandler.h" -#include <utils/qtcassert.h> - -#include <QAction> -#include <QComboBox> -#include <QDebug> -#include <QHeaderView> -#include <QMenu> -#include <QResizeEvent> -#include <QTreeView> -#include <QVBoxLayout> +#include <QtGui/QAction> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QHeaderView> +#include <QtGui/QMenu> using Debugger::Internal::ThreadsWindow; @@ -63,46 +56,38 @@ ThreadsWindow::ThreadsWindow(QWidget *parent) this, SLOT(setAlternatingRowColorsHelper(bool))); } -void ThreadsWindow::resizeEvent(QResizeEvent *event) -{ - //QHeaderView *hv = header(); - //int totalSize = event->size().width() - 120; - //hv->resizeSection(0, 45); - //hv->resizeSection(1, totalSize); - //hv->resizeSection(2, 55); - QTreeView::resizeEvent(event); -} - void ThreadsWindow::rowActivated(const QModelIndex &index) { - //qDebug() << "ACTIVATED: " << index.row() << index.column(); emit threadSelected(index.row()); } void ThreadsWindow::contextMenuEvent(QContextMenuEvent *ev) { QMenu menu; - QAction *act1 = menu.addAction(tr("Adjust column widths to contents")); - QAction *act2 = menu.addAction(tr("Always adjust column widths to contents")); - act2->setCheckable(true); - act2->setChecked(m_alwaysResizeColumnsToContents); - + QAction *adjustColumnAction = menu.addAction(tr("Adjust column widths to contents")); + QAction *alwaysAdjustColumnAction = menu.addAction(tr("Always adjust column widths to contents")); + alwaysAdjustColumnAction->setCheckable(true); + alwaysAdjustColumnAction->setChecked(m_alwaysResizeColumnsToContents); menu.addSeparator(); menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); + if(!act) + return; - if (act == act1) + if (act == adjustColumnAction) { resizeColumnsToContents(); - else if (act == act2) + } else if (act == alwaysAdjustColumnAction) { setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents); + } } void ThreadsWindow::resizeColumnsToContents() { - resizeColumnToContents(0); - //resizeColumnToContents(1); + const int columnCount = model()->columnCount(); + for (int c = 0 ; c < columnCount; c++) + resizeColumnToContents(c); } void ThreadsWindow::setAlwaysResizeColumnsToContents(bool on) @@ -111,6 +96,4 @@ void ThreadsWindow::setAlwaysResizeColumnsToContents(bool on) QHeaderView::ResizeMode mode = on ? QHeaderView::ResizeToContents : QHeaderView::Interactive; header()->setResizeMode(0, mode); - //header()->setResizeMode(1, mode); } - diff --git a/src/plugins/debugger/threadswindow.h b/src/plugins/debugger/threadswindow.h index b794b0eef65410c4d2dd9e4ac0b9a1fd40cf6a3c..0d47e3687cbbe1b40dd02cc6921501d825696f86 100644 --- a/src/plugins/debugger/threadswindow.h +++ b/src/plugins/debugger/threadswindow.h @@ -54,7 +54,6 @@ private slots: void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); } private: - void resizeEvent(QResizeEvent *ev); void contextMenuEvent(QContextMenuEvent *ev); bool m_alwaysResizeColumnsToContents; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index a0f524abcab44ea2b73ef8c184a43216e7ffd288..6b774591764af421b61abff2fa1e2f0017a9fe6b 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -105,6 +105,7 @@ WatchData::WatchData() : generation(-1), valueEnabled(true), valueEditable(true), + error(false), source(0), state(InitialState), changed(false) @@ -127,7 +128,8 @@ bool WatchData::isEqual(const WatchData &other) const && framekey == other.framekey && hasChildren == other.hasChildren && valueEnabled == other.valueEnabled - && valueEditable == other.valueEditable; + && valueEditable == other.valueEditable + && error == other.error; } void WatchData::setError(const QString &msg) @@ -137,6 +139,7 @@ void WatchData::setError(const QString &msg) setHasChildren(false); valueEnabled = false; valueEditable = false; + error = true; } void WatchData::setValue(const QString &value0) @@ -232,6 +235,8 @@ QString WatchData::toString() const str << "iname=\"" << iname << doubleQuoteComma; if (!name.isEmpty() && name != iname) str << "name=\"" << name << doubleQuoteComma; + if (error) + str << "error,"; if (!addr.isEmpty()) str << "addr=\"" << addr << doubleQuoteComma; if (!exp.isEmpty()) @@ -310,6 +315,19 @@ QString WatchData::toToolTip() const return res; } +QString WatchData::msgNotInScope() +{ + static const QString rc = QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>"); + return rc; +} + +QString WatchData::shadowedName(const QString &name, int seen) +{ + if (seen <= 0) + return name; + return QCoreApplication::translate("Debugger::Internal::WatchData", "%1 <shadowed %2>").arg(name).arg(seen); +} + /////////////////////////////////////////////////////////////////////// // // WatchModel @@ -590,9 +608,10 @@ void WatchModel::fetchMore(const QModelIndex &index) QTC_ASSERT(index.isValid(), return); QTC_ASSERT(!watchItem(index)->fetchTriggered, return); if (WatchItem *item = watchItem(index)) { + m_handler->m_expandedINames.insert(item->iname); item->fetchTriggered = true; - WatchData data = *item; if (item->children.isEmpty()) { + WatchData data = *item; data.setChildrenNeeded(); m_handler->m_manager->updateWatchData(data); } @@ -771,10 +790,13 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro { WatchItem &data = *watchItem(index); if (role == ExpandedRole) { - if (value.toBool()) + if (value.toBool()) { + // Should already have been triggered by fetchMore() + QTC_ASSERT(m_handler->m_expandedINames.contains(data.iname), /**/); m_handler->m_expandedINames.insert(data.iname); - else + } else { m_handler->m_expandedINames.remove(data.iname); + } } else if (role == TypeFormatRole) { m_handler->setFormat(data.type, value.toInt()); } else if (role == IndividualFormatRole) { diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index dc426f4e22de74d5f28256a0cbfc1c55b74f6b79..155d1de4116acca6962451e243c32e12775ef335 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -117,6 +117,9 @@ public: bool isEqual(const WatchData &other) const; + static QString msgNotInScope(); + static QString shadowedName(const QString &name, int seen); + public: QString iname; // internal name sth like 'local.baz.public.a' QString exp; // the expression @@ -135,6 +138,7 @@ public: int generation; // when updated? bool valueEnabled; // value will be greyed out or not bool valueEditable; // value will be editable + bool error; private: diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 6fe9256b74490a93add2977eecd4c534fece47f9..55e03207bdb65d8a1bda5e6134e6760f06205164 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -43,6 +43,9 @@ #include <cpptools/cpptoolsconstants.h> #include <cplusplus/ExpressionUnderCursor.h> +#include <cplusplus/Overview.h> +#include <Symbols.h> +#include <Scope.h> #include <extensionsystem/pluginmanager.h> @@ -51,6 +54,7 @@ #include <QtCore/QStringList> #include <QtCore/QCoreApplication> #include <QtCore/QTextStream> +#include <QtCore/QHash> #include <QtGui/QTextCursor> #include <QtGui/QPlainTextEdit> @@ -59,6 +63,78 @@ #include <ctype.h> enum { debug = 0 }; + +// Debug helpers for code model. @todo: Move to some CppTools library? +namespace CPlusPlus { + +static void debugCppSymbolRecursion(QTextStream &str, const Overview &o, + const Symbol &s, bool doRecurse = true, + int recursion = 0) +{ + for (int i = 0; i < recursion; i++) + str << " "; + str << "Symbol: " << o.prettyName(s.name()) << " at line " << s.line(); + if (s.isFunction()) + str << " function"; + if (s.isClass()) + str << " class"; + if (s.isDeclaration()) + str << " declaration"; + if (s.isBlock()) + str << " block"; + if (doRecurse && s.isScopedSymbol()) { + const ScopedSymbol *scoped = s.asScopedSymbol(); + const int size = scoped->memberCount(); + str << " scoped symbol of " << size << '\n'; + for (int m = 0; m < size; m++) + debugCppSymbolRecursion(str, o, *scoped->memberAt(m), true, recursion + 1); + } else { + str << '\n'; + } +} + +QDebug operator<<(QDebug d, const Symbol &s) +{ + QString output; + CPlusPlus::Overview o; + QTextStream str(&output); + debugCppSymbolRecursion(str, o, s, true, 0); + d.nospace() << output; + return d; +} + +QDebug operator<<(QDebug d, const Scope &scope) +{ + QString output; + Overview o; + QTextStream str(&output); + const int size = scope.symbolCount(); + str << "Scope of " << size; + if (scope.isNamespaceScope()) + str << " namespace"; + if (scope.isClassScope()) + str << " class"; + if (scope.isEnumScope()) + str << " enum"; + if (scope.isBlockScope()) + str << " block"; + if (scope.isFunctionScope()) + str << " function"; + if (scope.isPrototypeScope()) + str << " prototype"; + if (const Symbol *owner = scope.owner()) { + str << " owner: "; + debugCppSymbolRecursion(str, o, *owner, false, 0); + } else { + str << " 0-owner\n"; + } + for (int s = 0; s < size; s++) + debugCppSymbolRecursion(str, o, *scope.symbolAt(s), true, 2); + d.nospace() << output; + return d; +} +} // namespace CPlusPlus + namespace Debugger { namespace Internal { @@ -217,6 +293,135 @@ QString stripPointerType(QString type) return type; } +/* getUninitializedVariables(): Get variables that are not initialized + * at a certain line of a function from the code model to be able to + * indicate them as not in scope in the locals view. + * Find document + function in the code model, do a double check and + * collect declarative symbols that are in the function past or on + * the current line. blockRecursion() recurses up the scopes + * and collect symbols declared past or on the current line. + * Recursion goes up from the innermost scope, keeping a map + * of occurrences seen, to be able to derive the names of + * shadowed variables as the debugger sees them: +\code +int x; // Occurrence (1), should be reported as "x <shadowed 1>" +if (true) { + int x = 5; (2) // Occurrence (2), should be reported as "x" +} +\endcode + */ + +typedef QHash<QString, int> SeenHash; + +static void blockRecursion(const CPlusPlus::Overview &overview, + const CPlusPlus::Scope *scope, + unsigned line, + QStringList *uninitializedVariables, + SeenHash *seenHash, + int level = 0) +{ + const int size = scope->symbolCount(); + for (int s = 0; s < size; s++){ + const CPlusPlus::Symbol *symbol = scope->symbolAt(s); + if (symbol->isDeclaration()) { + // Find out about shadowed symbols by bookkeeping + // the already seen occurrences in a hash. + const QString name = overview.prettyName(symbol->name()); + SeenHash::iterator it = seenHash->find(name); + if (it == seenHash->end()) { + it = seenHash->insert(name, 0); + } else { + ++(it.value()); + } + // Is the declaration on or past the current line, that is, + // the variable not initialized. + if (symbol->line() >= line) + uninitializedVariables->push_back(WatchData::shadowedName(name, it.value())); + } + } + // Next block scope. + if (const CPlusPlus::Scope *enclosingScope = scope->enclosingBlockScope()) + blockRecursion(overview, enclosingScope, line, uninitializedVariables, seenHash, level + 1); +} + +// Inline helper with integer error return codes. +static inline +int getUninitializedVariablesI(const CPlusPlus::Snapshot &snapshot, + const QString &functionName, + const QString &file, + int line, + QStringList *uninitializedVariables) +{ + uninitializedVariables->clear(); + // Find document + if (snapshot.empty() || functionName.isEmpty() || file.isEmpty() || line < 1) + return 1; + const CPlusPlus::Snapshot::ConstIterator docIt = snapshot.constFind(file); + if (docIt == snapshot.constEnd()) + return 2; + const CPlusPlus::Document::Ptr doc = docIt.value(); + // Look at symbol at line and find its function. Either it is the + // function itself or some expression/variable. + const CPlusPlus::Symbol *symbolAtLine = doc->findSymbolAt(line, 0); + if (!symbolAtLine) + return 4; + // First figure out the function to do a safety name check + // and the innermost scope at cursor position + const CPlusPlus::Function *function = 0; + const CPlusPlus::Scope *innerMostScope = 0; + if (symbolAtLine->isFunction()) { + function = symbolAtLine->asFunction(); + if (function->memberCount() == 1) // Skip over function block + if (CPlusPlus::Block *block = function->memberAt(0)->asBlock()) + innerMostScope = block->members(); + } else { + if (const CPlusPlus::Scope *functionScope = symbolAtLine->enclosingFunctionScope()) { + function = functionScope->owner()->asFunction(); + innerMostScope = symbolAtLine->isBlock() ? + symbolAtLine->asBlock()->members() : + symbolAtLine->enclosingBlockScope(); + } + } + if (!function || !innerMostScope) + return 7; + // Compare function names with a bit off fuzz, + // skipping modules from a CDB symbol "lib!foo" or namespaces + // that the code model does not show at this point + CPlusPlus::Overview overview; + const QString name = overview.prettyName(function->name()); + if (!functionName.endsWith(name)) + return 11; + if (functionName.size() > name.size()) { + const char previousChar = functionName.at(functionName.size() - name.size() - 1).toLatin1(); + if (previousChar != ':' && previousChar != '!' ) + return 11; + } + // Starting from the innermost block scope, collect declarations. + SeenHash seenHash; + blockRecursion(overview, innerMostScope, line, uninitializedVariables, &seenHash); + return 0; +} + +bool getUninitializedVariables(const CPlusPlus::Snapshot &snapshot, + const QString &function, + const QString &file, + int line, + QStringList *uninitializedVariables) +{ + const int rc = getUninitializedVariablesI(snapshot, function, file, line, uninitializedVariables); + if (debug) { + QString msg; + QTextStream str(&msg); + str << "getUninitializedVariables() " << function << ' ' << file << ':' << line + << " returns (int) " << rc << " '" + << uninitializedVariables->join(QString(QLatin1Char(','))) << '\''; + if (rc) + str << " of " << snapshot.keys().size() << " documents"; + qDebug() << msg; + } + return rc == 0; +} + QString gdbQuoteTypes(const QString &type) { // gdb does not understand sizeof(Core::IFile*). diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 9cbb65948138a8c1cade2b7e807048743ffd7911..c7cf4bfdbed8ef7465fbc9c85abbcd3de9bc15fe 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -45,6 +45,10 @@ namespace Core { class IEditor; } +namespace CPlusPlus { + class Snapshot; +} + namespace Debugger { namespace Internal { @@ -89,6 +93,15 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, // Decode string data as returned by the dumper helpers. QString decodeData(const QByteArray &baIn, int encoding); +// Get variables that are not initialized at a certain line +// of a function from the code model. Shadowed variables will +// be reported using the debugger naming conventions '<shadowed n>' +bool getUninitializedVariables(const CPlusPlus::Snapshot &snapshot, + const QString &function, + const QString &file, + int line, + QStringList *uninitializedVariables); + /* Attempt to put common code of the dumper handling into a helper * class. * "Custom dumper" is a library compiled against the current diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 5cf8f4ff53431f27ce17188ea109b3216f83f58b..b4c7a55afff557c60b03a0635352df17aaf76817 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -136,10 +136,10 @@ WatchWindow::WatchWindow(Type type, DebuggerManager *manager, QWidget *parent) connect(act, SIGNAL(toggled(bool)), this, SLOT(setAlternatingRowColorsHelper(bool))); - connect(this, SIGNAL(expanded(QModelIndex)), - this, SLOT(expandNode(QModelIndex))); - connect(this, SIGNAL(collapsed(QModelIndex)), - this, SLOT(collapseNode(QModelIndex))); + connect(this, SIGNAL(expanded(QModelIndex)), + this, SLOT(expandNode(QModelIndex))); + connect(this, SIGNAL(collapsed(QModelIndex)), + this, SLOT(collapseNode(QModelIndex))); } void WatchWindow::expandNode(const QModelIndex &idx) @@ -253,10 +253,11 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) QAction *actInsertNewWatchItem = menu.addAction(tr("Insert new watch item")); QAction *actSelectWidgetToWatch = menu.addAction(tr("Select widget to watch")); + const bool actionsEnabled = m_manager->debuggerActionsEnabled(); const QString address = model()->data(mi0, AddressRole).toString(); QAction *actWatchKnownMemory = 0; QAction *actWatchUnknownMemory = new QAction(tr("Open memory editor..."), &menu); - actWatchUnknownMemory->setEnabled(m_manager->debuggerActionsEnabled()); + actWatchUnknownMemory->setEnabled(actionsEnabled); if (!address.isEmpty()) actWatchKnownMemory = new QAction(tr("Open memory editor at %1").arg(address), &menu); @@ -276,7 +277,9 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(theDebuggerAction(RecheckDebuggingHelpers)); menu.addAction(theDebuggerAction(UseDebuggingHelpers)); - + QAction *actClearCodeModelSnapshot = new QAction(tr("Refresh code model snapshot"), &menu); + actClearCodeModelSnapshot->setEnabled(actionsEnabled && theDebuggerAction(UseCodeModel)->isChecked()); + menu.addAction(actClearCodeModelSnapshot); menu.addSeparator(); menu.addAction(theDebuggerAction(UseToolTipsInLocalsView)); @@ -311,6 +314,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) } else if (act == actSelectWidgetToWatch) { grabMouse(Qt::CrossCursor); m_grabbing = true; + } else if (act == actClearCodeModelSnapshot) { + m_manager->clearCppCodeModelSnapshot(); } else { for (int i = 0; i != alternativeFormats.size(); ++i) { if (act == typeFormatActions.at(i)) diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index c74581df6af5eef12b0aaf96e068d9ce7208ed34..43606da69f9b0950e0ff3abd7fd008941c03287c 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -670,6 +670,7 @@ void S60DeviceRunControlBase::signsisProcessFinished() } m_launcher = new trk::Launcher(); connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished())); + connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString))); connect(m_launcher, SIGNAL(copyingStarted()), this, SLOT(printCopyingNotice())); connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(printCreateFileFailed(QString,QString))); connect(m_launcher, SIGNAL(canNotWriteFile(QString,QString)), this, SLOT(printWriteFileFailed(QString,QString))); @@ -713,6 +714,11 @@ void S60DeviceRunControlBase::printCloseFileFailed(const QString &filename, cons emit addToOutputWindow(this, msg.arg(filename, errorMessage)); } +void S60DeviceRunControlBase::printConnectFailed(const QString &errorMessage) +{ + emit addToOutputWindow(this, tr("Could not connect to App TRK on device: %1. Restarting App TRK might help.").arg(errorMessage)); +} + void S60DeviceRunControlBase::printCopyingNotice() { emit addToOutputWindow(this, tr("Copying install file...")); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h index aa8ce4db86913511877c27efb66ee3dffbc9eb2a..775804cb201781bac4ac2a142e7c63571792d62c 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h @@ -180,6 +180,7 @@ private slots: void makesisProcessFinished(); void signsisProcessFailed(); void signsisProcessFinished(); + void printConnectFailed(const QString &errorMessage); void printCopyingNotice(); void printCreateFileFailed(const QString &filename, const QString &errorMessage); void printWriteFileFailed(const QString &filename, const QString &errorMessage); diff --git a/src/shared/cplusplus/AST.cpp b/src/shared/cplusplus/AST.cpp index 21e8a1504c014fe5e27de1fc12d9eacc895c77ec..babf8380c5bcf8b5c0c656de07a4166ce6db7334 100644 --- a/src/shared/cplusplus/AST.cpp +++ b/src/shared/cplusplus/AST.cpp @@ -54,7 +54,7 @@ #include <cstddef> #include <algorithm> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; AST::AST() { } @@ -2493,4 +2493,4 @@ unsigned ObjCSynchronizedStatementAST::lastToken() const return synchronized_token + 1; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h index 4af1971e2ee357522755d2dfcb0e087ad155c068..05a78b08322ea48c6d3b0191ee7acd6d2c49fd7b 100644 --- a/src/shared/cplusplus/AST.h +++ b/src/shared/cplusplus/AST.h @@ -53,8 +53,8 @@ #include "ASTfwd.h" #include "MemoryPool.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { template <typename _Tp> class List: public Managed @@ -3168,7 +3168,7 @@ protected: virtual void accept0(ASTVisitor *visitor); }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_AST_H diff --git a/src/shared/cplusplus/ASTClone.cpp b/src/shared/cplusplus/ASTClone.cpp index e30fb2b43d17ad46f5d63ec1a3d336edc64b48cb..3c17829292ac5b2df169591399b214546a635130 100644 --- a/src/shared/cplusplus/ASTClone.cpp +++ b/src/shared/cplusplus/ASTClone.cpp @@ -30,7 +30,7 @@ #include "AST.h" #include "ASTVisitor.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; SimpleSpecifierAST *SimpleSpecifierAST::clone(MemoryPool *pool) const { @@ -986,7 +986,9 @@ SizeofExpressionAST *SizeofExpressionAST::clone(MemoryPool *pool) const // copy ExpressionAST // copy SizeofExpressionAST ast->sizeof_token = sizeof_token; + ast->lparen_token = lparen_token; if (expression) ast->expression = expression->clone(pool); + ast->rparen_token = rparen_token; return ast; } @@ -1207,7 +1209,7 @@ IdentifierListAST *IdentifierListAST::clone(MemoryPool *pool) const { IdentifierListAST *ast = new (pool) IdentifierListAST; // copy IdentifierListAST - if (ast->name) ast->name = name->clone(pool); + if (name) ast->name = name->clone(pool); ast->comma_token = comma_token; if (next) ast->next = next->clone(pool); return ast; @@ -1249,9 +1251,11 @@ ObjCClassDeclarationAST *ObjCClassDeclarationAST::clone(MemoryPool *pool) const ObjCProtocolForwardDeclarationAST *ObjCProtocolForwardDeclarationAST::clone(MemoryPool *pool) const { ObjCProtocolForwardDeclarationAST *ast = new (pool) ObjCProtocolForwardDeclarationAST; + // copy DeclarationAST + // copy ObjCProtocolForwardDeclarationAST if (attributes) ast->attributes = attributes->clone(pool); ast->protocol_token = protocol_token; - if (identifier_list) ast->identifier_list = identifier_list; + if (identifier_list) ast->identifier_list = identifier_list->clone(pool); ast->semicolon_token = semicolon_token; return ast; } @@ -1259,6 +1263,8 @@ ObjCProtocolForwardDeclarationAST *ObjCProtocolForwardDeclarationAST::clone(Memo ObjCProtocolDeclarationAST *ObjCProtocolDeclarationAST::clone(MemoryPool *pool) const { ObjCProtocolDeclarationAST *ast = new (pool) ObjCProtocolDeclarationAST; + // copy DeclarationAST + // copy ObjCProtocolDeclarationAST if (attributes) ast->attributes = attributes->clone(pool); ast->protocol_token = protocol_token; if (name) ast->name = name->clone(pool); @@ -1271,41 +1277,48 @@ ObjCProtocolDeclarationAST *ObjCProtocolDeclarationAST::clone(MemoryPool *pool) ObjCProtocolRefsAST *ObjCProtocolRefsAST::clone(MemoryPool *pool) const { ObjCProtocolRefsAST *ast = new (pool) ObjCProtocolRefsAST; + // copy ObjCProtocolRefsAST ast->less_token = less_token; - if (ast->identifier_list) ast->identifier_list = identifier_list->clone(pool); + if (identifier_list) ast->identifier_list = identifier_list->clone(pool); ast->greater_token = greater_token; return ast; } -ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) const +ObjCMessageArgumentAST *ObjCMessageArgumentAST::clone(MemoryPool *pool) const { - ObjCMessageExpressionAST *ast = new (pool) ObjCMessageExpressionAST; - ast->lbracket_token = lbracket_token; - if (receiver_expression) ast->receiver_expression = receiver_expression->clone(pool); - if (selector) ast->selector = selector->clone(pool); - if (argument_list) ast->argument_list = argument_list->clone(pool); - ast->rbracket_token = rbracket_token; + ObjCMessageArgumentAST *ast = new (pool) ObjCMessageArgumentAST; + // copy ObjCMessageArgumentAST + if (parameter_value_expression) ast->parameter_value_expression = parameter_value_expression->clone(pool); return ast; } ObjCMessageArgumentListAST *ObjCMessageArgumentListAST::clone(MemoryPool *pool) const { ObjCMessageArgumentListAST *ast = new (pool) ObjCMessageArgumentListAST; + // copy ObjCMessageArgumentListAST if (arg) ast->arg = arg->clone(pool); if (next) ast->next = next->clone(pool); return ast; } -ObjCMessageArgumentAST *ObjCMessageArgumentAST::clone(MemoryPool *pool) const +ObjCMessageExpressionAST *ObjCMessageExpressionAST::clone(MemoryPool *pool) const { - ObjCMessageArgumentAST *ast = new (pool) ObjCMessageArgumentAST; - if (parameter_value_expression) ast->parameter_value_expression = parameter_value_expression->clone(pool); + ObjCMessageExpressionAST *ast = new (pool) ObjCMessageExpressionAST; + // copy ExpressionAST + // copy ObjCMessageExpressionAST + ast->lbracket_token = lbracket_token; + if (receiver_expression) ast->receiver_expression = receiver_expression->clone(pool); + if (selector) ast->selector = selector->clone(pool); + if (argument_list) ast->argument_list = argument_list->clone(pool); + ast->rbracket_token = rbracket_token; return ast; } ObjCProtocolExpressionAST *ObjCProtocolExpressionAST::clone(MemoryPool *pool) const { ObjCProtocolExpressionAST *ast = new (pool) ObjCProtocolExpressionAST; + // copy ExpressionAST + // copy ObjCProtocolExpressionAST ast->protocol_token = protocol_token; ast->lparen_token = lparen_token; ast->identifier_token = identifier_token; @@ -1316,8 +1329,8 @@ ObjCProtocolExpressionAST *ObjCProtocolExpressionAST::clone(MemoryPool *pool) co ObjCTypeNameAST *ObjCTypeNameAST::clone(MemoryPool *pool) const { ObjCTypeNameAST *ast = new (pool) ObjCTypeNameAST; + // copy ObjCTypeNameAST ast->lparen_token = lparen_token; - ast->type_qualifier = type_qualifier; if (type_id) ast->type_id = type_id->clone(pool); ast->rparen_token = rparen_token; return ast; @@ -1326,6 +1339,8 @@ ObjCTypeNameAST *ObjCTypeNameAST::clone(MemoryPool *pool) const ObjCEncodeExpressionAST *ObjCEncodeExpressionAST::clone(MemoryPool *pool) const { ObjCEncodeExpressionAST *ast = new (pool) ObjCEncodeExpressionAST; + // copy ExpressionAST + // copy ObjCEncodeExpressionAST ast->encode_token = encode_token; if (type_name) ast->type_name = type_name->clone(pool); return ast; @@ -1334,6 +1349,8 @@ ObjCEncodeExpressionAST *ObjCEncodeExpressionAST::clone(MemoryPool *pool) const ObjCSelectorWithoutArgumentsAST *ObjCSelectorWithoutArgumentsAST::clone(MemoryPool *pool) const { ObjCSelectorWithoutArgumentsAST *ast = new (pool) ObjCSelectorWithoutArgumentsAST; + // copy ObjCSelectorAST + // copy ObjCSelectorWithoutArgumentsAST ast->name_token = name_token; return ast; } @@ -1341,6 +1358,7 @@ ObjCSelectorWithoutArgumentsAST *ObjCSelectorWithoutArgumentsAST::clone(MemoryPo ObjCSelectorArgumentAST *ObjCSelectorArgumentAST::clone(MemoryPool *pool) const { ObjCSelectorArgumentAST *ast = new (pool) ObjCSelectorArgumentAST; + // copy ObjCSelectorArgumentAST ast->name_token = name_token; ast->colon_token = colon_token; return ast; @@ -1349,6 +1367,7 @@ ObjCSelectorArgumentAST *ObjCSelectorArgumentAST::clone(MemoryPool *pool) const ObjCSelectorArgumentListAST *ObjCSelectorArgumentListAST::clone(MemoryPool *pool) const { ObjCSelectorArgumentListAST *ast = new (pool) ObjCSelectorArgumentListAST; + // copy ObjCSelectorArgumentListAST if (argument) ast->argument = argument->clone(pool); if (next) ast->next = next->clone(pool); return ast; @@ -1357,6 +1376,8 @@ ObjCSelectorArgumentListAST *ObjCSelectorArgumentListAST::clone(MemoryPool *pool ObjCSelectorWithArgumentsAST *ObjCSelectorWithArgumentsAST::clone(MemoryPool *pool) const { ObjCSelectorWithArgumentsAST *ast = new (pool) ObjCSelectorWithArgumentsAST; + // copy ObjCSelectorAST + // copy ObjCSelectorWithArgumentsAST if (selector_arguments) ast->selector_arguments = selector_arguments->clone(pool); return ast; } @@ -1364,6 +1385,8 @@ ObjCSelectorWithArgumentsAST *ObjCSelectorWithArgumentsAST::clone(MemoryPool *po ObjCSelectorExpressionAST *ObjCSelectorExpressionAST::clone(MemoryPool *pool) const { ObjCSelectorExpressionAST *ast = new (pool) ObjCSelectorExpressionAST; + // copy ExpressionAST + // copy ObjCSelectorExpressionAST ast->selector_token = selector_token; ast->lparen_token = lparen_token; if (selector) ast->selector = selector->clone(pool); @@ -1374,6 +1397,7 @@ ObjCSelectorExpressionAST *ObjCSelectorExpressionAST::clone(MemoryPool *pool) co ObjCInstanceVariablesDeclarationAST *ObjCInstanceVariablesDeclarationAST::clone(MemoryPool *pool) const { ObjCInstanceVariablesDeclarationAST *ast = new (pool) ObjCInstanceVariablesDeclarationAST; + // copy ObjCInstanceVariablesDeclarationAST ast->lbrace_token = lbrace_token; if (instance_variables) ast->instance_variables = instance_variables->clone(pool); ast->rbrace_token = rbrace_token; @@ -1383,6 +1407,8 @@ ObjCInstanceVariablesDeclarationAST *ObjCInstanceVariablesDeclarationAST::clone( ObjCVisibilityDeclarationAST *ObjCVisibilityDeclarationAST::clone(MemoryPool *pool) const { ObjCVisibilityDeclarationAST *ast = new (pool) ObjCVisibilityDeclarationAST; + // copy DeclarationAST + // copy ObjCVisibilityDeclarationAST ast->visibility_token = visibility_token; return ast; } @@ -1390,6 +1416,7 @@ ObjCVisibilityDeclarationAST *ObjCVisibilityDeclarationAST::clone(MemoryPool *po ObjCPropertyAttributeAST *ObjCPropertyAttributeAST::clone(MemoryPool *pool) const { ObjCPropertyAttributeAST *ast = new (pool) ObjCPropertyAttributeAST; + // copy ObjCPropertyAttributeAST ast->attribute_identifier_token = attribute_identifier_token; ast->equals_token = equals_token; if (method_selector) ast->method_selector = method_selector->clone(pool); @@ -1399,6 +1426,7 @@ ObjCPropertyAttributeAST *ObjCPropertyAttributeAST::clone(MemoryPool *pool) cons ObjCPropertyAttributeListAST *ObjCPropertyAttributeListAST::clone(MemoryPool *pool) const { ObjCPropertyAttributeListAST *ast = new (pool) ObjCPropertyAttributeListAST; + // copy ObjCPropertyAttributeListAST if (attr) ast->attr = attr->clone(pool); ast->comma_token = comma_token; if (next) ast->next = next->clone(pool); @@ -1408,6 +1436,8 @@ ObjCPropertyAttributeListAST *ObjCPropertyAttributeListAST::clone(MemoryPool *po ObjCPropertyDeclarationAST *ObjCPropertyDeclarationAST::clone(MemoryPool *pool) const { ObjCPropertyDeclarationAST *ast = new (pool) ObjCPropertyDeclarationAST; + // copy DeclarationAST + // copy ObjCPropertyDeclarationAST if (attributes) ast->attributes = attributes->clone(pool); ast->property_token = property_token; ast->lparen_token = lparen_token; @@ -1420,6 +1450,9 @@ ObjCPropertyDeclarationAST *ObjCPropertyDeclarationAST::clone(MemoryPool *pool) ObjCMessageArgumentDeclarationAST *ObjCMessageArgumentDeclarationAST::clone(MemoryPool *pool) const { ObjCMessageArgumentDeclarationAST *ast = new (pool) ObjCMessageArgumentDeclarationAST; + // copy ExpressionAST + // copy NameAST + // copy ObjCMessageArgumentDeclarationAST if (type_name) ast->type_name = type_name->clone(pool); if (attributes) ast->attributes = attributes->clone(pool); ast->param_name_token = param_name_token; @@ -1429,6 +1462,7 @@ ObjCMessageArgumentDeclarationAST *ObjCMessageArgumentDeclarationAST::clone(Memo ObjCMessageArgumentDeclarationListAST *ObjCMessageArgumentDeclarationListAST::clone(MemoryPool *pool) const { ObjCMessageArgumentDeclarationListAST *ast = new (pool) ObjCMessageArgumentDeclarationListAST; + // copy ObjCMessageArgumentDeclarationListAST if (argument_declaration) ast->argument_declaration = argument_declaration->clone(pool); if (next) ast->next = next->clone(pool); return ast; @@ -1437,9 +1471,12 @@ ObjCMessageArgumentDeclarationListAST *ObjCMessageArgumentDeclarationListAST::cl ObjCMethodPrototypeAST *ObjCMethodPrototypeAST::clone(MemoryPool *pool) const { ObjCMethodPrototypeAST *ast = new (pool) ObjCMethodPrototypeAST; + // copy ObjCMethodPrototypeAST ast->method_type_token = method_type_token; if (type_name) ast->type_name = type_name->clone(pool); + if (selector) ast->selector = selector->clone(pool); if (arguments) ast->arguments = arguments->clone(pool); + ast->dot_dot_dot_token = dot_dot_dot_token; if (attributes) ast->attributes = attributes->clone(pool); return ast; } @@ -1447,6 +1484,8 @@ ObjCMethodPrototypeAST *ObjCMethodPrototypeAST::clone(MemoryPool *pool) const ObjCMethodDeclarationAST *ObjCMethodDeclarationAST::clone(MemoryPool *pool) const { ObjCMethodDeclarationAST *ast = new (pool) ObjCMethodDeclarationAST; + // copy DeclarationAST + // copy ObjCMethodDeclarationAST if (method_prototype) ast->method_prototype = method_prototype->clone(pool); if (function_body) ast->function_body = function_body->clone(pool); ast->semicolon_token = semicolon_token; @@ -1456,15 +1495,15 @@ ObjCMethodDeclarationAST *ObjCMethodDeclarationAST::clone(MemoryPool *pool) cons ObjCSynthesizedPropertyAST *ObjCSynthesizedPropertyAST::clone(MemoryPool *pool) const { ObjCSynthesizedPropertyAST *ast = new (pool) ObjCSynthesizedPropertyAST; - ast->property_identifier = property_identifier; + // copy ObjCSynthesizedPropertyAST ast->equals_token = equals_token; - ast->property_alias_identifier = property_alias_identifier; return ast; } ObjCSynthesizedPropertyListAST *ObjCSynthesizedPropertyListAST::clone(MemoryPool *pool) const { ObjCSynthesizedPropertyListAST *ast = new (pool) ObjCSynthesizedPropertyListAST; + // copy ObjCSynthesizedPropertyListAST if (synthesized_property) ast->synthesized_property = synthesized_property->clone(pool); ast->comma_token = comma_token; if (next) ast->next = next->clone(pool); @@ -1474,6 +1513,8 @@ ObjCSynthesizedPropertyListAST *ObjCSynthesizedPropertyListAST::clone(MemoryPool ObjCSynthesizedPropertiesDeclarationAST *ObjCSynthesizedPropertiesDeclarationAST::clone(MemoryPool *pool) const { ObjCSynthesizedPropertiesDeclarationAST *ast = new (pool) ObjCSynthesizedPropertiesDeclarationAST; + // copy DeclarationAST + // copy ObjCSynthesizedPropertiesDeclarationAST ast->synthesized_token = synthesized_token; if (property_identifiers) ast->property_identifiers = property_identifiers->clone(pool); ast->semicolon_token = semicolon_token; @@ -1483,6 +1524,8 @@ ObjCSynthesizedPropertiesDeclarationAST *ObjCSynthesizedPropertiesDeclarationAST ObjCDynamicPropertiesDeclarationAST *ObjCDynamicPropertiesDeclarationAST::clone(MemoryPool *pool) const { ObjCDynamicPropertiesDeclarationAST *ast = new (pool) ObjCDynamicPropertiesDeclarationAST; + // copy DeclarationAST + // copy ObjCDynamicPropertiesDeclarationAST ast->dynamic_token = dynamic_token; if (property_identifiers) ast->property_identifiers = property_identifiers->clone(pool); ast->semicolon_token = semicolon_token; @@ -1492,6 +1535,8 @@ ObjCDynamicPropertiesDeclarationAST *ObjCDynamicPropertiesDeclarationAST::clone( ObjCFastEnumerationAST *ObjCFastEnumerationAST::clone(MemoryPool *pool) const { ObjCFastEnumerationAST *ast = new (pool) ObjCFastEnumerationAST; + // copy StatementAST + // copy ObjCFastEnumerationAST ast->for_token = for_token; ast->lparen_token = lparen_token; if (type_specifiers) ast->type_specifiers = type_specifiers->clone(pool); @@ -1507,6 +1552,8 @@ ObjCFastEnumerationAST *ObjCFastEnumerationAST::clone(MemoryPool *pool) const ObjCSynchronizedStatementAST *ObjCSynchronizedStatementAST::clone(MemoryPool *pool) const { ObjCSynchronizedStatementAST *ast = new (pool) ObjCSynchronizedStatementAST; + // copy StatementAST + // copy ObjCSynchronizedStatementAST ast->synchronized_token = synchronized_token; ast->lparen_token = lparen_token; if (synchronized_object) ast->synchronized_object = synchronized_object->clone(pool); @@ -1514,6 +1561,3 @@ ObjCSynchronizedStatementAST *ObjCSynchronizedStatementAST::clone(MemoryPool *po if (statement) ast->statement = statement->clone(pool); return ast; } - - -CPLUSPLUS_END_NAMESPACE diff --git a/src/shared/cplusplus/ASTVisit.cpp b/src/shared/cplusplus/ASTVisit.cpp index d5862271dcccf29466dd84191a4f73a589b77df9..7cd2075399929e24bc7913cfcf4d8c2928c2445c 100644 --- a/src/shared/cplusplus/ASTVisit.cpp +++ b/src/shared/cplusplus/ASTVisit.cpp @@ -30,7 +30,7 @@ #include "AST.h" #include "ASTVisitor.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; void SimpleSpecifierAST::accept0(ASTVisitor *visitor) { @@ -1465,4 +1465,4 @@ void ObjCSynchronizedStatementAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/ASTVisitor.cpp b/src/shared/cplusplus/ASTVisitor.cpp index 20c261318c00ba88be13a5405aa30031d88265dd..6f331515a08b5f89271275b4e0e65fc4107ba94a 100644 --- a/src/shared/cplusplus/ASTVisitor.cpp +++ b/src/shared/cplusplus/ASTVisitor.cpp @@ -51,7 +51,7 @@ #include "TranslationUnit.h" #include "Control.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; ASTVisitor::ASTVisitor(Control *control) : _control(control) @@ -111,4 +111,4 @@ void ASTVisitor::getTokenStartPosition(unsigned index, unsigned *line, unsigned void ASTVisitor::getTokenEndPosition(unsigned index, unsigned *line, unsigned *column) const { getPosition(tokenAt(index).end(), line, column); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/ASTVisitor.h b/src/shared/cplusplus/ASTVisitor.h index 5c2c85bfc62b8c3518338488a4ea39973f3f387f..7356e0f905608b393ac0ff8d4438a07ea70bcca1 100644 --- a/src/shared/cplusplus/ASTVisitor.h +++ b/src/shared/cplusplus/ASTVisitor.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "ASTfwd.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT ASTVisitor { @@ -371,7 +371,7 @@ private: Control *_control; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_ASTVISITOR_H diff --git a/src/shared/cplusplus/ASTfwd.h b/src/shared/cplusplus/ASTfwd.h index 5ac42923c638d93804ab956ff8d737c8225ffaed..f97bae2a84cb2c3cb03535774b187a2a3e0afd11 100644 --- a/src/shared/cplusplus/ASTfwd.h +++ b/src/shared/cplusplus/ASTfwd.h @@ -51,8 +51,8 @@ #include <CPlusPlusForwardDeclarations.h> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class AST; class ASTVisitor; @@ -203,7 +203,7 @@ class ObjCDynamicPropertiesDeclarationAST; class ObjCFastEnumerationAST; class ObjCSynchronizedStatementAST; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_ASTFWD_H diff --git a/src/shared/cplusplus/Array.h b/src/shared/cplusplus/Array.h index 34d2048eee42f9d84bbd314d812e3983181abc21..d749cbec81d22906457efa21e864cbfb57ffe28f 100644 --- a/src/shared/cplusplus/Array.h +++ b/src/shared/cplusplus/Array.h @@ -53,8 +53,8 @@ #include <new> #include <cstdlib> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { template <typename _Tp, int SEGMENT_SHIFT = 4> class Array @@ -125,7 +125,7 @@ private: int _count; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_ARRAY_H diff --git a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h index b060f11dfa5eaf8403aaf506de301cc7aecd3ef6..9e570d2c1afeb5c326250c0b2e0895fa887382c5 100644 --- a/src/shared/cplusplus/CPlusPlusForwardDeclarations.h +++ b/src/shared/cplusplus/CPlusPlusForwardDeclarations.h @@ -49,34 +49,19 @@ #ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H #define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H -#ifndef CPLUSPLUS_WITH_NO_QT +#ifndef CPLUSPLUS_WITHOUT_QT # include <QtCore/qglobal.h> -# define CPLUSPLUS_BEGIN_HEADER -# define CPLUSPLUS_END_HEADER + # if defined(CPLUSPLUS_BUILD_LIB) # define CPLUSPLUS_EXPORT Q_DECL_EXPORT # else # define CPLUSPLUS_EXPORT Q_DECL_IMPORT # endif -# define CPLUSPLUS_WITH_NAMESPACE #else -# define CPLUSPLUS_BEGIN_HEADER -# define CPLUSPLUS_END_HEADER # define CPLUSPLUS_EXPORT #endif -#ifdef CPLUSPLUS_WITH_NAMESPACE -# define CPLUSPLUS_BEGIN_NAMESPACE namespace CPlusPlus { -# define CPLUSPLUS_END_NAMESPACE } // end of namespace CPlusPLus -# define CPLUSPLUS_USE_NAMESPACE using namespace CPlusPlus; -#else -# define CPLUSPLUS_BEGIN_NAMESPACE -# define CPLUSPLUS_END_NAMESPACE -# define CPLUSPLUS_USE_NAMESPACE ; -#endif - -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE +namespace CPlusPlus { class TranslationUnit; class Semantic; @@ -144,7 +129,6 @@ class ObjCProtocol; class ObjCForwardProtocolDeclaration; class ObjCMethod; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus #endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp index b7143797ad89458abb3dab387797e3b015936af9..6a81784360a2f59bb6eeeea9b38d0e7f9529d3bd 100644 --- a/src/shared/cplusplus/CheckDeclaration.cpp +++ b/src/shared/cplusplus/CheckDeclaration.cpp @@ -57,9 +57,8 @@ #include "Control.h" #include "Literals.h" #include <cassert> -#include <QtCore/QByteArray> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckDeclaration::CheckDeclaration(Semantic *semantic) : SemanticCheck(semantic), @@ -228,7 +227,6 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) if (it->declarator && it->declarator->initializer) { FullySpecifiedType initTy = semantic()->check(it->declarator->initializer, _scope); - Q_UNUSED(initTy) } *decl_it = new (translationUnit()->memoryPool()) List<Declaration *>(); @@ -702,26 +700,26 @@ bool CheckDeclaration::visit(ObjCPropertyDeclarationAST *ast) if (!attrAst) continue; - const char *attrName = spell(attrAst->attribute_identifier_token); - if (!qstrcmp("getter", attrName)) { + Identifier *attrId = identifier(attrAst->attribute_identifier_token); + if (attrId == control()->objcGetterId()) { if (checkPropertyAttribute(attrAst, propAttrs, Getter)) { // TODO: find method declaration for getter } - } else if (!qstrcmp("setter", attrName)) { + } else if (attrId == control()->objcSetterId()) { if (checkPropertyAttribute(attrAst, propAttrs, Setter)) { // TODO: find method declaration for setter } - } else if (!qstrcmp("readwrite", attrName)) { + } else if (attrId == control()->objcReadwriteId()) { checkPropertyAttribute(attrAst, propAttrs, ReadWrite); - } else if (!qstrcmp("readonly", attrName)) { + } else if (attrId == control()->objcReadonlyId()) { checkPropertyAttribute(attrAst, propAttrs, ReadOnly); - } else if (!qstrcmp("assign", attrName)) { + } else if (attrId == control()->objcAssignId()) { checkPropertyAttribute(attrAst, propAttrs, Assign); - } else if (!qstrcmp("retain", attrName)) { + } else if (attrId == control()->objcRetainId()) { checkPropertyAttribute(attrAst, propAttrs, Retain); - } else if (!qstrcmp("copy", attrName)) { + } else if (attrId == control()->objcCopyId()) { checkPropertyAttribute(attrAst, propAttrs, Copy); - } else if (!qstrcmp("nonatomic", attrName)) { + } else if (attrId == control()->objcNonatomicId()) { checkPropertyAttribute(attrAst, propAttrs, NonAtomic); } } @@ -745,4 +743,4 @@ bool CheckDeclaration::visit(ObjCPropertyDeclarationAST *ast) return false; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckDeclaration.h b/src/shared/cplusplus/CheckDeclaration.h index fcb773dd0edc82b0820783edd878cbbd83393a9f..0e11a5398b44cb8d1cc519f92134306b0a246aae 100644 --- a/src/shared/cplusplus/CheckDeclaration.h +++ b/src/shared/cplusplus/CheckDeclaration.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "SemanticCheck.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckDeclaration: public SemanticCheck { @@ -111,7 +111,7 @@ private: bool _checkAnonymousArguments: 1; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKDECLARATION_H diff --git a/src/shared/cplusplus/CheckDeclarator.cpp b/src/shared/cplusplus/CheckDeclarator.cpp index 5867d6180aa8a254af1f2952c0a13828cf62da12..b44c90f955c8f4fa259e44da41296491b1d61330 100644 --- a/src/shared/cplusplus/CheckDeclarator.cpp +++ b/src/shared/cplusplus/CheckDeclarator.cpp @@ -55,7 +55,7 @@ #include "CoreTypes.h" #include "Symbols.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckDeclarator::CheckDeclarator(Semantic *semantic) : SemanticCheck(semantic), @@ -300,4 +300,4 @@ void CheckDeclarator::applyCvQualifiers(SpecifierAST *cv) } } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckDeclarator.h b/src/shared/cplusplus/CheckDeclarator.h index 2f4ba6ba9154549e9adfc94632cb40fda24a880a..b676abfacd8cceab058fd372aef551df698c310f 100644 --- a/src/shared/cplusplus/CheckDeclarator.h +++ b/src/shared/cplusplus/CheckDeclarator.h @@ -53,8 +53,8 @@ #include "SemanticCheck.h" #include "FullySpecifiedType.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckDeclarator: public SemanticCheck { @@ -106,7 +106,7 @@ private: FullySpecifiedType _fullySpecifiedType; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKDECLARATOR_H diff --git a/src/shared/cplusplus/CheckExpression.cpp b/src/shared/cplusplus/CheckExpression.cpp index 805975b62500560e60bee644d11cd5eca4ee8547..02263d6b828e8d79c014f551ea84fa9385495082 100644 --- a/src/shared/cplusplus/CheckExpression.cpp +++ b/src/shared/cplusplus/CheckExpression.cpp @@ -56,7 +56,7 @@ #include "Symbols.h" #include "Control.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckExpression::CheckExpression(Semantic *semantic) : SemanticCheck(semantic), @@ -207,7 +207,6 @@ bool CheckExpression::visit(NewExpressionAST *ast) if (ast->new_placement) { for (ExpressionListAST *it = ast->new_placement->expression_list; it; it = it->next) { FullySpecifiedType exprTy = semantic()->check(it->expression, _scope); - Q_UNUSED(exprTy) } } @@ -215,18 +214,15 @@ bool CheckExpression::visit(NewExpressionAST *ast) if (ast->new_type_id) { FullySpecifiedType ty = semantic()->check(ast->new_type_id->type_specifier, _scope); - Q_UNUSED(ty) for (NewArrayDeclaratorAST *it = ast->new_type_id->new_array_declarators; it; it = it->next) { FullySpecifiedType exprTy = semantic()->check(it->expression, _scope); - Q_UNUSED(exprTy) } } // ### process new-initializer if (ast->new_initializer) { FullySpecifiedType exprTy = semantic()->check(ast->new_initializer->expression, _scope); - Q_UNUSED(exprTy) } return false; @@ -397,4 +393,4 @@ bool CheckExpression::visit(ObjCSelectorExpressionAST *ast) return false; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckExpression.h b/src/shared/cplusplus/CheckExpression.h index 40cfc09f67e27dc495efcfb5bdc855f73b3e9640..a61371db43fc20c71a71d521a5c5fae26a8f0f76 100644 --- a/src/shared/cplusplus/CheckExpression.h +++ b/src/shared/cplusplus/CheckExpression.h @@ -53,8 +53,8 @@ #include "SemanticCheck.h" #include "FullySpecifiedType.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckExpression: public SemanticCheck { @@ -122,7 +122,7 @@ private: bool _checkOldStyleCasts: 1; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKEXPRESSION_H diff --git a/src/shared/cplusplus/CheckName.cpp b/src/shared/cplusplus/CheckName.cpp index 4a3e884a4727f971bf20cd974ea21da741901989..19e2eedf98ccb4e6cd9f2ff0d1cabc3ebd4d8312 100644 --- a/src/shared/cplusplus/CheckName.cpp +++ b/src/shared/cplusplus/CheckName.cpp @@ -58,7 +58,7 @@ #include "Scope.h" #include <cassert> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckName::CheckName(Semantic *semantic) : SemanticCheck(semantic), @@ -425,4 +425,4 @@ bool CheckName::visit(ObjCMessageArgumentDeclarationAST *ast) return false; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckName.h b/src/shared/cplusplus/CheckName.h index d6fb271d48f965643322fab9c0241a811a2c825a..ec2b97beea074292e3e97e311374a20a6b443430 100644 --- a/src/shared/cplusplus/CheckName.h +++ b/src/shared/cplusplus/CheckName.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "SemanticCheck.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckName: public SemanticCheck { @@ -89,7 +89,7 @@ private: Scope *_scope; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKNAME_H diff --git a/src/shared/cplusplus/CheckSpecifier.cpp b/src/shared/cplusplus/CheckSpecifier.cpp index d4de2c55176d6fb570c949e2e31f036d52e5d13a..6baef4682ed3aeae4f8cb45cad26aed33124c395 100644 --- a/src/shared/cplusplus/CheckSpecifier.cpp +++ b/src/shared/cplusplus/CheckSpecifier.cpp @@ -58,7 +58,7 @@ #include "Control.h" #include "Scope.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckSpecifier::CheckSpecifier(Semantic *semantic) : SemanticCheck(semantic), @@ -420,4 +420,4 @@ bool CheckSpecifier::visit(ObjCTypeNameAST * /*ast*/) return true; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckSpecifier.h b/src/shared/cplusplus/CheckSpecifier.h index 050981b3922ac924cabcd2862d78164c38a790f0..9f06a437714a03c6e36a751ae51198dd712ee5ef 100644 --- a/src/shared/cplusplus/CheckSpecifier.h +++ b/src/shared/cplusplus/CheckSpecifier.h @@ -53,8 +53,8 @@ #include "SemanticCheck.h" #include "FullySpecifiedType.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckSpecifier: public SemanticCheck { @@ -88,7 +88,7 @@ private: Scope *_scope; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKSPECIFIER_H diff --git a/src/shared/cplusplus/CheckStatement.cpp b/src/shared/cplusplus/CheckStatement.cpp index 086457f1c48c7b43c18f893a3d0699cd1062b251..79a4e2e33d7df61d35a8824805c6734ff0261cb0 100644 --- a/src/shared/cplusplus/CheckStatement.cpp +++ b/src/shared/cplusplus/CheckStatement.cpp @@ -55,7 +55,7 @@ #include "Control.h" #include "Symbols.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; CheckStatement::CheckStatement(Semantic *semantic) : SemanticCheck(semantic), @@ -307,4 +307,4 @@ bool CheckStatement::visit(WhileStatementAST *ast) return false; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CheckStatement.h b/src/shared/cplusplus/CheckStatement.h index 087b06928d1395ce663a101992f5039558e0a68c..6bd0c868ab9e9bbac0c1eccb32d5c156030934b4 100644 --- a/src/shared/cplusplus/CheckStatement.h +++ b/src/shared/cplusplus/CheckStatement.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "SemanticCheck.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT CheckStatement: public SemanticCheck { @@ -94,7 +94,7 @@ private: Scope *_scope; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CHECKSTATEMENT_H diff --git a/src/shared/cplusplus/Control.cpp b/src/shared/cplusplus/Control.cpp index 30c5552bbe8730da88db7261486eddde1e129029..249d671ae178f2695cfbc7fc517928758ceb5c8b 100644 --- a/src/shared/cplusplus/Control.cpp +++ b/src/shared/cplusplus/Control.cpp @@ -57,7 +57,7 @@ #include <map> // ### replace me with LiteralTable #include <string> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; template <typename _Iterator> @@ -89,7 +89,7 @@ public: : control(control), translationUnit(0), diagnosticClient(0) - { } + {} ~Data() { @@ -577,10 +577,31 @@ public: std::vector<ObjCForwardClassDeclaration *> objcForwardClassDeclarations; std::vector<ObjCForwardProtocolDeclaration *> objcForwardProtocolDeclarations; std::vector<ObjCMethod *> objcMethods; + + // ObjC context keywords: + Identifier *objcGetterId; + Identifier *objcSetterId; + Identifier *objcReadwriteId; + Identifier *objcReadonlyId; + Identifier *objcAssignId; + Identifier *objcRetainId; + Identifier *objcCopyId; + Identifier *objcNonatomicId; }; Control::Control() -{ d = new Data(this); } +{ + d = new Data(this); + + d->objcGetterId = findOrInsertIdentifier("getter"); + d->objcSetterId = findOrInsertIdentifier("setter"); + d->objcReadwriteId = findOrInsertIdentifier("readwrite"); + d->objcReadonlyId = findOrInsertIdentifier("readonly"); + d->objcAssignId = findOrInsertIdentifier("assign"); + d->objcRetainId = findOrInsertIdentifier("retain"); + d->objcCopyId = findOrInsertIdentifier("copy"); + d->objcNonatomicId = findOrInsertIdentifier("nonatomic"); +} Control::~Control() { delete d; } @@ -766,4 +787,26 @@ ObjCForwardProtocolDeclaration *Control::newObjCForwardProtocolDeclaration(unsig ObjCMethod *Control::newObjCMethod(unsigned sourceLocation, Name *name) { return d->newObjCMethod(sourceLocation, name); } -CPLUSPLUS_END_NAMESPACE +Identifier *Control::objcGetterId() const +{ return d->objcGetterId; } + +Identifier *Control::objcSetterId() const +{ return d->objcSetterId; } + +Identifier *Control::objcReadwriteId() const +{ return d->objcReadwriteId; } + +Identifier *Control::objcReadonlyId() const +{ return d->objcReadonlyId; } + +Identifier *Control::objcAssignId() const +{ return d->objcAssignId; } + +Identifier *Control::objcRetainId() const +{ return d->objcRetainId; } + +Identifier *Control::objcCopyId() const +{ return d->objcCopyId; } + +Identifier *Control::objcNonatomicId() const +{ return d->objcNonatomicId; } diff --git a/src/shared/cplusplus/Control.h b/src/shared/cplusplus/Control.h index 9a41629feaa310e54d283f4fbf0cd973f14a86b9..d4db273e4310de975ceff295e2cf18a20a51d7d2 100644 --- a/src/shared/cplusplus/Control.h +++ b/src/shared/cplusplus/Control.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include <cstddef> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Control { @@ -169,6 +169,16 @@ public: /// Creates a new Objective-C method symbol. ObjCMethod *newObjCMethod(unsigned sourceLocation, Name *name = 0); + // Objective-C specific context keywords. + Identifier *objcGetterId() const; + Identifier *objcSetterId() const; + Identifier *objcReadwriteId() const; + Identifier *objcReadonlyId() const; + Identifier *objcAssignId() const; + Identifier *objcRetainId() const; + Identifier *objcCopyId() const; + Identifier *objcNonatomicId() const; + Identifier *findIdentifier(const char *chars, unsigned size) const; Identifier *findOrInsertIdentifier(const char *chars, unsigned size); @@ -199,7 +209,7 @@ private: Data *d; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CONTROL_H diff --git a/src/shared/cplusplus/CoreTypes.cpp b/src/shared/cplusplus/CoreTypes.cpp index 07a6782908340cb1513b85555da7d4bddf0d8fac..141ce3dc87b856b9a42907c9b36581c7817e2caf 100644 --- a/src/shared/cplusplus/CoreTypes.cpp +++ b/src/shared/cplusplus/CoreTypes.cpp @@ -51,7 +51,7 @@ #include "Names.h" #include <algorithm> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; bool VoidType::isEqualTo(const Type *other) const @@ -230,4 +230,4 @@ bool NamedType::isEqualTo(const Type *other) const void NamedType::accept0(TypeVisitor *visitor) { visitor->visit(this); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/CoreTypes.h b/src/shared/cplusplus/CoreTypes.h index 64e96c174ba0adc28390656e635ac0f25e33dd63..67d8a79515703b3fe1aefe50f8ad3f20593b72fe 100644 --- a/src/shared/cplusplus/CoreTypes.h +++ b/src/shared/cplusplus/CoreTypes.h @@ -54,8 +54,8 @@ #include "FullySpecifiedType.h" #include <cstddef> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT UndefinedType : public Type { @@ -272,7 +272,7 @@ private: Name *_name; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_CORETYPES_H diff --git a/src/shared/cplusplus/DiagnosticClient.cpp b/src/shared/cplusplus/DiagnosticClient.cpp index 8c5d52d91f37a0a359638701deef9946c359a892..ed5573d632091bc5b5f759a710495f3ea229e21e 100644 --- a/src/shared/cplusplus/DiagnosticClient.cpp +++ b/src/shared/cplusplus/DiagnosticClient.cpp @@ -48,7 +48,7 @@ #include "DiagnosticClient.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; DiagnosticClient::DiagnosticClient() { } @@ -56,4 +56,4 @@ DiagnosticClient::DiagnosticClient() DiagnosticClient::~DiagnosticClient() { } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/DiagnosticClient.h b/src/shared/cplusplus/DiagnosticClient.h index d9f9ff53f497f838db0be3574edd23513afa2bea..ff83a4c6f9a010de6d9bf6d9e32511106b56693c 100644 --- a/src/shared/cplusplus/DiagnosticClient.h +++ b/src/shared/cplusplus/DiagnosticClient.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "stdarg.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT DiagnosticClient { @@ -76,7 +76,7 @@ public: const char *format, va_list ap) = 0; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_DIAGNOSTICCLIENT_H diff --git a/src/shared/cplusplus/FullySpecifiedType.cpp b/src/shared/cplusplus/FullySpecifiedType.cpp index 58711ac8a96b3b4ab8b10c8f9f652132bf085e1f..578c6c9b7d66c9e802ab1385a34bdf9abb6550ea 100644 --- a/src/shared/cplusplus/FullySpecifiedType.cpp +++ b/src/shared/cplusplus/FullySpecifiedType.cpp @@ -50,7 +50,7 @@ #include "Type.h" #include "CoreTypes.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; FullySpecifiedType::FullySpecifiedType(Type *type) : _type(type), _flags(0) @@ -209,4 +209,4 @@ FullySpecifiedType FullySpecifiedType::simplified() const return *this; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/FullySpecifiedType.h b/src/shared/cplusplus/FullySpecifiedType.h index b9a1c3fa3976dd99cea744ffa831f3fb0e96ac4b..6c9f83d9145d616c84c3eac79e34802a9326e2e8 100644 --- a/src/shared/cplusplus/FullySpecifiedType.h +++ b/src/shared/cplusplus/FullySpecifiedType.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT FullySpecifiedType { @@ -151,7 +151,7 @@ private: }; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_FULLYSPECIFIEDTYPE_H diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp index f620bb745c178a82c5aa0ccaf7ae7de89ab5ba1b..48af12447368460072e1f25d2064cfa19be595b7 100644 --- a/src/shared/cplusplus/Keywords.cpp +++ b/src/shared/cplusplus/Keywords.cpp @@ -49,7 +49,7 @@ #include "Lexer.h" #include "Token.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; static inline int classify2(const char *s, bool) { if (s[0] == 'd') { @@ -1400,4 +1400,4 @@ int Lexer::classifyOperator(const char *s, int n) { } // switch } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Lexer.cpp b/src/shared/cplusplus/Lexer.cpp index 79c9bf4af1c0aebfe0abc15889f6f3a4e8c5e623..a0cc9495d831e247e9f3c7d65d2e7d442bebeaa1 100644 --- a/src/shared/cplusplus/Lexer.cpp +++ b/src/shared/cplusplus/Lexer.cpp @@ -55,7 +55,7 @@ using namespace std; -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; Lexer::Lexer(TranslationUnit *unit) : _translationUnit(unit), @@ -720,4 +720,4 @@ void Lexer::scan_helper(Token *tok) } // switch } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Lexer.h b/src/shared/cplusplus/Lexer.h index 4f2e9e386282f53a678843557d34f12d85cf0c4e..2af593604d5e65c929656e8653fa4b780c43440b 100644 --- a/src/shared/cplusplus/Lexer.h +++ b/src/shared/cplusplus/Lexer.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "Token.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Lexer { @@ -152,7 +152,7 @@ private: unsigned _currentLine; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_LEXER_H diff --git a/src/shared/cplusplus/LiteralTable.h b/src/shared/cplusplus/LiteralTable.h index 64fd2e1dac57473ddbd3af6142147bf131ee363d..29de643002daba3bbc4d4fff3bf9f219711e8fb1 100644 --- a/src/shared/cplusplus/LiteralTable.h +++ b/src/shared/cplusplus/LiteralTable.h @@ -53,8 +53,8 @@ #include <cstring> #include <cstdlib> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { template <typename _Literal> class LiteralTable @@ -185,7 +185,7 @@ protected: int _allocatedBuckets; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_LITERALTABLE_H diff --git a/src/shared/cplusplus/Literals.cpp b/src/shared/cplusplus/Literals.cpp index 5175979dfb0d1ddb928590fb10b24a92eec701bf..40042eb66e431353c9d0f76cbdf3d2652b7c6d08 100644 --- a/src/shared/cplusplus/Literals.cpp +++ b/src/shared/cplusplus/Literals.cpp @@ -53,7 +53,7 @@ using namespace std; -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; //////////////////////////////////////////////////////////////////////////////// Literal::Literal(const char *chars, unsigned size) @@ -227,4 +227,4 @@ bool Identifier::isEqualTo(const Identifier *other) const return ! strcmp(chars(), other->chars()); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Literals.h b/src/shared/cplusplus/Literals.h index a7cefc76ec61fb17203965b524482c0b2cfb6d03..2a11cdada73bc3d12e4838230702885bf88a8c85 100644 --- a/src/shared/cplusplus/Literals.h +++ b/src/shared/cplusplus/Literals.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "Token.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Literal { @@ -135,7 +135,7 @@ public: bool isEqualTo(const Identifier *other) const; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_LITERALS_H diff --git a/src/shared/cplusplus/MemoryPool.cpp b/src/shared/cplusplus/MemoryPool.cpp index 90cf49999314d013599e23d2a3eafac96bbfcd68..2002a6543504d58dc8828e149bc128e3e2b74774 100644 --- a/src/shared/cplusplus/MemoryPool.cpp +++ b/src/shared/cplusplus/MemoryPool.cpp @@ -51,7 +51,7 @@ #include <cstring> #include <cassert> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; using namespace std; @@ -125,4 +125,4 @@ void Managed::operator delete(void *) void Managed::operator delete(void *, MemoryPool *) { } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/MemoryPool.h b/src/shared/cplusplus/MemoryPool.h index ef802eb359fb7a795b7365fd0e8ab46afff0a4b5..e0f1ff870170c179e8246679e55e2eac1c50c76c 100644 --- a/src/shared/cplusplus/MemoryPool.h +++ b/src/shared/cplusplus/MemoryPool.h @@ -53,8 +53,8 @@ #include <cstddef> #include <new> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT MemoryPool { @@ -110,7 +110,7 @@ public: void operator delete(void *, MemoryPool *); }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_MEMORYPOOL_H diff --git a/src/shared/cplusplus/Name.cpp b/src/shared/cplusplus/Name.cpp index bde12732a5afbc6840d7f9e643bbd6463d534381..6354382551da38d84d37076433c7d590c4616666 100644 --- a/src/shared/cplusplus/Name.cpp +++ b/src/shared/cplusplus/Name.cpp @@ -50,7 +50,7 @@ #include "Names.h" #include "NameVisitor.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; Name::Name() { } @@ -93,4 +93,4 @@ void Name::accept(Name *name, NameVisitor *visitor) name->accept(visitor); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Name.h b/src/shared/cplusplus/Name.h index 1324a08feb9d998cf49e9224c6ddd6c762fc1387..45dfef86e652416ba3f99a0c6f2bb9c25cae3bdb 100644 --- a/src/shared/cplusplus/Name.h +++ b/src/shared/cplusplus/Name.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Name { @@ -98,7 +98,7 @@ protected: virtual void accept0(NameVisitor *visitor) = 0; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_NAME_H diff --git a/src/shared/cplusplus/NameVisitor.cpp b/src/shared/cplusplus/NameVisitor.cpp index 85ae4206ae5c285cff617258ca4c4073a48b4f3b..29630661d78a0b12a9e7956c4738aa126ab049b3 100644 --- a/src/shared/cplusplus/NameVisitor.cpp +++ b/src/shared/cplusplus/NameVisitor.cpp @@ -49,7 +49,7 @@ #include "NameVisitor.h" #include "Names.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; NameVisitor::NameVisitor() { } @@ -60,4 +60,4 @@ NameVisitor::~NameVisitor() void NameVisitor::accept(Name *name) { Name::accept(name, this); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/NameVisitor.h b/src/shared/cplusplus/NameVisitor.h index 19c2e0efb3fe2b2262d1f5a20ccedfb335e3af16..f8889b7d7f6294f0a8e67fc3ae95d7b7dbf8faed 100644 --- a/src/shared/cplusplus/NameVisitor.h +++ b/src/shared/cplusplus/NameVisitor.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT NameVisitor { @@ -77,7 +77,7 @@ public: virtual void visit(SelectorNameId *) {} }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_NAMEVISITOR_H diff --git a/src/shared/cplusplus/Names.cpp b/src/shared/cplusplus/Names.cpp index 0adfaab053d6b93fad11a5a3abb73d11f1f61328..9e60804e77b908968bb59d469c726807f3a4dd80 100644 --- a/src/shared/cplusplus/Names.cpp +++ b/src/shared/cplusplus/Names.cpp @@ -52,7 +52,7 @@ #include <cstring> #include <algorithm> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; QualifiedNameId::QualifiedNameId(Name *const names[], unsigned nameCount, @@ -326,4 +326,4 @@ bool SelectorNameId::isEqualTo(const Name *other) const return true; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Names.h b/src/shared/cplusplus/Names.h index fa5dd6791f9feb29deb86f0893db37ca9f06f4cb..e5fef0cbec284d74cad14da0aa2da1c6535f0f35 100644 --- a/src/shared/cplusplus/Names.h +++ b/src/shared/cplusplus/Names.h @@ -53,8 +53,8 @@ #include "Name.h" #include "FullySpecifiedType.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT QualifiedNameId: public Name { @@ -304,7 +304,7 @@ private: bool _hasArguments; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_NAMES_H diff --git a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp index 3f8fc7c396fcd5c15879ead5d68af75799b2024f..cd42d045dd1b59e11507ae416e2ea9877ff20373 100644 --- a/src/shared/cplusplus/ObjectiveCAtKeywords.cpp +++ b/src/shared/cplusplus/ObjectiveCAtKeywords.cpp @@ -1,7 +1,7 @@ #include "Lexer.h" #include "Token.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; static inline int classify3(const char *s) { if (s[0] == 'e') { @@ -461,4 +461,4 @@ int Lexer::classifyObjCAtKeyword(const char *s, int n) { } // switch } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp b/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp index b3063f3bf0d8de190619ee21a7b8f6e32f29f5d8..654ce88104ed474c37939e02ca289114758dad79 100644 --- a/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp +++ b/src/shared/cplusplus/ObjectiveCTypeQualifiers.cpp @@ -29,7 +29,7 @@ #include "ObjectiveCTypeQualifiers.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; static inline int classify2(const char *s) { if (s[0] == 'N') { @@ -315,7 +315,7 @@ static inline int classify9(const char *s) { return Token_identifier; } -int classifyObjectiveCTypeQualifiers(const char *s, int n) { +int CPlusPlus::classifyObjectiveCTypeQualifiers(const char *s, int n) { switch (n) { case 2: return classify2(s); case 3: return classify3(s); @@ -328,4 +328,4 @@ int classifyObjectiveCTypeQualifiers(const char *s, int n) { } // switch } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/ObjectiveCTypeQualifiers.h b/src/shared/cplusplus/ObjectiveCTypeQualifiers.h index 163777862a5c2e7fb6e3d7d4ef794d9939ad4bd1..731dd9c6aff25dcaf3f84b73c2ad625a0dd79c96 100644 --- a/src/shared/cplusplus/ObjectiveCTypeQualifiers.h +++ b/src/shared/cplusplus/ObjectiveCTypeQualifiers.h @@ -31,8 +31,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { enum { Token_NO, @@ -65,7 +65,7 @@ enum { CPLUSPLUS_EXPORT int classifyObjectiveCTypeQualifiers(const char *s, int n); -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_OBJC_TYPEQUALIFIERS_H diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp index 958d740a5875d48ad74143367ebf2902af418085..8f3bd549ce490ed864df5074c5ff3c939bede71e 100644 --- a/src/shared/cplusplus/Parser.cpp +++ b/src/shared/cplusplus/Parser.cpp @@ -55,9 +55,38 @@ #include "ObjectiveCTypeQualifiers.h" #include <cstdlib> #include <cstring> +#include <iostream> #include <cassert> -#include <QDebug> -CPLUSPLUS_BEGIN_NAMESPACE +#include <string> + +#define CPLUSPLUS_NO_DEBUG_RULE + +using namespace CPlusPlus; + +namespace { + +class DebugRule { + const char *name; + static int depth; + +public: + DebugRule(const char *name) + : name(name) + { std::cout << std::string(depth++, ' ') << name << std::endl; } + + ~DebugRule() + { --depth; } +}; + +int DebugRule::depth = 0; + +} // end of anonymous namespace + +#ifndef CPLUSPLUS_NO_DEBUG_RULE +# define DEBUG_THIS_RULE() DebugRule __debug_rule__(__func__) +#else +# define DEBUG_THIS_RULE() do {} while (0) +#endif Parser::Parser(TranslationUnit *unit) : _translationUnit(unit), @@ -246,6 +275,7 @@ void Parser::match(int kind, unsigned *token) bool Parser::parseClassOrNamespaceName(NameAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_IDENTIFIER) { unsigned identifier_token = cursor(); @@ -271,6 +301,7 @@ bool Parser::parseClassOrNamespaceName(NameAST *&node) bool Parser::parseTemplateId(NameAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_IDENTIFIER && LA(2) == T_LESS) { TemplateIdAST *ast = new (_pool) TemplateIdAST; ast->identifier_token = consumeToken(); @@ -290,6 +321,7 @@ bool Parser::parseTemplateId(NameAST *&node) bool Parser::parseNestedNameSpecifier(NestedNameSpecifierAST *&node, bool /*acceptTemplateId*/) { + DEBUG_THIS_RULE(); NestedNameSpecifierAST **nested_name_specifier = &node; NameAST *class_or_namespace_name = 0; if (parseClassOrNamespaceName(class_or_namespace_name) && @@ -323,6 +355,7 @@ bool Parser::parseNestedNameSpecifier(NestedNameSpecifierAST *&node, bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name, bool acceptTemplateId) { + DEBUG_THIS_RULE(); unsigned start = cursor(); if (! parseNestedNameSpecifier(name, acceptTemplateId)) rewind(start); @@ -331,6 +364,7 @@ bool Parser::parseNestedNameSpecifierOpt(NestedNameSpecifierAST *&name, bool Parser::parseName(NameAST *&node, bool acceptTemplateId) { + DEBUG_THIS_RULE(); unsigned global_scope_token = 0; if (LA() == T_COLON_COLON) global_scope_token = consumeToken(); @@ -360,6 +394,7 @@ bool Parser::parseName(NameAST *&node, bool acceptTemplateId) bool Parser::parseTranslationUnit(TranslationUnitAST *&node) { + DEBUG_THIS_RULE(); TranslationUnitAST *ast = new (_pool) TranslationUnitAST; DeclarationListAST **decl = &ast->declarations; @@ -384,6 +419,7 @@ bool Parser::parseTranslationUnit(TranslationUnitAST *&node) bool Parser::parseEmptyDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_SEMICOLON) { EmptyDeclarationAST *ast = new (_pool) EmptyDeclarationAST; ast->semicolon_token = consumeToken(); @@ -395,6 +431,7 @@ bool Parser::parseEmptyDeclaration(DeclarationAST *&node) bool Parser::parseDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_SEMICOLON: return parseEmptyDeclaration(node); @@ -461,6 +498,7 @@ bool Parser::parseDeclaration(DeclarationAST *&node) bool Parser::parseLinkageSpecification(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_EXTERN && LA(2) == T_STRING_LITERAL) { LinkageSpecificationAST *ast = new (_pool) LinkageSpecificationAST; ast->extern_token = consumeToken(); @@ -480,6 +518,7 @@ bool Parser::parseLinkageSpecification(DeclarationAST *&node) bool Parser::parseLinkageBody(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LBRACE) { LinkageBodyAST *ast = new (_pool) LinkageBodyAST; ast->lbrace_token = consumeToken(); @@ -510,6 +549,7 @@ bool Parser::parseLinkageBody(DeclarationAST *&node) // ### rename parseNamespaceAliarOrDeclaration? bool Parser::parseNamespace(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_NAMESPACE) return false; @@ -544,6 +584,7 @@ bool Parser::parseNamespace(DeclarationAST *&node) bool Parser::parseUsing(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_USING) return false; @@ -564,6 +605,7 @@ bool Parser::parseUsing(DeclarationAST *&node) bool Parser::parseUsingDirective(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_USING && LA(2) == T_NAMESPACE) { UsingDirectiveAST *ast = new (_pool) UsingDirectiveAST; ast->using_token = consumeToken(); @@ -580,6 +622,7 @@ bool Parser::parseUsingDirective(DeclarationAST *&node) bool Parser::parseConversionFunctionId(NameAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_OPERATOR) return false; unsigned operator_token = consumeToken(); @@ -601,6 +644,7 @@ bool Parser::parseConversionFunctionId(NameAST *&node) bool Parser::parseOperatorFunctionId(NameAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_OPERATOR) return false; unsigned operator_token = consumeToken(); @@ -618,6 +662,7 @@ bool Parser::parseOperatorFunctionId(NameAST *&node) bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node) { + DEBUG_THIS_RULE(); TemplateArgumentListAST **template_argument_ptr = &node; ExpressionAST *template_argument = 0; if (parseTemplateArgument(template_argument)) { @@ -641,6 +686,7 @@ bool Parser::parseTemplateArgumentList(TemplateArgumentListAST *&node) bool Parser::parseAsmDefinition(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_ASM) return false; @@ -682,6 +728,7 @@ bool Parser::parseAsmDefinition(DeclarationAST *&node) bool Parser::parseAsmOperandList() { + DEBUG_THIS_RULE(); if (LA() != T_STRING_LITERAL) return true; @@ -698,6 +745,7 @@ bool Parser::parseAsmOperandList() bool Parser::parseAsmOperand() { + DEBUG_THIS_RULE(); unsigned string_literal_token = 0; match(T_STRING_LITERAL, &string_literal_token); @@ -718,6 +766,7 @@ bool Parser::parseAsmOperand() bool Parser::parseAsmClobberList() { + DEBUG_THIS_RULE(); if (LA() != T_STRING_LITERAL) return false; @@ -733,6 +782,7 @@ bool Parser::parseAsmClobberList() bool Parser::parseTemplateDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (! (LA(1) == T_TEMPLATE || ((LA(1) == T_EXPORT || LA(1) == T_EXTERN) && LA(2) == T_TEMPLATE))) return false; @@ -757,6 +807,7 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) bool Parser::parseOperator(OperatorAST *&node) // ### FIXME { + DEBUG_THIS_RULE(); OperatorAST *ast = new (_pool) OperatorAST; switch (LA()) { @@ -828,6 +879,7 @@ bool Parser::parseOperator(OperatorAST *&node) // ### FIXME bool Parser::parseCvQualifiers(SpecifierAST *&node) { + DEBUG_THIS_RULE(); unsigned start = cursor(); SpecifierAST **ast = &node; while (*ast) @@ -852,6 +904,7 @@ bool Parser::parseCvQualifiers(SpecifierAST *&node) bool Parser::parsePtrOperator(PtrOperatorAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_AMPER) { ReferenceAST *ast = new (_pool) ReferenceAST; ast->amp_token = consumeToken(); @@ -889,6 +942,7 @@ bool Parser::parsePtrOperator(PtrOperatorAST *&node) bool Parser::parseTemplateArgument(ExpressionAST *&node) { + DEBUG_THIS_RULE(); unsigned start = cursor(); if (parseTypeId(node) && (LA() == T_COMMA || LA() == T_GREATER)) return true; @@ -904,6 +958,7 @@ bool Parser::parseDeclSpecifierSeq(SpecifierAST *&decl_specifier_seq, bool onlyTypeSpecifiers, bool simplified) { + DEBUG_THIS_RULE(); bool has_type_specifier = false; NameAST *named_type_specifier = 0; SpecifierAST **decl_specifier_seq_ptr = &decl_specifier_seq; @@ -951,6 +1006,7 @@ bool Parser::parseDeclSpecifierSeq(SpecifierAST *&decl_specifier_seq, bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node) { + DEBUG_THIS_RULE(); unsigned start = cursor(); bool blocked = blockErrors(true); if (parseDeclarator(node)) { @@ -964,6 +1020,7 @@ bool Parser::parseDeclaratorOrAbstractDeclarator(DeclaratorAST *&node) bool Parser::parseCoreDeclarator(DeclaratorAST *&node) { + DEBUG_THIS_RULE(); unsigned start = cursor(); SpecifierAST *attributes = 0; SpecifierAST **attribute_ptr = &attributes; @@ -1013,6 +1070,7 @@ bool Parser::parseCoreDeclarator(DeclaratorAST *&node) bool Parser::parseDeclarator(DeclaratorAST *&node, bool stopAtCppInitializer) { + DEBUG_THIS_RULE(); if (! parseCoreDeclarator(node)) return false; @@ -1099,6 +1157,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node, bool stopAtCppInitializer) bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node) { + DEBUG_THIS_RULE(); PtrOperatorAST *ptr_operators = 0, **ptr_operators_tail = &ptr_operators; while (parsePtrOperator(*ptr_operators_tail)) ptr_operators_tail = &(*ptr_operators_tail)->next; @@ -1133,6 +1192,7 @@ bool Parser::parseAbstractCoreDeclarator(DeclaratorAST *&node) bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) { + DEBUG_THIS_RULE(); if (! parseAbstractCoreDeclarator(node)) return false; @@ -1176,6 +1236,7 @@ bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) bool Parser::parseEnumSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_ENUM) { unsigned enum_token = consumeToken(); NameAST *name = 0; @@ -1214,6 +1275,7 @@ bool Parser::parseEnumSpecifier(SpecifierAST *&node) bool Parser::parseTemplateParameterList(DeclarationListAST *&node) { + DEBUG_THIS_RULE(); DeclarationListAST **template_parameter_ptr = &node; DeclarationAST *declaration = 0; if (parseTemplateParameter(declaration)) { @@ -1238,6 +1300,7 @@ bool Parser::parseTemplateParameterList(DeclarationListAST *&node) bool Parser::parseTemplateParameter(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (parseTypeParameter(node)) return true; bool previousTemplateArguments = switchTemplateArguments(true); @@ -1248,6 +1311,7 @@ bool Parser::parseTemplateParameter(DeclarationAST *&node) bool Parser::parseTypenameTypeParameter(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_CLASS || LA() == T_TYPENAME) { TypenameTypeParameterAST *ast = new (_pool) TypenameTypeParameterAST; ast->classkey_token = consumeToken(); @@ -1264,6 +1328,7 @@ bool Parser::parseTypenameTypeParameter(DeclarationAST *&node) bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_TEMPLATE) { TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; ast->template_token = consumeToken(); @@ -1290,6 +1355,7 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) bool Parser::parseTypeParameter(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_CLASS || LA() == T_TYPENAME) return parseTypenameTypeParameter(node); else if (LA() == T_TEMPLATE) @@ -1300,6 +1366,7 @@ bool Parser::parseTypeParameter(DeclarationAST *&node) bool Parser::parseTypeId(ExpressionAST *&node) { + DEBUG_THIS_RULE(); SpecifierAST *type_specifier = 0; if (parseTypeSpecifier(type_specifier)) { TypeIdAST *ast = new (_pool) TypeIdAST; @@ -1313,6 +1380,7 @@ bool Parser::parseTypeId(ExpressionAST *&node) bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_RPAREN) return true; // nothing to do @@ -1344,6 +1412,7 @@ bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&nod bool Parser::parseParameterDeclarationList(DeclarationListAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_DOT_DOT_DOT || (LA() == T_COMMA && LA(2) == T_DOT_DOT_DOT)) return false; // nothing to do. @@ -1373,6 +1442,7 @@ bool Parser::parseParameterDeclarationList(DeclarationListAST *&node) bool Parser::parseParameterDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); SpecifierAST *decl_specifier_seq = 0; if (parseDeclSpecifierSeq(decl_specifier_seq)) { ParameterDeclarationAST *ast = new (_pool) ParameterDeclarationAST; @@ -1391,6 +1461,7 @@ bool Parser::parseParameterDeclaration(DeclarationAST *&node) bool Parser::parseClassSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); if (! lookAtClassKey()) return false; @@ -1474,6 +1545,7 @@ bool Parser::parseClassSpecifier(SpecifierAST *&node) bool Parser::parseAccessSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_PUBLIC: case T_PROTECTED: @@ -1491,6 +1563,7 @@ bool Parser::parseAccessSpecifier(SpecifierAST *&node) bool Parser::parseAccessDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_PUBLIC || LA() == T_PROTECTED || LA() == T_PRIVATE || LA() == T_Q_SIGNALS) { bool isSignals = LA() == T_Q_SIGNALS; AccessDeclarationAST *ast = new (_pool) AccessDeclarationAST; @@ -1506,6 +1579,7 @@ bool Parser::parseAccessDeclaration(DeclarationAST *&node) bool Parser::parseMemberSpecification(DeclarationAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_SEMICOLON: return parseEmptyDeclaration(node); @@ -1529,6 +1603,7 @@ bool Parser::parseMemberSpecification(DeclarationAST *&node) bool Parser::parseCtorInitializer(CtorInitializerAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_COLON) { unsigned colon_token = consumeToken(); @@ -1544,6 +1619,7 @@ bool Parser::parseCtorInitializer(CtorInitializerAST *&node) bool Parser::parseElaboratedTypeSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); if (lookAtClassKey() || LA() == T_ENUM || LA() == T_TYPENAME) { unsigned classkey_token = consumeToken(); NameAST *name = 0; @@ -1562,6 +1638,7 @@ bool Parser::parseElaboratedTypeSpecifier(SpecifierAST *&node) bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_THROW) { ExceptionSpecificationAST *ast = new (_pool) ExceptionSpecificationAST; ast->throw_token = consumeToken(); @@ -1581,6 +1658,7 @@ bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) bool Parser::parseEnumerator(EnumeratorAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_IDENTIFIER) { EnumeratorAST *ast = new (_pool) EnumeratorAST; ast->identifier_token = consumeToken(); @@ -1598,6 +1676,7 @@ bool Parser::parseEnumerator(EnumeratorAST *&node) bool Parser::parseInitDeclarator(DeclaratorAST *&node, bool acceptStructDeclarator) { + DEBUG_THIS_RULE(); unsigned start = cursor(); if (acceptStructDeclarator && LA() == T_COLON) { @@ -1641,6 +1720,7 @@ bool Parser::parseInitDeclarator(DeclaratorAST *&node, bool Parser::parseBaseClause(BaseSpecifierAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_COLON) { consumeToken(); @@ -1665,6 +1745,7 @@ bool Parser::parseBaseClause(BaseSpecifierAST *&node) bool Parser::parseInitializer(ExpressionAST *&node, unsigned *equals_token) { + DEBUG_THIS_RULE(); if (LA() == T_LPAREN) { return parsePrimaryExpression(node); } else if (LA() == T_EQUAL) { @@ -1676,6 +1757,7 @@ bool Parser::parseInitializer(ExpressionAST *&node, unsigned *equals_token) bool Parser::parseMemInitializerList(MemInitializerAST *&node) { + DEBUG_THIS_RULE(); MemInitializerAST **initializer = &node; if (parseMemInitializer(*initializer)) { @@ -1695,6 +1777,7 @@ bool Parser::parseMemInitializerList(MemInitializerAST *&node) bool Parser::parseMemInitializer(MemInitializerAST *&node) { + DEBUG_THIS_RULE(); NameAST *name = 0; if (parseName(name) && LA() == T_LPAREN) { MemInitializerAST *ast = new (_pool) MemInitializerAST; @@ -1711,6 +1794,7 @@ bool Parser::parseMemInitializer(MemInitializerAST *&node) bool Parser::parseTypeIdList(ExpressionListAST *&node) { + DEBUG_THIS_RULE(); ExpressionListAST **expression_list_ptr = &node; ExpressionAST *typeId = 0; if (parseTypeId(typeId)) { @@ -1734,6 +1818,7 @@ bool Parser::parseTypeIdList(ExpressionListAST *&node) bool Parser::parseExpressionList(ExpressionListAST *&node) { + DEBUG_THIS_RULE(); ExpressionListAST **expression_list_ptr = &node; ExpressionAST *expression = 0; if (parseAssignmentExpression(expression)) { @@ -1757,6 +1842,7 @@ bool Parser::parseExpressionList(ExpressionListAST *&node) bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) { + DEBUG_THIS_RULE(); BaseSpecifierAST *ast = new (_pool) BaseSpecifierAST; if (LA() == T_VIRTUAL) { @@ -1783,6 +1869,7 @@ bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) bool Parser::parseInitializerList(ExpressionListAST *&node) { + DEBUG_THIS_RULE(); ExpressionListAST **initializer_ptr = &node; ExpressionAST *initializer = 0; if (parseInitializerClause(initializer)) { @@ -1804,6 +1891,7 @@ bool Parser::parseInitializerList(ExpressionListAST *&node) bool Parser::parseInitializerClause(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LBRACE) { ArrayInitializerAST *ast = new (_pool) ArrayInitializerAST; ast->lbrace_token = consumeToken(); @@ -1817,6 +1905,7 @@ bool Parser::parseInitializerClause(ExpressionAST *&node) bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId) { + DEBUG_THIS_RULE(); if (LA() == T_TILDE && LA(2) == T_IDENTIFIER) { DestructorNameAST *ast = new (_pool) DestructorNameAST; ast->tilde_token = consumeToken(); @@ -1853,6 +1942,7 @@ bool Parser::parseUnqualifiedName(NameAST *&node, bool acceptTemplateId) bool Parser::parseStringLiteral(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! (LA() == T_STRING_LITERAL || LA() == T_WIDE_STRING_LITERAL)) return false; @@ -1868,6 +1958,7 @@ bool Parser::parseStringLiteral(ExpressionAST *&node) bool Parser::parseExpressionStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); ExpressionAST *expression = 0; if (LA() == T_SEMICOLON || parseExpression(expression)) { ExpressionStatementAST *ast = new (_pool) ExpressionStatementAST; @@ -1881,6 +1972,7 @@ bool Parser::parseExpressionStatement(StatementAST *&node) bool Parser::parseStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_WHILE: return parseWhileStatement(node); @@ -1951,6 +2043,7 @@ bool Parser::parseStatement(StatementAST *&node) bool Parser::parseBreakStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_BREAK) { BreakStatementAST *ast = new (_pool) BreakStatementAST; ast->break_token = consumeToken(); @@ -1963,6 +2056,7 @@ bool Parser::parseBreakStatement(StatementAST *&node) bool Parser::parseContinueStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_CONTINUE) { ContinueStatementAST *ast = new (_pool) ContinueStatementAST; ast->continue_token = consumeToken(); @@ -1975,6 +2069,7 @@ bool Parser::parseContinueStatement(StatementAST *&node) bool Parser::parseGotoStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_GOTO) { GotoStatementAST *ast = new (_pool) GotoStatementAST; ast->goto_token = consumeToken(); @@ -1988,6 +2083,7 @@ bool Parser::parseGotoStatement(StatementAST *&node) bool Parser::parseReturnStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_RETURN) { ReturnStatementAST *ast = new (_pool) ReturnStatementAST; ast->return_token = consumeToken(); @@ -1999,87 +2095,100 @@ bool Parser::parseReturnStatement(StatementAST *&node) return false; } -bool Parser::maybeFunctionCall(SimpleDeclarationAST *simpleDecl) const +bool Parser::isPointerDeclaration(DeclarationStatementAST *ast) const { - if (! simpleDecl) - return false; - else if (! simpleDecl->decl_specifier_seq) - return false; - else if (simpleDecl->decl_specifier_seq->next) + if (! ast) return false; - NamedTypeSpecifierAST *type_spec = simpleDecl->decl_specifier_seq->asNamedTypeSpecifier(); - if (! type_spec) - return false; + if (SimpleDeclarationAST *declaration = ast->declaration->asSimpleDeclaration()) { + if (SpecifierAST *spec = declaration->decl_specifier_seq) { + if (spec->asNamedTypeSpecifier() && ! spec->next) { + if (DeclaratorListAST *declarators = declaration->declarators) { + if (DeclaratorAST *declarator = declarators->declarator) { + if (declarator->ptr_operators && declarator->equals_token && declarator->initializer) { + return true; + } + } + } + } + } + } - DeclaratorListAST *first_declarator = simpleDecl->declarators; - if (! first_declarator) - return false; - else if (first_declarator->next) - return false; + return false; +} - DeclaratorAST *declarator = first_declarator->declarator; - if (! declarator) - return false; - else if (declarator->ptr_operators) - return false; - else if (declarator->postfix_declarators) - return false; - else if (declarator->initializer) - return false; - else if (! declarator->core_declarator) +bool Parser::maybeAmbiguousStatement(DeclarationStatementAST *ast) const +{ + if (! ast) return false; - NestedDeclaratorAST *nested_declarator = declarator->core_declarator->asNestedDeclarator(); - if (! nested_declarator) - return false; + if (SimpleDeclarationAST *declaration = ast->declaration->asSimpleDeclaration()) { + if (SpecifierAST *spec = declaration->decl_specifier_seq) { + if (spec->asNamedTypeSpecifier() && ! spec->next) { + if (DeclaratorListAST *declarators = declaration->declarators) { + if (DeclaratorAST *declarator = declarators->declarator) { + if (declarator->core_declarator && + declarator->core_declarator->asNestedDeclarator()) { + // recognized name(id-expression) + return true; + } + } + } + } - return true; -} + } else if (DeclaratorListAST *declarators = declaration->declarators) { + // no decl_specifiers... + if (DeclaratorAST *declarator = declarators->declarator) { + if (declarator->postfix_declarators && declarator->postfix_declarators->asFunctionDeclarator() + && ! declarator->initializer) { + return false; + } + } -bool Parser::maybeSimpleExpression(SimpleDeclarationAST *simpleDecl) const -{ - if (! simpleDecl->declarators) { - SpecifierAST *spec = simpleDecl->decl_specifier_seq; - if (spec && ! spec->next && spec->asNamedTypeSpecifier()) { return true; } } + return false; } bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_SEMICOLON) return parseExpressionStatement(node); unsigned start = cursor(); bool blocked = blockErrors(true); + if (parseDeclarationStatement(node)) { DeclarationStatementAST *stmt = static_cast<DeclarationStatementAST *>(node); - SimpleDeclarationAST *simpleDecl = 0; - if (stmt->declaration) - simpleDecl = stmt->declaration->asSimpleDeclaration(); - if (simpleDecl && simpleDecl->decl_specifier_seq && - ! maybeFunctionCall(simpleDecl) && ! maybeSimpleExpression(simpleDecl)) { + if (isPointerDeclaration(stmt)) { + blockErrors(blocked); + return true; + } + + if (! maybeAmbiguousStatement(stmt)) { unsigned end_of_declaration_statement = cursor(); rewind(start); + StatementAST *expression = 0; - if (! parseExpressionStatement(expression) || cursor() != end_of_declaration_statement) { - rewind(end_of_declaration_statement); - } else { - ExpressionOrDeclarationStatementAST *ast = - new (_pool) ExpressionOrDeclarationStatementAST; + if (parseExpressionStatement(expression) && cursor() == end_of_declaration_statement) { + // it's an ambiguous expression-or-declaration statement. + ExpressionOrDeclarationStatementAST *ast = new (_pool) ExpressionOrDeclarationStatementAST; ast->declaration = node; ast->expression = expression; node = ast; } + + rewind(end_of_declaration_statement); blockErrors(blocked); return true; } } + // it's not a declaration statement. blockErrors(blocked); rewind(start); return parseExpressionStatement(node); @@ -2087,6 +2196,7 @@ bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) bool Parser::parseCondition(ExpressionAST *&node) { + DEBUG_THIS_RULE(); unsigned start = cursor(); bool blocked = blockErrors(true); @@ -2112,6 +2222,7 @@ bool Parser::parseCondition(ExpressionAST *&node) bool Parser::parseWhileStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_WHILE) { WhileStatementAST *ast = new (_pool) WhileStatementAST; ast->while_token = consumeToken(); @@ -2127,6 +2238,7 @@ bool Parser::parseWhileStatement(StatementAST *&node) bool Parser::parseDoStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_DO) { DoStatementAST *ast = new (_pool) DoStatementAST; ast->do_token = consumeToken(); @@ -2144,6 +2256,7 @@ bool Parser::parseDoStatement(StatementAST *&node) bool Parser::parseForeachStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_Q_FOREACH) { ForeachStatementAST *ast = new (_pool) ForeachStatementAST; ast->foreach_token = consumeToken(); @@ -2179,6 +2292,7 @@ bool Parser::parseForeachStatement(StatementAST *&node) bool Parser::parseForStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_FOR) return false; @@ -2249,11 +2363,13 @@ bool Parser::parseForStatement(StatementAST *&node) bool Parser::parseForInitStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); return parseExpressionOrDeclarationStatement(node); } bool Parser::parseCompoundStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LBRACE) { CompoundStatementAST *ast = new (_pool) CompoundStatementAST; ast->lbrace_token = consumeToken(); @@ -2282,6 +2398,7 @@ bool Parser::parseCompoundStatement(StatementAST *&node) bool Parser::parseIfStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_IF) { IfStatementAST *ast = new (_pool) IfStatementAST; ast->if_token = consumeToken(); @@ -2303,6 +2420,7 @@ bool Parser::parseIfStatement(StatementAST *&node) bool Parser::parseSwitchStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_SWITCH) { SwitchStatementAST *ast = new (_pool) SwitchStatementAST; ast->switch_token = consumeToken(); @@ -2318,6 +2436,7 @@ bool Parser::parseSwitchStatement(StatementAST *&node) bool Parser::parseLabeledStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_IDENTIFIER: if (LA(2) == T_COLON) { @@ -2357,6 +2476,7 @@ bool Parser::parseLabeledStatement(StatementAST *&node) bool Parser::parseBlockDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_USING: return parseUsing(node); @@ -2375,6 +2495,7 @@ bool Parser::parseBlockDeclaration(DeclarationAST *&node) bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_NAMESPACE && LA(2) == T_IDENTIFIER && LA(3) == T_EQUAL) { NamespaceAliasDefinitionAST *ast = new (_pool) NamespaceAliasDefinitionAST; ast->namespace_token = consumeToken(); @@ -2390,10 +2511,19 @@ bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node) bool Parser::parseDeclarationStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); + unsigned start = cursor(); DeclarationAST *declaration = 0; if (! parseBlockDeclaration(declaration)) return false; + if (SimpleDeclarationAST *simpleDeclaration = declaration->asSimpleDeclaration()) { + if (! simpleDeclaration->decl_specifier_seq) { + rewind(start); + return false; + } + } + DeclarationStatementAST *ast = new (_pool) DeclarationStatementAST; ast->declaration = declaration; node = ast; @@ -2477,6 +2607,7 @@ bool Parser::lookAtClassKey() const bool Parser::parseAttributeSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T___ATTRIBUTE__) return false; @@ -2493,6 +2624,7 @@ bool Parser::parseAttributeSpecifier(SpecifierAST *&node) bool Parser::parseAttributeList(AttributeAST *&node) { + DEBUG_THIS_RULE(); AttributeAST **attribute_ptr = &node; while (LA() == T_IDENTIFIER || LA() == T_CONST) { AttributeAST *ast = new (_pool) AttributeAST; @@ -2523,6 +2655,7 @@ bool Parser::parseAttributeList(AttributeAST *&node) bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T___ATTRIBUTE__) { return parseAttributeSpecifier(node); } else if (LA() == T___TYPEOF__) { @@ -2553,6 +2686,7 @@ bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node) bool Parser::parseSimpleDeclaration(DeclarationAST *&node, bool acceptStructDeclarator) { + DEBUG_THIS_RULE(); unsigned qt_invokable_token = 0; if (acceptStructDeclarator && (LA() == T_Q_SIGNAL || LA() == T_Q_SLOT)) qt_invokable_token = consumeToken(); @@ -2653,6 +2787,12 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, return false; } + // if there is no valid declarator + // and it doesn't look like a fwd or a class declaration + // then it's not a declarations + if (! declarator && ! maybeForwardOrClassDeclaration(decl_specifier_seq)) + return false; + DeclaratorAST *firstDeclarator = declarator; if (declarator) { @@ -2709,8 +2849,22 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, return false; } +bool Parser::maybeForwardOrClassDeclaration(SpecifierAST *decl_specifier_seq) const +{ + // look at the decl_specifier for possible fwd or class declarations. + if (SpecifierAST *spec = decl_specifier_seq) { + if (! spec->next && (spec->asElaboratedTypeSpecifier() || + spec->asEnumSpecifier() || + spec->asClassSpecifier())) + return true; + } + + return false; +} + bool Parser::parseFunctionBody(StatementAST *&node) { + DEBUG_THIS_RULE(); if (_translationUnit->skipFunctionBody()) { unsigned token_lbrace = 0; match(T_LBRACE, &token_lbrace); @@ -2733,6 +2887,7 @@ bool Parser::parseFunctionBody(StatementAST *&node) bool Parser::parseTryBlockStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_TRY) { TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST; ast->try_token = consumeToken(); @@ -2748,6 +2903,7 @@ bool Parser::parseTryBlockStatement(StatementAST *&node) bool Parser::parseCatchClause(CatchClauseAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_CATCH) { CatchClauseAST *ast = new (_pool) CatchClauseAST; ast->catch_token = consumeToken(); @@ -2763,6 +2919,7 @@ bool Parser::parseCatchClause(CatchClauseAST *&node) bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_DOT_DOT_DOT) { ExceptionDeclarationAST *ast = new (_pool) ExceptionDeclarationAST; ast->dot_dot_dot_token = consumeToken(); @@ -2783,6 +2940,7 @@ bool Parser::parseExceptionDeclaration(ExceptionDeclarationAST *&node) bool Parser::parseBoolLiteral(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_TRUE || LA() == T_FALSE) { BoolLiteralAST *ast = new (_pool) BoolLiteralAST; ast->literal_token = consumeToken(); @@ -2794,6 +2952,7 @@ bool Parser::parseBoolLiteral(ExpressionAST *&node) bool Parser::parseNumericLiteral(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_NUMERIC_LITERAL || LA() == T_CHAR_LITERAL || LA() == T_WIDE_CHAR_LITERAL) { @@ -2807,6 +2966,7 @@ bool Parser::parseNumericLiteral(ExpressionAST *&node) bool Parser::parseThisExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_THIS) { ThisExpressionAST *ast = new (_pool) ThisExpressionAST; ast->this_token = consumeToken(); @@ -2818,6 +2978,7 @@ bool Parser::parseThisExpression(ExpressionAST *&node) bool Parser::parsePrimaryExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_STRING_LITERAL: case T_WIDE_STRING_LITERAL: @@ -2865,6 +3026,7 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) bool Parser::parseObjCExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_AT_ENCODE: return parseObjCEncodeExpression(node); @@ -2889,6 +3051,7 @@ bool Parser::parseObjCExpression(ExpressionAST *&node) bool Parser::parseObjCStringLiteral(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_STRING_LITERAL) return false; @@ -2904,6 +3067,7 @@ bool Parser::parseObjCStringLiteral(ExpressionAST *&node) bool Parser::parseObjCSynchronizedStatement(StatementAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_SYNCHRONIZED) return false; @@ -2921,6 +3085,7 @@ bool Parser::parseObjCSynchronizedStatement(StatementAST *&node) bool Parser::parseObjCEncodeExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_ENCODE) return false; @@ -2933,6 +3098,7 @@ bool Parser::parseObjCEncodeExpression(ExpressionAST *&node) bool Parser::parseObjCProtocolExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_PROTOCOL) return false; @@ -2947,6 +3113,7 @@ bool Parser::parseObjCProtocolExpression(ExpressionAST *&node) bool Parser::parseObjCSelectorExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_SELECTOR) return false; @@ -2985,27 +3152,45 @@ bool Parser::parseObjCSelectorExpression(ExpressionAST *&node) bool Parser::parseObjCMessageExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_LBRACKET) return false; - ObjCMessageExpressionAST *ast = new (_pool) ObjCMessageExpressionAST; - ast->lbracket_token = consumeToken(); + unsigned start = cursor(); - parseObjCMessageReceiver(ast->receiver_expression); - parseObjCMessageArguments(ast->selector, ast->argument_list); + unsigned lbracket_token = consumeToken(); + ExpressionAST *receiver_expression = 0; + ObjCSelectorAST *selector = 0; + ObjCMessageArgumentListAST *argument_list = 0; - match(T_RBRACKET, &(ast->rbracket_token)); - node = ast; - return true; + if (parseObjCMessageReceiver(receiver_expression) && + parseObjCMessageArguments(selector, argument_list)) { + + ObjCMessageExpressionAST *ast = new (_pool) ObjCMessageExpressionAST; + ast->lbracket_token = lbracket_token; + ast->receiver_expression = receiver_expression; + ast->selector = selector; + ast->argument_list = argument_list; + + match(T_RBRACKET, &(ast->rbracket_token)); + node = ast; + + return true; + } + + rewind(start); + return false; } bool Parser::parseObjCMessageReceiver(ExpressionAST *&node) { + DEBUG_THIS_RULE(); return parseExpression(node); } bool Parser::parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArgumentListAST *& argNode) { + DEBUG_THIS_RULE(); if (LA() == T_RBRACKET) return false; // nothing to do. @@ -3051,19 +3236,25 @@ bool Parser::parseObjCMessageArguments(ObjCSelectorAST *&selNode, ObjCMessageArg selNode = selWithArgs; argNode = argAst; + return true; } else { rewind(start); + unsigned name_token = 0; + if (!parseObjCSelector(name_token)) + return false; ObjCSelectorWithoutArgumentsAST *sel = new (_pool) ObjCSelectorWithoutArgumentsAST; - parseObjCSelector(sel->name_token); + sel->name_token = name_token; selNode = sel; argNode = 0; + return true; } - return true; + return false; } bool Parser::parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessageArgumentAST *&argNode) { + DEBUG_THIS_RULE(); unsigned selector_token = 0; if (!parseObjCSelector(selector_token)) return false; @@ -3087,6 +3278,7 @@ bool Parser::parseObjCSelectorArg(ObjCSelectorArgumentAST *&selNode, ObjCMessage bool Parser::parseObjCMethodSignature() { + DEBUG_THIS_RULE(); unsigned selector_token = 0; if (parseObjCSelector(selector_token)) { while (LA() == T_COMMA) { @@ -3100,20 +3292,37 @@ bool Parser::parseObjCMethodSignature() bool Parser::parseNameId(NameAST *&name) { + DEBUG_THIS_RULE(); unsigned start = cursor(); if (! parseName(name)) return false; - TemplateIdAST *template_id = name->asTemplateId(); - if (LA() == T_LPAREN && template_id) { + QualifiedNameAST *qualified_name_id = name->asQualifiedName(); + + TemplateIdAST *template_id = 0; + if (qualified_name_id) { + if (NameAST *unqualified_name = qualified_name_id->unqualified_name) + template_id = unqualified_name->asTemplateId(); + } else { + template_id = name->asTemplateId(); + } + + if (! template_id) + return true; // it's not a template-id, there's nothing to rewind. + + else if (LA() == T_LPAREN) { + // a template-id followed by a T_LPAREN if (TemplateArgumentListAST *template_arguments = template_id->template_arguments) { if (! template_arguments->next && template_arguments->template_argument && template_arguments->template_argument->asBinaryExpression()) { + unsigned saved = cursor(); ExpressionAST *expr = 0; + bool blocked = blockErrors(true); bool lookAtCastExpression = parseCastExpression(expr); (void) blockErrors(blocked); + if (lookAtCastExpression) { if (CastExpressionAST *cast_expression = expr->asCastExpression()) { if (cast_expression->lparen_token && cast_expression->rparen_token @@ -3130,26 +3339,34 @@ bool Parser::parseNameId(NameAST *&name) } } - if (LA() == T_COMMA || LA() == T_SEMICOLON || - LA() == T_LBRACKET || LA() == T_LPAREN) + switch (LA()) { + case T_COMMA: + case T_SEMICOLON: + case T_LBRACKET: + case T_LPAREN: return true; - else if (LA() == T_IDENTIFIER || - LA() == T_STATIC_CAST || - LA() == T_DYNAMIC_CAST || - LA() == T_REINTERPRET_CAST || - LA() == T_CONST_CAST || - tok().isLiteral() || - tok().isOperator()) - { + + case T_IDENTIFIER: + case T_STATIC_CAST: + case T_DYNAMIC_CAST: + case T_REINTERPRET_CAST: + case T_CONST_CAST: rewind(start); return parseName(name, false); - } + + default: + if (tok().isLiteral() || tok().isOperator()) { + rewind(start); + return parseName(name, false); + } + } // switch return true; } bool Parser::parseNestedExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LPAREN) { unsigned lparen_token = consumeToken(); @@ -3184,6 +3401,7 @@ bool Parser::parseNestedExpression(ExpressionAST *&node) bool Parser::parseCppCastExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_DYNAMIC_CAST || LA() == T_STATIC_CAST || LA() == T_REINTERPRET_CAST || LA() == T_CONST_CAST) { CppCastExpressionAST *ast = new (_pool) CppCastExpressionAST; @@ -3204,6 +3422,7 @@ bool Parser::parseCppCastExpression(ExpressionAST *&node) // typename ::opt nested-name-specifier templateopt template-id ( expression-listopt ) bool Parser::parseTypenameCallExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_TYPENAME) { unsigned typename_token = consumeToken(); NameAST *name = 0; @@ -3225,6 +3444,7 @@ bool Parser::parseTypenameCallExpression(ExpressionAST *&node) // typeid ( type-id ) bool Parser::parseTypeidExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_TYPEID) { TypeidExpressionAST *ast = new (_pool) TypeidExpressionAST; ast->typeid_token = consumeToken(); @@ -3244,13 +3464,22 @@ bool Parser::parseTypeidExpression(ExpressionAST *&node) bool Parser::parseCorePostfixExpression(ExpressionAST *&node) { - if (parseCppCastExpression(node)) - return true; - else if (parseTypenameCallExpression(node)) - return true; - else if (parseTypeidExpression(node)) - return true; - else { + DEBUG_THIS_RULE(); + + switch (LA()) { + case T_DYNAMIC_CAST: + case T_STATIC_CAST: + case T_REINTERPRET_CAST: + case T_CONST_CAST: + return parseCppCastExpression(node); + + case T_TYPENAME: + return parseTypenameCallExpression(node); + + case T_TYPEID: + return parseTypeidExpression(node); + + default: { unsigned start = cursor(); SpecifierAST *type_specifier = 0; bool blocked = blockErrors(true); @@ -3297,11 +3526,13 @@ bool Parser::parseCorePostfixExpression(ExpressionAST *&node) blockErrors(blocked); return parsePrimaryExpression(node); - } + } // default + } // switch } bool Parser::parsePostfixExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (parseCorePostfixExpression(node)) { PostfixAST *postfix_expressions = 0, **postfix_ptr = &postfix_expressions; @@ -3351,6 +3582,7 @@ bool Parser::parsePostfixExpression(ExpressionAST *&node) bool Parser::parseUnaryExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_PLUS_PLUS: case T_MINUS_MINUS: @@ -3415,6 +3647,7 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) // new-placement ::= T_LPAREN expression-list T_RPAREN bool Parser::parseNewPlacement(NewPlacementAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LPAREN) { unsigned lparen_token = consumeToken(); ExpressionListAST *expression_list = 0; @@ -3438,6 +3671,7 @@ bool Parser::parseNewPlacement(NewPlacementAST *&node) // T_LPAREN type-id T_RPAREN new-initializer.opt bool Parser::parseNewExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! (LA() == T_NEW || (LA() == T_COLON_COLON && LA(2) == T_NEW))) return false; @@ -3501,6 +3735,7 @@ bool Parser::parseNewExpression(ExpressionAST *&node) bool Parser::parseNewTypeId(NewTypeIdAST *&node) { + DEBUG_THIS_RULE(); SpecifierAST *typeSpec = 0; if (! parseTypeSpecifier(typeSpec)) return false; @@ -3520,6 +3755,7 @@ bool Parser::parseNewTypeId(NewTypeIdAST *&node) bool Parser::parseNewArrayDeclarator(NewArrayDeclaratorAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_LBRACKET) return false; @@ -3533,6 +3769,7 @@ bool Parser::parseNewArrayDeclarator(NewArrayDeclaratorAST *&node) bool Parser::parseNewInitializer(NewInitializerAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LPAREN) { unsigned lparen_token = consumeToken(); ExpressionAST *expression = 0; @@ -3550,6 +3787,7 @@ bool Parser::parseNewInitializer(NewInitializerAST *&node) bool Parser::parseDeleteExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_DELETE || (LA() == T_COLON_COLON && LA(2) == T_DELETE)) { DeleteExpressionAST *ast = new (_pool) DeleteExpressionAST; @@ -3572,6 +3810,7 @@ bool Parser::parseDeleteExpression(ExpressionAST *&node) bool Parser::parseCastExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_LPAREN) { unsigned lparen_token = consumeToken(); ExpressionAST *type_id = 0; @@ -3595,6 +3834,7 @@ bool Parser::parseCastExpression(ExpressionAST *&node) bool Parser::parsePmExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseCastExpression(node)) return false; @@ -3616,6 +3856,7 @@ bool Parser::parsePmExpression(ExpressionAST *&node) bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parsePmExpression(node)) return false; @@ -3637,6 +3878,7 @@ bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) bool Parser::parseAdditiveExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseMultiplicativeExpression(node)) return false; @@ -3658,6 +3900,7 @@ bool Parser::parseAdditiveExpression(ExpressionAST *&node) bool Parser::parseShiftExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseAdditiveExpression(node)) return false; @@ -3679,6 +3922,7 @@ bool Parser::parseShiftExpression(ExpressionAST *&node) bool Parser::parseRelationalExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseShiftExpression(node)) return false; @@ -3701,6 +3945,7 @@ bool Parser::parseRelationalExpression(ExpressionAST *&node) bool Parser::parseEqualityExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseRelationalExpression(node)) return false; @@ -3722,6 +3967,7 @@ bool Parser::parseEqualityExpression(ExpressionAST *&node) bool Parser::parseAndExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseEqualityExpression(node)) return false; @@ -3743,6 +3989,7 @@ bool Parser::parseAndExpression(ExpressionAST *&node) bool Parser::parseExclusiveOrExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseAndExpression(node)) return false; @@ -3764,6 +4011,7 @@ bool Parser::parseExclusiveOrExpression(ExpressionAST *&node) bool Parser::parseInclusiveOrExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseExclusiveOrExpression(node)) return false; @@ -3786,6 +4034,7 @@ bool Parser::parseInclusiveOrExpression(ExpressionAST *&node) bool Parser::parseLogicalAndExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseInclusiveOrExpression(node)) return false; @@ -3807,6 +4056,7 @@ bool Parser::parseLogicalAndExpression(ExpressionAST *&node) bool Parser::parseLogicalOrExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseLogicalAndExpression(node)) return false; @@ -3829,6 +4079,7 @@ bool Parser::parseLogicalOrExpression(ExpressionAST *&node) bool Parser::parseConditionalExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseLogicalOrExpression(node)) return false; @@ -3868,6 +4119,7 @@ bool Parser::lookAtAssignmentOperator() const bool Parser::parseAssignmentExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_THROW) return parseThrowExpression(node); else if (! parseConditionalExpression(node)) @@ -3892,6 +4144,7 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node) bool Parser::parseQtMethod(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_SIGNAL || LA() == T_SLOT) { QtMethodAST *ast = new (_pool) QtMethodAST; ast->method_token = consumeToken(); @@ -3908,16 +4161,19 @@ bool Parser::parseQtMethod(ExpressionAST *&node) bool Parser::parseConstantExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); return parseConditionalExpression(node); } bool Parser::parseExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); return parseCommaExpression(node); } bool Parser::parseCommaExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (! parseAssignmentExpression(node)) return false; @@ -3939,6 +4195,7 @@ bool Parser::parseCommaExpression(ExpressionAST *&node) bool Parser::parseThrowExpression(ExpressionAST *&node) { + DEBUG_THIS_RULE(); if (LA() == T_THROW) { ThrowExpressionAST *ast = new (_pool) ThrowExpressionAST; ast->throw_token = consumeToken(); @@ -3978,6 +4235,7 @@ bool Parser::lookAtObjCSelector() const // bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_CLASS) return false; @@ -4028,6 +4286,7 @@ bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node) bool Parser::parseObjCInterface(DeclarationAST *&node, SpecifierAST *attributes) { + DEBUG_THIS_RULE(); if (! attributes && LA() == T___ATTRIBUTE__) { SpecifierAST **attr = &attributes; while (parseAttributeSpecifier(*attr)) @@ -4117,6 +4376,7 @@ bool Parser::parseObjCInterface(DeclarationAST *&node, bool Parser::parseObjCProtocol(DeclarationAST *&node, SpecifierAST *attributes) { + DEBUG_THIS_RULE(); if (! attributes && LA() == T___ATTRIBUTE__) { SpecifierAST **attr = &attributes; while (parseAttributeSpecifier(*attr)) @@ -4189,6 +4449,7 @@ bool Parser::parseObjCProtocol(DeclarationAST *&node, // bool Parser::parseObjCImplementation(DeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_AT_IMPLEMENTATION) return false; @@ -4241,6 +4502,7 @@ bool Parser::parseObjCImplementation(DeclarationAST *&node) bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node) { + DEBUG_THIS_RULE(); DeclarationListAST **next = &node; while (LA() && LA() != T_AT_END) { @@ -4345,6 +4607,7 @@ bool Parser::parseObjCMethodDefinitionList(DeclarationListAST *&node) bool Parser::parseObjCMethodDefinition(DeclarationAST *&node) { + DEBUG_THIS_RULE(); ObjCMethodPrototypeAST *method_prototype = 0; if (! parseObjCMethodPrototype(method_prototype)) return false; @@ -4370,6 +4633,7 @@ bool Parser::parseObjCMethodDefinition(DeclarationAST *&node) // bool Parser::parseObjCProtocolRefs(ObjCProtocolRefsAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_LESS) return false; @@ -4408,6 +4672,7 @@ bool Parser::parseObjCProtocolRefs(ObjCProtocolRefsAST *&node) // bool Parser::parseObjClassInstanceVariables(ObjCInstanceVariablesDeclarationAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_LBRACE) return false; @@ -4443,6 +4708,7 @@ bool Parser::parseObjClassInstanceVariables(ObjCInstanceVariablesDeclarationAST // objc-interface-declaration ::= objc-method-prototype bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_AT_END: return false; @@ -4491,6 +4757,7 @@ bool Parser::parseObjCInterfaceMemberDeclaration(DeclarationAST *&node) // bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node) { + DEBUG_THIS_RULE(); switch (LA()) { case T_AT_PRIVATE: case T_AT_PROTECTED: @@ -4512,6 +4779,7 @@ bool Parser::parseObjCInstanceVariableDeclaration(DeclarationAST *&node) // bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierAST *attributes) { + DEBUG_THIS_RULE(); if (LA() != T_AT_PROPERTY) return false; @@ -4558,6 +4826,7 @@ bool Parser::parseObjCPropertyDeclaration(DeclarationAST *&node, SpecifierAST *a // bool Parser::parseObjCMethodPrototype(ObjCMethodPrototypeAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_PLUS && LA() != T_MINUS) return false; @@ -4629,6 +4898,7 @@ bool Parser::parseObjCMethodPrototype(ObjCMethodPrototypeAST *&node) // objc-property-attribute ::= nonatomic bool Parser::parseObjCPropertyAttribute(ObjCPropertyAttributeAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_IDENTIFIER) return false; @@ -4676,6 +4946,7 @@ bool Parser::parseObjCPropertyAttribute(ObjCPropertyAttributeAST *&node) // bool Parser::parseObjCTypeName(ObjCTypeNameAST *&node) { + DEBUG_THIS_RULE(); if (LA() != T_LPAREN) return false; @@ -4692,6 +4963,7 @@ bool Parser::parseObjCTypeName(ObjCTypeNameAST *&node) // bool Parser::parseObjCSelector(unsigned &selector_token) { + DEBUG_THIS_RULE(); if (! lookAtObjCSelector()) return false; @@ -4703,6 +4975,7 @@ bool Parser::parseObjCSelector(unsigned &selector_token) // bool Parser::parseObjCKeywordDeclaration(ObjCSelectorArgumentAST *&argument, ObjCMessageArgumentDeclarationAST *&node) { + DEBUG_THIS_RULE(); if (! (LA() == T_COLON || (lookAtObjCSelector() && LA(2) == T_COLON))) return false; @@ -4725,6 +4998,7 @@ bool Parser::parseObjCKeywordDeclaration(ObjCSelectorArgumentAST *&argument, Obj bool Parser::parseObjCTypeQualifiers(unsigned &type_qualifier) { + DEBUG_THIS_RULE(); if (LA() != T_IDENTIFIER) return false; @@ -4748,6 +5022,8 @@ bool Parser::peekAtObjCContextKeyword(int kind) bool Parser::parseObjCContextKeyword(int kind, unsigned &in_token) { + DEBUG_THIS_RULE(); + if (peekAtObjCContextKeyword(kind)) { in_token = consumeToken(); return true; @@ -4756,4 +5032,4 @@ bool Parser::parseObjCContextKeyword(int kind, unsigned &in_token) } } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Parser.h b/src/shared/cplusplus/Parser.h index 2f274e93ab546af2c652e61d9659d6d5542239ef..3ca3371d815956cbbe47ced8f091a0010b89194e 100644 --- a/src/shared/cplusplus/Parser.h +++ b/src/shared/cplusplus/Parser.h @@ -54,8 +54,8 @@ #include "Token.h" #include "TranslationUnit.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Parser { @@ -264,8 +264,9 @@ public: void match(int kind, unsigned *token); - bool maybeFunctionCall(SimpleDeclarationAST *simpleDecl) const; - bool maybeSimpleExpression(SimpleDeclarationAST *simpleDecl) const; + bool maybeAmbiguousStatement(DeclarationStatementAST *ast) const; + bool maybeForwardOrClassDeclaration(SpecifierAST *decl_specifier_seq) const; + bool isPointerDeclaration(DeclarationStatementAST *ast) const; private: bool switchTemplateArguments(bool templateArguments); @@ -302,7 +303,7 @@ private: void operator =(const Parser& source); }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_PARSER_H diff --git a/src/shared/cplusplus/Scope.cpp b/src/shared/cplusplus/Scope.cpp index fcb5a68027cd80c317c3f9da376fe5aa5eea8ffa..16026f8060a9d8b149e158ca988153bcdfcc03c7 100644 --- a/src/shared/cplusplus/Scope.cpp +++ b/src/shared/cplusplus/Scope.cpp @@ -57,7 +57,7 @@ using namespace std; -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; Scope::Scope(ScopedSymbol *owner) : _owner(owner), @@ -312,4 +312,4 @@ Scope::iterator Scope::firstSymbol() const Scope::iterator Scope::lastSymbol() const { return _symbols + _symbolCount + 1; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Scope.h b/src/shared/cplusplus/Scope.h index 1abc41530df381cebbf5f1626812f81d2a0c7784..c05a718ff379c9f467db23839cc2287010dab73e 100644 --- a/src/shared/cplusplus/Scope.h +++ b/src/shared/cplusplus/Scope.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Scope { @@ -153,7 +153,7 @@ private: int _hashSize; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_SCOPE_H diff --git a/src/shared/cplusplus/Semantic.cpp b/src/shared/cplusplus/Semantic.cpp index c2ea233d6978477d03eed4870c8e2b4f97932cc1..e3b4b0b7ca4e4de0ac01f14fcf57494a72e7a5a2 100644 --- a/src/shared/cplusplus/Semantic.cpp +++ b/src/shared/cplusplus/Semantic.cpp @@ -59,7 +59,7 @@ #include "CheckExpression.h" #include "CheckName.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; class Semantic::Data { @@ -252,4 +252,4 @@ int Semantic::visibilityForClassKey(int tokenKind) const } } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Semantic.h b/src/shared/cplusplus/Semantic.h index 8a0df9a111fc7a6c620fb38f2ee997aaab73ce1c..b07883e8473d854b597d4e9b6c9f67df95c3d7e3 100644 --- a/src/shared/cplusplus/Semantic.h +++ b/src/shared/cplusplus/Semantic.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "ASTfwd.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Semantic { @@ -114,7 +114,7 @@ private: Data *d; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_SEMANTIC_H diff --git a/src/shared/cplusplus/SemanticCheck.cpp b/src/shared/cplusplus/SemanticCheck.cpp index 92fdbf83897505d595bc99f9739a0ab607976ed3..1feffd93aa5a35a5d97e6bc63617a69663573567 100644 --- a/src/shared/cplusplus/SemanticCheck.cpp +++ b/src/shared/cplusplus/SemanticCheck.cpp @@ -49,7 +49,7 @@ #include "SemanticCheck.h" #include "Semantic.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; SemanticCheck::SemanticCheck(Semantic *semantic) : ASTVisitor(semantic->control()), @@ -65,4 +65,4 @@ Semantic *SemanticCheck::semantic() const Control *SemanticCheck::control() const { return _semantic->control(); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/SemanticCheck.h b/src/shared/cplusplus/SemanticCheck.h index 219a216e6ed55d7d03fe0626ea407eec9e447bc7..64523d903cee3aabc55855dfb2ee088c7275bea2 100644 --- a/src/shared/cplusplus/SemanticCheck.h +++ b/src/shared/cplusplus/SemanticCheck.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include "ASTVisitor.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT SemanticCheck: public ASTVisitor { @@ -68,7 +68,7 @@ private: Semantic *_semantic; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_SEMANTICCHECK_H diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp index dc80add92b2c92c9a7295ab19e74ee3bbe210b54..c04df48bafe68caa89d4d42a077c44bc16a8d372 100644 --- a/src/shared/cplusplus/Symbol.cpp +++ b/src/shared/cplusplus/Symbol.cpp @@ -59,7 +59,7 @@ #include <cstddef> #include <cassert> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; class Symbol::HashCode: protected NameVisitor { @@ -476,4 +476,4 @@ bool Symbol::isObjCForwardProtocolDeclaration() const bool Symbol::isObjCMethod() const { return asObjCMethod() != 0; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h index 0857673d3f4df62b9a9e14d3841f69375ed899dc..93d730b0cfb1821789b5c27a36002d7595a120c9 100644 --- a/src/shared/cplusplus/Symbol.h +++ b/src/shared/cplusplus/Symbol.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Symbol { @@ -331,7 +331,7 @@ private: friend class Scope; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_SYMBOL_H diff --git a/src/shared/cplusplus/SymbolVisitor.cpp b/src/shared/cplusplus/SymbolVisitor.cpp index 09556c07738e5ecf83d0a8aa86f4458cffb9c42f..de2a5f7eaf3a2a47a5ae326667bf6c94e024f932 100644 --- a/src/shared/cplusplus/SymbolVisitor.cpp +++ b/src/shared/cplusplus/SymbolVisitor.cpp @@ -49,7 +49,7 @@ #include "SymbolVisitor.h" #include "Symbol.h" -CPLUSPLUS_USE_NAMESPACE +using namespace CPlusPlus; SymbolVisitor::SymbolVisitor() { } diff --git a/src/shared/cplusplus/SymbolVisitor.h b/src/shared/cplusplus/SymbolVisitor.h index 8708ab03212ea7c5a08f80a09441078e875e564c..4bfa3794308ecb67902b83d8524dd20b7aa8039a 100644 --- a/src/shared/cplusplus/SymbolVisitor.h +++ b/src/shared/cplusplus/SymbolVisitor.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT SymbolVisitor { @@ -90,7 +90,7 @@ public: virtual bool visit(ObjCMethod *) { return true; } }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // SYMBOLVISITOR_H diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp index d5fa07a99b9b103d09d7a5944b34a743de196ea2..aa15735410f7b2fb68bfd76bb39c97eb4360f7a5 100644 --- a/src/shared/cplusplus/Symbols.cpp +++ b/src/shared/cplusplus/Symbols.cpp @@ -53,7 +53,7 @@ #include "Scope.h" #include <cstdlib> -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; TemplateParameters::TemplateParameters(Scope *scope) : _previous(0), _scope(scope) @@ -819,4 +819,4 @@ void ObjCMethod::visitSymbol0(SymbolVisitor *visitor) } } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h index 10eb0366bffce04386977009c63551c182c9ec69..acd13085f5b06bf2ce001175561342029c203110 100644 --- a/src/shared/cplusplus/Symbols.h +++ b/src/shared/cplusplus/Symbols.h @@ -55,8 +55,8 @@ #include "FullySpecifiedType.h" #include "Array.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class TemplateParameters { @@ -729,7 +729,7 @@ private: Scope *_arguments; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_SYMBOLS_H diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp index 547849b1ccb7adfcd42b8d135949f84aa472ec85..48bf61354f023cc8c12fd696dc2ed8bfa471ec0f 100644 --- a/src/shared/cplusplus/Token.cpp +++ b/src/shared/cplusplus/Token.cpp @@ -49,7 +49,7 @@ #include "Token.h" #include "Literals.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; static const char *token_names[] = { (""), ("<error>"), @@ -133,4 +133,4 @@ const char *Token::spell() const } // switch } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h index 00d42b7f89c9927c93b04714c75a0a91177f54e1..8bafc446875c31a3a62990cda1d385e292509d0e 100644 --- a/src/shared/cplusplus/Token.h +++ b/src/shared/cplusplus/Token.h @@ -52,8 +52,8 @@ #include "CPlusPlusForwardDeclarations.h" #include <cstddef> -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { enum Kind { T_EOF_SYMBOL = 0, @@ -336,7 +336,7 @@ public: }; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_TOKEN_H diff --git a/src/shared/cplusplus/TranslationUnit.cpp b/src/shared/cplusplus/TranslationUnit.cpp index b661bf26a0474cb8ca55b448cbafcc4f75951ca9..0cecccf3199753b9daf5ab26bb80e1c4457c47b3 100644 --- a/src/shared/cplusplus/TranslationUnit.cpp +++ b/src/shared/cplusplus/TranslationUnit.cpp @@ -61,7 +61,7 @@ using namespace std; -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; TranslationUnit::TranslationUnit(Control *control, StringLiteral *fileId) : _control(control), @@ -517,4 +517,4 @@ void TranslationUnit::release() _tokens = 0; } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/TranslationUnit.h b/src/shared/cplusplus/TranslationUnit.h index 608d510f70bba7e47eec51760fa14b820b63c8b3..cc26f44be414936485bea93709397073f5c58836 100644 --- a/src/shared/cplusplus/TranslationUnit.h +++ b/src/shared/cplusplus/TranslationUnit.h @@ -56,8 +56,8 @@ #include <stdio.h> // for FILE* #include <vector> // ### remove me -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT TranslationUnit { @@ -204,7 +204,7 @@ private: }; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_TRANSLATIONUNIT_H diff --git a/src/shared/cplusplus/Type.cpp b/src/shared/cplusplus/Type.cpp index 99cef5fab4c6bca723df5fbec6f85966cc27e926..56a521cd85ac6d839a86b1acf2433a2109231c2b 100644 --- a/src/shared/cplusplus/Type.cpp +++ b/src/shared/cplusplus/Type.cpp @@ -51,7 +51,7 @@ #include "CoreTypes.h" #include "Symbols.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; Type::Type() { } @@ -131,4 +131,4 @@ void Type::accept(Type *type, TypeVisitor *visitor) type->accept(visitor); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/Type.h b/src/shared/cplusplus/Type.h index a3c5fb0c006cc33b03b5ff8f9a493f1915a28522..82dfa1f63a2cacd883ce96fd3bba8b8df6506271 100644 --- a/src/shared/cplusplus/Type.h +++ b/src/shared/cplusplus/Type.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT Type { @@ -130,7 +130,7 @@ protected: virtual void accept0(TypeVisitor *visitor) = 0; }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_TYPE_H diff --git a/src/shared/cplusplus/TypeVisitor.cpp b/src/shared/cplusplus/TypeVisitor.cpp index 1f1b7eff163836f96d6c2c24f94c3c9e99179a3f..4c795c96e0b9b88b40e0ef009e36796b33b72b11 100644 --- a/src/shared/cplusplus/TypeVisitor.cpp +++ b/src/shared/cplusplus/TypeVisitor.cpp @@ -49,7 +49,7 @@ #include "TypeVisitor.h" #include "Type.h" -CPLUSPLUS_BEGIN_NAMESPACE +using namespace CPlusPlus; TypeVisitor::TypeVisitor() { } @@ -60,4 +60,4 @@ TypeVisitor::~TypeVisitor() void TypeVisitor::accept(Type *type) { Type::accept(type, this); } -CPLUSPLUS_END_NAMESPACE + diff --git a/src/shared/cplusplus/TypeVisitor.h b/src/shared/cplusplus/TypeVisitor.h index 50337ae93f3ddaf61f174c95f4df3c5c30663c50..5d0ef4cd54206ae5a348679929ddbee8ab4afc76 100644 --- a/src/shared/cplusplus/TypeVisitor.h +++ b/src/shared/cplusplus/TypeVisitor.h @@ -51,8 +51,8 @@ #include "CPlusPlusForwardDeclarations.h" -CPLUSPLUS_BEGIN_HEADER -CPLUSPLUS_BEGIN_NAMESPACE + +namespace CPlusPlus { class CPLUSPLUS_EXPORT TypeVisitor { @@ -88,7 +88,7 @@ public: virtual void visit(ObjCForwardProtocolDeclaration*) {} }; -CPLUSPLUS_END_NAMESPACE -CPLUSPLUS_END_HEADER +} // end of namespace CPlusPlus + #endif // CPLUSPLUS_TYPEVISITOR_H diff --git a/src/shared/trk/launcher.cpp b/src/shared/trk/launcher.cpp index 5bd9ff5da177d3adddc1064a73d9e2252124ca47..08af4a215359f409423ac4bcde93d3b9bc744b16 100644 --- a/src/shared/trk/launcher.cpp +++ b/src/shared/trk/launcher.cpp @@ -64,10 +64,12 @@ struct LauncherPrivate { QString m_installFileName; int m_verbose; Launcher::Actions m_startupActions; + bool m_connected; }; LauncherPrivate::LauncherPrivate() : - m_verbose(0) + m_verbose(0), + m_connected(false) { } @@ -148,18 +150,28 @@ bool Launcher::startServer(QString *errorMessage) if (!d->m_device.open(d->m_trkServerName, errorMessage)) return false; d->m_device.sendTrkInitialPing(); - d->m_device.sendTrkMessage(TrkConnect); // Connect + d->m_device.sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected d->m_device.sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask)); d->m_device.sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType)); d->m_device.sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion)); + if (d->m_startupActions != ActionPingOnly) + d->m_device.sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect)); + return true; +} +void Launcher::handleConnect(const TrkResult &result) +{ + if (result.errorCode()) { + emit canNotConnect(result.errorString()); + return; + } + d->m_connected = true; if (d->m_startupActions & ActionCopy) copyFileToRemote(); else if (d->m_startupActions & ActionInstall) installRemotePackageSilently(); else if (d->m_startupActions & ActionRun) startInferiorIfNeeded(); - return true; } void Launcher::setVerbose(int v) @@ -176,11 +188,24 @@ void Launcher::logMessage(const QString &msg) void Launcher::terminate() { - //TODO handle case where application has not been started - QByteArray ba; - appendShort(&ba, 0x0000, TargetByteOrder); - appendInt(&ba, d->m_session.pid, TargetByteOrder); - d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleWaitForFinished), ba); + if (d->m_session.pid) { + QByteArray ba; + appendShort(&ba, 0x0000, TargetByteOrder); + appendInt(&ba, d->m_session.pid, TargetByteOrder); + d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba); + } else if (d->m_connected) { + if (d->m_copyState.copyFileHandle) + closeRemoteFile(true); + disconnectTrk(); + } else { + emit finished(); + } +} + +void Launcher::handleRemoteProcessKilled(const TrkResult &result) +{ + Q_UNUSED(result) + disconnectTrk(); } void Launcher::handleResult(const TrkResult &result) @@ -267,7 +292,7 @@ void Launcher::handleResult(const TrkResult &result) if (itemType == 0 // process && result.data.size() >= 10 && d->m_session.pid == extractInt(result.data.data() + 6)) { - d->m_device.sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); + disconnectTrk(); } break; } @@ -321,7 +346,7 @@ void Launcher::handleFileCreation(const TrkResult &result) { if (result.errorCode() || result.data.size() < 6) { emit canNotCreateFile(d->m_copyState.destinationFileName, result.errorString()); - emit finished(); + disconnectTrk(); return; } const char *data = result.data.data(); @@ -339,7 +364,7 @@ void Launcher::handleCopy(const TrkResult &result) if (result.errorCode() || result.data.size() < 4) { closeRemoteFile(true); emit canNotWriteFile(d->m_copyState.destinationFileName, result.errorString()); - emit finished(); + disconnectTrk(); } else { continueCopying(extractShort(result.data.data() + 2)); } @@ -374,6 +399,8 @@ void Launcher::closeRemoteFile(bool failed) failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied), ba); d->m_copyState.data.reset(); + d->m_copyState.copyFileHandle = 0; + d->m_copyState.position = 0; } void Launcher::handleFileCopied(const TrkResult &result) @@ -385,7 +412,7 @@ void Launcher::handleFileCopied(const TrkResult &result) else if (d->m_startupActions & ActionRun) startInferiorIfNeeded(); else - emit finished(); + disconnectTrk(); } void Launcher::handleCpuType(const TrkResult &result) @@ -410,7 +437,7 @@ void Launcher::handleCreateProcess(const TrkResult &result) { if (result.errorCode()) { emit canNotRun(result.errorString()); - emit finished(); + disconnectTrk(); return; } // 40 00 00] @@ -511,6 +538,11 @@ void Launcher::cleanUp() // Error: 0x00 } +void Launcher::disconnectTrk() +{ + d->m_device.sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished)); +} + void Launcher::copyFileToRemote() { emit copyingStarted(); @@ -533,11 +565,11 @@ void Launcher::handleInstallPackageFinished(const TrkResult &result) { if (result.errorCode()) { emit canNotInstall(d->m_installFileName, result.errorString()); - emit finished(); + disconnectTrk(); } else if (d->m_startupActions & ActionRun) { startInferiorIfNeeded(); } else { - emit finished(); + disconnectTrk(); } } diff --git a/src/shared/trk/launcher.h b/src/shared/trk/launcher.h index aafb6e4896719959aeed2cbd881599c3053b499b..a216b79fcb33cbc89179ba8890e13726fbb50fcf 100644 --- a/src/shared/trk/launcher.h +++ b/src/shared/trk/launcher.h @@ -69,6 +69,7 @@ public: signals: void copyingStarted(); + void canNotConnect(const QString &errorMessage); void canNotCreateFile(const QString &filename, const QString &errorMessage); void canNotWriteFile(const QString &filename, const QString &errorMessage); void canNotCloseFile(const QString &filename, const QString &errorMessage); @@ -90,7 +91,10 @@ private slots: private: // kill process and breakpoints void cleanUp(); + void disconnectTrk(); + void handleRemoteProcessKilled(const TrkResult &result); + void handleConnect(const TrkResult &result); void handleFileCreation(const TrkResult &result); void handleCopy(const TrkResult &result); void continueCopying(uint lastCopiedBlockSize = 0); diff --git a/tests/auto/cplusplus/ast/tst_ast.cpp b/tests/auto/cplusplus/ast/tst_ast.cpp index cad9d51caccdeba3a448665e3938192ef2519ef5..24fbe7865faacf5ef3d50fb81f9828bb7d6ed878 100644 --- a/tests/auto/cplusplus/ast/tst_ast.cpp +++ b/tests/auto/cplusplus/ast/tst_ast.cpp @@ -3,10 +3,11 @@ #include <QtDebug> #include <Control.h> +#include <Literals.h> #include <Parser.h> #include <AST.h> -CPLUSPLUS_USE_NAMESPACE +using namespace CPlusPlus; class tst_AST: public QObject { @@ -15,19 +16,22 @@ class tst_AST: public QObject Control control; public: + TranslationUnit *parse(const QByteArray &source, - TranslationUnit::ParseMode mode) + TranslationUnit::ParseMode mode, + bool blockErrors = false) { StringLiteral *fileId = control.findOrInsertStringLiteral("<stdin>"); TranslationUnit *unit = new TranslationUnit(&control, fileId); unit->setObjCEnabled(true); unit->setSource(source.constData(), source.length()); + unit->blockErrors(blockErrors); unit->parse(mode); return unit; } - TranslationUnit *parseDeclaration(const QByteArray &source) - { return parse(source, TranslationUnit::ParseDeclaration); } + TranslationUnit *parseDeclaration(const QByteArray &source, bool blockErrors = false) + { return parse(source, TranslationUnit::ParseDeclaration, blockErrors); } TranslationUnit *parseExpression(const QByteArray &source) { return parse(source, TranslationUnit::ParseExpression); } @@ -40,25 +44,41 @@ private slots: void gcc_attributes_1(); // expressions - void simple_name(); - void template_id(); + void simple_name_1(); + void template_id_1(); void new_expression_1(); void new_expression_2(); void condition_1(); void init_1(); // statements - void if_statement(); + void if_statement_1(); + void if_statement_2(); + void if_statement_3(); void if_else_statement(); void while_statement(); void while_condition_statement(); void for_statement(); void cpp_initializer_or_function_declaration(); + void simple_declaration_1(); + void function_call_1(); + void function_call_2(); + void function_call_3(); + void function_call_4(); + void nested_deref_expression(); + void assignment_1(); + void assignment_2(); // objc++ void objc_attributes_followed_by_at_keyword(); void objc_protocol_forward_declaration_1(); void objc_protocol_definition_1(); + + // expressions with (square) brackets + void normal_array_access(); + void array_access_with_nested_expression(); + void objc_msg_send_expression(); + void objc_msg_send_expression_without_selector(); }; void tst_AST::gcc_attributes_1() @@ -68,7 +88,20 @@ void tst_AST::gcc_attributes_1() )); } -void tst_AST::simple_name() +void tst_AST::simple_declaration_1() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("\n" +"a * b = 10;" + )); + + AST *ast = unit->ast(); + QVERIFY(ast); + + DeclarationStatementAST *declStmt = ast->asDeclarationStatement(); + QVERIFY(declStmt); +} + +void tst_AST::simple_name_1() { QSharedPointer<TranslationUnit> unit(parseExpression("a")); AST *ast = unit->ast(); @@ -78,7 +111,7 @@ void tst_AST::simple_name() QCOMPARE(ast->asSimpleName()->identifier_token, 1U); } -void tst_AST::template_id() +void tst_AST::template_id_1() { QSharedPointer<TranslationUnit> unit(parseExpression("list<10>")); AST *ast = unit->ast(); @@ -151,7 +184,7 @@ void tst_AST::new_expression_2() void tst_AST::condition_1() { QSharedPointer<TranslationUnit> unit(parseExpression("\n" -"(x < 0 && y > (int) a" +"(x < 0 && y > (int) a)" )); AST *ast = unit->ast(); @@ -168,7 +201,63 @@ void tst_AST::init_1() QVERIFY(ast != 0); } -void tst_AST::if_statement() +void tst_AST::function_call_1() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("retranslateUi(blah);")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::function_call_2() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("retranslateUi(10);")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::function_call_3() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("advance();")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::function_call_4() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("checkPropertyAttribute(attrAst, propAttrs, ReadWrite);")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::nested_deref_expression() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("(*blah);")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::assignment_1() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("a(x) = 3;")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::assignment_2() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("(*blah) = 10;")); + AST *ast = unit->ast(); + QVERIFY(ast != 0); + QVERIFY(ast->asExpressionStatement()); +} + +void tst_AST::if_statement_1() { QSharedPointer<TranslationUnit> unit(parseStatement("if (a) b;")); @@ -185,7 +274,7 @@ void tst_AST::if_statement() QCOMPARE(stmt->else_token, 0U); QVERIFY(stmt->else_statement == 0); - // check the `then' statement + // check the `then' statement1 ExpressionStatementAST *then_stmt = stmt->statement->asExpressionStatement(); QVERIFY(then_stmt != 0); QVERIFY(then_stmt->expression != 0); @@ -196,6 +285,34 @@ void tst_AST::if_statement() QCOMPARE(id_expr->identifier_token, 5U); } +void tst_AST::if_statement_2() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("if (x<0 && y>a);")); + + AST *ast = unit->ast(); + QVERIFY(ast != 0); + + IfStatementAST *stmt = ast->asIfStatement(); + QVERIFY(stmt != 0); + + QVERIFY(stmt->condition); + QVERIFY(stmt->condition->asBinaryExpression()); + QCOMPARE(unit->tokenKind(stmt->condition->asBinaryExpression()->binary_op_token), int(T_AMPER_AMPER)); +} + +void tst_AST::if_statement_3() +{ + QSharedPointer<TranslationUnit> unit(parseStatement("if (x<0 && x<0 && x<0 && x<0 && x<0 && x<0 && x<0);")); + + AST *ast = unit->ast(); + QVERIFY(ast != 0); + + IfStatementAST *stmt = ast->asIfStatement(); + QVERIFY(stmt != 0); + + QVERIFY(stmt->condition); +} + void tst_AST::if_else_statement() { QSharedPointer<TranslationUnit> unit(parseStatement("if (a) b; else c;")); @@ -421,5 +538,201 @@ void tst_AST::objc_protocol_definition_1() AST *ast = unit->ast(); } +void tst_AST::normal_array_access() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" + "int f() {\n" + " int a[10];\n" + " int b = 1;\n" + " return a[b];\n" + "}" + )); + AST *ast = unit->ast(); + QVERIFY(ast); + + FunctionDefinitionAST *func = ast->asFunctionDefinition(); + QVERIFY(func); + + StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statements; + QVERIFY(bodyStatements); + QVERIFY(bodyStatements->next); + QVERIFY(bodyStatements->next->next); + QVERIFY(bodyStatements->next->next->statement); + ExpressionAST *expr = bodyStatements->next->next->statement->asReturnStatement()->expression; + QVERIFY(expr); + + PostfixExpressionAST *postfixExpr = expr->asPostfixExpression(); + QVERIFY(postfixExpr); + + { + ExpressionAST *lhs = postfixExpr->base_expression; + QVERIFY(lhs); + SimpleNameAST *a = lhs->asSimpleName(); + QVERIFY(a); + QCOMPARE(QLatin1String(unit->identifier(a->identifier_token)->chars()), QLatin1String("a")); + } + + { + QVERIFY(postfixExpr->postfix_expressions && !postfixExpr->postfix_expressions->next); + ArrayAccessAST *rhs = postfixExpr->postfix_expressions->asArrayAccess(); + QVERIFY(rhs && rhs->expression); + SimpleNameAST *b = rhs->expression->asSimpleName(); + QVERIFY(b); + QCOMPARE(QLatin1String(unit->identifier(b->identifier_token)->chars()), QLatin1String("b")); + } +} + +void tst_AST::array_access_with_nested_expression() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" + "int f() {\n" + " int a[15];\n" + " int b = 1;\n" + " return (a)[b];\n" + "}" + )); + AST *ast = unit->ast(); + QVERIFY(ast); + + FunctionDefinitionAST *func = ast->asFunctionDefinition(); + QVERIFY(func); + + StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statements; + QVERIFY(bodyStatements && bodyStatements->next && bodyStatements->next->next && bodyStatements->next->next->statement); + ExpressionAST *expr = bodyStatements->next->next->statement->asReturnStatement()->expression; + QVERIFY(expr); + + CastExpressionAST *castExpr = expr->asCastExpression(); + QVERIFY(!castExpr); + + PostfixExpressionAST *postfixExpr = expr->asPostfixExpression(); + QVERIFY(postfixExpr); + + { + ExpressionAST *lhs = postfixExpr->base_expression; + QVERIFY(lhs); + NestedExpressionAST *nested_a = lhs->asNestedExpression(); + QVERIFY(nested_a && nested_a->expression); + SimpleNameAST *a = nested_a->expression->asSimpleName(); + QVERIFY(a); + QCOMPARE(QLatin1String(unit->identifier(a->identifier_token)->chars()), QLatin1String("a")); + } + + { + QVERIFY(postfixExpr->postfix_expressions && !postfixExpr->postfix_expressions->next); + ArrayAccessAST *rhs = postfixExpr->postfix_expressions->asArrayAccess(); + QVERIFY(rhs && rhs->expression); + SimpleNameAST *b = rhs->expression->asSimpleName(); + QVERIFY(b); + QCOMPARE(QLatin1String(unit->identifier(b->identifier_token)->chars()), QLatin1String("b")); + } +} + +void tst_AST::objc_msg_send_expression() +{ + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" + "int f() {\n" + " NSObject *obj = [[[NSObject alloc] init] autorelease];\n" + " return [obj description];\n" + "}" + )); + AST *ast = unit->ast(); + QVERIFY(ast); + + FunctionDefinitionAST *func = ast->asFunctionDefinition(); + QVERIFY(func); + + StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statements; + QVERIFY(bodyStatements && bodyStatements->next && !bodyStatements->next->next && bodyStatements->next->statement); + + {// check the NSObject declaration + DeclarationStatementAST *firstStatement = bodyStatements->statement->asDeclarationStatement(); + QVERIFY(firstStatement); + DeclarationAST *objDecl = firstStatement->declaration; + QVERIFY(objDecl); + SimpleDeclarationAST *simpleDecl = objDecl->asSimpleDeclaration(); + QVERIFY(simpleDecl); + + {// check the type (NSObject) + QVERIFY(simpleDecl->decl_specifier_seq && !simpleDecl->decl_specifier_seq->next); + NamedTypeSpecifierAST *namedType = simpleDecl->decl_specifier_seq->asNamedTypeSpecifier(); + QVERIFY(namedType && namedType->name); + SimpleNameAST *typeName = namedType->name->asSimpleName(); + QVERIFY(typeName); + QCOMPARE(QLatin1String(unit->identifier(typeName->identifier_token)->chars()), QLatin1String("NSObject")); + } + + {// check the assignment + QVERIFY(simpleDecl->declarators && !simpleDecl->declarators->next); + DeclaratorAST *declarator = simpleDecl->declarators->declarator; + QVERIFY(declarator); + QVERIFY(!declarator->attributes); + + QVERIFY(declarator->ptr_operators && !declarator->ptr_operators->next && declarator->ptr_operators->asPointer() && !declarator->ptr_operators->asPointer()->cv_qualifier_seq); + + QVERIFY(declarator->core_declarator && declarator->core_declarator->asDeclaratorId()); + NameAST *objNameId = declarator->core_declarator->asDeclaratorId()->name; + QVERIFY(objNameId && objNameId->asSimpleName()); + QCOMPARE(QLatin1String(unit->identifier(objNameId->asSimpleName()->identifier_token)->chars()), QLatin1String("obj")); + + QVERIFY(!declarator->postfix_declarators); + QVERIFY(!declarator->post_attributes); + ExpressionAST *initializer = declarator->initializer; + QVERIFY(initializer); + + ObjCMessageExpressionAST *expr1 = initializer->asObjCMessageExpression(); + QVERIFY(expr1 && expr1->receiver_expression && expr1->selector && !expr1->argument_list); + + ObjCMessageExpressionAST *expr2 = expr1->receiver_expression->asObjCMessageExpression(); + QVERIFY(expr2 && expr2->receiver_expression && expr2->selector && !expr2->argument_list); + + ObjCMessageExpressionAST *expr3 = expr2->receiver_expression->asObjCMessageExpression(); + QVERIFY(expr3 && expr3->receiver_expression && expr3->selector && !expr3->argument_list); + } + } + + {// check the return statement + ExpressionAST *expr = bodyStatements->next->statement->asReturnStatement()->expression; + QVERIFY(expr); + + ObjCMessageExpressionAST *msgExpr = expr->asObjCMessageExpression(); + QVERIFY(msgExpr); + + QVERIFY(msgExpr->receiver_expression); + SimpleNameAST *receiver = msgExpr->receiver_expression->asSimpleName(); + QVERIFY(receiver); + QCOMPARE(QLatin1String(unit->identifier(receiver->identifier_token)->chars()), QLatin1String("obj")); + + QVERIFY(msgExpr->argument_list == 0); + + QVERIFY(msgExpr->selector); + ObjCSelectorWithoutArgumentsAST *sel = msgExpr->selector->asObjCSelectorWithoutArguments(); + QVERIFY(sel); + QCOMPARE(QLatin1String(unit->identifier(sel->name_token)->chars()), QLatin1String("description")); + } +} + +void tst_AST::objc_msg_send_expression_without_selector() +{ + // This test is to verify that no ObjCMessageExpressionAST element is created as the expression for the return statement. + QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" + "int f() {\n" + " NSObject *obj = [[[NSObject alloc] init] autorelease];\n" + " return [obj];\n" + "}", + true)); + AST *ast = unit->ast(); + QVERIFY(ast); + + FunctionDefinitionAST *func = ast->asFunctionDefinition(); + QVERIFY(func); + + StatementListAST *bodyStatements = func->function_body->asCompoundStatement()->statements; + QVERIFY(bodyStatements && bodyStatements->next); + QVERIFY(bodyStatements->next->statement); + QVERIFY(bodyStatements->next->statement->asReturnStatement()); + QVERIFY(!bodyStatements->next->statement->asReturnStatement()->expression); +} + QTEST_APPLESS_MAIN(tst_AST) #include "tst_ast.moc" diff --git a/tests/auto/cplusplus/lookup/tst_lookup.cpp b/tests/auto/cplusplus/lookup/tst_lookup.cpp index f3e6a570d5a81ac02eadfc4091a55e605abaf633..8b64c58395de4a89a02d8e47a8f6558f498f58ab 100644 --- a/tests/auto/cplusplus/lookup/tst_lookup.cpp +++ b/tests/auto/cplusplus/lookup/tst_lookup.cpp @@ -10,7 +10,7 @@ #include <Symbols.h> #include <Overview.h> -CPLUSPLUS_USE_NAMESPACE +using namespace CPlusPlus; template <template <typename, typename> class _Map, typename _T1, typename _T2> _Map<_T2, _T1> invert(const _Map<_T1, _T2> &m) diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp index 996d45ed0646badf40e8151b6b29b9c1b854ae2a..3df6573ccdac25302223d4816ecead66407f4300 100644 --- a/tests/auto/cplusplus/semantic/tst_semantic.cpp +++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp @@ -13,7 +13,7 @@ #include <Literals.h> #include <DiagnosticClient.h> -CPLUSPLUS_USE_NAMESPACE +using namespace CPlusPlus; class tst_Semantic: public QObject { diff --git a/tests/auto/debugger/tst_gdb.cpp b/tests/auto/debugger/tst_gdb.cpp index e33a67aea6c4012f1c4de13ba150c1e85f952564..433b11f819227450f6b2322add7a69f24f8307fb 100644 --- a/tests/auto/debugger/tst_gdb.cpp +++ b/tests/auto/debugger/tst_gdb.cpp @@ -1,4 +1,6 @@ +//#define DO_DEBUG 1 + #include <QtCore/QThread> #include <QtCore/QMutex> #include <QtCore/QWaitCondition> @@ -29,7 +31,6 @@ # define NSY "" #endif -//#define DO_DEBUG 1 #undef DEBUG #if DO_DEBUG # define DEBUG(s) qDebug() << s @@ -127,13 +128,14 @@ public: void cleanupTestCase(); void prepare(const QByteArray &function); void run(const QByteArray &label, const QByteArray &expected, - const QByteArray &expanded = QByteArray()); + const QByteArray &expanded = QByteArray(), bool fancy = true); void next(int n = 1); signals: void writeToGdb(const QByteArray &ba); private slots: + void dumpMisc(); void dumpQList_int(); void dumpQString(); void dumpQStringList(); @@ -2243,11 +2245,11 @@ void tst_Gdb::prepare(const QByteArray &function) writeToGdb("call " + function + "()"); } -void tst_Gdb::run(const QByteArray &label, - const QByteArray &expected0, const QByteArray &expanded) +void tst_Gdb::run(const QByteArray &label, const QByteArray &expected0, + const QByteArray &expanded, bool fancy) { - //qDebug() << "\nABOUT TO RUN TEST: " << function << m_thread.m_proc; - writeToGdb("bb 1 " + expanded); + //qDebug() << "\nABOUT TO RUN TEST: " << expanded; + writeToGdb("bb " + QByteArray::number(int(fancy)) + " " + expanded); m_mutex.lock(); m_waitCondition.wait(&m_mutex); QByteArray ba = m_thread.m_output; @@ -2269,17 +2271,16 @@ void tst_Gdb::run(const QByteArray &label, bool ok = l1.size() == l2.size(); if (ok) { for (int i = 0 ; i < l1.size(); ++i) { - if (l1.at(i) != l2.at(i)) - if (!l1.at(i).startsWith("addr") || !l2.at(i).startsWith("addr")) - ok = false; + // Use "-" as joker. + if (l1.at(i) != l2.at(i) && !l2.at(i).endsWith("'-'")) + ok = false; } } if (!ok) { int i = 0; for ( ; i < l1.size() && i < l2.size(); ++i) { - if (l1.at(i) == l2.at(i) - || (l1.at(i).startsWith("addr") && l2.at(i).startsWith("addr"))) { + if (l1.at(i) == l2.at(i) || l2.at(i).endsWith("'-'")) { qWarning() << "== " << l1.at(i); } else { //qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30); @@ -2397,6 +2398,24 @@ void tst_Gdb::dumpQList_QString() } */ +void dumpMisc() +{ + /* A */ int *s = new int(1); + /* B */ *s += 1; + /* D */ (void) s; +} + +void tst_Gdb::dumpMisc() +{ + prepare("dumpMisc"); + next(); + run("B","{iname='local.s',addr='-',name='s',type='int *'," + "value='-',numchild='1'}", "", 0); + run("B","{iname='local.s',addr='-',name='s',type='int *'," + "value='-',numchild='1',children=[{iname='local.s.*'," + "name='*s',type='int',value='1',numchild='0'}]}", "local.s", 0); +} + void dumpQStringTest() { /* A */ QString s; @@ -2412,7 +2431,13 @@ void tst_Gdb::dumpQString() "value='<not in scope>',numchild='0'}"); next(); run("B","{iname='local.s',addr='-',name='s',type='"NS"QString'," - "valueencoded='7',value='',numchild='0'}"); + "valueencoded='7',value='',numchild='0'}", "local.s"); + // Plain C: + run("B","{iname='local.s',addr='-',name='s',type='"NS"QString'," + "value='{...}',numchild='5'}", "", 0); + run("B","{iname='local.s',addr='-',name='s',type='"NS"QString'," + "value='{...}',numchild='5',children=[]}", "local.s", 0); +return; next(); run("C","{iname='local.s',addr='-',name='s',type='"NS"QString'," "valueencoded='7',value='680061006c006c006f00',numchild='0'}"); @@ -2432,8 +2457,8 @@ void dumpQStringListTest() void tst_Gdb::dumpQStringList() { prepare("dumpQStringListTest"); - run("A","{iname='local.s',addr='-',name='s',type='"NS"QStringList'," - "value='<not in scope>',numchild='0'}"); + //run("A","{iname='local.s',addr='-',name='s',type='"NS"QStringList'," + // "value='<not in scope>',numchild='0'}"); next(); run("B","{iname='local.s',addr='-',name='s',type='"NS"QStringList'," "value='<0 items>',numchild='0'}");