diff --git a/lib/cppparser/parser.cpp b/lib/cppparser/parser.cpp index df97c50cb..fab9d486f 100644 --- a/lib/cppparser/parser.cpp +++ b/lib/cppparser/parser.cpp @@ -1,4374 +1,4376 @@ /* This file is part of KDevelop Copyright (C) 2002, 2003 Roberto Raggi This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, see . */ // c++ support #include "parser.h" #include "driver.h" #include "lexer.h" #include "errors.h" #include "optionstate.h" // qt #include #include #if QT_VERSION >= 0x050000 #else #include #endif #include using namespace std; DEBUG_REGISTER_DISABLED(Parser) #define ADVANCE(tk, descr) \ { \ const Token& token = m_lexer->lookAhead(0); \ if(token != tk){ \ reportError(i18n("'%1' expected found '%2'").arg(QLatin1String(descr)).arg(token.text())); \ return false; \ } \ nextToken(); \ } #define ADVANCE_NR(tk, descr) \ { \ const Token& token = m_lexer->lookAhead(0); \ if(token != tk){ \ reportError(i18n("'%1' expected found '%2'").arg(QLatin1String(descr)).arg(token.text())); \ } \ else \ nextToken(); \ } #define CHECK(tk, descr) \ { \ const Token& token = m_lexer->lookAhead(0); \ if(token != tk){ \ return false; \ } \ nextToken(); \ } #define MATCH(tk, descr) \ { \ const Token& token = m_lexer->lookAhead(0); \ if(token != tk){ \ reportError(Errors::SyntaxError); \ return false; \ } \ } #define UPDATE_POS(node, start, end) \ { \ int line, col; \ const Token &a = m_lexer->tokenAt(start); \ const Token &b = m_lexer->tokenAt(end!=start ? end-1 : end); \ a.getStartPosition(&line, &col); \ (node)->setStartPosition(line, col); \ b.getEndPosition(&line, &col); \ (node)->setEndPosition(line, col); \ if((node)->nodeType() == NodeType_Generic) { \ if ((start) == (end) || (end) == (start)+1) \ (node)->setSlice(m_lexer->source(), a.position(), a.length()); \ else \ (node)->setText(toString((start),(end))); \ } \ } #define AST_FROM_TOKEN(node, tk) \ AST::Node node = CreateNode(); \ UPDATE_POS(node, (tk), (tk)+1); //@todo remove me enum { OBJC_CLASS, OBJC_PROTOCOL, OBJC_ALIAS }; struct ParserPrivateData { ParserPrivateData() {} }; Parser::Parser(Driver* driver, Lexer* lexer) : m_driver(driver), m_lexer(lexer), m_problems(0) { d = new ParserPrivateData(); m_maxProblems = 5; objcp = false; } Parser::~Parser() { delete d; d = 0; } bool Parser::reportError(const Error& err) { PARSER_DEBUG_METHOD; if (m_problems < m_maxProblems) { ++m_problems; int line=0, col=0; const Token& token = m_lexer->lookAhead(0); m_lexer->getTokenPosition(token, &line, &col); QString s = m_lexer->lookAhead(0).text(); s = s.left(30).trimmed(); if (s.isEmpty()) s = i18n(""); m_driver->addProblem(m_driver->currentFileName(), Problem(err.text.arg(s), line, col)); } return true; } bool Parser::reportError(const QString& msg) { PARSER_DEBUG_METHOD; if (m_problems < m_maxProblems) { ++m_problems; int line=0, col=0; const Token& token = m_lexer->lookAhead(0); m_lexer->getTokenPosition(token, &line, &col); m_driver->addProblem(m_driver->currentFileName(), Problem(msg, line, col)); } return true; } void Parser::syntaxError() { (void) reportError(Errors::SyntaxError); } bool Parser::skipUntil(int token) { PARSER_DEBUG_METHOD; while (!m_lexer->lookAhead(0).isNull()) { if (m_lexer->lookAhead(0) == token) return true; nextToken(); } return false; } bool Parser::skipUntilDeclaration() { PARSER_DEBUG_METHOD; clearComment(); while (!m_lexer->lookAhead(0).isNull()) { switch (m_lexer->lookAhead(0)) { case ';': case '~': case Token_scope: case Token_identifier: case Token_operator: case Token_char: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: case Token_extern: case Token_namespace: case Token_using: case Token_typedef: case Token_asm: case Token_template: case Token_export: case Token_const: // cv case Token_const_expr: // cv case Token_volatile: // cv case Token_mutable: // cv case Token_public: case Token_protected: case Token_private: case Token_signals: // Qt case Token_slots: // Qt return true; default: nextToken(); } } return false; } bool Parser::skipUntilStatement() { PARSER_DEBUG_METHOD; while (!m_lexer->lookAhead(0).isNull()) { switch (m_lexer->lookAhead(0)) { case ';': case '{': case '}': case Token_const: case Token_const_expr: case Token_volatile: case Token_mutable: case Token_identifier: case Token_case: case Token_default: case Token_if: case Token_switch: case Token_while: case Token_do: case Token_for: case Token_break: case Token_continue: case Token_return: case Token_goto: case Token_try: case Token_catch: case Token_throw: case Token_char: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: case Token_class: case Token_struct: case Token_union: case Token_enum: case Token_scope: case Token_template: case Token_using: return true; default: nextToken(); } } return false; } bool Parser::skip(int l, int r) { int count = 0; while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); if (tk == l) ++count; else if (tk == r) --count; else if (l != '{' && (tk == '{' || tk == '}' || tk == ';')) return false; if (count == 0) return true; nextToken(); } return false; } bool Parser::skipCommaExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node expr; if (!skipExpression(expr)) return false; while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!skipExpression(expr)) { reportError(i18n("expression expected")); return false; } } AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::skipExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); switch (tk) { case '(': skip('(', ')'); nextToken(); break; case '[': skip('[', ']'); nextToken(); break; #if 0 case Token_identifier: nextToken(); if (m_lexer->lookAhead(0) == Token_identifier) return true; break; #endif case ';': case ',': case ']': case ')': case '{': case '}': case Token_case: case Token_default: case Token_if: case Token_while: case Token_do: case Token_for: case Token_break: case Token_continue: case Token_return: case Token_goto: { AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); } return true; default: nextToken(); } } return false; } bool Parser::parseName(NameAST::Node& node) { PARSER_DEBUG_METHOD; GroupAST::Node winDeclSpec; parseWinDeclSpec(winDeclSpec); int start = m_lexer->index(); NameAST::Node ast = CreateNode(); if (m_lexer->lookAhead(0) == Token_scope) { ast->setGlobal(true); nextToken(); } int idx = m_lexer->index(); while (true) { ClassOrNamespaceNameAST::Node n; if (!parseUnqualifiedName(n)) { return false; } if (m_lexer->lookAhead(0) == Token_scope) { nextToken(); ast->addClassOrNamespaceName(n); if (m_lexer->lookAhead(0) == Token_template) nextToken(); /// skip optional template #### @todo CHECK } else { ast->setUnqualifiedName(n); break; } } if (idx == m_lexer->index()) return false; UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTranslationUnit(TranslationUnitAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); m_problems = 0; TranslationUnitAST::Node tun = CreateNode(); node = tun; // only setup file comment if present at first line, and first column if (m_lexer->lookAhead(0) == Token_comment) { processComment(); if (m_lexer->lookAhead(0).position() == 0) { if (comment()) { tun->setComment(comment()); clearComment(); } } nextToken(); } else if (m_lexer->lookAhead(0) == '<' && m_lexer->lookAhead(1) == '?' && m_lexer->lookAhead(2) == Token_identifier && m_lexer->lookAhead(2).text() == QLatin1String("php") ) { uDebug() << "found php tag"; nextToken(); nextToken(); nextToken(); } while (!m_lexer->lookAhead(0).isNull()) { DeclarationAST::Node def; int startDecl = m_lexer->index(); if (!parseDeclaration(def)) { // error recovery if (startDecl == m_lexer->index()) nextToken(); // skip at least one token skipUntilDeclaration(); } node->addDeclaration(def); } UPDATE_POS(node, start, m_lexer->index()); // force (0,0) as start position node->setStartPosition(0, 0); return m_problems == 0; } bool Parser::parseDeclaration(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); switch (m_lexer->lookAhead(0)) { case ';': nextToken(); return true; case Token_extern: return parseLinkageSpecification(node); case Token_namespace: return parseNamespace(node); case Token_using: return parseUsing(node); case Token_typedef: return parseTypedef(node); case Token_asm: return parseAsmDefinition(node); case Token_template: case Token_export: return parseTemplateDeclaration(node); default: { // m_lexer->setIndex(start); if (objcp && parseObjcDef(node)) return true; m_lexer->setIndex(start); GroupAST::Node storageSpec; parseStorageClassSpecifier(storageSpec); GroupAST::Node cv; parseCvQualify(cv); TypeSpecifierAST::Node spec; AST::Node declarator; if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { int line, c; spec->getEndPosition(&line, &c); spec->setCvQualify(cv); GroupAST::Node cv2; parseCvQualify(cv2); spec->setCv2Qualify(cv2); InitDeclaratorListAST::Node declarators; parseInitDeclaratorList(declarators); SimpleDeclarationAST::Node ast = CreateNode(); ADVANCE(';', ";"); preparseLineComments(line); ast->setComment(m_commentStore.getCommentInRange(line)); ast->setStorageSpecifier(storageSpec); ast->setTypeSpec(spec); ast->setInitDeclaratorList(declarators); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } m_lexer->setIndex(start); return parseDeclarationInternal(node); } } // end switch } bool Parser::parseLinkageSpecification(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_extern) { return false; } nextToken(); LinkageSpecificationAST::Node ast = CreateNode(); int startExternType = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_string_literal) { nextToken(); AST::Node externType = CreateNode(); UPDATE_POS(externType, startExternType, m_lexer->index()); ast->setExternType(externType); } if (m_lexer->lookAhead(0) == '{') { LinkageBodyAST::Node linkageBody; parseLinkageBody(linkageBody); ast->setLinkageBody(linkageBody); } else { DeclarationAST::Node decl; if (!parseDeclaration(decl)) { reportError(i18n("Declaration syntax error")); } ast->setDeclaration(decl); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseLinkageBody(LinkageBodyAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != '{') { return false; } nextToken(); LinkageBodyAST::Node lba = CreateNode(); node = std::move(lba); while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); if (tk == '}') break; DeclarationAST::Node def; int startDecl = m_lexer->index(); if (parseDeclaration(def)) { node->addDeclaration(def); } else { // error recovery if (startDecl == m_lexer->index()) nextToken(); // skip at least one token skipUntilDeclaration(); } } clearComment(); if (m_lexer->lookAhead(0) != '}') { reportError(i18n("} expected")); } else nextToken(); UPDATE_POS(node, start, m_lexer->index()); return true; } bool Parser::parseNamespace(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_namespace) { return false; } nextToken(); int startNamespaceName = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_identifier) { nextToken(); } AST::Node namespaceName = CreateNode(); UPDATE_POS(namespaceName, startNamespaceName, m_lexer->index()); if (m_lexer->lookAhead(0) == '=') { // namespace alias nextToken(); NameAST::Node name; if (parseName(name)) { ADVANCE(';', ";"); NamespaceAliasAST::Node ast = CreateNode(); ast->setNamespaceName(namespaceName); ast->setAliasName(name); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } else { reportError(i18n("namespace expected")); return false; } } else if (m_lexer->lookAhead(0) == '\\') { // php namespace while (m_lexer->lookAhead(0) == '\\' || m_lexer->lookAhead(0) == Token_identifier) // namespace alias nextToken(); } else if (m_lexer->lookAhead(0) != '{') { reportError(i18n("{ expected")); return false; } NamespaceAST::Node ast = CreateNode(); ast->setNamespaceName(namespaceName); LinkageBodyAST::Node linkageBody; parseLinkageBody(linkageBody); ast->setLinkageBody(linkageBody); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseUsing(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_using) { return false; } nextToken(); if (m_lexer->lookAhead(0) == Token_namespace) { if (!parseUsingDirective(node)) { return false; } UPDATE_POS(node, start, m_lexer->index()); return true; } UsingAST::Node ast = CreateNode(); int startTypeName = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_typename) { nextToken(); AST::Node tn = CreateNode(); UPDATE_POS(tn, startTypeName, m_lexer->index()); ast->setTypeName(tn); } NameAST::Node name; if (!parseName(name)) return false; ast->setName(name); ADVANCE(';', ";"); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseUsingDirective(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_namespace) { return false; } nextToken(); NameAST::Node name; if (!parseName(name)) { reportError(i18n("Namespace name expected")); return false; } ADVANCE(';', ";"); UsingDirectiveAST::Node ast = CreateNode(); ast->setName(name); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseOperatorFunctionId(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_operator) { return false; } nextToken(); AST::Node op; if(parseOperator(op)){ AST::Node asn = CreateNode(); node = std::move(asn); UPDATE_POS(node, start, m_lexer->index()); if (node->text() == QLatin1String("operator > >")) node->setText(QLatin1String("operator >>")); return true; } else { // parse cast operator GroupAST::Node cv; parseCvQualify(cv); TypeSpecifierAST::Node spec; if (!parseSimpleTypeSpecifier(spec)) { syntaxError(); return false; } spec->setCvQualify(cv); GroupAST::Node cv2; parseCvQualify(cv2); spec->setCv2Qualify(cv2); AST::Node ptrOp; while (parsePtrOperator(ptrOp)) ; AST::Node asn = CreateNode(); node = std::move(asn); UPDATE_POS(node, start, m_lexer->index()); return true; } } bool Parser::parseTemplateArgumentList(TemplateArgumentListAST::Node& node, bool reportError) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); TemplateArgumentListAST::Node ast = CreateNode(); AST::Node templArg; if (!parseTemplateArgument(templArg)) return false; ast->addArgument(templArg); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseTemplateArgument(templArg)) { if (reportError) { syntaxError(); break; } else return false; } ast->addArgument(templArg); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTypedef(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_typedef) { return false; } nextToken(); TypeSpecifierAST::Node spec; if (!parseTypeSpecifierOrClassSpec(spec)) { reportError(i18n("Need a type specifier to declare")); return false; } InitDeclaratorListAST::Node declarators; if (!parseInitDeclaratorList(declarators)) { //reportError(i18n("Need an identifier to declare")); //return false; } TypedefAST::Node ast = CreateNode(); if (comment()) { ast->setComment(comment()); clearComment(); preparseLineComments(currentLine()); if (comment()) { ast->addComment(comment()); clearComment(); } } ADVANCE(';', ";"); ast->setTypeSpec(spec); ast->setInitDeclaratorList(declarators); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseAsmDefinition(DeclarationAST::Node& /*node*/) { PARSER_DEBUG_METHOD; ADVANCE(Token_asm, "asm"); GroupAST::Node cv; parseCvQualify(cv); skip('(', ')'); ADVANCE(')', ")"); ADVANCE(';', ";"); return true; } bool Parser::parseTemplateDeclaration(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node exp; int startExport = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_export) { nextToken(); AST::Node n = CreateNode(); UPDATE_POS(n, startExport, m_lexer->index()); exp = std::move(n); } if (m_lexer->lookAhead(0) != Token_template) { return false; } nextToken(); TemplateParameterListAST::Node params; if (m_lexer->lookAhead(0) == '<') { nextToken(); parseTemplateParameterList(params); ADVANCE('>', ">"); } DeclarationAST::Node def; if (!parseDeclaration(def)) { reportError(i18n("expected a declaration")); } TemplateDeclarationAST::Node ast = CreateNode(); ast->setExported(exp); ast->setTemplateParameterList(params); ast->setDeclaration(def); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseOperator(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; QString text = m_lexer->lookAhead(0).text(); switch (m_lexer->lookAhead(0)) { case Token_new: case Token_delete: nextToken(); if (m_lexer->lookAhead(0) == '[' && m_lexer->lookAhead(1) == ']') { nextToken(); nextToken(); text += QLatin1String("[]"); } return true; case '+': case '-': case '*': case '/': case '%': case '^': case '&': case '|': case '~': case '!': case '=': case '<': case '>': case ',': case Token_assign: case Token_shift: case Token_eq: case Token_not_eq: case Token_leq: case Token_geq: case Token_and: case Token_or: case Token_incr: case Token_decr: case Token_ptrmem: case Token_arrow: nextToken(); if (m_lexer->lookAhead(0) == '>') nextToken(); return true; default: if (m_lexer->lookAhead(0) == '(' && m_lexer->lookAhead(1) == ')') { nextToken(); nextToken(); return true; } else if (m_lexer->lookAhead(0) == '[' && m_lexer->lookAhead(1) == ']') { nextToken(); nextToken(); return true; } } return false; } bool Parser::parseCvQualify(GroupAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); GroupAST::Node ast = CreateNode(); int n = 0; while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); if (tk == Token_const || tk == Token_volatile || tk == Token_mutable) { ++n; int startWord = m_lexer->index(); nextToken(); AST::Node word = CreateNode(); UPDATE_POS(word, startWord, m_lexer->index()); ast->addNode(word); } else break; } if (n == 0) return false; PARSER_DEBUG_METHOD; UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST::Node& node) { int start = m_lexer->index(); bool isIntegral = false; bool done = false; while (!done) { switch (m_lexer->lookAhead(0)) { case Token_char: case Token_wchar_t: case Token_bool: case Token_short: case Token_int: case Token_long: case Token_signed: case Token_unsigned: case Token_float: case Token_double: case Token_void: isIntegral = true; nextToken(); break; default: done = true; } } TypeSpecifierAST::Node ast = CreateNode(); if (isIntegral) { ClassOrNamespaceNameAST::Node cl = CreateNode(); AST::Node n = CreateNode(); UPDATE_POS(n, start, m_lexer->index()); cl->setName(n); UPDATE_POS(cl, start, m_lexer->index()); NameAST::Node name = CreateNode(); name->setUnqualifiedName(cl); UPDATE_POS(name, start, m_lexer->index()); ast->setName(name); } else { NameAST::Node name; if (!parseName(name)) { m_lexer->setIndex(start); return false; } ast->setName(name); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parsePtrOperator(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) == '&') { nextToken(); } else if (m_lexer->lookAhead(0) == '*') { nextToken(); } else { int index = m_lexer->index(); AST::Node memPtr; if (!parsePtrToMember(memPtr)) { m_lexer->setIndex(index); return false; } } GroupAST::Node cv; parseCvQualify(cv); AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTemplateArgument(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (parseTypeId(node)) { if (m_lexer->lookAhead(0) == ',' || m_lexer->lookAhead(0) == '>') return true; } m_lexer->setIndex(start); if (!parseLogicalOrExpression(node, true)) { return false; } return true; } bool Parser::parseTypeSpecifier(TypeSpecifierAST::Node& spec) { PARSER_DEBUG_METHOD; GroupAST::Node cv; parseCvQualify(cv); if (parseElaboratedTypeSpecifier(spec) || parseSimpleTypeSpecifier(spec)) { spec->setCvQualify(cv); GroupAST::Node cv2; parseCvQualify(cv2); spec->setCv2Qualify(cv2); return true; } return false; } bool Parser::parseDeclarator(DeclaratorAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); DeclaratorAST::Node ast = CreateNode(); DeclaratorAST::Node decl; NameAST::Node declId; AST::Node ptrOp; while (parsePtrOperator(ptrOp)) { ast->addPtrOp(ptrOp); } if (m_lexer->lookAhead(0) == '(') { nextToken(); if (!parseDeclarator(decl)) { return false; } ast->setSubDeclarator(decl); if (m_lexer->lookAhead(0) != ')') { return false; } nextToken(); } else { if (m_lexer->lookAhead(0) == ':') { // unnamed bitfield } else if (parseDeclaratorId(declId)) { ast->setDeclaratorId(declId); } else { m_lexer->setIndex(start); return false; } if (m_lexer->lookAhead(0) == ':') { nextToken(); AST::Node expr; if (!parseConstantExpression(expr)) { reportError(i18n("Constant expression expected")); } goto update_pos; } } { bool isVector = true; while (m_lexer->lookAhead(0) == '[') { int startArray = m_lexer->index(); nextToken(); AST::Node expr; parseCommaExpression(expr); ADVANCE(']', "]"); AST::Node array = CreateNode(); UPDATE_POS(array, startArray, m_lexer->index()); ast->addArrayDimension(array); isVector = true; } bool skipParen = false; if (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(1) == '(' && m_lexer->lookAhead(2) == '(') { nextToken(); nextToken(); skipParen = true; } if (ast->subDeclarator() && (!isVector || m_lexer->lookAhead(0) != '(')) { m_lexer->setIndex(start); return false; } int index = m_lexer->index(); if (m_lexer->lookAhead(0) == '(') { nextToken(); ParameterDeclarationClauseAST::Node params; if (!parseParameterDeclarationClause(params)) { PARSER_DEBUG_METHOD; m_lexer->setIndex(index); goto update_pos; } ast->setParameterDeclarationClause(params); if (m_lexer->lookAhead(0) != ')') { m_lexer->setIndex(index); goto update_pos; } nextToken(); // skip ')' int startConstant = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_const) { nextToken(); AST::Node constant = CreateNode(); UPDATE_POS(constant, startConstant, m_lexer->index()); ast->setConstant(constant); } if (Settings::optionState().codeImportState.supportCPP11) { int startOverride = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_override) { nextToken(); AST::Node override = CreateNode(); UPDATE_POS(override, startOverride, m_lexer->index()); ast->setOverride(override); } } GroupAST::Node except; if (parseExceptionSpecification(except)) { ast->setExceptionSpecification(except); } } if (skipParen) { if (m_lexer->lookAhead(0) != ')') { reportError(i18n("')' expected")); } else nextToken(); } } update_pos: UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseAbstractDeclarator(DeclaratorAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); DeclaratorAST::Node ast = CreateNode(); DeclaratorAST::Node decl; NameAST::Node declId; AST::Node ptrOp; while (parsePtrOperator(ptrOp)) { ast->addPtrOp(ptrOp); } if (m_lexer->lookAhead(0) == '(') { nextToken(); if (!parseAbstractDeclarator(decl)) { return false; } ast->setSubDeclarator(decl); if (m_lexer->lookAhead(0) != ')') { return false; } nextToken(); } { while (m_lexer->lookAhead(0) == '[') { int startArray = m_lexer->index(); nextToken(); AST::Node expr; skipCommaExpression(expr); ADVANCE(']', "]"); AST::Node array = CreateNode(); UPDATE_POS(array, startArray, m_lexer->index()); ast->addArrayDimension(array); } bool skipParen = false; if (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(1) == '(' && m_lexer->lookAhead(2) == '(') { nextToken(); nextToken(); skipParen = true; } int index = m_lexer->index(); if (m_lexer->lookAhead(0) == '(') { nextToken(); ParameterDeclarationClauseAST::Node params; if (!parseParameterDeclarationClause(params)) { m_lexer->setIndex(index); goto UPDATE_POS; } ast->setParameterDeclarationClause(params); if (m_lexer->lookAhead(0) != ')') { m_lexer->setIndex(index); goto UPDATE_POS; } else nextToken(); int startConstant = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_const) { nextToken(); AST::Node constant = CreateNode(); UPDATE_POS(constant, startConstant, m_lexer->index()); ast->setConstant(constant); } if (Settings::optionState().codeImportState.supportCPP11) { int startOverride = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_override) { nextToken(); AST::Node override = CreateNode(); UPDATE_POS(override, startOverride, m_lexer->index()); ast->setOverride(override); } } GroupAST::Node except; if (parseExceptionSpecification(except)) { ast->setExceptionSpecification(except); } } if (skipParen) { if (m_lexer->lookAhead(0) != ')') { reportError(i18n("')' expected")); } else nextToken(); } } UPDATE_POS: UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseEnumSpecifier(TypeSpecifierAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_enum) { return false; } nextToken(); Comment c = comment(); clearComment(); NameAST::Node name; parseName(name); if (m_lexer->lookAhead(0) != '{') { m_lexer->setIndex(start); return false; } nextToken(); EnumSpecifierAST::Node ast = CreateNode(); ast->setName(name); ast->setComment(c); EnumeratorAST::Node enumerator; if (parseEnumerator(enumerator)) { ast->addEnumerator(enumerator); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseEnumerator(enumerator)) { //reportError(i18n("Enumerator expected")); break; } ast->addEnumerator(enumerator); } } clearComment(); if (m_lexer->lookAhead(0) != '}') reportError(i18n("} missing")); else nextToken(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTemplateParameterList(TemplateParameterListAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); TemplateParameterListAST::Node ast = CreateNode(); TemplateParameterAST::Node param; if (!parseTemplateParameter(param)) { return false; } ast->addTemplateParameter(param); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseTemplateParameter(param)) { syntaxError(); break; } else { ast->addTemplateParameter(param); } } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTemplateParameter(TemplateParameterAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); TemplateParameterAST::Node ast = CreateNode(); TypeParameterAST::Node typeParameter; ParameterDeclarationAST::Node param; int tk = m_lexer->lookAhead(0); if ((tk == Token_class || tk == Token_typename || tk == Token_template) && parseTypeParameter(typeParameter)) { ast->setTypeParameter(typeParameter); goto ok; } if (!parseParameterDeclaration(param)) return false; ast->setTypeValueParameter(param); ok: UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTypeParameter(TypeParameterAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); TypeParameterAST::Node ast = CreateNode(); AST_FROM_TOKEN(kind, m_lexer->index()); ast->setKind(kind); switch (m_lexer->lookAhead(0)) { case Token_class: case Token_typename: { nextToken(); // skip class // parse optional name NameAST::Node name; if (parseName(name)) { ast->setName(name); if (m_lexer->lookAhead(0) == '=') { nextToken(); AST::Node typeId; if (!parseTypeId(typeId)) { syntaxError(); return false; } ast->setTypeId(typeId); } } } break; case Token_template: { nextToken(); // skip template ADVANCE('<', "<"); TemplateParameterListAST::Node params; if (!parseTemplateParameterList(params)) { return false; } ast->setTemplateParameterList(params); ADVANCE('>', ">"); if (m_lexer->lookAhead(0) == Token_class) nextToken(); // parse optional name NameAST::Node name; if (parseName(name)) { ast->setName(name); if (m_lexer->lookAhead(0) == '=') { nextToken(); AST::Node typeId; if (!parseTypeId(typeId)) { syntaxError(); return false; } ast->setTypeId(typeId); } } if (m_lexer->lookAhead(0) == '=') { nextToken(); NameAST::Node templ_name; parseName(templ_name); } } break; default: return false; } // end switch UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseStorageClassSpecifier(GroupAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); GroupAST::Node ast = CreateNode(); while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); if (tk == Token_friend || tk == Token_auto || tk == Token_register || tk == Token_static || tk == Token_extern || tk == Token_mutable || tk == Token_const_expr ) { int startNode = m_lexer->index(); nextToken(); AST::Node n = CreateNode(); UPDATE_POS(n, startNode, m_lexer->index()); ast->addNode(n); } else break; } if (ast->nodeList().count() == 0) return false; UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseFunctionSpecifier(GroupAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); GroupAST::Node ast = CreateNode(); while (!m_lexer->lookAhead(0).isNull()) { int tk = m_lexer->lookAhead(0); if (tk == Token_inline || tk == Token_virtual || tk == Token_explicit) { int startNode = m_lexer->index(); nextToken(); AST::Node n = CreateNode(); UPDATE_POS(n, startNode, m_lexer->index()); ast->addNode(n); } else { break; } } if (ast->nodeList().count() == 0) return false; UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseTypeId(AST::Node& node) { PARSER_DEBUG_METHOD; /// @todo implement the AST for typeId int start = m_lexer->index(); AST::Node ast = CreateNode(); TypeSpecifierAST::Node spec; if (!parseTypeSpecifier(spec)) { return false; } DeclaratorAST::Node decl; parseAbstractDeclarator(decl); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseInitDeclaratorList(InitDeclaratorListAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); InitDeclaratorListAST::Node ast = CreateNode(); InitDeclaratorAST::Node decl; if (!parseInitDeclarator(decl)) { return false; } ast->addInitDeclarator(decl); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseInitDeclarator(decl)) { syntaxError(); break; } ast->addInitDeclarator(decl); } PARSER_DEBUG_METHOD; UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ParameterDeclarationClauseAST::Node ast = CreateNode(); ParameterDeclarationListAST::Node params; if (!parseParameterDeclarationList(params)) { if (m_lexer->lookAhead(0) == ')') goto good; if (m_lexer->lookAhead(0) == Token_ellipsis && m_lexer->lookAhead(1) == ')') { AST_FROM_TOKEN(ellipsis, m_lexer->index()); ast->setEllipsis(ellipsis); nextToken(); goto good; } return false; } if (m_lexer->lookAhead(0) == Token_ellipsis) { AST_FROM_TOKEN(ellipsis, m_lexer->index()); ast->setEllipsis(ellipsis); nextToken(); } good: ast->setParameterDeclarationList(params); /// @todo add ellipsis UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } void Parser::nextToken(bool skipComm) { m_lexer->nextToken(); if (skipComm) { if (m_lexer->lookAhead(0) == Token_comment) { processComment(); nextToken(); } } } Comment Parser::comment() { return m_commentStore.latestComment(); } void Parser::preparseLineComments(int l) { for (int a = 0; a < 40; a++) { if (m_lexer->lookAhead(a).isNull()) break; int line, col; m_lexer->lookAhead(a).getStartPosition(&line, &col); if (line < l) { continue; } else if (line == l) { if (m_lexer->lookAhead(a) == Token_comment) { processComment(a); } } else { break; } } } void Parser::processComment(int offset) { int line, col; m_lexer->lookAhead(offset).getStartPosition(&line, &col); m_commentStore.addComment(Comment(m_lexer->lookAhead(offset).text(), line)); } template void Parser::eventuallyTakeComment(int startLn, int endLn, Type& ast) { if (comment().line() >= startLn && comment().line() <= endLn) { if (&(*ast)) { if (comment()) { ast->setComment(comment()); } } clearComment(); } } template void Parser::eventuallyTakeComment(Type& ast) { if (&(*ast) && comment()) { ast->setComment(comment()); } clearComment(); } void Parser::clearComment() { m_commentStore.clear(); } int Parser::currentLine() { int ln, col; m_lexer->lookAhead(0).getStartPosition(&ln, &col); return ln; } bool Parser::parseParameterDeclarationList(ParameterDeclarationListAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ParameterDeclarationListAST::Node ast = CreateNode(); ParameterDeclarationAST::Node param; if (!parseParameterDeclaration(param)) { m_lexer->setIndex(start); return false; } ast->addParameter(param); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (m_lexer->lookAhead(0) == Token_ellipsis) break; if (!parseParameterDeclaration(param)) { m_lexer->setIndex(start); return false; } ast->addParameter(param); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseParameterDeclaration(ParameterDeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); // parse decl spec TypeSpecifierAST::Node spec; if (!parseTypeSpecifier(spec)) { m_lexer->setIndex(start); return false; } int index = m_lexer->index(); DeclaratorAST::Node decl; if (!parseDeclarator(decl)) { m_lexer->setIndex(index); // try with abstract declarator if (!parseAbstractDeclarator(decl)) return false; } AST::Node expr; if (m_lexer->lookAhead(0) == '=') { nextToken(); if (!parseLogicalOrExpression(expr,true)) { //reportError(i18n("Expression expected")); } } ParameterDeclarationAST::Node ast = CreateNode(); ast->setTypeSpec(spec); ast->setDeclarator(decl); ast->setExpression(expr); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseClassSpecifier(TypeSpecifierAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node classKey; int classKeyStart = m_lexer->index(); int kind = m_lexer->lookAhead(0); if (kind == Token_class || kind == Token_struct || kind == Token_union) { AST::Node asn = CreateNode(); classKey = std::move(asn); nextToken(); UPDATE_POS(classKey, classKeyStart, m_lexer->index()); } else { return false; } GroupAST::Node winDeclSpec; parseWinDeclSpec(winDeclSpec); while (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(1) == Token_identifier) nextToken(); NameAST::Node name; parseName(name); BaseClauseAST::Node bases; if (m_lexer->lookAhead(0) == ':') { if (!parseBaseClause(bases)) { skipUntil('{'); } } if (m_lexer->lookAhead(0) != '{') { m_lexer->setIndex(start); return false; } ClassSpecifierAST::Node ast = CreateNode(); eventuallyTakeComment(ast); ADVANCE('{', "{"); ast->setWinDeclSpec(winDeclSpec); ast->setClassKey(classKey); ast->setName(name); ast->setBaseClause(bases); while (!m_lexer->lookAhead(0).isNull()) { if (m_lexer->lookAhead(0) == '}') break; DeclarationAST::Node memSpec; int startDecl = m_lexer->index(); if (!parseMemberSpecification(memSpec)) { if (startDecl == m_lexer->index()) nextToken(); // skip at least one token skipUntilDeclaration(); } else ast->addDeclaration(memSpec); } clearComment(); if (m_lexer->lookAhead(0) != '}') { reportError(i18n("} missing")); } else nextToken(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseAccessSpecifier(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); switch (m_lexer->lookAhead(0)) { case Token_public: case Token_protected: case Token_private: { AST::Node asn = CreateNode(); node = std::move(asn); nextToken(); UPDATE_POS(node, start, m_lexer->index()); return true; } } return false; } bool Parser::parseMemberSpecification(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node access; if (m_lexer->lookAhead(0) == ';') { nextToken(); return true; } else if (m_lexer->lookAhead(0) == Token_Q_OBJECT || m_lexer->lookAhead(0) == Token_K_DCOP) { nextToken(); return true; } else if (m_lexer->lookAhead(0) == Token_signals || m_lexer->lookAhead(0) == Token_k_dcop || m_lexer->lookAhead(0) == Token_k_dcop_signals) { AccessDeclarationAST::Node ast = CreateNode(); nextToken(); AST::Node n = CreateNode(); UPDATE_POS(n, start, m_lexer->index()); ast->addAccess(n); ADVANCE(':', ":"); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } else if (parseTypedef(node)) { return true; } else if (parseUsing(node)) { return true; } else if (parseTemplateDeclaration(node)) { return true; } else if (parseAccessSpecifier(access)) { AccessDeclarationAST::Node ast = CreateNode(); ast->addAccess(access); int startSlot = m_lexer->index(); if (m_lexer->lookAhead(0) == Token_slots) { nextToken(); AST::Node sl = CreateNode(); UPDATE_POS(sl, startSlot, m_lexer->index()); ast->addAccess(sl); } ADVANCE(':', ":"); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } m_lexer->setIndex(start); GroupAST::Node storageSpec; parseStorageClassSpecifier(storageSpec); GroupAST::Node cv; parseCvQualify(cv); TypeSpecifierAST::Node spec; if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { spec->setCvQualify(cv); GroupAST::Node cv2; parseCvQualify(cv2); spec->setCv2Qualify(cv2); InitDeclaratorListAST::Node declarators; parseInitDeclaratorList(declarators); ADVANCE(';', ";"); SimpleDeclarationAST::Node ast = CreateNode(); ast->setTypeSpec(spec); ast->setInitDeclaratorList(declarators); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } m_lexer->setIndex(start); return parseDeclarationInternal(node); } bool Parser::parseCtorInitializer(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) != ':') { return false; } nextToken(); AST::Node inits; if (!parseMemInitializerList(inits)) { reportError(i18n("Member initializers expected")); } return true; } bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); int tk = m_lexer->lookAhead(0); if (tk == Token_class || tk == Token_struct || tk == Token_union || tk == Token_enum || tk == Token_typename) { AST::Node kind = CreateNode(); nextToken(); UPDATE_POS(kind, start, m_lexer->index()); NameAST::Node name; if (parseName(name)) { ElaboratedTypeSpecifierAST::Node ast = CreateNode(); ast->setKind(kind); ast->setName(name); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } } m_lexer->setIndex(start); return false; } bool Parser::parseDeclaratorId(NameAST::Node& node) { PARSER_DEBUG_METHOD; return parseName(node); } bool Parser::parseExceptionSpecification(GroupAST::Node& node) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) != Token_throw) { return false; } nextToken(); ADVANCE('(', "("); if (m_lexer->lookAhead(0) == Token_ellipsis) { // extension found in MSVC++ 7.x headers int start = m_lexer->index(); GroupAST::Node ast = CreateNode(); AST_FROM_TOKEN(ellipsis, m_lexer->index()); ast->addNode(ellipsis); nextToken(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); } else if (m_lexer->lookAhead(0) == ')') { node = CreateNode(); } else { parseTypeIdList(node); } ADVANCE(')', ")"); return true; } bool Parser::parseEnumerator(EnumeratorAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_identifier) { return false; } nextToken(); EnumeratorAST::Node ena = CreateNode(); node = std::move(ena); AST::Node id = CreateNode(); UPDATE_POS(id, start, m_lexer->index()); node->setId(id); int line = currentLine(); if (m_lexer->lookAhead(0) == '=') { nextToken(); AST::Node expr; line = currentLine(); if (!parseConstantExpression(expr)) { reportError(i18n("Constant expression expected")); } node->setExpr(expr); } UPDATE_POS(node, start, m_lexer->index()); preparseLineComments(line); node->setComment(m_commentStore.getCommentInRange(line)); return true; } bool Parser::parseInitDeclarator(InitDeclaratorAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); DeclaratorAST::Node decl; AST::Node init; if (!parseDeclarator(decl)) { return false; } parseInitializer(init); InitDeclaratorAST::Node ast = CreateNode(); ast->setDeclarator(decl); ast->setInitializer(init); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseBaseClause(BaseClauseAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != ':') { return false; } nextToken(); BaseClauseAST::Node bca = CreateNode(); BaseSpecifierAST::Node baseSpec; if (parseBaseSpecifier(baseSpec)) { bca->addBaseSpecifier(baseSpec); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseBaseSpecifier(baseSpec)) { reportError(i18n("Base class specifier expected")); return false; } bca->addBaseSpecifier(baseSpec); } } else return false; UPDATE_POS(bca, start, m_lexer->index()); node = std::move(bca); return true; } bool Parser::parseInitializer(AST::Node& node) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) == '=') { nextToken(); AST::Node init; if (!parseInitializerClause(node)) { reportError(i18n("Initializer clause expected")); return false; } } else if (m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node expr; skipCommaExpression(expr); ADVANCE(')', ")"); } return false; } bool Parser::parseMemInitializerList(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node init; if (!parseMemInitializer(init)) { return false; } while (m_lexer->lookAhead(0) == ',') { nextToken(); if (parseMemInitializer(init)) { } else { break; } } return true; } bool Parser::parseMemInitializer(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; NameAST::Node initId; if (!parseMemInitializerId(initId)) { reportError(i18n("Identifier expected")); return false; } ADVANCE('(', "("); AST::Node expr; skipCommaExpression(expr); ADVANCE(')', ")"); return true; } bool Parser::parseTypeIdList(GroupAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node typeId; if (!parseTypeId(typeId)) { return false; } GroupAST::Node ast = CreateNode(); ast->addNode(typeId); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (parseTypeId(typeId)) { ast->addNode(typeId); } else { reportError(i18n("Type id expected")); break; } } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseBaseSpecifier(BaseSpecifierAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); BaseSpecifierAST::Node ast = CreateNode(); AST::Node access; if (m_lexer->lookAhead(0) == Token_virtual) { AST_FROM_TOKEN(virt, m_lexer->index()); ast->setIsVirtual(virt); nextToken(); parseAccessSpecifier(access); } else { parseAccessSpecifier(access); if (m_lexer->lookAhead(0) == Token_virtual) { AST_FROM_TOKEN(virt, m_lexer->index()); ast->setIsVirtual(virt); nextToken(); } } NameAST::Node name; if (!parseName(name)) { reportError(i18n("Class name expected")); } ast->setAccess(access); ast->setName(name); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseInitializerClause(AST::Node& node) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) == '{') { if (!skip('{','}')) { reportError(i18n("} missing")); } else { clearComment(); nextToken(); } } else { if (!parseAssignmentExpression(node)) { //reportError(i18n("Expression expected")); } } return true; } bool Parser::parseMemInitializerId(NameAST::Node& node) { PARSER_DEBUG_METHOD; return parseName(node); } bool Parser::parsePtrToMember(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) == Token_scope) { nextToken(); } while (m_lexer->lookAhead(0) == Token_identifier) { nextToken(); if (m_lexer->lookAhead(0) == Token_scope && m_lexer->lookAhead(1) == '*') { nextToken(); // skip :: nextToken(); // skip * return true; } else break; } return false; } bool Parser::parseUnqualifiedName(ClassOrNamespaceNameAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); bool isDestructor = false; ClassOrNamespaceNameAST::Node ast = CreateNode(); if (m_lexer->lookAhead(0) == Token_identifier) { int startName = m_lexer->index(); AST::Node n = CreateNode(); nextToken(); UPDATE_POS(n, startName, m_lexer->index()); ast->setName(n); } else if (m_lexer->lookAhead(0) == '~' && m_lexer->lookAhead(1) == Token_identifier) { int startName = m_lexer->index(); AST::Node n = CreateNode(); nextToken(); // skip ~ nextToken(); // skip classname UPDATE_POS(n, startName, m_lexer->index()); ast->setName(n); isDestructor = true; } else if (m_lexer->lookAhead(0) == Token_operator) { AST::Node n; if (!parseOperatorFunctionId(n)) return false; ast->setName(n); } else { return false; } if (!isDestructor) { int index = m_lexer->index(); if (m_lexer->lookAhead(0) == '<') { nextToken(); // optional template arguments TemplateArgumentListAST::Node args; parseTemplateArgumentList(args); if (m_lexer->lookAhead(0) != '>') { m_lexer->setIndex(index); } else { nextToken(); ast->setTemplateArgumentList(args); } } } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseStringLiteral(AST::Node& /*node*/) { while (!m_lexer->lookAhead(0).isNull()) { if (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(0).text() == QLatin1String("L") && m_lexer->lookAhead(1) == Token_string_literal) { nextToken(); nextToken(); } else if (m_lexer->lookAhead(0) == Token_string_literal) { nextToken(); } else return false; } return true; } bool Parser::skipExpressionStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node expr; skipCommaExpression(expr); ADVANCE(';', ";"); ExpressionStatementAST::Node ast = CreateNode(); ast->setExpression(expr); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseStatement(StatementAST::Node& node) // thanks to fiore@8080.it ;) { PARSER_DEBUG_METHOD; switch (m_lexer->lookAhead(0)) { case Token_while: return parseWhileStatement(node); case Token_do: return parseDoStatement(node); case Token_for: return parseForStatement(node); case Token_foreach: return parseForEachStatement(node); case Token_if: return parseIfStatement(node); case Token_switch: return parseSwitchStatement(node); case Token_try: return parseTryBlockStatement(node); case Token_case: case Token_default: return parseLabeledStatement(node); case Token_break: case Token_continue: nextToken(); ADVANCE(';', ";"); return true; case Token_goto: nextToken(); ADVANCE(Token_identifier, "identifier"); ADVANCE(';', ";"); return true; case Token_return: { nextToken(); AST::Node expr; skipCommaExpression(expr); ADVANCE(';', ";"); } return true; case '{': return parseCompoundStatement(node); case Token_identifier: if (parseLabeledStatement(node)) return true; break; } PARSER_DEBUG_METHOD; if (parseDeclarationStatement(node)) return true; return skipExpressionStatement(node); } bool Parser::parseCondition(ConditionAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ConditionAST::Node ast = CreateNode(); TypeSpecifierAST::Node spec; if (parseTypeSpecifier(spec)) { DeclaratorAST::Node decl; if (parseDeclarator(decl)) { if (m_lexer->lookAhead(0) == '=') { nextToken(); AST::Node expr; if (skipExpression(expr)) { ast->setTypeSpec(spec); ast->setDeclarator(decl); ast->setExpression(expr); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } } else { ast->setTypeSpec(spec); ast->setDeclarator(decl); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } } } m_lexer->setIndex(start); AST::Node expr; if (!skipCommaExpression(expr)) return false; ast->setExpression(expr); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseWhileStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ADVANCE(Token_while, "while"); ADVANCE('(' , "("); ConditionAST::Node cond; if (!parseCondition(cond)) { reportError(i18n("condition expected")); return false; } ADVANCE(')', ")"); StatementAST::Node body; if (!parseStatement(body)) { reportError(i18n("statement expected")); } WhileStatementAST::Node ast = CreateNode(); ast->setCondition(cond); ast->setStatement(body); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseDoStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ADVANCE(Token_do, "do"); StatementAST::Node body; if (!parseStatement(body)) { reportError(i18n("statement expected")); //return false; } ADVANCE_NR(Token_while, "while"); ADVANCE_NR('(' , "("); AST::Node expr; if (!skipCommaExpression(expr)) { reportError(i18n("expression expected")); //return false; } ADVANCE_NR(')', ")"); ADVANCE_NR(';', ";"); DoStatementAST::Node ast = CreateNode(); ast->setStatement(body); //ast->setCondition(condition); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseForStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ADVANCE(Token_for, "for"); ADVANCE('(', "("); StatementAST::Node init; if (!parseForInitStatement(init)) { reportError(i18n("for initialization expected")); return false; } ConditionAST::Node cond; parseCondition(cond); ADVANCE(';', ";"); AST::Node expr; skipCommaExpression(expr); ADVANCE(')', ")"); StatementAST::Node body; if (!parseStatement(body)) { reportError(i18n("statement expected")); } ForStatementAST::Node ast = CreateNode(); ast->setInitStatement(init); ast->setCondition(cond); // ast->setExpression(expression); ast->setStatement(body); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } // qt4 [erbsland] ///@todo add the right parsing for the foreach statement bool Parser::parseForEachStatement(StatementAST::Node& node) { int start = m_lexer->index(); ADVANCE(Token_foreach, "foreach"); ADVANCE('(', "("); AST::Node expr; // replace with the right parsing skipCommaExpression(expr); ADVANCE(')', ")"); StatementAST::Node body; if (!parseStatement(body)) { reportError(i18n("statement expected")); } ForEachStatementAST::Node ast = CreateNode(); // add here the parser results ast->setStatement(body); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseForInitStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; if (parseDeclarationStatement(node)) return true; return skipExpressionStatement(node); } bool Parser::parseCompoundStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != '{') { return false; } nextToken(); StatementListAST::Node ast = CreateNode(); while (!m_lexer->lookAhead(0).isNull()) { if (m_lexer->lookAhead(0) == '}') break; StatementAST::Node stmt; int startStmt = m_lexer->index(); if (!parseStatement(stmt)) { if (startStmt == m_lexer->index()) nextToken(); skipUntilStatement(); } else { ast->addStatement(stmt); } } clearComment(); if (m_lexer->lookAhead(0) != '}') { reportError(i18n("} expected")); } else { nextToken(); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseIfStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ADVANCE(Token_if, "if"); ADVANCE('(' , "("); IfStatementAST::Node ast = CreateNode(); ConditionAST::Node cond; if (!parseCondition(cond)) { reportError(i18n("condition expected")); return false; } ADVANCE(')', ")"); StatementAST::Node stmt; if (!parseStatement(stmt)) { reportError(i18n("statement expected")); } ast->setCondition(cond); ast->setStatement(stmt); if (m_lexer->lookAhead(0) == Token_else) { nextToken(); StatementAST::Node elseStmt; if (!parseStatement(elseStmt)) { reportError(i18n("statement expected")); } ast->setElseStatement(elseStmt); } UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseSwitchStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); ADVANCE(Token_switch, "switch"); ADVANCE('(' , "("); ConditionAST::Node cond; if (!parseCondition(cond)) { reportError(i18n("condition expected")); return false; } ADVANCE(')', ")"); StatementAST::Node stmt; if (!parseCompoundStatement(stmt)) { syntaxError(); return false; } SwitchStatementAST::Node ast = CreateNode(); ast->setCondition(cond); ast->setStatement(stmt); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseLabeledStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; switch (m_lexer->lookAhead(0)) { case Token_identifier: case Token_default: if (m_lexer->lookAhead(1) == ':') { nextToken(); nextToken(); StatementAST::Node stmt; if (parseStatement(stmt)) { node = std::move(stmt); return true; } } break; case Token_case: { nextToken(); AST::Node expr; if (!parseConstantExpression(expr)) { reportError(i18n("expression expected")); } else if (m_lexer->lookAhead(0) == Token_ellipsis) { nextToken(); AST::Node expr2; if (!parseConstantExpression(expr2)) { reportError(i18n("expression expected")); } } ADVANCE(':', ":"); StatementAST::Node stmt; if (parseStatement(stmt)) { node = std::move(stmt); return true; } } break; } return false; } bool Parser::parseBlockDeclaration(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; switch (m_lexer->lookAhead(0)) { case Token_typedef: return parseTypedef(node); case Token_using: return parseUsing(node); case Token_asm: return parseAsmDefinition(node); case Token_namespace: return parseNamespaceAliasDefinition(node); } int start = m_lexer->index(); GroupAST::Node storageSpec; parseStorageClassSpecifier(storageSpec); GroupAST::Node cv; parseCvQualify(cv); TypeSpecifierAST::Node spec; if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?! m_lexer->setIndex(start); return false; } spec->setCvQualify(cv); GroupAST::Node cv2; parseCvQualify(cv2); spec->setCv2Qualify(cv2); InitDeclaratorListAST::Node declarators; parseInitDeclaratorList(declarators); if (m_lexer->lookAhead(0) != ';') { m_lexer->setIndex(start); return false; } nextToken(); SimpleDeclarationAST::Node ast = CreateNode(); ast->setTypeSpec(spec); ast->setInitDeclaratorList(declarators); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseNamespaceAliasDefinition(DeclarationAST::Node& /*node*/) { if (m_lexer->lookAhead(0) != Token_namespace) { return false; } nextToken(); ADVANCE(Token_identifier, "identifier"); ADVANCE('=', "="); NameAST::Node name; if (!parseName(name)) { reportError(i18n("Namespace name expected")); } ADVANCE(';', ";"); return true; } bool Parser::parseDeclarationStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); DeclarationAST::Node decl; if (!parseBlockDeclaration(decl)) { return false; } DeclarationStatementAST::Node ast = CreateNode(); ast->setDeclaration(decl); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); PARSER_DEBUG_METHOD; return true; } bool Parser::parseDeclarationInternal(DeclarationAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); // that is for the case '__declspec(dllexport) int ...' or // '__declspec(dllexport) inline int ...', etc. GroupAST::Node winDeclSpec; parseWinDeclSpec(winDeclSpec); GroupAST::Node funSpec; bool hasFunSpec = parseFunctionSpecifier(funSpec); GroupAST::Node storageSpec; bool hasStorageSpec = parseStorageClassSpecifier(storageSpec); if (hasStorageSpec && !hasFunSpec) hasFunSpec = parseFunctionSpecifier(funSpec); // that is for the case 'friend __declspec(dllexport) ....' GroupAST::Node winDeclSpec2; parseWinDeclSpec(winDeclSpec2); GroupAST::Node cv; parseCvQualify(cv); int index = m_lexer->index(); NameAST::Node name; if (parseName(name) && m_lexer->lookAhead(0) == '(') { // no type specifier, maybe a constructor or a cast operator?? m_lexer->setIndex(index); InitDeclaratorAST::Node declarator; if (parseInitDeclarator(declarator)) { int endSignature = m_lexer->index(); switch (m_lexer->lookAhead(0)) { case ';': { nextToken(); InitDeclaratorListAST::Node declarators = CreateNode(); // update declarators position int startLine, startColumn, endLine, endColumn; if (declarator.get()) { declarator->getStartPosition(&startLine, &startColumn); declarator->getEndPosition(&endLine, &endColumn); declarators->setStartPosition(startLine, startColumn); declarators->setEndPosition(endLine, endColumn); } declarators->addInitDeclarator(declarator); SimpleDeclarationAST::Node ast = CreateNode(); ast->setInitDeclaratorList(declarators); + if (hasFunSpec) + ast->setFunctionSpecifier(funSpec); ast->setText(toString(start, endSignature)); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } break; case ':': { AST::Node ctorInit; StatementListAST::Node funBody; if (parseCtorInitializer(ctorInit) && parseFunctionBody(funBody)) { FunctionDefinitionAST::Node ast = CreateNode(); ast->setStorageSpecifier(storageSpec); ast->setFunctionSpecifier(funSpec); ast->setInitDeclarator(declarator); ast->setFunctionBody(funBody); ast->setText(toString(start, endSignature)); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } } break; case '{': { StatementListAST::Node funBody; if (parseFunctionBody(funBody)) { FunctionDefinitionAST::Node ast = CreateNode(); ast->setStorageSpecifier(storageSpec); ast->setFunctionSpecifier(funSpec); ast->setInitDeclarator(declarator); ast->setText(toString(start, endSignature)); ast->setFunctionBody(funBody); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } } break; case '(': case '[': // ops!! it seems a declarator goto start_decl; break; } } syntaxError(); return false; } start_decl: m_lexer->setIndex(index); if (m_lexer->lookAhead(0) == Token_const && m_lexer->lookAhead(1) == Token_identifier && m_lexer->lookAhead(2) == '=') { // constant definition nextToken(); InitDeclaratorListAST::Node declarators; if (parseInitDeclaratorList(declarators)) { ADVANCE(';', ";"); DeclarationAST::Node ast = CreateNode(); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } syntaxError(); return false; } Comment mcomment = comment(); clearComment(); TypeSpecifierAST::Node spec; if (parseTypeSpecifier(spec)) { if (!hasFunSpec) parseFunctionSpecifier(funSpec); // e.g. "void inline" spec->setCvQualify(cv); InitDeclaratorListAST::Node declarators; InitDeclaratorAST::Node decl; int startDeclarator = m_lexer->index(); bool maybeFunctionDefinition = false; if (m_lexer->lookAhead(0) != ';') { if (parseInitDeclarator(decl) && m_lexer->lookAhead(0) == '{') { // function definition maybeFunctionDefinition = true; } else { m_lexer->setIndex(startDeclarator); if (!parseInitDeclaratorList(declarators)) { syntaxError(); return false; } } } int endSignature = m_lexer->index(); switch (m_lexer->lookAhead(0)) { case ';': { nextToken(); SimpleDeclarationAST::Node ast = CreateNode(); int line, col; ast->setComment(mcomment); if (&(*decl)) { decl->getEndPosition(&line, &col); preparseLineComments(line); Comment c = m_commentStore.getCommentInRange(line); if (c) { ast->addComment(c); } } ast->setStorageSpecifier(storageSpec); ast->setFunctionSpecifier(funSpec); ast->setText(toString(start, endSignature)); ast->setTypeSpec(spec); ast->setWinDeclSpec(winDeclSpec); ast->setInitDeclaratorList(declarators); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); } return true; case '{': { if (!maybeFunctionDefinition) { syntaxError(); return false; } StatementListAST::Node funBody; if (parseFunctionBody(funBody)) { FunctionDefinitionAST::Node ast = CreateNode(); ast->setComment(mcomment); ast->setWinDeclSpec(winDeclSpec); ast->setStorageSpecifier(storageSpec); ast->setFunctionSpecifier(funSpec); ast->setText(toString(start, endSignature)); ast->setTypeSpec(spec); ast->setFunctionBody(funBody); ast->setInitDeclarator(decl); node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } } break; } } syntaxError(); return false; } bool Parser::parseFunctionBody(StatementListAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != '{') { return false; } nextToken(); StatementListAST::Node ast = CreateNode(); while (!m_lexer->lookAhead(0).isNull()) { if (m_lexer->lookAhead(0) == '}') break; StatementAST::Node stmt; int startStmt = m_lexer->index(); if (!parseStatement(stmt)) { if (startStmt == m_lexer->index()) nextToken(); skipUntilStatement(); } else ast->addStatement(stmt); } clearComment(); if (m_lexer->lookAhead(0) != '}') { reportError(i18n("} expected")); } else nextToken(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } QString Parser::toString(int start, int end, const QString& sep) const { QStringList l; for (int i=start; itokenAt(i); if (t != Token_comment) l << t.text(); } return l.join(sep).trimmed(); } bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST::Node& node) { if (parseClassSpecifier(node)) return true; else if (parseEnumSpecifier(node)) return true; else if (parseTypeSpecifier(node)) return true; return false; } bool Parser::parseTryBlockStatement(StatementAST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_try) { return false; } nextToken(); StatementAST::Node stmt; if (!parseCompoundStatement(stmt)) { syntaxError(); } if (m_lexer->lookAhead(0) != Token_catch) { reportError(i18n("catch expected")); } CatchStatementListAST::Node list = CreateNode(); while (m_lexer->lookAhead(0) == Token_catch) { nextToken(); ADVANCE('(', "("); ConditionAST::Node cond; if (!parseCondition(cond)) { reportError(i18n("condition expected")); return false; } ADVANCE(')', ")"); StatementAST::Node body; if (!parseCompoundStatement(body)) { syntaxError(); } CatchStatementAST::Node cstmt = CreateNode(); cstmt->setCondition(cond); cstmt->setStatement(body); int l=0, c=0; if (cond.get()) cond->getStartPosition(&l, &c); else if (body.get()) body->getStartPosition(&l, &c); cstmt->setStartPosition(l, c); if (body.get()) body->getEndPosition(&l, &c); cstmt->setEndPosition(l, c); list->addStatement(cstmt); } TryBlockStatementAST::Node ast = CreateNode(); ast->setStatement(stmt); ast->setCatchStatementList(list); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parsePrimaryExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; switch (m_lexer->lookAhead(0)) { case Token_string_literal: { AST::Node lit; parseStringLiteral(lit); } return true; case Token_number_literal: case Token_char_literal: case Token_true: case Token_false: nextToken(); return true; case Token_this: nextToken(); return true; case Token_dynamic_cast: case Token_static_cast: case Token_reinterpret_cast: case Token_const_cast: { nextToken(); CHECK('<', "<"); AST::Node typeId; parseTypeId(typeId); CHECK('>', ">"); CHECK('(', "("); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); } return true; case Token_typeid: { nextToken(); CHECK('(', "("); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); } return true; case '(': { nextToken(); PARSER_DEBUG_METHOD; AST::Node expr; if (!parseExpression(expr)) { return false; } CHECK(')', ")"); } return true; default: { int start = m_lexer->index(); TypeSpecifierAST::Node typeSpec; if (parseSimpleTypeSpecifier(typeSpec) && m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); return true; } m_lexer->setIndex(start); NameAST::Node name; if (parseName(name)) return true; } } return false; } bool Parser::parsePostfixExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parsePrimaryExpression(expr)) return false; while (true) { switch (m_lexer->lookAhead(0)) { case '[': { nextToken(); AST::Node e; parseCommaExpression(e); CHECK(']', "]"); } break; case '(': { nextToken(); AST::Node funArgs; parseCommaExpression(funArgs); CHECK(')', ")"); } break; case Token_incr: case Token_decr: nextToken(); break; case '.': case Token_arrow: { nextToken(); if (m_lexer->lookAhead(0) == Token_template) nextToken(); NameAST::Node name; if (!parseName(name)) { return false; } } break; case Token_typename: { nextToken(); NameAST::Node name; if (!parseName(name)) { return false; } CHECK('(', "("); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); } return true; default: return true; } // end switch } // end while return true; } bool Parser::parseUnaryExpression(AST::Node& node) { PARSER_DEBUG_METHOD; switch (m_lexer->lookAhead(0)) { case Token_incr: case Token_decr: case '*': case '&': case '+': case '-': case '!': case '~': { nextToken(); AST::Node expr; return parseCastExpression(expr); } case Token_sizeof: { nextToken(); int index = m_lexer->index(); if (m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node typeId; if (parseTypeId(typeId) && m_lexer->lookAhead(0) == ')') { nextToken(); return true; } m_lexer->setIndex(index); } AST::Node expr; return parseUnaryExpression(expr); } case Token_new: return parseNewExpression(node); case Token_delete: return parseDeleteExpression(node); } return parsePostfixExpression(node); } bool Parser::parseNewExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) == Token_scope && m_lexer->lookAhead(1) == Token_new) nextToken(); CHECK(Token_new, "new"); if (m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); } if (m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node typeId; parseTypeId(typeId); CHECK(')', ")"); } else { AST::Node typeId; parseNewTypeId(typeId); } AST::Node init; parseNewInitializer(init); return true; } bool Parser::parseNewTypeId(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; TypeSpecifierAST::Node typeSpec; if (parseTypeSpecifier(typeSpec)) { AST::Node declarator; parseNewDeclarator(declarator); return true; } return false; } bool Parser::parseNewDeclarator(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node ptrOp; if (parsePtrOperator(ptrOp)) { AST::Node declarator; parseNewDeclarator(declarator); return true; } if (m_lexer->lookAhead(0) == '[') { while (m_lexer->lookAhead(0) == '[') { nextToken(); AST::Node expr; parseExpression(expr); ADVANCE(']', "]"); } return true; } return false; } bool Parser::parseNewInitializer(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) != '(') return false; nextToken(); AST::Node expr; parseCommaExpression(expr); CHECK(')', ")"); return true; } bool Parser::parseDeleteExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) == Token_scope && m_lexer->lookAhead(1) == Token_delete) nextToken(); CHECK(Token_delete, "delete"); if (m_lexer->lookAhead(0) == '[') { nextToken(); CHECK(']', "]"); } AST::Node expr; return parseCastExpression(expr); } bool Parser::parseCastExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; int index = m_lexer->index(); if (m_lexer->lookAhead(0) == '(') { nextToken(); AST::Node typeId; if (parseTypeId(typeId)) { if (m_lexer->lookAhead(0) == ')') { nextToken(); AST::Node expr; if (parseCastExpression(expr)) return true; } } } m_lexer->setIndex(index); AST::Node expr; return parseUnaryExpression(expr); } bool Parser::parsePmExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseCastExpression(expr)) return false; while (m_lexer->lookAhead(0) == Token_ptrmem) { nextToken(); if (!parseCastExpression(expr)) return false; } return true; } bool Parser::parseMultiplicativeExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parsePmExpression(expr)) return false; while (m_lexer->lookAhead(0) == '*' || m_lexer->lookAhead(0) == '/' || m_lexer->lookAhead(0) == '%') { nextToken(); if (!parsePmExpression(expr)) return false; } return true; } bool Parser::parseAdditiveExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseMultiplicativeExpression(expr)) return false; while (m_lexer->lookAhead(0) == '+' || m_lexer->lookAhead(0) == '-') { nextToken(); if (!parseMultiplicativeExpression(expr)) return false; } return true; } bool Parser::parseShiftExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseAdditiveExpression(expr)) return false; while (m_lexer->lookAhead(0) == Token_shift || (m_lexer->lookAhead(0) == '>' && m_lexer->lookAhead(1) == '>')) { nextToken(); if (!parseAdditiveExpression(expr)) return false; } return true; } bool Parser::parseRelationalExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseShiftExpression(expr)) return false; while (m_lexer->lookAhead(0) == '<' || (m_lexer->lookAhead(0) == '>' && !templArgs) || m_lexer->lookAhead(0) == Token_leq || m_lexer->lookAhead(0) == Token_geq) { nextToken(); if (!parseShiftExpression(expr)) return false; } return true; } bool Parser::parseEqualityExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseRelationalExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == Token_eq || m_lexer->lookAhead(0) == Token_not_eq) { nextToken(); if (!parseRelationalExpression(expr, templArgs)) return false; } return true; } bool Parser::parseAndExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseEqualityExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == '&') { nextToken(); if (!parseEqualityExpression(expr, templArgs)) return false; } return true; } bool Parser::parseExclusiveOrExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseAndExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == '^') { nextToken(); if (!parseAndExpression(expr, templArgs)) return false; } return true; } bool Parser::parseInclusiveOrExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseExclusiveOrExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == '|') { nextToken(); if (!parseExclusiveOrExpression(expr, templArgs)) return false; } return true; } bool Parser::parseLogicalAndExpression(AST::Node& /*node*/, bool templArgs) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseInclusiveOrExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == Token_and) { nextToken(); if (!parseInclusiveOrExpression(expr, templArgs)) return false; } return true; } bool Parser::parseLogicalOrExpression(AST::Node& node, bool templArgs) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node expr; if (!parseLogicalAndExpression(expr, templArgs)) return false; while (m_lexer->lookAhead(0) == Token_or) { nextToken(); if (!parseLogicalAndExpression(expr, templArgs)) return false; } AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseConditionalExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; AST::Node expr; if (!parseLogicalOrExpression(expr)) return false; if (m_lexer->lookAhead(0) == '?') { nextToken(); if (!parseExpression(expr)) return false; CHECK(':', ":"); if (!parseAssignmentExpression(expr)) return false; } return true; } bool Parser::parseAssignmentExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node expr; if (m_lexer->lookAhead(0) == Token_throw && !parseThrowExpression(expr)) return false; else if (!parseConditionalExpression(expr)) return false; while (m_lexer->lookAhead(0) == Token_assign || m_lexer->lookAhead(0) == '=') { nextToken(); if (!parseConditionalExpression(expr)) return false; } AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseConstantExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (parseConditionalExpression(node)) { AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } return false; } bool Parser::parseExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); if (!parseCommaExpression(node)) return false; AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseCommaExpression(AST::Node& node) { PARSER_DEBUG_METHOD; int start = m_lexer->index(); AST::Node expr; if (!parseAssignmentExpression(expr)) return false; while (m_lexer->lookAhead(0) == ',') { nextToken(); if (!parseAssignmentExpression(expr)) return false; } AST::Node ast = CreateNode(); UPDATE_POS(ast, start, m_lexer->index()); node = std::move(ast); return true; } bool Parser::parseThrowExpression(AST::Node& /*node*/) { PARSER_DEBUG_METHOD; if (m_lexer->lookAhead(0) != Token_throw) return false; CHECK(Token_throw, "throw"); AST::Node expr; if (!parseAssignmentExpression(expr)) return false; return true; } bool Parser::parseIvarDeclList(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseIvarDecls(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseIvarDecl(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseIvars(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseIvarDeclarator(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseMethodDecl(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseUnarySelector(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordSelector(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseSelector(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordDecl(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseReceiver(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcMessageExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseMessageArgs(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordArgList(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordArg(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseReservedWord(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseMyParms(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseMyParm(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseOptParmList(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcSelectorExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseSelectorArg(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordNameList(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseKeywordName(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcEncodeExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcString(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseProtocolRefs(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseIdentifierList(GroupAST::Node & node) { int start = m_lexer->index(); if (m_lexer->lookAhead(0) != Token_identifier) return false; GroupAST::Node ast = CreateNode(); AST_FROM_TOKEN(tk, m_lexer->index()); ast->addNode(tk); nextToken(); while (m_lexer->lookAhead(0) == ',') { nextToken(); if (m_lexer->lookAhead(0) == Token_identifier) { AST_FROM_TOKEN(tk, m_lexer->index()); ast->addNode(tk); // nextToken(); } ADVANCE(Token_identifier, "identifier"); } node = std::move(ast); UPDATE_POS(node, start, m_lexer->index()); return true; } bool Parser::parseIdentifierColon(AST::Node & node) { Q_UNUSED(node); if (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(1) == ':') { nextToken(); nextToken(); return true; } // ### else if PTYPENAME -> return true ; return false; } bool Parser::parseObjcProtocolExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcOpenBracketExpr(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcCloseBracket(AST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcDef(DeclarationAST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcClassDef(DeclarationAST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcClassDecl(DeclarationAST::Node & node) { Q_UNUSED(node); ADVANCE(OBJC_CLASS, "@class"); GroupAST::Node idList; if (!parseIdentifierList(idList)) return false; ADVANCE(';', ";"); return true; } bool Parser::parseObjcProtocolDecl(DeclarationAST::Node & node) { Q_UNUSED(node); ADVANCE(OBJC_PROTOCOL, "@protocol"); GroupAST::Node idList; if (!parseIdentifierList(idList)) return false; ADVANCE(';', ";"); return true; } bool Parser::parseObjcAliasDecl(DeclarationAST::Node & node) { Q_UNUSED(node); ADVANCE(OBJC_ALIAS, "@alias"); GroupAST::Node idList; if (!parseIdentifierList(idList)) return false; ADVANCE(';', ";"); return true; } bool Parser::parseObjcProtocolDef(DeclarationAST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseObjcMethodDef(DeclarationAST::Node & node) { Q_UNUSED(node); return false; } bool Parser::parseWinDeclSpec(GroupAST::Node & node) { if (m_lexer->lookAhead(0) == Token_identifier && m_lexer->lookAhead(0).text() == QLatin1String("__declspec") && m_lexer->lookAhead(1) == '(' && m_lexer->lookAhead(2) != ')') { int start = m_lexer->index(); nextToken(); nextToken(); // skip '(' if (!parseIdentifierList(node)) return false; ADVANCE(')', ")"); UPDATE_POS(node, start, m_lexer->index()); return true; } return false; } diff --git a/lib/kdev5-php/kdevphpsupport.json b/lib/kdev5-php/kdevphpsupport.json index 8d4bbec42..5420d59e6 100644 --- a/lib/kdev5-php/kdevphpsupport.json +++ b/lib/kdev5-php/kdevphpsupport.json @@ -1,59 +1,59 @@ { "KPlugin": { "Category": "Language Support", "Description": "PHP Language Support", "Description[ca@valencia]": "Implementació del llenguatge PHP", "Description[ca]": "Implementació del llenguatge PHP", "Description[cs]": "Podpora jazyka PHP", "Description[da]": "Understøttelse af PHP-sproget", "Description[de]": "Sprachunterstützung für PHP", "Description[es]": "Implementación del lenguaje PHP", "Description[fr]": "Prise en charge du langage PHP", "Description[gl]": "Compatibilidade coa linguaxe PHP", "Description[it]": "Supporto al linguaggio PHP", "Description[nl]": "Ondersteuning van de PHP-taal", "Description[pt]": "Suporte da Linguagem PHP", "Description[sk]": "Jazyková podpora PHP", "Description[sl]": "Podpora jeziku PHP", "Description[sv]": "PHP-språkstöd", "Description[uk]": "Підтримка мови PHP", "Description[x-test]": "xxPHP Language Supportxx", - "Description[zh_CN]": "Php 语言支持", + "Description[zh_CN]": "PHP 语言支持", "Icon": "application-x-php", "Id": "KDevPhpSupport", "Name": "PHP Language Support", "Name[ca@valencia]": "Implementació del llenguatge PHP", "Name[ca]": "Implementació del llenguatge PHP", "Name[cs]": "Podpora jazyka PHP", "Name[da]": "Understøttelse af PHP-sproget", "Name[de]": "Sprachunterstützung für PHP", "Name[es]": "Implementación del lenguaje PHP", "Name[fr]": "Prise en charge du langage PHP", "Name[gl]": "Compatibilidade coa linguaxe PHP", "Name[it]": "Supporto al linguaggio PHP", "Name[nl]": "Ondersteuning van de PHP-taal", "Name[pt]": "Suporte da Linguagem PHP", "Name[sk]": "Jazyková podpora PHP", "Name[sl]": "Podpora jeziku PHP", "Name[sv]": "PHP-språkstöd", "Name[uk]": "Підтримка мови PHP", "Name[x-test]": "xxPHP Language Supportxx", "Name[zh_CN]": "Php 语言支持", "ServiceTypes": [ "KDevelop/Plugin" ] }, "X-KDevelop-Args": "PHP", "X-KDevelop-Interfaces": [ "ILanguageSupport", "org.kdevelop.PHPSupport" ], "X-KDevelop-Languages": [ "Php" ], "X-KDevelop-LoadMode": "AlwaysOn", "X-KDevelop-Mode": "NoGUI", "X-KDevelop-SupportedMimeTypes": [ "application/x-php" ] } diff --git a/test/import/cxx/explicit-constructor.h b/test/import/cxx/explicit-constructor.h new file mode 100644 index 000000000..42c62b9d3 --- /dev/null +++ b/test/import/cxx/explicit-constructor.h @@ -0,0 +1,7 @@ +class ExplicitConstructorDeclaration { + explicit ExplicitConstructorDeclaration(QString ¶m); +}; + +class ExplicitConstructorDefinition { + explicit ExplicitConstructorDefinition(QString ¶m) {} +}; diff --git a/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp b/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp index 53190a226..54a407a30 100644 --- a/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp +++ b/umbrello/codeimport/kdevcppparser/cpptree2uml.cpp @@ -1,784 +1,794 @@ /*************************************************************************** * Based on kdevelop-3.0 languages/cpp/store_walker.cpp by Roberto Raggi * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * copyright (C) 2004-2014 * * Umbrello UML Modeller Authors * ***************************************************************************/ // own header #include "cpptree2uml.h" // app includes #include "uml.h" #include "umldoc.h" #include "umllistview.h" #include "datatype.h" #include "operation.h" #include "debug_utils.h" #include "ast_utils.h" #include "codeimpthread.h" #include "driver.h" #include "import_utils.h" // FIXME: The sole reason for the next 2 includes is parseTypedef(). // Make capsule methods in ClassImport, and remove these includes. #include "classifier.h" // FIXME The next include is motivated by template params #include "template.h" // qt includes #include #include #include #include CppTree2Uml::CppTree2Uml(const QString& fileName, CodeImpThread* thread) : m_thread(thread), m_rootFolder(0), m_doc(UMLApp::app()->document()) { clear(); QDir dir(fileName); m_fileName = dir.canonicalPath(); } CppTree2Uml::~CppTree2Uml() { } void CppTree2Uml::clear() { m_currentScope.clear(); m_currentNamespace[0] = 0; // index 0 is reserved (always 0) m_currentClass[0] = 0; // index 0 is reserved (always 0) m_nsCnt = 0; m_clsCnt = 0; m_currentAccess = Uml::Visibility::Public; m_inSlots = false; m_inSignals = false; m_inStorageSpec = false; m_inTypedef = false; m_currentDeclarator = 0; m_anon = 0; } void CppTree2Uml::setRootPath(const QString &rootPath) { m_rootPath = rootPath; if (Settings::optionState().codeImportState.createArtifacts) { if (!m_rootFolder) { UMLFolder *componentView = m_doc->rootFolder(Uml::ModelType::Component); if (!m_rootPath.isEmpty()) { UMLFolder *root = Import_Utils::createSubDir(m_rootPath, componentView); m_rootFolder = root; } else { m_rootFolder = componentView; } } } } void CppTree2Uml::parseTranslationUnit(const ParsedFile &file) { clear(); if (Settings::optionState().codeImportState.createArtifacts) { QFileInfo fi(file.fileName()); UMLFolder *parent = m_rootFolder; QString path = fi.path().replace(m_rootPath, QLatin1String("")); if (!path.isEmpty()) parent = Import_Utils::createSubDir(path.mid(1), m_rootFolder); Import_Utils::createArtifact(fi.fileName(), parent, file->comment()); } TreeParser::parseTranslationUnit(file); } void CppTree2Uml::parseNamespace(NamespaceAST* ast) { if (m_clsCnt > 0) { uDebug() << "error - cannot nest namespace inside class"; return; } QString nsName; if (!ast->namespaceName() || ast->namespaceName()->text().isEmpty()){ QFileInfo fileInfo(m_fileName); QString shortFileName = fileInfo.baseName(); nsName.sprintf("(%s_%d)", shortFileName.toLocal8Bit().constData(), m_anon++); } else { nsName = ast->namespaceName()->text(); } uDebug() << nsName; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("namespace ") + nsName); } UMLObject *o = m_doc->findUMLObject(nsName, UMLObject::ot_Package, m_currentNamespace[m_nsCnt]); if (!o) o = m_doc->findUMLObject(nsName, UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (o && o->stereotype() == QLatin1String("class-or-package")) { o->setStereotype(QString()); o->setBaseType(UMLObject::ot_Package); } // TODO reduce multiple finds else o = Import_Utils::createUMLObject(UMLObject::ot_Package, nsName, m_currentNamespace[m_nsCnt], ast->comment()); UMLPackage *ns = (UMLPackage *)o; m_currentScope.push_back(nsName); if (++m_nsCnt > STACKSIZE) { uError() << "excessive namespace nesting"; m_nsCnt = STACKSIZE; } m_currentNamespace[m_nsCnt] = ns; TreeParser::parseNamespace(ast); --m_nsCnt; m_currentScope.pop_back(); } void CppTree2Uml::parseTypedef(TypedefAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); if (typeSpec && declarators){ QString typeId; if (typeSpec->name()) typeId = typeSpec->name()->text(); QList l(declarators->initDeclaratorList()); InitDeclaratorAST* initDecl = 0; for (int i = 0; i < l.size(); ++i) { initDecl = l.at(i); if (initDecl==0) break; QString type, id; if (initDecl->declarator()){ type = typeOfDeclaration(typeSpec, initDecl->declarator()); DeclaratorAST* d = initDecl->declarator(); while (d->subDeclarator()){ d = d->subDeclarator(); } if (d->declaratorId()) id = d->declaratorId()->text(); } /* @todo Trace typedefs back to their root type for deciding whether to build a Datatype (for pointers.) */ /* check out if the ID type is a Datatype ex: typedef unsigned int uint; where unsigned int is a known datatype I'm not sure if setIsReference() should be run */ bool isDatatype = Import_Utils::isDatatype(typeId, m_currentNamespace[m_nsCnt]); if (type.contains(QLatin1Char('*')) || isDatatype) { UMLObject *inner = 0; if (m_currentNamespace[m_nsCnt] && m_currentNamespace[m_nsCnt]->baseType() == UMLObject::ot_Class && typeId == m_currentNamespace[m_nsCnt]->name()) inner = m_currentNamespace[m_nsCnt]; else inner = Import_Utils::createUMLObject(UMLObject::ot_Class, type, m_currentNamespace[m_nsCnt]); UMLObject *typedefObj = Import_Utils::createUMLObject(UMLObject::ot_Datatype, id, m_currentNamespace[m_nsCnt]); UMLDatatype *dt = typedefObj->asUMLDatatype(); if (dt) { dt->setIsReference(); dt->setOriginType(inner->asUMLClassifier()); } else { uError() << "Could not create datatype from" << id; } } else { Import_Utils::createUMLObject(UMLObject::ot_Class, id, m_currentNamespace[m_nsCnt], QString() /* doc */, QLatin1String("typedef") /* stereotype */); } } } } void CppTree2Uml::parseTemplateDeclaration(TemplateDeclarationAST* ast) { TemplateParameterListAST* parmListAST = ast->templateParameterList(); if (parmListAST == 0) return; QList parmList = parmListAST->templateParameterList(); for (int i = 0; i < parmList.size(); ++i) { // The template is either a typeParameter or a typeValueParameter. TemplateParameterAST* tmplParmNode = parmList.at(i); TypeParameterAST* typeParmNode = tmplParmNode->typeParameter(); if (typeParmNode) { NameAST* nameNode = typeParmNode->name(); if (nameNode) { QString typeName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(typeName, 0); m_templateParams.append(nt); } else { uError() << "nameNode is NULL"; } } ParameterDeclarationAST* valueNode = tmplParmNode->typeValueParameter(); if (valueNode) { TypeSpecifierAST* typeSpec = valueNode->typeSpec(); if (typeSpec == 0) { uError() << "typeSpec is NULL"; continue; } QString typeName = typeSpec->name()->text(); UMLObject *t = Import_Utils::createUMLObject(UMLObject::ot_UMLObject, typeName, m_currentNamespace[m_nsCnt]); DeclaratorAST* declNode = valueNode->declarator(); NameAST* nameNode = declNode->declaratorId(); if (nameNode == 0) { uError() << "CppTree2Uml::parseTemplateDeclaration(value):" << " nameNode is NULL"; continue; } QString paramName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(paramName, t); m_templateParams.append(nt); } } if (ast->declaration()) TreeParser::parseDeclaration(ast->declaration()); } void CppTree2Uml::parseSimpleDeclaration(SimpleDeclarationAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); GroupAST* storageSpec = ast->storageSpecifier(); if (storageSpec && storageSpec->text() == QLatin1String("friend")) return; m_comment = ast->comment(); if (typeSpec) parseTypeSpecifier(typeSpec); if (declarators){ QList l = declarators->initDeclaratorList(); for (int i = 0; i < l.size(); ++i) { parseDeclaration2(ast->functionSpecifier(), ast->storageSpecifier(), typeSpec, l.at(i)); } } } void CppTree2Uml::parseFunctionDefinition(FunctionDefinitionAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); GroupAST* funSpec = ast->functionSpecifier(); GroupAST* storageSpec = ast->storageSpecifier(); if (!ast->initDeclarator()) return; DeclaratorAST* d = ast->initDeclarator()->declarator(); if (!d->declaratorId()) return; bool isFriend = false; bool isVirtual = false; bool isStatic = false; bool isInline = false; bool isConstructor = false; bool isDestructor = false; - + bool isExplicit = false; bool isConstExpression = false; if (funSpec){ QList l = funSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("virtual")) isVirtual = true; else if (text == QLatin1String("inline")) isInline = true; + else if (text == QLatin1String("explicit")) + isExplicit = true; } } if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("constexpr")) isConstExpression = true; } } QString id = d->declaratorId()->unqualifiedName()->text().trimmed(); if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("method ") + id); } uDebug() << id; UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); if (isVirtual) m->setVirtual(true); if (isInline) m->setInline(true); if (d->override()) m->setOverride(true); if (d->constant()) m->setConst(true); // if a class has no return type, it could be a constructor or // a destructor if (d && returnType.isEmpty()) { if (id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; else isDestructor = true; } parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, false /*isAbstract*/, isFriend, isConstructor, isDestructor, m_comment); m_comment = QString(); + if (isExplicit && isConstructor) + m->setStereotype(QLatin1String("explicit constructor")); /* For reference, Kdevelop does some more: method->setFileName(m_fileName); if (m_inSignals) method->setSignal(true); if (m_inSlots) method->setSlot(true); */ } void CppTree2Uml::parseClassSpecifier(ClassSpecifierAST* ast) { Uml::Visibility::Enum oldAccess = m_currentAccess; bool oldInSlots = m_inSlots; bool oldInSignals = m_inSignals; QString kind = ast->classKey()->text(); m_currentAccess = Uml::Visibility::fromString(kind); m_inSlots = false; m_inSignals = false; QString className; if (!ast->name() && m_currentDeclarator && m_currentDeclarator->declaratorId()) { className = m_currentDeclarator->declaratorId()->text().trimmed(); } else if (!ast->name()){ QFileInfo fileInfo(m_fileName); QString shortFileName = fileInfo.baseName(); className.sprintf("(%s_%d)", shortFileName.toLocal8Bit().constData(), m_anon++); } else { className = ast->name()->unqualifiedName()->text().trimmed(); } uDebug() << "name=" << className; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("class ") + className); } QStringList scope = scopeOfName(ast->name(), QStringList()); UMLObject *localParent = 0; if (!scope.isEmpty()) { localParent = m_doc->findUMLObject(scope.join(QLatin1String("::")), UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (!localParent) localParent = m_doc->findUMLObject(scope.join(QLatin1String("::")), UMLObject::ot_Package, m_currentNamespace[m_nsCnt]); if (!localParent) { localParent = Import_Utils::createUMLObject(UMLObject::ot_Class, className, m_currentNamespace[m_nsCnt], ast->comment(), QString(), true); localParent->setStereotype(QLatin1String("class-or-package")); } m_currentNamespace[++m_nsCnt] = localParent->asUMLPackage(); } if (className.isEmpty()) { className = QLatin1String("anon_") + QString::number(m_anon); m_anon++; } UMLObject *o = m_doc->findUMLObject(className, UMLObject::ot_Class, m_currentNamespace[m_nsCnt]); if (!o) o = m_doc->findUMLObject(className, UMLObject::ot_Datatype, m_currentNamespace[m_nsCnt]); if (o && o->stereotype() == QLatin1String("class-or-package")) { o->setStereotype(QString()); o->setBaseType(UMLObject::ot_Class); } // TODO reduce multiple finds else o = Import_Utils::createUMLObject(UMLObject::ot_Class, className, m_currentNamespace[m_nsCnt], ast->comment(), QString(), true); UMLClassifier *klass = o->asUMLClassifier(); flushTemplateParams(klass); if (ast->baseClause()) parseBaseClause(ast->baseClause(), klass); m_currentScope.push_back(className); if (++m_clsCnt > STACKSIZE) { uError() << "excessive class nesting"; m_clsCnt = STACKSIZE; } m_currentClass[m_clsCnt] = klass; if (++m_nsCnt > STACKSIZE) { uError() << "excessive namespace nesting"; m_nsCnt = STACKSIZE; } m_currentNamespace[m_nsCnt] = (UMLPackage*)klass; TreeParser::parseClassSpecifier(ast); --m_nsCnt; --m_clsCnt; m_currentScope.pop_back(); // check is class is an interface bool isInterface = true; foreach(UMLOperation *op, klass->getOpList()) { if (!op->isDestructorOperation() && op->isAbstract() == false) isInterface = false; } foreach(UMLAttribute *attr, klass->getAttributeList()) { if (!(attr->isStatic() && attr->getTypeName().contains(QLatin1String("const")))) isInterface = false; } if (isInterface) klass->setBaseType(UMLObject::ot_Interface); m_currentAccess = oldAccess; m_inSlots = oldInSlots; m_inSignals = oldInSignals; if (localParent) m_currentNamespace[m_nsCnt--] = 0; } void CppTree2Uml::parseEnumSpecifier(EnumSpecifierAST* ast) { NameAST *nameNode = ast->name(); if (nameNode == 0) return; // skip constants QString typeName = nameNode->unqualifiedName()->text().trimmed(); if (typeName.isEmpty()) return; // skip constants UMLObject *o = Import_Utils::createUMLObject(UMLObject::ot_Enum, typeName, m_currentNamespace[m_nsCnt], ast->comment()); QList l = ast->enumeratorList(); for (int i = 0; i < l.size(); ++i) { QString enumLiteral = l.at(i)->id()->text(); QString enumLiteralValue = QString(); if (l.at(i)->expr()) { enumLiteralValue = l.at(i)->expr()->text(); } Import_Utils::addEnumLiteral((UMLEnum*)o, enumLiteral, QString(), enumLiteralValue); } } void CppTree2Uml::parseElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST* typeSpec) { // This is invoked for forward declarations. /// @todo Refine - Currently only handles class forward declarations. /// - Using typeSpec->text() is probably not good, decode /// the kind() instead. QString text = typeSpec->text(); uDebug() << "forward declaration of " << text; if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("forward declaration of ") + text); } text.remove(QRegExp(QLatin1String("^class\\s+"))); #if 0 if (m_thread) { //:TODO: for testing only int answer; m_thread->emitAskQuestion("Soll CppTree2Uml::parseElaboratedTypeSpecifier ausgeführt werden?"); uDebug() << "Antwort: " << answer; } #endif UMLObject *o = Import_Utils::createUMLObject(UMLObject::ot_Class, text, m_currentNamespace[m_nsCnt]); #if 0 if (m_thread) { //:TODO: for testing only m_thread->emitAskQuestion("Soll nach CppTree2Uml::parseElaboratedTypeSpecifier weiter gemacht werden?"); } #endif flushTemplateParams(o->asUMLClassifier()); } void CppTree2Uml::parseDeclaration2(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl) { if (m_inStorageSpec) return; DeclaratorAST* d = decl->declarator(); if (!d) return; if (!d->subDeclarator() && d->parameterDeclarationClause()) return parseFunctionDeclaration(funSpec, storageSpec, typeSpec, decl); DeclaratorAST* t = d; while (t && t->subDeclarator()) t = t->subDeclarator(); QString id; if (t && t->declaratorId() && t->declaratorId()->unqualifiedName()) id = t->declaratorId()->unqualifiedName()->text(); if (!scopeOfDeclarator(d, QStringList()).isEmpty()){ uDebug() << id << ": skipping."; return; } UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString typeName = typeOfDeclaration(typeSpec, d); bool isFriend = false; bool isStatic = false; //:unused: bool isInitialized = decl->initializer() != 0; if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("mutable")) typeName.prepend(text + QLatin1String(" ")); else if (text == QLatin1String("friend")) isFriend = true; } } UMLAttribute *attribute = Import_Utils::insertAttribute(c, m_currentAccess, id, typeName, m_comment, isStatic); if (isFriend) attribute->setStereotype(QLatin1String("friend")); m_comment = QString(); } void CppTree2Uml::parseAccessDeclaration(AccessDeclarationAST * access) { QList l = access->accessList(); QString accessStr = l.at(0)->text(); m_currentAccess=Uml::Visibility::fromString(accessStr); m_inSlots = l.count() > 1 ? l.at(1)->text() == QLatin1String("slots") : false; m_inSignals = l.count() >= 1 ? l.at(0)->text() == QLatin1String("signals") : false; } void CppTree2Uml::parseFunctionDeclaration(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl) { bool isFriend = false; bool isVirtual = false; bool isStatic = false; bool isInline = false; bool isPure = decl->initializer() != 0; bool isConstructor = false; bool isConstExpression = false; bool isDestructor = false; + bool isExplicit = false; if (funSpec){ QList l = funSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("virtual")) isVirtual = true; else if (text == QLatin1String("inline")) isInline = true; + else if (text == QLatin1String("explicit")) + isExplicit = true; } } if (storageSpec){ QList l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; else if (text == QLatin1String("constexpr")) isConstExpression = true; } } DeclaratorAST* d = decl->declarator(); QString id = d->declaratorId()->unqualifiedName()->text(); UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == 0) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); if (d->override()) m->setOverride(true); if (d->constant()) m->setConst(true); if (isConstExpression) m->setStereotype(QLatin1String("constexpr")); if (isVirtual) m->setVirtual(true); if (isInline) m->setInline(true); // if a class has no return type, it could de a constructor or // a destructor if (d && returnType.isEmpty()) { if (id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; else isDestructor = true; } parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, isPure, isFriend, isConstructor, isDestructor, m_comment); if (isPure) c->setAbstract(true); + if (isExplicit && isConstructor) + m->setStereotype(QLatin1String("explicit constructor")); + m_comment = QString(); } void CppTree2Uml::parseFunctionArguments(DeclaratorAST* declarator, UMLOperation* method) { if (!declarator) return; ParameterDeclarationClauseAST* clause = declarator->parameterDeclarationClause(); if (clause && clause->parameterDeclarationList()){ ParameterDeclarationListAST* params = clause->parameterDeclarationList(); QList l(params->parameterList()); for (int i = 0; i < l.size(); ++i) { ParameterDeclarationAST* param = l.at(i); QString name; if (param->declarator()) name = declaratorToString(param->declarator(), QString(), true); QString tp = typeOfDeclaration(param->typeSpec(), param->declarator()); if (tp != QLatin1String("void")) Import_Utils::addMethodParameter(method, tp, name); } } } QString CppTree2Uml::typeOfDeclaration(TypeSpecifierAST* typeSpec, DeclaratorAST* declarator) { if (!typeSpec || !declarator) return QString(); QString text; text += typeSpec->text(); QList ptrOpList = declarator->ptrOpList(); for (int i = 0; i < ptrOpList.size(); ++i) { text += ptrOpList.at(i)->text(); } QList arrays = declarator->arrayDimensionList(); for(int i = 0; i < arrays.size(); ++i) { text += arrays.at(i)->text().replace(QLatin1String(" "), QLatin1String("")); } return text; } void CppTree2Uml::parseBaseClause(BaseClauseAST * baseClause, UMLClassifier* klass) { QList l = baseClause->baseSpecifierList(); for (int i = 0; i < l.size(); ++i) { BaseSpecifierAST* baseSpecifier = l.at(i); if (baseSpecifier->name() == 0) { uDebug() << "baseSpecifier->name() is NULL"; continue; } QString baseName = baseSpecifier->name()->text(); // uDebug() << "CppTree2Uml::parseBaseClause : baseSpecifier is " << baseName; Import_Utils::putAtGlobalScope(true); UMLObject *c = Import_Utils::createUMLObject(UMLObject::ot_Class, baseName, m_currentNamespace[m_nsCnt], baseSpecifier->comment()); Import_Utils::putAtGlobalScope(false); Import_Utils::createGeneralization(klass, c->asUMLClassifier()); } } QStringList CppTree2Uml::scopeOfName(NameAST* id, const QStringList& startScope) { QStringList scope = startScope; if (id && id->classOrNamespaceNameList().count()){ if (id->isGlobal()) scope.clear(); QList l = id->classOrNamespaceNameList(); for (int i = 0; i < l.size(); ++i) { if (l.at(i)->name()){ scope << l.at(i)->name()->text(); } } } return scope; } QStringList CppTree2Uml::scopeOfDeclarator(DeclaratorAST* d, const QStringList& startScope) { return scopeOfName(d->declaratorId(), startScope); } /** * Flush template parameters pending in m_templateParams to the klass. */ void CppTree2Uml::flushTemplateParams(UMLClassifier *klass) { if (m_templateParams.count()) { Model_Utils::NameAndType_ListIt it; for (it = m_templateParams.begin(); it != m_templateParams.end(); ++it) { const Model_Utils::NameAndType &nt = *it; uDebug() << "adding template param: " << nt.m_name; UMLTemplate *tmpl = klass->addTemplate(nt.m_name); tmpl->setType(nt.m_type); } m_templateParams.clear(); } }