aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Hoi <wanghoi@126.com>2014-05-05 22:56:15 +0800
committerNikolai Kosjar <nikolai.kosjar@digia.com>2014-06-17 16:23:23 +0200
commitc56b999ffff249d4cb7dc7e8026a3297b63ff56d (patch)
tree007d1f5208cd7e03fdc2eceb4cefe3dd4a12ded8
parentd70485180a676c3d97108bb87ec1c32223ee0f2b (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>
-rw-r--r--src/libs/3rdparty/cplusplus/AST.cpp66
-rw-r--r--src/libs/3rdparty/cplusplus/AST.h68
-rw-r--r--src/libs/3rdparty/cplusplus/ASTClone.cpp18
-rw-r--r--src/libs/3rdparty/cplusplus/ASTMatch0.cpp16
-rw-r--r--src/libs/3rdparty/cplusplus/ASTMatcher.cpp28
-rw-r--r--src/libs/3rdparty/cplusplus/ASTMatcher.h2
-rw-r--r--src/libs/3rdparty/cplusplus/ASTPatternBuilder.h22
-rw-r--r--src/libs/3rdparty/cplusplus/ASTVisit.cpp16
-rw-r--r--src/libs/3rdparty/cplusplus/ASTVisitor.h4
-rw-r--r--src/libs/3rdparty/cplusplus/ASTfwd.h4
-rw-r--r--src/libs/3rdparty/cplusplus/Parser.cpp48
-rw-r--r--src/libs/3rdparty/cplusplus/Parser.h5
-rw-r--r--src/libs/3rdparty/cplusplus/Token.h1
-rw-r--r--src/libs/cplusplus/CppDocument.cpp1
-rw-r--r--src/plugins/cppeditor/cppautocompleter.cpp1
-rw-r--r--src/plugins/cppeditor/cpphighlighter.cpp1
-rw-r--r--src/plugins/cpptools/cppchecksymbols.cpp7
-rw-r--r--src/plugins/cpptools/cppchecksymbols.h2
-rw-r--r--src/plugins/cpptools/cpphighlightingsupportinternal.cpp1
-rw-r--r--tests/auto/cplusplus/c99/c99.pro8
-rw-r--r--tests/auto/cplusplus/c99/c99.qbs21
-rw-r--r--tests/auto/cplusplus/c99/data/designatedInitializer.1.c9
-rw-r--r--tests/auto/cplusplus/c99/data/designatedInitializer.2.c12
-rw-r--r--tests/auto/cplusplus/c99/tst_c99.cpp153
-rw-r--r--tests/auto/cplusplus/cplusplus.pro1
-rw-r--r--tests/auto/cplusplus/cplusplus.qbs1
-rw-r--r--tests/tools/cplusplus-ast2png/dumpers.inc15
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;
+}
+