diff options
author | Wang Hoi <wanghoi@126.com> | 2014-05-05 22:56:15 +0800 |
---|---|---|
committer | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2014-06-17 16:23:23 +0200 |
commit | c56b999ffff249d4cb7dc7e8026a3297b63ff56d (patch) | |
tree | 007d1f5208cd7e03fdc2eceb4cefe3dd4a12ded8 | |
parent | d70485180a676c3d97108bb87ec1c32223ee0f2b (diff) |
C: Parser: Support parsing of c99 designated initializers
In case:
int a[6] = { [4] = 29, [2] = 15 };
struct point { int x, y; };
struct point p = { .y = 3, .x = 2 };
Grammar change when c99 language feature is enabled:
old grammar:
braced-init-list :: '{' initializer-list '}'
new grammar:
braced-init-list :: '{' designated-initializer-list '}'
designated-initializer-list :: designated-initializer (',' designated-initializer )*
designated-initializer :: designator* initializer-clause
designator :: '.' identifier
| '[' constant-expression ']'
Task-number: QTCREATORBUG-1902
Change-Id: Ib99d6f553f8d0f50ba3eff86f3a2e86d73372426
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
27 files changed, 529 insertions, 2 deletions
diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 5e166b83b2..dd341db6d9 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -4450,3 +4450,69 @@ unsigned AliasDeclarationAST::lastToken() const return 1; } +/** \generated */ +unsigned DesignatedInitializerAST::firstToken() const +{ + if (designator_list) + if (unsigned candidate = designator_list->firstToken()) + return candidate; + if (equal_token) + return equal_token; + if (initializer) + if (unsigned candidate = initializer->firstToken()) + return candidate; + return 0; +} + +/** \generated */ +unsigned DesignatedInitializerAST::lastToken() const +{ + if (initializer) + if (unsigned candidate = initializer->lastToken()) + return candidate; + if (equal_token) + return equal_token + 1; + if (designator_list) + if (unsigned candidate = designator_list->lastToken()) + return candidate; + return 1; +} + +unsigned DesignatorAST::firstToken() const +{ + if (type == DesignatorAST::Dot) { + if (u.dot.dot_token) + return u.dot.dot_token; + if (u.dot.identifier_token) + return u.dot.identifier_token; + } else if (type == DesignatorAST::Bracket) { + if (u.bracket.lbracket_token) + return u.bracket.lbracket_token; + if (u.bracket.expression) + if (unsigned candidate = u.bracket.expression->firstToken()) + return candidate; + if (u.bracket.rbracket_token) + return u.bracket.rbracket_token; + } + return 0; +} + +unsigned DesignatorAST::lastToken() const +{ + if (type == DesignatorAST::Dot) { + if (u.dot.identifier_token) + return u.dot.identifier_token + 1; + if (u.dot.dot_token) + return u.dot.dot_token + 1; + } else if (type == DesignatorAST::Bracket) { + if (u.bracket.rbracket_token) + return u.bracket.rbracket_token + 1; + if (u.bracket.expression) + if (unsigned candidate = u.bracket.expression->lastToken()) + return candidate; + if (u.bracket.lbracket_token) + return u.bracket.lbracket_token + 1; + } + return 1; +} + diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 556f898f6d..41c630aea8 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -161,6 +161,8 @@ public: virtual DeclaratorIdAST *asDeclaratorId() { return 0; } virtual DecltypeSpecifierAST *asDecltypeSpecifier() { return 0; } virtual DeleteExpressionAST *asDeleteExpression() { return 0; } + virtual DesignatedInitializerAST *asDesignatedInitializer() { return 0; } + virtual DesignatorAST *asDesignator() { return 0; } virtual DestructorNameAST *asDestructorName() { return 0; } virtual DoStatementAST *asDoStatement() { return 0; } virtual DynamicExceptionSpecificationAST *asDynamicExceptionSpecification() { return 0; } @@ -4527,6 +4529,72 @@ protected: virtual bool match0(AST *, ASTMatcher *); }; +class DesignatorAST: public AST +{ +public: + enum Type + { + Invalid, + Dot, + Bracket + }; + Type type; + union Designator + { + struct DotDesignator + { + unsigned dot_token; + unsigned identifier_token; + } dot; + struct BracketDesignator + { + unsigned lbracket_token; + ExpressionAST *expression; + unsigned rbracket_token; + } bracket; + } u; + +public: + DesignatorAST() + : type(Invalid) + {} + + virtual DesignatorAST *asDesignator() { return this; } + virtual unsigned firstToken() const; + virtual unsigned lastToken() const; + + virtual DesignatorAST *clone(MemoryPool *pool) const; + +protected: + virtual void accept0(ASTVisitor *visitor); + virtual bool match0(AST *, ASTMatcher *); +}; + +class DesignatedInitializerAST: public ExpressionAST +{ +public: + DesignatorListAST *designator_list; + unsigned equal_token; + ExpressionAST *initializer; + +public: + DesignatedInitializerAST() + : designator_list(0) + , equal_token(0) + , initializer(0) + {} + + virtual DesignatedInitializerAST *asDesignatedInitializer() { return this; } + virtual unsigned firstToken() const; + virtual unsigned lastToken() const; + + virtual DesignatedInitializerAST *clone(MemoryPool *pool) const; + +protected: + virtual void accept0(ASTVisitor *visitor); + virtual bool match0(AST *, ASTMatcher *); +}; + } // namespace CPlusPlus #endif // CPLUSPLUS_AST_H diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 8ff5d0e9d7..086b12b1c9 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -1762,3 +1762,21 @@ BracedInitializerAST *BracedInitializerAST::clone(MemoryPool *pool) const return ast; } +DesignatorAST *DesignatorAST::clone(MemoryPool *pool) const +{ + DesignatorAST *ast = new (pool) DesignatorAST; + return ast; +} + +DesignatedInitializerAST *DesignatedInitializerAST::clone(MemoryPool *pool) const +{ + DesignatedInitializerAST *ast = new (pool) DesignatedInitializerAST; + for (DesignatorListAST *iter = designator_list, **ast_iter = &ast->designator_list; + iter; iter = iter->next, ast_iter = &(*ast_iter)->next) + *ast_iter = new (pool) DesignatorListAST((iter->value) ? iter->value->clone(pool) : 0); + ast->equal_token = equal_token; + if (initializer) + ast->initializer = initializer->clone(pool); + return ast; +} + diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index 69e3daf615..efeb2c57e0 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -1192,3 +1192,19 @@ bool BracedInitializerAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool DesignatorAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (DesignatorAST *_other = pattern->asDesignator()) + return matcher->match(this, _other); + + return false; +} + +bool DesignatedInitializerAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (DesignatedInitializerAST *_other = pattern->asDesignatedInitializer()) + return matcher->match(this, _other); + + return false; +} + diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index 105f236070..02cdb9f068 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -2999,3 +2999,31 @@ bool ASTMatcher::match(BracedInitializerAST *node, BracedInitializerAST *pattern return true; } +bool ASTMatcher::match(DesignatorAST *node, DesignatorAST *pattern) +{ + (void) node; + (void) pattern; + + return true; +} + +bool ASTMatcher::match(DesignatedInitializerAST *node, DesignatedInitializerAST *pattern) +{ + (void) node; + (void) pattern; + + if (! pattern->designator_list) + pattern->designator_list = node->designator_list; + else if (! AST::match(node->designator_list, pattern->designator_list, this)) + return false; + + pattern->equal_token = node->equal_token; + + if (! pattern->initializer) + pattern->initializer = node->initializer; + else if (! AST::match(node->initializer, pattern->initializer, this)) + return false; + + return true; +} + diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index eee507b941..ebb18884e3 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -66,6 +66,8 @@ public: virtual bool match(DeclaratorIdAST *node, DeclaratorIdAST *pattern); virtual bool match(DecltypeSpecifierAST *node, DecltypeSpecifierAST *pattern); virtual bool match(DeleteExpressionAST *node, DeleteExpressionAST *pattern); + virtual bool match(DesignatedInitializerAST *node, DesignatedInitializerAST *pattern); + virtual bool match(DesignatorAST *node, DesignatorAST *pattern); virtual bool match(DestructorNameAST *node, DestructorNameAST *pattern); virtual bool match(DoStatementAST *node, DoStatementAST *pattern); virtual bool match(DynamicExceptionSpecificationAST *node, DynamicExceptionSpecificationAST *pattern); diff --git a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h index b4d413efd8..ce55ccfe81 100644 --- a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h +++ b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.h @@ -1147,6 +1147,20 @@ public: return __ast; } + DesignatorAST *Designator() + { + DesignatorAST *__ast = new (&pool) DesignatorAST; + return __ast; + } + + DesignatedInitializerAST *DesignatedInitializer(DesignatorListAST *designator_list = 0, ExpressionAST *initializer = 0) + { + DesignatedInitializerAST *__ast = new (&pool) DesignatedInitializerAST; + __ast->designator_list = designator_list; + __ast->initializer = initializer; + return __ast; + } + AttributeListAST *AttributeList(AttributeAST *value, AttributeListAST *next = 0) { AttributeListAST *__list = new (&pool) AttributeListAST; @@ -1195,6 +1209,14 @@ public: return __list; } + DesignatorListAST *DesignatorList(DesignatorAST *value, DesignatorListAST *next = 0) + { + DesignatorListAST *__list = new (&pool) DesignatorListAST; + __list->next = next; + __list->value = value; + return __list; + } + EnumeratorListAST *EnumeratorList(EnumeratorAST *value, EnumeratorListAST *next = 0) { EnumeratorListAST *__list = new (&pool) EnumeratorListAST; diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index 69ce44c8f1..983f09fc29 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -1279,3 +1279,19 @@ void BracedInitializerAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void DesignatorAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + } + visitor->endVisit(this); +} + +void DesignatedInitializerAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) { + accept(designator_list, visitor); + accept(initializer, visitor); + } + visitor->endVisit(this); +} + diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index d9578a4061..66c6c011f4 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -108,6 +108,8 @@ public: virtual bool visit(DeclaratorIdAST *) { return true; } virtual bool visit(DecltypeSpecifierAST *) { return true; } virtual bool visit(DeleteExpressionAST *) { return true; } + virtual bool visit(DesignatedInitializerAST *) { return true; } + virtual bool visit(DesignatorAST *) { return true; } virtual bool visit(DestructorNameAST *) { return true; } virtual bool visit(DoStatementAST *) { return true; } virtual bool visit(DynamicExceptionSpecificationAST *) { return true; } @@ -254,6 +256,8 @@ public: virtual void endVisit(DeclaratorIdAST *) {} virtual void endVisit(DecltypeSpecifierAST *) {} virtual void endVisit(DeleteExpressionAST *) {} + virtual void endVisit(DesignatedInitializerAST *) {} + virtual void endVisit(DesignatorAST *) {} virtual void endVisit(DestructorNameAST *) {} virtual void endVisit(DoStatementAST *) {} virtual void endVisit(DynamicExceptionSpecificationAST *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index 7b79947cb9..a3382c89d6 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -68,6 +68,8 @@ class DeclaratorAST; class DeclaratorIdAST; class DecltypeSpecifierAST; class DeleteExpressionAST; +class DesignatedInitializerAST; +class DesignatorAST; class DestructorNameAST; class DoStatementAST; class DynamicExceptionSpecificationAST; @@ -215,6 +217,8 @@ typedef List<ObjCPropertyAttributeAST *> ObjCPropertyAttributeListAST; typedef List<ObjCMessageArgumentDeclarationAST *> ObjCMessageArgumentDeclarationListAST; typedef List<ObjCSynthesizedPropertyAST *> ObjCSynthesizedPropertyListAST; +typedef List<DesignatorAST *> DesignatorListAST; + } // namespace CPlusPlus diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index dfd6d1e49a..0163046176 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -2664,7 +2664,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node) ExpressionListAST **expression_list_ptr = &node; ExpressionAST *expression = 0; - if (parseInitializerClause0x(expression)) { + if (parseDesignatedInitializer(expression)) { *expression_list_ptr = new (_pool) ExpressionListAST; (*expression_list_ptr)->value = expression; expression_list_ptr = &(*expression_list_ptr)->next; @@ -2675,7 +2675,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node) while (LA() == T_COMMA && LA(2) != T_RBRACE) { consumeToken(); // consume T_COMMA - if (parseInitializerClause0x(expression)) { + if (parseDesignatedInitializer(expression)) { *expression_list_ptr = new (_pool) ExpressionListAST; (*expression_list_ptr)->value = expression; @@ -5484,6 +5484,50 @@ bool Parser::lookAtObjCSelector() const return false; } +// designated-initializer ::= designator* T_EQUAL initializer-clause +// +bool Parser::parseDesignatedInitializer(ExpressionAST *&node) +{ + DEBUG_THIS_RULE(); + if (!_languageFeatures.c99Enabled || (LA() != T_DOT && LA() != T_LBRACKET)) + return parseInitializerClause0x(node); + + DesignatedInitializerAST *ast = new (_pool) DesignatedInitializerAST; + DesignatorListAST **designator_list_ptr = &ast->designator_list; + DesignatorAST *designator = 0; + while (parseDesignator(designator)) { + *designator_list_ptr = new (_pool) DesignatorListAST; + (*designator_list_ptr)->value = designator; + designator_list_ptr = &(*designator_list_ptr)->next; + } + match(T_EQUAL, &ast->equal_token); + parseInitializerClause0x(ast->initializer); + node = ast; + return true; +} + +// designator ::= T_DOT T_IDENTIFIER +// T_LBRACKET constant-expression T_BRACKET +// +bool Parser::parseDesignator(DesignatorAST *&node) +{ + DesignatorAST *ast = new (_pool) DesignatorAST; + if (LA() == T_DOT) { + ast->type = DesignatorAST::Dot; + ast->u.dot.dot_token = consumeToken(); + match(T_IDENTIFIER, &ast->u.dot.identifier_token); + } else if (LA() == T_LBRACKET) { + ast->type = DesignatorAST::Bracket; + ast->u.bracket.lbracket_token = consumeToken(); + parseConstantExpression(ast->u.bracket.expression); + match(T_RBRACKET, &ast->u.bracket.rbracket_token); + } else { + return false; + } + node = ast; + return true; +} + // objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON // bool Parser::parseObjCClassForwardDeclaration(DeclarationAST *&node) diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index ea49df5e56..c18a079e4e 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -246,6 +246,11 @@ public: bool lookAtObjCSelector() const; + // c99 + bool parseDesignatedInitializerList(ExpressionListAST *&node); + bool parseDesignatedInitializer(ExpressionAST *&node); + bool parseDesignator(DesignatorAST *&node); + bool skipUntil(int token); void skipUntilDeclaration(); bool skipUntilStatement(); diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index ec10483852..d4a2901c34 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -390,6 +390,7 @@ struct LanguageFeatures unsigned int qtKeywordsEnabled : 1; // If Qt is used but QT_NO_KEYWORDS defined unsigned int cxx11Enabled : 1; unsigned int objCEnabled : 1; + unsigned int c99Enabled : 1; }; }; }; diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index e159f774b3..9a18343eda 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -288,6 +288,7 @@ Document::Document(const QString &fileName) features.qtKeywordsEnabled = true; features.cxx11Enabled = true; features.objCEnabled = true; + features.c99Enabled = true; _translationUnit = new TranslationUnit(_control, fileId); _translationUnit->setLanguageFeatures(features); (void) _control->switchTranslationUnit(_translationUnit); diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp index aa37b846aa..23c546004f 100644 --- a/src/plugins/cppeditor/cppautocompleter.cpp +++ b/src/plugins/cppeditor/cppautocompleter.cpp @@ -106,6 +106,7 @@ bool CppAutoCompleter::isInCommentHelper(const QTextCursor &cursor, Token *retTo features.qtKeywordsEnabled = false; features.qtMocRunEnabled = false; features.cxx11Enabled = true; + features.c99Enabled = true; SimpleLexer tokenize; tokenize.setLanguageFeatures(features); diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 2617d262b3..241619ded0 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -77,6 +77,7 @@ void CppHighlighter::highlightBlock(const QString &text) // FIXME: Check defaults or get from document. LanguageFeatures features; features.cxx11Enabled = true; + features.c99Enabled = true; SimpleLexer tokenize; tokenize.setLanguageFeatures(features); diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index acc5c7f7d2..3f69c86ac3 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -495,6 +495,13 @@ bool CheckSymbols::visit(EnumeratorAST *ast) return true; } +bool CheckSymbols::visit(DesignatorAST *ast) +{ + if (ast->type == DesignatorAST::Dot) + addUse(ast->u.dot.identifier_token, CppHighlightingSupport::FieldUse); + return true; +} + bool CheckSymbols::visit(SimpleDeclarationAST *ast) { NameAST *declrIdNameAST = 0; diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h index 3fcf1ee698..3d3a7302c4 100644 --- a/src/plugins/cpptools/cppchecksymbols.h +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -160,6 +160,8 @@ protected: virtual bool visit(CPlusPlus::MemInitializerAST *ast); virtual bool visit(CPlusPlus::EnumeratorAST *ast); + virtual bool visit(CPlusPlus::DesignatorAST *ast); + CPlusPlus::NameAST *declaratorId(CPlusPlus::DeclaratorAST *ast) const; static unsigned referenceToken(CPlusPlus::NameAST *name); diff --git a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp b/src/plugins/cpptools/cpphighlightingsupportinternal.cpp index 26dc9cf253..852868cc77 100644 --- a/src/plugins/cpptools/cpphighlightingsupportinternal.cpp +++ b/src/plugins/cpptools/cpphighlightingsupportinternal.cpp @@ -83,6 +83,7 @@ QFuture<TextEditor::HighlightingResult> CppHighlightingSupportInternal::highligh // FIXME: Check default values or get from document. LanguageFeatures features; features.cxx11Enabled = true; + features.c99Enabled = true; SimpleLexer tokenize; tokenize.setLanguageFeatures(features); diff --git a/tests/auto/cplusplus/c99/c99.pro b/tests/auto/cplusplus/c99/c99.pro new file mode 100644 index 0000000000..b40c99036d --- /dev/null +++ b/tests/auto/cplusplus/c99/c99.pro @@ -0,0 +1,8 @@ +include(../shared/shared.pri) + +# Inject the source dir for referencing test data from shadow builds. +DEFINES += SRCDIR=\\\"$$PWD\\\" + +SOURCES += tst_c99.cpp +OTHER_FILES += \ + data/designatedInitializer.1.c diff --git a/tests/auto/cplusplus/c99/c99.qbs b/tests/auto/cplusplus/c99/c99.qbs new file mode 100644 index 0000000000..24da3535cf --- /dev/null +++ b/tests/auto/cplusplus/c99/c99.qbs @@ -0,0 +1,21 @@ +import qbs +import "../cplusplusautotest.qbs" as CPlusPlusAutotest + +CPlusPlusAutotest { + name: "C99 autotest" + Group { + name: "Source Files" + files: "tst_c99.cpp" + } + + Group { + name: "Data Files" + prefix: "data/" + fileTags: ["data"] + files: [ + "designatedInitializer.1.c", + ] + } + + cpp.defines: base.concat(['SRCDIR="' + path + '"']) +} diff --git a/tests/auto/cplusplus/c99/data/designatedInitializer.1.c b/tests/auto/cplusplus/c99/data/designatedInitializer.1.c new file mode 100644 index 0000000000..43db4b6647 --- /dev/null +++ b/tests/auto/cplusplus/c99/data/designatedInitializer.1.c @@ -0,0 +1,9 @@ +int aa[4] = { [2] = 3, [1] = 6 }; +static short grid[3] [4] = { [0][0]=8, [0][1]=6, + [0][2]=4, [0][3]=1, + [2][0]=9, [2][1]=3, + [2][2]=1, [2][3]=1 }; +int a[10] = {2, 4, [8]=9, 10}; +int a[MAX] = { + 1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0 +}; diff --git a/tests/auto/cplusplus/c99/data/designatedInitializer.2.c b/tests/auto/cplusplus/c99/data/designatedInitializer.2.c new file mode 100644 index 0000000000..cf2d84f5a3 --- /dev/null +++ b/tests/auto/cplusplus/c99/data/designatedInitializer.2.c @@ -0,0 +1,12 @@ +struct xyz { + int a; + int b; + int c; +} klm = { .a = 99, .c = 100 }; +struct a { + struct b { + int c; + int d; + } e; + float f; +} g = {.e.c = 3 }; diff --git a/tests/auto/cplusplus/c99/tst_c99.cpp b/tests/auto/cplusplus/c99/tst_c99.cpp new file mode 100644 index 0000000000..1e7afb65c6 --- /dev/null +++ b/tests/auto/cplusplus/c99/tst_c99.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include <cplusplus/CPlusPlus.h> +#include <cplusplus/CppDocument.h> +#include <cplusplus/LookupContext.h> + +#include <QtTest> +#include <QObject> +#include <QFile> + +//TESTED_COMPONENT=src/libs/cplusplus +using namespace CPlusPlus; + +#define VERIFY_ERRORS() \ + do { \ + QByteArray expectedErrors; \ + if (!errorFile.isEmpty()) { \ + QFile e(testdata(errorFile)); \ + if (e.open(QFile::ReadOnly)) \ + expectedErrors = QTextStream(&e).readAll().toUtf8(); \ + } \ + QCOMPARE(QString::fromLatin1(errors), QString::fromLatin1(expectedErrors)); \ + } while (0) + + +class tst_c99: public QObject +{ + Q_OBJECT + + /* + Returns the path to some testdata file or directory. + */ + static QString testdata(const QString &name = QString()) + { + static const QString dataDirectory = QLatin1String(SRCDIR "/data"); + + QString result = dataDirectory; + if (!name.isEmpty()) { + result += QLatin1Char('/'); + result += name; + } + return result; + } + + struct Client: CPlusPlus::DiagnosticClient { + QByteArray *errors; + + Client(QByteArray *errors) + : errors(errors) + { + } + + virtual void report(int level, + const StringLiteral *fileName, + unsigned line, unsigned column, + const char *format, va_list ap) + { + if (! errors) + return; + + static const char *const pretty[] = { "warning", "error", "fatal" }; + + QString str; + str.sprintf("%s:%d:%d: %s: ", fileName->chars(), line, column, pretty[level]); + errors->append(str.toUtf8()); + + str.vsprintf(format, ap); + errors->append(str.toUtf8()); + + errors->append('\n'); + } + }; + + Document::Ptr document(const QString &fileName, QByteArray *errors = 0) + { + Document::Ptr doc = Document::create(fileName); + QFile file(testdata(fileName)); + if (file.open(QFile::ReadOnly)) { + LanguageFeatures features; + features.c99Enabled = true; + Client client(errors); + doc->control()->setDiagnosticClient(&client); + doc->setUtf8Source(QTextStream(&file).readAll().toUtf8()); + doc->translationUnit()->setLanguageFeatures(features); + doc->check(); + doc->control()->setDiagnosticClient(0); + } else { + qWarning() << "could not read file" << fileName; + } + return doc; + } + +private Q_SLOTS: + // + // checks for the syntax + // + void parse_data(); + void parse(); +}; + + +void tst_c99::parse_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("errorFile"); + + QTest::newRow("designatedInitializer.1") << "designatedInitializer.1.c" << ""; + QTest::newRow("designatedInitializer.2") << "designatedInitializer.2.c" << ""; +} + +void tst_c99::parse() +{ + QFETCH(QString, file); + QFETCH(QString, errorFile); + + QByteArray errors; + Document::Ptr doc = document(file, &errors); + + if (! qgetenv("DEBUG").isNull()) + printf("%s\n", errors.constData()); + + VERIFY_ERRORS(); +} + +QTEST_APPLESS_MAIN(tst_c99) +#include "tst_c99.moc" diff --git a/tests/auto/cplusplus/cplusplus.pro b/tests/auto/cplusplus/cplusplus.pro index 3cbc0dfdf2..b44d24b6cf 100644 --- a/tests/auto/cplusplus/cplusplus.pro +++ b/tests/auto/cplusplus/cplusplus.pro @@ -10,6 +10,7 @@ SUBDIRS = \ semantic \ typeprettyprinter \ misc \ + c99 \ cxx11 \ checksymbols \ lexer \ diff --git a/tests/auto/cplusplus/cplusplus.qbs b/tests/auto/cplusplus/cplusplus.qbs index 338a7c9b4b..973ec1bd45 100644 --- a/tests/auto/cplusplus/cplusplus.qbs +++ b/tests/auto/cplusplus/cplusplus.qbs @@ -4,6 +4,7 @@ Project { name: "CPlusPlus autotests" references: [ "ast/ast.qbs", + "c99/c99.qbs", "checksymbols/checksymbols.qbs", "codeformatter/codeformatter.qbs", "cxx11/cxx11.qbs", diff --git a/tests/tools/cplusplus-ast2png/dumpers.inc b/tests/tools/cplusplus-ast2png/dumpers.inc index caf4b8d772..8cc0aedcfe 100644 --- a/tests/tools/cplusplus-ast2png/dumpers.inc +++ b/tests/tools/cplusplus-ast2png/dumpers.inc @@ -1698,3 +1698,18 @@ virtual bool visit(BracedInitializerAST *ast) return false; } +virtual bool visit(DesignatorAST *ast) +{ + return false; +} + +virtual bool visit(DesignatedInitializerAST *ast) +{ + for (DesignatorListAST *iter = ast->designator_list; iter; iter = iter->next) + nonterminal(iter->value); + if (ast->equal_token) + terminal(ast->equal_token, ast); + nonterminal(ast->initializer); + return false; +} + |