Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Corbat2018-05-23 07:02:03 -0400
committerThomas Corbat2019-08-05 03:00:35 -0400
commitacbceb04ee9e472119ef3255a47986c833fcf4c2 (patch)
treec27f6cf457270d83047b8c01a9c790c2d0d5ef7b
parentaf88842969b538dc3a33eab84b3b9631194bd9a3 (diff)
downloadorg.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.tar.gz
org.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.tar.xz
org.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.zip
Bug 522200: [C++17] Add support for structured binding declarations
Adds support for structured bindings: - Parser updated - Semantics updated - Tests for parser and bindings added Change-Id: I1de7b760041ac4ce4601f1b5032fdb0a197212a1 Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch> Signed-off-by: Thomas Corbat <tcorbat@hsr.ch>
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPAttributeTests.java6
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCPPTypes.java72
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCTypes.java42
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java2
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java75
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/InitCaptureTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/VariableTemplateTests.java1
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/AllConstexprEvalTests.java2
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/StructuredBindingTests.java468
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/TestBase.java6
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingIndexTests.java295
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingTests.java418
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java2
-rw-r--r--core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterAttributeTestSource.awts7
-rw-r--r--core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclarationTestSource.awts14
-rw-r--r--core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts15
-rw-r--r--core/org.eclipse.cdt.core/META-INF/MANIFEST.MF3
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java108
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java12
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java34
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java15
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java5
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java210
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java53
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java13
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java239
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java59
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java78
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java46
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java3
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java248
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java19
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java29
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java11
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java15
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java3
-rw-r--r--core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java78
-rw-r--r--core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java72
-rw-r--r--core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java48
-rw-r--r--core/org.eclipse.cdt.ui.tests/resources/ceditor/occurrences.cpp11
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java182
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/MarkOccurrenceTest.java26
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java34
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java29
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java8
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties9
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java52
58 files changed, 3043 insertions, 163 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPAttributeTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPAttributeTests.java
index 4ac1c542fc..a579e8f183 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPAttributeTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPAttributeTests.java
@@ -335,6 +335,12 @@ public class AST2CPPAttributeTests extends AST2TestBase {
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTSimpleDeclSpecifier.class);
}
+ //auto [[maybe_unused]] variable;
+ public void testAttributeAutoDeclSpecifer() throws Exception {
+ IASTTranslationUnit tu = parseAndCheckBindings();
+ checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTSimpleDeclSpecifier.class);
+ }
+
// const volatile unsigned long int [[attr]] cvuli;
public void testAttributedTypeSpecifier() throws Exception {
IASTTranslationUnit tu = parseAndCheckBindings();
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCPPTypes.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCPPTypes.java
new file mode 100644
index 0000000000..24f4fa9632
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCPPTypes.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Nathan Ridge.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.tests.ast2;
+
+import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
+
+/**
+ *
+ * Helper class for common type wrapping operations for tests.
+ *
+ */
+public class CommonCPPTypes {
+ public static IType char_ = CPPBasicType.CHAR;
+ public static IType int_ = CPPBasicType.INT;
+ public static IType void_ = CPPBasicType.VOID;
+ public static IType double_ = new CPPBasicType(Kind.eDouble, 0);
+ public static IType float_ = new CPPBasicType(Kind.eFloat, 0);
+ public static IType constChar = constOf(char_);
+ public static IType constInt = constOf(int_);
+ public static IType pointerToInt = pointerTo(int_);
+ public static IType constPointerToInt = constPointerTo(int_);
+ public static IType pointerToConstChar = pointerTo(constChar);
+ public static IType pointerToConstInt = pointerTo(constInt);
+ public static IType referenceToInt = referenceTo(int_);
+ public static IType referenceToConstInt = referenceTo(constInt);
+ public static IType rvalueReferenceToInt = rvalueReferenceTo(int_);
+ public static IType rvalueReferenceToConstInt = rvalueReferenceTo(constInt);
+
+ public static IType pointerTo(IType type) {
+ return new CPPPointerType(type);
+ }
+
+ // Not quite the same as constOf(pointerTo(type)) because of the
+ // idiosyncratic way we represent cosnt pointers using a flag
+ // on the CPPPointerType rather than using CPPQualifierType.
+ private static IType constPointerTo(IType type) {
+ return new CPPPointerType(type, true, false, false);
+ }
+
+ public static IType constOf(IType type) {
+ return new CPPQualifierType(type, true, false);
+ }
+
+ public static IType volatileOf(IType type) {
+ return new CPPQualifierType(type, false, true);
+ }
+
+ public static IType constVolatileOf(IType type) {
+ return new CPPQualifierType(type, true, true);
+ }
+
+ public static IType referenceTo(IType type) {
+ return new CPPReferenceType(type, false);
+ }
+
+ public static IType rvalueReferenceTo(IType type) {
+ return new CPPReferenceType(type, true);
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCTypes.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCTypes.java
new file mode 100644
index 0000000000..d1548dc2cd
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommonCTypes.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Nathan Ridge.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.parser.tests.ast2;
+
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.internal.core.dom.parser.c.CBasicType;
+import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType;
+import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType;
+
+public class CommonCTypes {
+ public static IType pointerToVoid = pointerTo(CBasicType.VOID);
+ public static IType pointerToConstVoid = pointerTo(constOf(CBasicType.VOID));
+ public static IType pointerToInt = pointerTo(CBasicType.INT);
+ public static IType pointerToConstInt = pointerTo(constOf(CBasicType.INT));
+ public static IType pointerToVolatileInt = pointerTo(volatileOf(CBasicType.INT));
+ public static IType pointerToConstVolatileInt = pointerTo(constVolatileOf(CBasicType.INT));
+
+ private static IType pointerTo(IType type) {
+ return new CPointerType(type, 0);
+ }
+
+ private static IType constOf(IType type) {
+ return new CQualifierType(type, true, false, false);
+ }
+
+ private static IType volatileOf(IType type) {
+ return new CQualifierType(type, false, true, false);
+ }
+
+ private static IType constVolatileOf(IType type) {
+ return new CQualifierType(type, true, true, false);
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java
index b7174a8adb..5f17ae73f3 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java
@@ -21,6 +21,7 @@ import org.eclipse.cdt.core.parser.tests.ast2.cxx14.InitCaptureTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx17.LambdaExpressionTests;
+import org.eclipse.cdt.core.parser.tests.ast2.cxx17.StructuredBindingTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx17.TemplateAutoTests;
import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite;
@@ -74,6 +75,7 @@ public class DOMParserTestSuite extends TestCase {
// C++17 tests
suite.addTest(TemplateAutoTests.suite());
suite.addTestSuite(LambdaExpressionTests.class);
+ suite.addTestSuite(StructuredBindingTests.class);
return suite;
}
}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java
index aff2182fed..2c0eb1f687 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java
@@ -30,13 +30,6 @@ import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
-import org.eclipse.cdt.internal.core.dom.parser.c.CBasicType;
-import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType;
-import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
/**
@@ -51,70 +44,6 @@ public class SemanticTestBase extends BaseTestCase {
super(name);
}
- protected static class CommonCTypes {
- public static IType pointerToVoid = pointerTo(CBasicType.VOID);
- public static IType pointerToConstVoid = pointerTo(constOf(CBasicType.VOID));
- public static IType pointerToInt = pointerTo(CBasicType.INT);
- public static IType pointerToConstInt = pointerTo(constOf(CBasicType.INT));
- public static IType pointerToVolatileInt = pointerTo(volatileOf(CBasicType.INT));
- public static IType pointerToConstVolatileInt = pointerTo(constVolatileOf(CBasicType.INT));
-
- private static IType pointerTo(IType type) {
- return new CPointerType(type, 0);
- }
-
- private static IType constOf(IType type) {
- return new CQualifierType(type, true, false, false);
- }
-
- private static IType volatileOf(IType type) {
- return new CQualifierType(type, false, true, false);
- }
-
- private static IType constVolatileOf(IType type) {
- return new CQualifierType(type, true, true, false);
- }
- }
-
- protected static class CommonCPPTypes {
- public static IType char_ = CPPBasicType.CHAR;
- public static IType int_ = CPPBasicType.INT;
- public static IType void_ = CPPBasicType.VOID;
- public static IType constChar = constOf(char_);
- public static IType constInt = constOf(int_);
- public static IType pointerToInt = pointerTo(int_);
- public static IType constPointerToInt = constPointerTo(int_);
- public static IType pointerToConstChar = pointerTo(constChar);
- public static IType pointerToConstInt = pointerTo(constInt);
- public static IType referenceToInt = referenceTo(int_);
- public static IType referenceToConstInt = referenceTo(constInt);
- public static IType rvalueReferenceToInt = rvalueReferenceTo(int_);
- public static IType rvalueReferenceToConstInt = rvalueReferenceTo(constInt);
-
- // Not quite the same as constOf(pointerTo(type)) because of the
- // idiosyncratic way we represent cosnt pointers using a flag
- // on the CPPPointerType rather than using CPPQualifierType.
- private static IType constPointerTo(IType type) {
- return new CPPPointerType(type, true, false, false);
- }
-
- private static IType pointerTo(IType type) {
- return new CPPPointerType(type);
- }
-
- public static IType constOf(IType type) {
- return new CPPQualifierType(type, true, false);
- }
-
- private static IType referenceTo(IType type) {
- return new CPPReferenceType(type, false);
- }
-
- private static IType rvalueReferenceTo(IType type) {
- return new CPPReferenceType(type, true);
- }
- }
-
protected static void assertSameType(IType expected, IType actual) {
assertNotNull(expected);
assertNotNull(actual);
@@ -122,6 +51,10 @@ public class SemanticTestBase extends BaseTestCase {
+ ASTTypeUtil.getType(actual, false) + "'", expected.isSameType(actual));
}
+ protected static void assertType(IVariable variable, IType expectedType) {
+ assertSameType(expectedType, variable.getType());
+ }
+
protected static SizeAndAlignment getSizeAndAlignment(IType type, IASTNode lookupPoint) {
try {
CPPSemantics.pushLookupPoint(lookupPoint);
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java
index 25013a2e93..f273310034 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java
@@ -11,6 +11,7 @@
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
import org.eclipse.cdt.internal.index.tests.IndexBindingResolutionTestBase;
/**
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java
index dd16e67f70..58c73597d6 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java
@@ -12,6 +12,7 @@ package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
/**
* AST tests for C++14 generic lambdas.
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/InitCaptureTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/InitCaptureTests.java
index 2e38a3f274..1dd1795e0b 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/InitCaptureTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/InitCaptureTests.java
@@ -15,6 +15,7 @@
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
/**
* AST tests for C++14 lambda init captures.
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java
index ebcbd0e93f..0a152b2798 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
import org.eclipse.cdt.internal.index.tests.IndexBindingResolutionTestBase;
public class ReturnTypeDeductionIndexTests extends IndexBindingResolutionTestBase {
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java
index 6c86c33877..529e70904e 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java
@@ -18,6 +18,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
public class ReturnTypeDeductionTests extends AST2CPPTestBase {
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/VariableTemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/VariableTemplateTests.java
index 599d01d92a..df3a1b5710 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/VariableTemplateTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/VariableTemplateTests.java
@@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariableTemplate;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldTemplateSpecialization;
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/AllConstexprEvalTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/AllConstexprEvalTests.java
index 16deda4065..79eb731d11 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/AllConstexprEvalTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/AllConstexprEvalTests.java
@@ -65,6 +65,8 @@ public class AllConstexprEvalTests {
suite.addTest(FloatingPointValueTests.SingleProject.suite());
suite.addTest(CStringValueTests.NonIndexing.suite());
suite.addTest(CStringValueTests.SingleProject.suite());
+ suite.addTest(StructuredBindingTests.NonIndexing.suite());
+ suite.addTest(StructuredBindingTests.SingleProject.suite());
return suite;
}
}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/StructuredBindingTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/StructuredBindingTests.java
new file mode 100644
index 0000000000..dd6b20c6cb
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/StructuredBindingTests.java
@@ -0,0 +1,468 @@
+/*******************************************************************************
+* Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+* Rapperswil, University of applied sciences and others
+*
+* This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License 2.0
+* which accompanies this distribution, and is available at
+* https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+*******************************************************************************/
+package org.eclipse.cdt.core.parser.tests.ast2.cxx14.constexpr;
+
+import junit.framework.TestSuite;
+
+public class StructuredBindingTests extends TestBase {
+ public static class NonIndexing extends StructuredBindingTests {
+ public NonIndexing() {
+ setStrategy(new NonIndexingTestStrategy());
+ }
+
+ public static TestSuite suite() {
+ return suite(NonIndexing.class);
+ }
+ }
+
+ public static class SingleProject extends StructuredBindingTests {
+ public SingleProject() {
+ setStrategy(new SinglePDOMTestStrategy(true, false));
+ }
+
+ public static TestSuite suite() {
+ return suite(SingleProject.class);
+ }
+ }
+
+ // constexpr int f() {
+ // int arr[]{8, 9};
+ // auto [first, second] = arr;
+ // return first;
+ // }
+
+ // constexpr int x = f();
+ public void testBindingFirstElementOfArray() throws Exception {
+ assertEvaluationEquals(8);
+ }
+
+ // constexpr int f() {
+ // int arr[]{8, 9};
+ // auto [first, second] = arr;
+ // return second;
+ // }
+
+ // constexpr int x = f();
+ public void testBindingSecondElementOfArray() throws Exception {
+ assertEvaluationEquals(9);
+ }
+
+ // constexpr int f() {
+ // int arr[]{8, 9};
+ // auto [first, second, third] = arr;
+ // return third;
+ // }
+
+ // constexpr int x = f();
+ public void testBindingOutOfBoundElementOfArray() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // struct Pair {
+ // int i;
+ // double d;
+ // } p{42, 5.0};
+ // constexpr auto f() {
+ // auto [first, second] = p;
+ // return first;
+ // }
+
+ // constexpr auto x = f();
+ public void testBindingFirstMemberOfObject() throws Exception {
+ assertEvaluationEquals(42);
+ }
+
+ // struct Pair {
+ // int i;
+ // double d;
+ // } p{42, 5.0};
+ // constexpr auto f() {
+ // auto [first, second] = p;
+ // return second;
+ // }
+
+ // constexpr auto x = f();
+ public void testBindingSecondMemberOfObject() throws Exception {
+ assertEvaluationEquals(5.0);
+ }
+
+ // struct Base {
+ // int i;
+ // };
+ // struct Sub : Base {
+ // } s{5};
+ // auto [inherited] = s;
+
+ // auto x = inherited;
+ public void testBindingInheritedMember() throws Exception {
+ assertEvaluationEquals(5);
+ }
+
+ // struct Mono {
+ // int i;
+ // } p{42};
+ // constexpr auto f() {
+ // auto [first, second] = p;
+ // return second;
+ // }
+
+ // constexpr auto x = f();
+ public void testBindingOutOfBoundElementOfObject() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // constexpr auto f() {
+ // auto [first, second];
+ // return second;
+ // }
+
+ // constexpr auto x = f();
+ public void testUninitializedStructuredBinding() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return t;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeObjectWithMemberGet() throws Exception {
+ assertEvaluationEquals(3);
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // template <size_t I, typename T, size_t N>
+ // constexpr auto get(std::array<T, N> const & values) {
+ // return values.elements[I];
+ // }
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return t;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeObjectWithFreeGet() throws Exception {
+ assertEvaluationEquals(3);
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 2> values{{1, 2}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return t;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeObjectWithTooFewElements() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s] = createValues();
+ // return f;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeObjectWithTooManyElements() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // static const size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return s;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeValueMemberIsStaticConst() throws Exception {
+ assertEvaluationEquals(2);
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return f;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeValueMemberIsNonConstexpr() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return f;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeValueMemberIsNonStatic() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static double value = static_cast<double>(N);
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return f;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeValueMemberIsNonIntegral() throws Exception {
+ assertEvaluationProblem();
+ }
+
+ // namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // template <size_t I>
+ // constexpr auto get() {
+ // return elements[I];
+ // }
+ // };
+ // size_t nonConstexprFunction() {
+ // return 3;
+ // }
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // static const size_t value = nonConstexprFunction();
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ // }
+ // constexpr auto createValues() {
+ // std::array<int, 3> values{{1, 2, 3}};
+ // return values;
+ // }
+ // constexpr auto foo() {
+ // auto [f, s, t] = createValues();
+ // return s;
+ // }
+
+ // constexpr auto x = foo();
+ public void testBindingOutOfTupleLikeValueMemberWithNonConstexprInitialization() throws Exception {
+ assertEvaluationProblem();
+ }
+} \ No newline at end of file
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/TestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/TestBase.java
index 3083093cf5..1c473cfbfd 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/TestBase.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/TestBase.java
@@ -41,6 +41,7 @@ import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
import org.eclipse.cdt.internal.core.dom.parser.CStringValue;
import org.eclipse.cdt.internal.core.dom.parser.FloatingPointValue;
+import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.GNUCPPSourceParser;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
@@ -63,6 +64,11 @@ public class TestBase extends IndexBindingResolutionTestBase {
return map;
}
+ protected void assertEvaluationProblem() throws Exception {
+ IValue value = getValue();
+ assertTrue(IntegralValue.ERROR.equals(value) || IntegralValue.UNKNOWN.equals(value));
+ }
+
protected void assertEvaluationEquals(boolean expectedValue) throws Exception {
IValue value = getValue();
Number num = value.numberValue();
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingIndexTests.java
new file mode 100644
index 0000000000..ed3a76cc23
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingIndexTests.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.tests.ast2.cxx17;
+
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.char_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.double_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.int_;
+
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.internal.index.tests.IndexBindingResolutionTestBase;
+
+public class StructuredBindingIndexTests extends IndexBindingResolutionTestBase {
+ public StructuredBindingIndexTests() {
+ setStrategy(new SinglePDOMTestStrategy(true));
+ }
+
+ //struct S {
+ // int i;
+ //} s{};
+
+ //auto [z] = s;
+ public void testLocalStructuredBindingFromMemberOfBasicType() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("z"), int_);
+ }
+
+ //struct S {
+ // int i;
+ //} s{};
+ //auto [z] = s;
+
+ //auto x = z;
+ public void testExternalStructuredBindingFromMemberOfBasicType() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("z"), int_);
+ }
+
+ //struct T {
+ //};
+ //struct S {
+ // T t;
+ //} s{};
+
+ //auto [z] = s;
+ //T localT{};
+ public void testLocalStructuredBindingFromMemberOfUserDefinedType() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ IVariable variable = helper.assertNonProblem("z");
+ IType variableType = variable.getType();
+
+ IVariable localT = helper.assertNonProblem("localT");
+ IType typeT = localT.getType();
+
+ assertSameType(typeT, variableType);
+ }
+
+ //struct T {
+ //};
+ //struct S {
+ // T t;
+ //} s{};
+ //auto [z] = s;
+
+ //auto x = z;
+ //T localT{};
+ public void testExternalStructuredBindingFromMemberOfUserDefinedType() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ IVariable variable = helper.assertNonProblem("z");
+ IType variableType = variable.getType();
+
+ IVariable localT = helper.assertNonProblem("localT");
+ IType typeT = localT.getType();
+
+ assertSameType(typeT, variableType);
+ }
+
+ //struct T {
+ //};
+ //struct Base1 {
+ //};
+ //struct Base2 {
+ // T t;
+ // int i;
+ // double d;
+ // char c;
+ //};
+ //struct S : Base1, Base2 {
+ //} s{};
+
+ //auto [t, i, d, c] = s;
+ //T localT{};
+ public void testMultipleVariablesInStructuredBindingFromMembers() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ IVariable variableT = helper.assertNonProblem("t,", 1);
+ IType variableTType = variableT.getType();
+ IVariable localT = helper.assertNonProblem("localT");
+ IType typeT = localT.getType();
+ assertSameType(typeT, variableTType);
+
+ assertType(helper.assertNonProblem("i,", 1), int_);
+ assertType(helper.assertNonProblem("d,", 1), double_);
+ assertType(helper.assertNonProblem("c]", 1), char_);
+ }
+
+ //struct T {
+ //};
+ //struct Base1 {
+ // T t;
+ // int i;
+ // double d;
+ // char c;
+ //};
+ //struct Base2 : Base1 {
+ //};
+ //struct S : Base2 {
+ //} s{};
+
+ //auto [t, i, d, c] = s;
+ //T localT{};
+ public void testMultipleVariablesDeepBaseStructure() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ IVariable variableT = helper.assertNonProblem("t,", 1);
+ IType variableTType = variableT.getType();
+ IVariable localT = helper.assertNonProblem("localT");
+ IType typeT = localT.getType();
+ assertSameType(typeT, variableTType);
+
+ assertType(helper.assertNonProblem("i,", 1), int_);
+ assertType(helper.assertNonProblem("d,", 1), double_);
+ assertType(helper.assertNonProblem("c]", 1), char_);
+ }
+
+ //struct S {
+ // int i;
+ // static float f;
+ // double d;
+ //} s{};
+
+ //auto [i, d] = s;
+ public void testStaticFieldsAreNotConsidered() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("i,", 1), int_);
+ assertType(helper.assertNonProblem("d]", 1), double_);
+ }
+
+ //namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ //}
+
+ //auto [f, s, t] = std::array<int, 3>{1, 2, 3};
+ public void testStandardArray() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ //Target code lacks the required get() functions determine the value of the names f, s and t.
+ //But the types can still be resolved with tuple_element
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s,", 1), int_);
+ assertType(helper.assertNonProblem("t]", 1), int_);
+ }
+
+ //namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T1, typename T2>
+ // struct pair {
+ // T1 t1;
+ // T2 t2;
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T1, typename T2>
+ // struct tuple_size<pair<T1, T2>> {
+ // constexpr static size_t value = 2;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <typename T>
+ // struct tuple_element_base {
+ // using type = T;
+ // };
+ // template <typename T1, typename T2>
+ // struct tuple_element<0, pair<T1, T2>> : tuple_element_base<T1> {
+ // };
+ // template <typename T1, typename T2>
+ // struct tuple_element<1, pair<T1, T2>> : tuple_element_base<T2> {
+ // };
+ // template <size_t I, typename T1, typename T2>
+ // auto get(pair<T1, T2> const & p) {
+ // if constexpr (I == 0) {
+ // return p.t1;
+ // } else {
+ // return p.t2;
+ // }
+ // }
+ //}
+
+ //auto [a, b] = std::pair<int, double>{42, 3.14};
+ public void testRecursiveTupleElement() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("a,", 1), int_);
+ assertType(helper.assertNonProblem("b]", 1), double_);
+ }
+
+ //namespace std {
+ // using size_t = unsigned long long;
+ // template <typename T, size_t N>
+ // struct array {
+ // T elements[N];
+ // };
+ // template <typename T>
+ // struct tuple_size;
+ // template <typename T, size_t N>
+ // struct tuple_size<array<T, N>> {
+ // constexpr static size_t value = N;
+ // };
+ // template <size_t I, typename T>
+ // struct tuple_element;
+ // template <size_t I, typename T, size_t N>
+ // struct tuple_element<I, array<T, N>> {
+ // using type = T;
+ // };
+ //}
+ //struct X {
+ // int first;
+ // int second;
+ //};
+
+ //int main() {
+ // auto arr = std::array<X, 3>{X{1,2}, X{3,4}, X{5,6}};
+ // for (auto [firstX, secondX] : arr.elements) {
+ // auto sum = firstX + secondX;
+ // }
+ //}
+ public void testStandardArrayInLoop() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ //Target code lacks the required get() functions determine the value of the names f, s and t.
+ //But the types can still be resolved with tuple_element
+ assertType(helper.assertNonProblem("firstX,", 6), int_);
+ assertType(helper.assertNonProblem("secondX]", 7), int_);
+ assertType(helper.assertNonProblem("sum", 3), int_);
+ }
+
+ //struct X {
+ // int first;
+ // int second;
+ // void fun();
+ //};
+
+ //void X::fun() {
+ // auto [f, s] = *this;
+ //}
+ public void testBindStarThis() throws Exception {
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), int_);
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingTests.java
new file mode 100644
index 0000000000..5bbaebd81f
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/StructuredBindingTests.java
@@ -0,0 +1,418 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.parser.tests.ast2.cxx17;
+
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.char_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.constInt;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.double_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.float_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.int_;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.referenceTo;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.referenceToConstInt;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.referenceToInt;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.rvalueReferenceTo;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.rvalueReferenceToInt;
+import static org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes.volatileOf;
+
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IValue;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
+import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
+import org.eclipse.cdt.core.parser.tests.ast2.CommonCPPTypes;
+import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
+import org.eclipse.cdt.internal.core.dom.parser.FloatingPointValue;
+import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPStructuredBindingComposite;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
+
+public class StructuredBindingTests extends AST2CPPTestBase {
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //auto [f1, s1] = S{1, 2};
+ //auto f2 = f1;
+ //auto s2 = s1;
+ public void testFromTemporary() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ IBinding f1Declaration = helper.assertNonProblem("f1, ", 2);
+ IBinding f1Reference = helper.assertNonProblem("f1;", 2);
+ assertSame(f1Declaration, f1Reference);
+
+ IBinding s1Declaration = helper.assertNonProblem("s1] ", 2);
+ IBinding s1Reference = helper.assertNonProblem("s1;", 2);
+ assertSame(s1Declaration, s1Reference);
+ }
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //S createS() {
+ // return {1, 2};
+ //}
+ //auto [f, s] = createS();
+ public void testFromReturnValue() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //S createS() {
+ // return {1, 2};
+ //}
+ //auto [f, s]{createS()};
+ public void testBracedInitialization() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //S createS() {
+ // return {1, 2};
+ //}
+ //auto [f, s](createS());
+ public void testCopyInitialization() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //struct S {
+ // int first;
+ // int second;
+ // float third;
+ // double fourth;
+ // char fifth;
+ //};
+ //auto [f, s, t, fo, fif] = S{1, 2, 1.5f, 3.1415, '*'};
+ public void testWithManyInitializers() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s,", 1), int_);
+ assertType(helper.assertNonProblem("t,", 1), float_);
+ assertType(helper.assertNonProblem("fo,", 2), double_);
+ assertType(helper.assertNonProblem("fif]", 3), char_);
+ }
+
+ //struct Base {
+ // int bi;
+ //};
+ //struct Sub : Base {
+ // static double sd;
+ //};
+ //auto [b] = Sub{1};
+ public void testWithBaseClass() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("b]", 1), int_);
+ }
+
+ //auto f() -> int(&)[2];
+ //auto [x, y] = f();
+ //auto & [xr, yr] = f();
+ public void testStandardExample1() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("xr,", 2), referenceToInt);
+ assertType(helper.assertNonProblem("yr]", 2), referenceToInt);
+ }
+
+ //struct S {
+ // int x1 : 2;
+ // volatile double y1;
+ //};
+ //S createS();
+ //auto const [x, y] = createS();
+ public void testStandardExample2() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("x,", 1), constInt);
+ assertType(helper.assertNonProblem("y]", 1), CommonCPPTypes.constVolatileOf(double_));
+ }
+
+ //int arr[]{1, 2, 3};
+ //auto [f, s, t] = arr;
+ public void testFromArray() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s,", 1), int_);
+ assertType(helper.assertNonProblem("t]", 1), int_);
+ }
+
+ //struct S {
+ // int i;
+ //} s{};
+ //auto && [f] = s;
+ public void testForwardingReferenceWithLvalue() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f]", 1), referenceToInt);
+ }
+
+ //struct S {
+ // int i;
+ //} s{};
+ //auto && [f] = static_cast<S&&>(s);
+ public void testForwardingReferenceWithXvalue() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f]", 1), rvalueReferenceToInt);
+ }
+
+ //struct S {
+ // int i;
+ //};
+ //auto && [f] = S{};
+ public void testForwardingReferenceWithRvalue() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f]", 1), rvalueReferenceToInt);
+ }
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //
+ //namespace std {
+ // template <typename>
+ // struct tuple_size;
+ //}
+ //auto [f, s] = S{};
+ public void testUnspecializedTupleSizeTemplate() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //namespace std {
+ // using size_t = unsigned long long;
+ //}
+ //
+ //struct S {
+ // int first() const {
+ // return 1;
+ // }
+ // double second() const {
+ // return 2.0;
+ // }
+ // template <std::size_t V>
+ // auto get() {
+ // if constexpr (V == 0) {
+ // return first();
+ // } else if (V == 1) {
+ // return second();
+ // }
+ // static_assert(V < 2);
+ // }
+ //};
+ //
+ //namespace std {
+ // template <typename>
+ // struct tuple_size;
+ // template <>
+ // struct tuple_size<S> {
+ // constexpr static size_t value = 2;
+ // };
+ // template <std::size_t, typename>
+ // struct tuple_element;
+ // template <>
+ // struct tuple_element<0, S> {
+ // using type = int;
+ // };
+ // template <>
+ // struct tuple_element<1, S> {
+ // using type = double;
+ // };
+ //}
+ //auto [f, s] = S{};
+ public void testFromTupleLikeDecompositionWithMemberGet() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //namespace std {
+ // using size_t = unsigned long long;
+ //}
+ //
+ //struct S {
+ // int first() const {
+ // return 1;
+ // }
+ // double second() const {
+ // return 2.0;
+ // }
+ //};
+ //template <std::size_t V>
+ //auto get(S s) {
+ // if constexpr (V == 0) {
+ // return s.first();
+ // } else if (V == 1) {
+ // return s.second();
+ // }
+ // static_assert(V < 2);
+ //}
+ //
+ //namespace std {
+ // template <typename>
+ // struct tuple_size;
+ // template <>
+ // struct tuple_size<S> {
+ // constexpr static size_t value = 2;
+ // };
+ // template <std::size_t, typename>
+ // struct tuple_element;
+ // template <>
+ // struct tuple_element<0, S> {
+ // using type = int;
+ // };
+ // template <>
+ // struct tuple_element<1, S> {
+ // using type = double;
+ // };
+ //}
+ //auto [f, s] = S{};
+ public void testFromTupleLikeDecompositionWithInheritedTupleElementType() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("f,", 1), int_);
+ assertType(helper.assertNonProblem("s]", 1), double_);
+ }
+
+ //struct S {
+ // int member;
+ //} s{1};
+ //auto [valueLarg] = s;
+ //auto [valueRarg] = S{1};
+ //auto const [valueConstLarg] = s;
+ //auto const [valueConstRarg] = S{1};
+ //auto & [lrefLarg] = s;
+ //auto & [lrefRarg] = S{1};
+ //auto const & [lrefConstLarg] = s;
+ //auto const & [lrefConstRarg] = S{1};
+ //auto && [frefLarg] = s;
+ //auto && [frefRarg] = S{1};
+ //auto const && [rrefConstLarg] = s;
+ //auto const && [rrefConstRarg] = S{1};
+ //auto const sConst = s;
+ //auto & [lrefLConstarg] = sConst;
+ //auto && [frefLConstarg] = sConst;
+ //S volatile sVolatile{1};
+ //auto & [lrefLVolatilearg] = sVolatile;
+ //auto && [frefLVolatilearg] = sVolatile;
+ public void testResultingTypes() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("valueLarg"), int_);
+ assertType(helper.assertNonProblem("valueRarg"), int_);
+ assertType(helper.assertNonProblem("valueConstLarg"), constInt);
+ assertType(helper.assertNonProblem("valueConstRarg"), constInt);
+ assertType(helper.assertNonProblem("lrefLarg"), referenceToInt);
+ assertType(helper.assertNonProblem("lrefRarg"), referenceToInt);
+ assertType(helper.assertNonProblem("lrefConstLarg"), referenceToConstInt);
+ assertType(helper.assertNonProblem("lrefConstRarg"), referenceToConstInt);
+ assertType(helper.assertNonProblem("frefLarg"), referenceToInt);
+ assertType(helper.assertNonProblem("frefRarg"), rvalueReferenceToInt);
+ assertType(helper.assertNonProblem("rrefConstLarg"), rvalueReferenceTo(constInt));
+ assertType(helper.assertNonProblem("rrefConstRarg"), rvalueReferenceTo(constInt));
+ assertType(helper.assertNonProblem("lrefLConstarg"), referenceToConstInt);
+ assertType(helper.assertNonProblem("frefLConstarg"), referenceToConstInt);
+ assertType(helper.assertNonProblem("lrefLVolatilearg"), referenceTo(volatileOf(int_)));
+ assertType(helper.assertNonProblem("frefLVolatilearg"), referenceTo(volatileOf(int_)));
+ }
+
+ //struct Aggregate {
+ // int i;
+ // double d;
+ // auto first() {
+ // auto [field1, _] = *this;
+ // return field1;
+ // }
+ // auto second() {
+ // auto [_, field2] = *this;
+ // return field2;
+ // }
+ //};
+ public void testThisDecomposition() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+
+ assertType(helper.assertNonProblem("field1;", 6), int_);
+ assertType(helper.assertNonProblem("field2;", 6), double_);
+ }
+
+ //struct S {
+ // int first;
+ // double second;
+ //};
+ //constexpr S createS() {
+ // return S{1, 2.0};
+ //}
+ //auto [f, s] = createS();
+ public void testIVariablePropertiesOfImplicitNameForInitializer() throws Exception {
+ parseAndCheckBindings();
+ BindingAssertionHelper helper = getAssertionHelper();
+ ICPPClassType classS = helper.assertNonProblem("S", 1);
+ IASTImplicitName[] implicitNames = helper.getImplicitNames("= createS();", 11);
+ assertEquals(1, implicitNames.length);
+ IASTImplicitName implicitName = implicitNames[0];
+ IBinding binding = implicitName.getBinding();
+ CPPStructuredBindingComposite variable = assertInstance(binding, CPPStructuredBindingComposite.class);
+ assertType(variable, classS);
+ IValue initialValue = variable.getInitialValue();
+ CompositeValue compositeValue = assertInstance(initialValue, CompositeValue.class);
+ ICPPEvaluation[] subvalues = compositeValue.getAllSubValues();
+ assertEquals(2, subvalues.length);
+ assertEquals(IntegralValue.create(1), subvalues[0].getValue());
+ assertEquals(FloatingPointValue.create(2.0), subvalues[1].getValue());
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java
index 6543e39655..12a6ac0f34 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java
@@ -16,6 +16,7 @@ package org.eclipse.cdt.internal.index.tests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.GenericLambdaIndexTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests;
+import org.eclipse.cdt.core.parser.tests.ast2.cxx17.StructuredBindingIndexTests;
import org.eclipse.cdt.core.parser.tests.ast2.cxx17.TemplateAutoIndexTests;
import junit.framework.Test;
@@ -48,6 +49,7 @@ public class IndexTests extends TestSuite {
// C++17 index test suites
suite.addTestSuite(TemplateAutoIndexTests.class);
+ suite.addTestSuite(StructuredBindingIndexTests.class);
IndexCPPBindingResolutionBugs.addTests(suite);
IndexCPPBindingResolutionTest.addTests(suite);
diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterAttributeTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterAttributeTestSource.awts
index 64a636b530..6b9412cb0d 100644
--- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterAttributeTestSource.awts
+++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterAttributeTestSource.awts
@@ -376,4 +376,9 @@ int __declspec(selectany)* pi2 = 0;
//!MS declspec attribute on simple declaration
//%CPP GNU
-__declspec(thread) int tls_i = 1; \ No newline at end of file
+__declspec(thread) int tls_i = 1;
+
+//!Attributed structured binding declaration
+//%CPP
+int arr[]{1, 2, 3};
+[[nodiscard]] auto [a, b, c] = arr;
diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclarationTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclarationTestSource.awts
index 0228c73822..e15e59ece6 100644
--- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclarationTestSource.awts
+++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterDeclarationTestSource.awts
@@ -214,3 +214,17 @@ enum struct [[foo]] X{ };
//!Attributed scoped enum declaration with keyword class
//%CPP
enum class [[foo]] X{ };
+
+//!Structured binding declarations
+//%CPP
+struct S
+{
+ int first, second, third;
+} s{};
+int arr[]{1, 2, 3};
+auto [a, b, c] = arr;
+auto [d, e, f]{s};
+auto [g, h, i](arr);
+auto& [j, k, l] = arr;
+const auto& [m, n, o] = S{};
+auto&& [p, q, r] = S{};
diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts
index 41cd52b2d2..64fe167a37 100644
--- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts
+++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts
@@ -421,4 +421,19 @@ void f()
case 42:
break;
}
+}
+
+//!Range-based for with structured binding
+//%CPP
+struct S
+{
+ int i;
+ float f;
+};
+
+void rangedBasedForContext()
+{
+ S esses[] = {S{}, S{}, S{}};
+ for (auto [l, r]: esses){
+ }
} \ No newline at end of file
diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
index 36394ef428..dc9f1a468d 100644
--- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
@@ -129,7 +129,8 @@ Require-Bundle: org.eclipse.cdt.core.native;bundle-version="[5.10.1,6.0.0)";visi
org.eclipse.ltk.core.refactoring;bundle-version="[3.10.100,4.0.0)",
org.eclipse.text;bundle-version="[3.8.200,4.0.0)",
com.ibm.icu;bundle-version="4.4.2",
- com.google.gson
+ com.google.gson,
+ org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: javax.xml.bind;version="2.2.0"
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java
index 4e5f33bcb4..3134e58fad 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java
@@ -50,6 +50,8 @@ public interface ISemanticProblem {
int TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = 10007;
/** @since 6.3 */
int TYPE_AUTO_FOR_VIRTUAL_METHOD = 10008;
+ /** @since 6.9 */
+ int TYPE_CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE = 10009;
/**
* Returns the ID of the problem.
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java
new file mode 100644
index 0000000000..8eff34af47
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.dom.ast.cpp;
+
+import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
+import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * This is a structured binding declaration which contains a sequence names,
+ * in square brackets, that decompose an initializer.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li><code>auto [x, y]{coordinate};</code></li>
+ * <li><code>auto & [x, y](coordinate);</code></li>
+ * <li><code>auto && [x, y] = createCoordinte();</code></li>
+ * </ul>
+ *
+ * @since 6.9
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ICPPASTStructuredBindingDeclaration
+ extends IASTSimpleDeclaration, IASTNameOwner, IASTImplicitNameOwner {
+ /**
+ * <code>IDENTIFIER</code> represents the relationship between an
+ * <code>ICPPASTStructuredBindingDeclaration</code> and its
+ * <code>IASTName</code>s.
+ */
+ public static final ASTNodeProperty IDENTIFIER = new ASTNodeProperty(
+ "ICPPASTStructuredBindingDeclaration.IDENTIFIER - IASTName for ICPPASTStructuredBindingDeclaration"); //$NON-NLS-1$
+
+ /**
+ * <code>INITIALIZER</code> represents the relationship between an
+ * <code>ICPPASTStructuredBindingDeclaration</code> and its <code>IASTInitializer</code>.
+ */
+ public static final ASTNodeProperty INITIALIZER = new ASTNodeProperty(
+ "ICPPASTStructuredBindingDeclaration.INITIALIZER - IASTInitializer for ICPPASTStructuredBindingDeclaration"); //$NON-NLS-1$
+
+ /**
+ * Returns the <code>RefQualifier</code> of the structured binding. For either lvalue or
+ * rvalue reference qualifiers.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>For <code>auto [x, y] = coordinate;</code> it returns the empty <code>Optional</code></li>
+ * <li>For <code>auto & [x, y] = coordinate;</code> it returns <code>Optional.of(RefQualifier.LVALUE)</code></li>
+ * <li>For <code>auto && [x, y] = createCoordinte();</code> it returns <code>Optional.of(RefQualifier.RVALUE)</code></li>
+ * </ul>
+ *
+ * @return The returned <code>RefQualifier</code> of the C++ declaration or <code>null</code> if there is no reference qualifier.
+ * if the structured binding does not have a reference qualifier.
+ * @see RefQualifier
+ */
+ @Nullable
+ RefQualifier getRefQualifier();
+
+ /**
+ * Returns the list of names declared by this structured binding declaration.
+ * <p>
+ * Example: For <code>auto & [x, y] = coordinate;</code> it returns the names <code>x</code> and <code>y</code>.
+ *
+ * @return All declared names of the structured binding as<code>IASTName[]</code>
+ * @see IASTName
+ */
+ IASTName[] getNames();
+
+ /**
+ * Returns the initializer of the structured binding declaration.
+ *
+ * This will not be present if the structured binding is part of a range-based for loop.
+ *
+ * * Examples:
+ * <ul>
+ * <li>For <code>auto [x, y]{coordinate};</code> it returns an <code>ICPPASTInitializerList</code></li>
+ * <li>For <code>auto & [x, y](coordinate);</code> it returns an <code>ICPPASTConstructorInitializer</code></li>
+ * <li>For <code>auto && [x, y] = createCoordinte();</code> it returns an <code>IASTEqualsInitializer</code></li>
+ * </ul>
+ *
+ * @return The <code>IASTInitializer</code> of this structured binding. It can be <code>null</code> if the C++ declaration is lacking an initializer.
+ * @see IASTInitializer
+ * @see ICPPASTInitializerList
+ * @see ICPPASTConstructorInitializer
+ * @see IASTEqualsInitializer
+ */
+ @Nullable
+ IASTInitializer getInitializer();
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
index 995be0308b..11af18db9f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java
@@ -34,6 +34,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier.ScopeStyle;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation.Operator;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTArrayRangeDesignator;
import org.eclipse.cdt.core.dom.parser.cpp.ICPPASTAttributeSpecifier;
@@ -503,4 +504,15 @@ public interface ICPPNodeFactory extends INodeFactory {
*/
@Deprecated
public ICPPASTAttributeSpecifier newAttributeSpecifier();
+
+ /**
+ * @since 6.9
+ */
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration();
+
+ /**
+ * @since 6.9
+ */
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration(ICPPASTSimpleDeclSpecifier declSpecifier,
+ RefQualifier refQualifier, IASTName[] names, IASTInitializer initializer);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
index f5aaab6410..9698bfac8e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
@@ -132,6 +132,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
public IASTDeclarator fDtor2;
public IToken fDtorToken1;
+ public boolean isAtStartOfStructuredBinding = false;
+
public Decl set(IASTDeclSpecifier declspec, IASTDeclarator dtor, IToken dtorToken) {
fDeclSpec1 = declspec;
fDtor1 = dtor;
@@ -1676,6 +1678,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
/**
+ * Checks whether the type specified by the {@code declSpecifier} is "auto" and
+ * the subsequent token, when looking beyond potential ref-qualifiers (& and &&),
+ * will be a single opening bracket ([) followed by an identifier.
+ */
+ protected boolean isAtStartOfStructuredBinding(IASTDeclSpecifier declSpecifier) {
+ if (!isAutoType(declSpecifier)) {
+ return false;
+ }
+ int expectedBracketOffset = 1;
+ int nextToken = LTcatchEOF(expectedBracketOffset);
+ if (nextToken == IToken.tAMPER || nextToken == IToken.tAND) {
+ expectedBracketOffset++;
+ }
+ return LTcatchEOF(expectedBracketOffset) == IToken.tLBRACKET
+ && LTcatchEOF(expectedBracketOffset + 1) == IToken.tIDENTIFIER;
+ }
+
+ /**
* Parses for two alternatives of a declspec sequence followed by a initDeclarator.
* A second alternative is accepted only, if it ends at the same point of the first alternative. Otherwise the
* longer alternative is selected.
@@ -1689,6 +1709,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (lt1 == IToken.tEOC)
return result;
+ // support for structured bindings
+ if (isAtStartOfStructuredBinding(result.fDeclSpec1)) {
+ result.isAtStartOfStructuredBinding = true;
+ return result;
+ }
+
// support simple declarations without declarators
final boolean acceptEmpty = acceptCompoundWithoutDtor && isLegalWithoutDtor(result.fDeclSpec1);
if (acceptEmpty) {
@@ -2056,6 +2082,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return false;
}
+ protected static boolean isAutoType(IASTDeclSpecifier declSpec) {
+ if (declSpec instanceof IASTSimpleDeclSpecifier) {
+ IASTSimpleDeclSpecifier simpleDeclSpecifier = (IASTSimpleDeclSpecifier) declSpec;
+ return simpleDeclSpecifier.getType() == IASTSimpleDeclSpecifier.t_auto;
+ }
+ return false;
+ }
+
protected abstract IASTAmbiguousStatement createAmbiguousStatement();
protected IASTStatement parseLabelStatement() throws EndOfFileException, BacktrackException {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
index fab7f54602..cc215747ed 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
@@ -52,7 +52,7 @@ public interface ITypeMarshalBuffer {
EXEC_DECLARATION_STATEMENT = 0x05, EXEC_DECLARATOR = 0x06, EXEC_DEFAULT = 0x07,
EXEC_SIMPLE_DECLARATION = 0x08, EXEC_RETURN = 0x09, EXEC_EXPRESSION_STATEMENT = 0x0A, EXEC_IF = 0x0B,
EXEC_WHILE = 0x0C, EXEC_DO = 0x0D, EXEC_FOR = 0x0E, EXEC_RANGE_BASED_FOR = 0x0F, EXEC_SWITCH = 0x10,
- EXEC_CONSTRUCTOR_CHAIN = 0x11;
+ EXEC_CONSTRUCTOR_CHAIN = 0x11, EXEC_INCOMPLETE = 0x12;
// Can add more executions up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
static final short KIND_MASK = 0x001F;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
index e2a026f862..24eeb562e3 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
@@ -27,6 +27,8 @@ public class ProblemType implements IProblemType, ISerializableType {
public static final IType AUTO_FOR_VIRTUAL_METHOD = new ProblemType(TYPE_AUTO_FOR_VIRTUAL_METHOD);
public static final IType CANNOT_DEDUCE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_AUTO_TYPE);
public static final IType CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE);
+ public static final IType CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE = new ProblemType(
+ TYPE_CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
public static final IType ENUMERATION_EXPECTED = new ProblemType(TYPE_ENUMERATION_EXPECTED);
public static final IType NO_NAME = new ProblemType(TYPE_NO_NAME);
public static final IType NOT_PERSISTED = new ProblemType(TYPE_NOT_PERSISTED);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
index d693071b73..fb757d85f8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
@@ -51,8 +51,10 @@ import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
@@ -96,6 +98,8 @@ public abstract class VariableReadWriteFlags {
if (binding instanceof IVariable) {
return rwAssignmentToType(((IVariable) binding).getType(), indirection);
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
@@ -113,10 +117,21 @@ public abstract class VariableReadWriteFlags {
}
}
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
+ protected int rwInStructuredBinding(ICPPASTStructuredBindingDeclaration declaration) {
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier != null && !declaration.getDeclSpecifier().isConst()) {
+ return READ | WRITE;
+ } else {
+ return READ;
+ }
+ }
+
protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
if (expr instanceof IASTIdExpression) {
return rwAnyNode(expr, indirection);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
index e8d638ce2b..b15def18a0 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
@@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.Keywords;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSearch;
@@ -35,6 +36,10 @@ public class CPPASTImplicitName extends CPPASTName implements IASTImplicitName {
private boolean isOperator;
private boolean isDefinition;
+ public CPPASTImplicitName(IASTNode parent) {
+ this(CharArrayUtils.EMPTY, parent);
+ }
+
public CPPASTImplicitName(char[] name, IASTNode parent) {
super(name);
setParent(parent);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
index a7d76c5f1f..5ab051c26a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
@@ -46,11 +46,15 @@ public class CPPASTSimpleDeclaration extends CPPASTAttributeOwner implements IAS
@Override
public CPPASTSimpleDeclaration copy(CopyStyle style) {
CPPASTSimpleDeclaration copy = new CPPASTSimpleDeclaration();
+ return copy(copy, style);
+ }
+
+ protected <T extends CPPASTSimpleDeclaration> T copy(T copy, CopyStyle style) {
copy.setDeclSpecifier(declSpecifier == null ? null : declSpecifier.copy(style));
for (IASTDeclarator declarator : getDeclarators()) {
copy.addDeclarator(declarator == null ? null : declarator.copy(style));
}
- return copy(copy, style);
+ return super.copy(copy, style);
}
@Override
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java
new file mode 100644
index 0000000000..41779d21ff
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import java.util.Arrays;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
+import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecDeclarator;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIncomplete;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclaration;
+import org.eclipse.jdt.annotation.NonNull;
+
+public class CPPASTStructuredBindingDeclaration extends CPPASTSimpleDeclaration
+ implements ICPPASTStructuredBindingDeclaration {
+
+ private RefQualifier refQualifier;
+ private IASTName[] names;
+ private IASTInitializer initializer;
+ private IASTImplicitName implicitInitializerName;
+
+ public CPPASTStructuredBindingDeclaration() {
+ }
+
+ public CPPASTStructuredBindingDeclaration(IASTDeclSpecifier declSpecifier, RefQualifier refQualifier,
+ IASTName[] names, IASTInitializer initializer) {
+ super(declSpecifier);
+ this.refQualifier = refQualifier;
+ for (IASTName name : names) {
+ addName(name);
+ }
+ setInitializer(initializer);
+ }
+
+ @Override
+ public RefQualifier getRefQualifier() {
+ return refQualifier;
+ }
+
+ public void setRefQualifier(RefQualifier refQualifier) {
+ assertNotFrozen();
+ this.refQualifier = refQualifier;
+ }
+
+ @Override
+ public IASTName[] getNames() {
+ if (names == null) {
+ return IASTName.EMPTY_NAME_ARRAY;
+ }
+ names = ArrayUtil.trim(names);
+ return names;
+ }
+
+ @Override
+ public IASTInitializer getInitializer() {
+ return initializer;
+ }
+
+ @Override
+ public boolean accept(ASTVisitor action) {
+ if (action.shouldVisitDeclarations) {
+ switch (action.visit(this)) {
+ case ASTVisitor.PROCESS_ABORT:
+ return false;
+ case ASTVisitor.PROCESS_SKIP:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ IASTDeclSpecifier declSpecifier = getDeclSpecifier();
+ if (declSpecifier != null && !declSpecifier.accept(action)) {
+ return false;
+ }
+
+ for (IASTName name : getNames()) {
+ if (!name.accept(action)) {
+ return false;
+ }
+ }
+
+ if (initializer != null && !initializer.accept(action)) {
+ return false;
+ }
+
+ if (action.shouldVisitImplicitNames && !getImplicitNames()[0].accept(action)) {
+ return false;
+ }
+
+ if (action.shouldVisitDeclarations) {
+ switch (action.leave(this)) {
+ case ASTVisitor.PROCESS_ABORT:
+ return false;
+ case ASTVisitor.PROCESS_SKIP:
+ return true;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
+ protected void addName(IASTName name) {
+ assertNotFrozen();
+ if (name != null) {
+ names = ArrayUtil.append(IASTName.class, names, name);
+ name.setParent(this);
+ name.setPropertyInParent(IDENTIFIER);
+ }
+ }
+
+ protected void setInitializer(IASTInitializer initializer) {
+ assertNotFrozen();
+ if (initializer != null) {
+ this.initializer = initializer;
+ initializer.setParent(this);
+ initializer.setPropertyInParent(INITIALIZER);
+ }
+ }
+
+ @Override
+ public CPPASTStructuredBindingDeclaration copy() {
+ return copy(CopyStyle.withoutLocations);
+ }
+
+ @Override
+ public CPPASTStructuredBindingDeclaration copy(CopyStyle style) {
+ CPPASTStructuredBindingDeclaration copy = new CPPASTStructuredBindingDeclaration();
+ return copy(copy, style);
+ }
+
+ protected <T extends CPPASTStructuredBindingDeclaration> T copy(@NonNull T copy, CopyStyle style) {
+ copy.setRefQualifier(refQualifier);
+ if (initializer != null) {
+ copy.setInitializer(initializer.copy(style));
+ }
+
+ for (IASTName name : names) {
+ if (name == null) {
+ break;
+ }
+ copy.addName(name.copy(style));
+ }
+ return super.copy(copy, style);
+ }
+
+ @Override
+ public ICPPExecution getExecution() {
+ IASTName[] names = getNames();
+ ICPPExecution[] nameExecutions = Arrays.stream(names).map(name -> {
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof CPPVariable) {
+ CPPVariable variable = (CPPVariable) binding;
+ ICPPEvaluation initializerEval = variable.getInitializerEvaluation();
+ return new ExecDeclarator((ICPPBinding) binding, initializerEval);
+ }
+ return ExecIncomplete.INSTANCE;
+ }).toArray(ICPPExecution[]::new);
+ return new ExecSimpleDeclaration(nameExecutions);
+ }
+
+ @Override
+ public int getRoleForName(IASTName name) {
+ return r_definition;
+ }
+
+ @Override
+ public IASTImplicitName[] getImplicitNames() {
+ if (implicitInitializerName == null) {
+ ICPPEvaluation initializerEvaluation = CPPVariable.evaluationOfInitializer(initializer);
+ if (initializerEvaluation == null) {
+ initializerEvaluation = EvalFixed.INCOMPLETE;
+ }
+ CPPASTImplicitName implicitName = new CPPASTImplicitName(this);
+ implicitName.setIsDefinition(true);
+ if (initializer != null) {
+ implicitName.setOffsetAndLength((ASTNode) initializer);
+ }
+ implicitInitializerName = implicitName;
+ CPPStructuredBindingComposite implicitInitializerVariable = new CPPStructuredBindingComposite(
+ implicitInitializerName, initializerEvaluation);
+ implicitInitializerName.setBinding(implicitInitializerVariable);
+ }
+ return new IASTImplicitName[] { implicitInitializerName };
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java
new file mode 100644
index 0000000000..c4ec33b459
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.IValue;
+
+/**
+ * Represents a variable implicitly created in C++ code.
+ * For example the initializer of a structured binding decomposition [dcl.struct.bind]:
+ * <code>auto [first, second] = decomposed;</code>
+ *
+ * The <code>initializerEvaluation</code> has to be supplied.
+ *
+ */
+public class CPPImplicitVariable extends CPPVariable {
+
+ private ICPPEvaluation initializerEvaluation;
+
+ public CPPImplicitVariable(IASTImplicitName name, ICPPEvaluation initializerEvaluation) {
+ super(name);
+ this.initializerEvaluation = initializerEvaluation;
+ }
+
+ @Override
+ public ICPPEvaluation getInitializerEvaluation() {
+ return initializerEvaluation;
+ }
+
+ @Override
+ public IType getType() {
+ return initializerEvaluation.getType();
+ }
+
+ @Override
+ public IValue getInitialValue() {
+ return initializerEvaluation.getValue();
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
index 176335f6c0..b659a58cc1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
@@ -91,6 +91,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
@@ -119,6 +120,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -914,4 +916,15 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory {
public ICPPASTWhileStatement newWhileStatement(IASTExpression condition, IASTStatement body) {
return new CPPASTWhileStatement(condition, body);
}
+
+ @Override
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration() {
+ return new CPPASTStructuredBindingDeclaration();
+ }
+
+ @Override
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration(ICPPASTSimpleDeclSpecifier declSpecifier,
+ RefQualifier refQualifier, IASTName[] names, IASTInitializer initializer) {
+ return new CPPASTStructuredBindingDeclaration(declSpecifier, refQualifier, names, initializer);
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java
new file mode 100644
index 0000000000..e9c1bbc85b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor.IS_STATIC_VARIABLE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IArrayType;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.ICompositeType;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IScope;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
+import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinary;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinding;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionCall;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalMemberAccess;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.LookupData;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
+
+/**
+ * Represents the implicit object created for the initializer of a structured binding declaration.
+ * It is used for caching the evaluation strategy used to determine the <code>ICPPEvaluation</code> of
+ * the names introduced by the declaration.
+ *
+ */
+public class CPPStructuredBindingComposite extends CPPImplicitVariable {
+
+ private static final char[] GET_NAME = "get".toCharArray(); //$NON-NLS-1$
+ private static final IStructuredBindingNameEvaluationStrategy INCOMPLETE_INITIALIZER = new IStructuredBindingNameEvaluationStrategy() {
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ return EvalFixed.INCOMPLETE;
+ }
+ };
+
+ private IStructuredBindingNameEvaluationStrategy evaluationStrategy = null;
+ private ICPPASTStructuredBindingDeclaration declaration;
+
+ public CPPStructuredBindingComposite(IASTImplicitName name, ICPPEvaluation initializerEvaluation) {
+ super(name, initializerEvaluation);
+ IASTNode nameParent = name.getParent();
+ assert (nameParent instanceof ICPPASTStructuredBindingDeclaration);
+ this.declaration = (ICPPASTStructuredBindingDeclaration) nameParent;
+ }
+
+ public ICPPEvaluation getEvaluationForName(IASTName name) {
+ int index = ArrayUtil.indexOf(declaration.getNames(), name);
+ return getNameEvaluationStrategy().getEvaluation(index);
+ }
+
+ private IStructuredBindingNameEvaluationStrategy getNameEvaluationStrategy() {
+ if (evaluationStrategy == null) {
+ evaluationStrategy = createEvaluationStrategy(declaration);
+ }
+ return evaluationStrategy;
+ }
+
+ private IStructuredBindingNameEvaluationStrategy createEvaluationStrategy(
+ ICPPASTStructuredBindingDeclaration structuredBinding) {
+ IASTInitializer initializer = structuredBinding.getInitializer();
+ ICPPEvaluation initializerEvaluation = getInitializerEvaluation();
+ if (initializer != null && initializerEvaluation != null) {
+ IType initializerType = getType();
+ IType unwrappedType = SemanticUtil.getNestedType(initializerType, SemanticUtil.ALLCVQ | SemanticUtil.REF);
+ if (unwrappedType instanceof IArrayType) {
+ return new ArrayElement(initializer, initializerEvaluation);
+ }
+ if (unwrappedType instanceof ICPPClassType) {
+ IASTName[] definedNames = structuredBinding.getNames();
+ long numberOfNames = definedNames.length;
+ ICPPClassType classType = (ICPPClassType) unwrappedType;
+ if (numberOfNames > 0) {
+ IScope scope = CPPSemantics.getLookupScope(definedNames[0]);
+ Optional<ICPPClassSpecialization> tupleSizeInstance = CPPVisitor
+ .findTupleSizeWithValueMember(unwrappedType, scope, structuredBinding);
+ if (tupleSizeInstance.isPresent()) {
+ if (CPPVisitor.hasConstexprStaticIntegralValueField(tupleSizeInstance.get(), numberOfNames)) {
+ return new TupleElement(initializer, initializerEvaluation, classType);
+ }
+ } else {
+ return new MemberElement(initializer, initializerEvaluation, classType);
+ }
+ }
+ }
+ }
+ return INCOMPLETE_INITIALIZER;
+ }
+
+ private abstract static class IStructuredBindingNameEvaluationStrategy {
+ abstract public ICPPEvaluation getEvaluation(int nameIndex);
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has array type.
+ */
+ private class ArrayElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+
+ private ArrayElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ EvalFixed indexEvaluation = new EvalFixed(CPPBasicType.UNSIGNED_INT, ValueCategory.PRVALUE,
+ IntegralValue.create(nameIndex));
+ return new EvalBinary(EvalBinary.op_arrayAccess, initializerEvaluation, indexEvaluation, initializer);
+ }
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has class type for which std::tuple_size is specialized.
+ */
+ private class TupleElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+ private ICPPClassType initializerType;
+
+ private TupleElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation,
+ ICPPClassType initializerType) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ this.initializerType = initializerType;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ EvalFixed indexEvaluation = new EvalFixed(CPPBasicType.UNSIGNED_INT, ValueCategory.PRVALUE,
+ IntegralValue.create(nameIndex));
+ IBinding resolvedFunction = resolveGetFunction(initializerType, initializer, initializerEvaluation,
+ indexEvaluation);
+ if (resolvedFunction instanceof ICPPMethod) {
+ ICPPEvaluation eExpressionEvaluation = new EvalMemberAccess(initializerType,
+ initializerEvaluation.getValueCategory(), resolvedFunction, initializerEvaluation, false,
+ initializer);
+ return new EvalFunctionCall(new ICPPEvaluation[] { eExpressionEvaluation }, null, initializer);
+ } else if (resolvedFunction instanceof ICPPFunction) {
+ EvalBinding functionEvaluation = new EvalBinding(resolvedFunction,
+ ((ICPPFunction) resolvedFunction).getType(), initializer);
+ return new EvalFunctionCall(new ICPPEvaluation[] { functionEvaluation, initializerEvaluation }, null,
+ initializer);
+ }
+ return EvalFixed.INCOMPLETE;
+ }
+
+ /**
+ *
+ * Resolves the member or non-member get() function template for a type and given arguments.
+ *
+ * Returns {@code null} if the function cannot be resolved
+ */
+ private IBinding resolveGetFunction(ICompositeType classType, IASTNode point, ICPPEvaluation argument,
+ ICPPEvaluation index) {
+ //find member and non-member get() bindings in class scope and all parent scopes
+ IBinding[] allGetBindings = CPPSemantics.findBindings(classType.getCompositeScope(), GET_NAME, false,
+ point);
+ ICPPFunction[] functions = Arrays.stream(allGetBindings).filter(IFunction.class::isInstance)
+ .map(IFunction.class::cast).toArray(ICPPFunction[]::new);
+ ICPPTemplateArgument[] arguments = new ICPPTemplateArgument[] { new CPPTemplateNonTypeArgument(index) };
+ LookupData lookupGet = new LookupData(GET_NAME, arguments, point);
+ //LookupData::containsImpliedObject is ignored for non-member functions in CPPSemantics.resolveFunction
+ //and will therefore find the the free get function using the arguments
+ lookupGet.setFunctionArguments(true, argument);
+ try {
+ return CPPSemantics.resolveFunction(lookupGet, functions, true, true);
+ } catch (DOMException e) {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has class type with public members.
+ */
+ private class MemberElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+ private ICPPClassType initializerType;
+
+ private MemberElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation,
+ ICPPClassType initializerType) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ this.initializerType = initializerType;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ IField[] nonStaticFields = Arrays.stream(ClassTypeHelper.getFields(initializerType))
+ .filter(IS_STATIC_VARIABLE.negate()).toArray(IField[]::new);
+ //TODO (tcorbat): Further restrictions to structured bindings that are not checked. Maybe add a Codan checker.
+ // * Add further check that all members origin from the same class/base class
+ // * classType must not have an anonymous union member
+ // * Check accessibility of the members
+ if (nameIndex >= 0 && nameIndex < nonStaticFields.length) {
+ IField boundField = nonStaticFields[nameIndex];
+ return new EvalMemberAccess(initializerType, initializerEvaluation.getValueCategory(), boundField,
+ initializerEvaluation, false, initializer);
+ }
+ return EvalFixed.INCOMPLETE;
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
index 9bce0ccd1f..b77e1b8703 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
@@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
@@ -41,6 +42,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -52,7 +54,6 @@ import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConstructor;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUtil;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.core.runtime.PlatformObject;
@@ -258,7 +259,7 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
IValue initialValue = null;
final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE);
if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition,
- fDeclarations, getType())) == IntegralValue.UNKNOWN) {
+ fDeclarations, getType())) == IntegralValue.UNKNOWN || getStructuredBindingDeclaration() != null) {
ICPPEvaluation initEval = getInitializerEvaluation();
if (initEval == null) {
return null;
@@ -319,21 +320,48 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
if (constructor != null) {
ICPPEvaluation[] arguments = EvalConstructor.extractArguments(initializer, constructor);
return new EvalConstructor(getType(), constructor, arguments, declarator);
- } else if (initializer instanceof IASTEqualsInitializer) {
- IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
- ICPPASTInitializerClause clause = (ICPPASTInitializerClause) equalsInitializer.getInitializerClause();
- return clause.getEvaluation();
- } else if (initializer instanceof ICPPASTInitializerList) {
- return ((ICPPASTInitializerClause) initializer).getEvaluation();
- } else if (initializer instanceof ICPPASTConstructorInitializer) {
- ICPPASTConstructorInitializer ctorInitializer = (ICPPASTConstructorInitializer) initializer;
- ICPPASTInitializerClause evalOwner = (ICPPASTInitializerClause) ctorInitializer.getArguments()[0];
- return evalOwner.getEvaluation();
- } else if (initializer == null) {
- return null;
}
+ return evaluationOfInitializer(initializer);
}
- return EvalFixed.INCOMPLETE;
+
+ ICPPASTStructuredBindingDeclaration structuredBinding = getStructuredBindingDeclaration();
+ if (structuredBinding != null) {
+ return evaluationOfStructuredBindingInitializer(structuredBinding);
+ }
+ return null;
+ }
+
+ private ICPPEvaluation evaluationOfStructuredBindingInitializer(
+ ICPPASTStructuredBindingDeclaration structuredBinding) {
+ IASTImplicitName implicitName = structuredBinding.getImplicitNames()[0];
+ CPPStructuredBindingComposite variable = (CPPStructuredBindingComposite) implicitName.getBinding();
+ return variable.getEvaluationForName(fDefinition);
+ }
+
+ public static ICPPEvaluation evaluationOfInitializer(IASTInitializer initializer) {
+ if (initializer instanceof IASTEqualsInitializer) {
+ IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
+ ICPPASTInitializerClause clause = (ICPPASTInitializerClause) equalsInitializer.getInitializerClause();
+ return clause.getEvaluation();
+ } else if (initializer instanceof ICPPASTInitializerList) {
+ return ((ICPPASTInitializerClause) initializer).getEvaluation();
+ } else if (initializer instanceof ICPPASTConstructorInitializer) {
+ ICPPASTConstructorInitializer ctorInitializer = (ICPPASTConstructorInitializer) initializer;
+ ICPPASTInitializerClause evalOwner = (ICPPASTInitializerClause) ctorInitializer.getArguments()[0];
+ return evalOwner.getEvaluation();
+ }
+ return null;
+ }
+
+ private ICPPASTStructuredBindingDeclaration getStructuredBindingDeclaration() {
+ IASTNode definition = getDefinition();
+ if (definition != null) {
+ IASTNode parent = definition.getParent();
+ if (parent instanceof ICPPASTStructuredBindingDeclaration) {
+ return (ICPPASTStructuredBindingDeclaration) parent;
+ }
+ }
+ return null;
}
private static ICPPConstructor getImplicitlyCalledCtor(ICPPASTDeclarator declarator) {
@@ -350,4 +378,5 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
public void allDeclarationsDefinitionsAdded() {
fAllResolved = true;
}
+
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
index cf8815ba4f..ebdf710df1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
@@ -134,6 +134,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -2886,6 +2887,51 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return super.isLegalWithoutDtor(declSpec);
}
+ private RefQualifier optionalRefQualifier() throws EndOfFileException {
+ int nextToken = LT(1);
+ switch (nextToken) {
+ case IToken.tAMPER:
+ consume();
+ return RefQualifier.LVALUE;
+
+ case IToken.tAND:
+ consume();
+ return RefQualifier.RVALUE;
+
+ default:
+ return null;
+ }
+ }
+
+ private ICPPASTStructuredBindingDeclaration structuredBinding(ICPPASTSimpleDeclSpecifier simpleDeclSpecifier,
+ List<IASTAttributeSpecifier> attributes) throws BacktrackException, EndOfFileException {
+ RefQualifier refQualifier = optionalRefQualifier();
+ consume(IToken.tLBRACKET);
+ IASTName[] identifiers = identifierList();
+ int endOffset = consume(IToken.tRBRACKET).getEndOffset();
+
+ IASTInitializer initializer = null;
+ if (LT(1) != IToken.tCOLON) {
+ switch (LT(1)) {
+ case IToken.tASSIGN:
+ initializer = equalsInitalizerClause(false);
+ break;
+ case IToken.tLBRACE:
+ case IToken.tLPAREN:
+ initializer = bracedOrCtorStyleInitializer();
+ break;
+ }
+
+ endOffset = consume(IToken.tSEMI).getEndOffset();
+ }
+
+ ICPPASTStructuredBindingDeclaration structuredBinding = getNodeFactory()
+ .newStructuredBindingDeclaration(simpleDeclSpecifier, refQualifier, identifiers, initializer);
+ setRange(structuredBinding, simpleDeclSpecifier, endOffset);
+ addAttributeSpecifiers(attributes, structuredBinding);
+ return structuredBinding;
+ }
+
/**
* Parses a declaration with the given options.
*/
@@ -2903,6 +2949,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IASTDeclSpecifier altDeclSpec = null;
IASTDeclarator altDtor = null;
IToken markBeforDtor = null;
+ boolean isAtStartOfStructuredBinding = false;
try {
Decl decl = declSpecifierSequence_initDeclarator(declOption, true);
markBeforDtor = decl.fDtorToken1;
@@ -2910,6 +2957,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
dtor = decl.fDtor1;
altDeclSpec = decl.fDeclSpec2;
altDtor = decl.fDtor2;
+ isAtStartOfStructuredBinding = decl.isAtStartOfStructuredBinding;
} catch (FoundAggregateInitializer lie) {
declSpec = lie.fDeclSpec;
// scalability: don't keep references to tokens, initializer may be large
@@ -2925,6 +2973,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throw e;
}
+ if (isAtStartOfStructuredBinding && declSpec instanceof ICPPASTSimpleDeclSpecifier) {
+ ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec;
+ return structuredBinding(simpleDeclSpecifier, attributes);
+ }
+
IASTDeclarator[] declarators = IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
if (dtor != null) {
declarators = new IASTDeclarator[] { dtor };
@@ -4765,17 +4818,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
// ref-qualifiers
- switch (LT(1)) {
- case IToken.tAMPER:
- fc.setRefQualifier(RefQualifier.LVALUE);
- endOffset = consume().getEndOffset();
- break;
- case IToken.tAND:
- fc.setRefQualifier(RefQualifier.RVALUE);
- endOffset = consume().getEndOffset();
- break;
- default:
- break;
+ RefQualifier refQualifier = optionalRefQualifier();
+ if (refQualifier != null) {
+ fc.setRefQualifier(refQualifier);
+ endOffset = getEndOffset();
}
// throws clause
@@ -5673,4 +5719,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IASTAlignmentSpecifier typeId) {
return new CPPASTAmbiguousAlignmentSpecifier(expression, typeId);
}
+
+ protected IASTName[] identifierList() throws EndOfFileException, BacktrackException {
+ List<IASTName> result = new ArrayList<>();
+ result.add(identifier());
+ while (LT(1) == IToken.tCOMMA) {
+ consume();
+ result.add(identifier());
+ }
+ return result.toArray(new IASTName[result.size()]);
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
index df7c37954f..34adee0f83 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
@@ -31,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
@@ -120,6 +121,9 @@ public class VariableHelpers {
if (firstCandidate == null) {
firstCandidate = (IArrayType) t;
}
+ } else if (node instanceof ICPPASTStructuredBindingDeclaration) {
+ ICPPASTStructuredBindingDeclaration parent = (ICPPASTStructuredBindingDeclaration) node;
+ return CPPVisitor.createType(parent, n);
}
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
index 6728e38cb7..bcb87fc8d9 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
@@ -141,6 +141,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -938,7 +939,7 @@ public class CPPSemantics {
}
}
- static ICPPScope getLookupScope(IASTName name) throws DOMException {
+ public static ICPPScope getLookupScope(IASTName name) {
IASTNode parent = name.getParent();
IScope scope = null;
if (parent instanceof ICPPASTBaseSpecifier) {
@@ -1822,7 +1823,9 @@ public class CPPSemantics {
return;
}
- if (declaration instanceof IASTSimpleDeclaration) {
+ if (declaration instanceof ICPPASTStructuredBindingDeclaration) {
+ handleStructuredBinding((ICPPASTStructuredBindingDeclaration) declaration, scope);
+ } else if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration;
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
IASTDeclarator[] declarators = simpleDeclaration.getDeclarators();
@@ -1944,6 +1947,12 @@ public class CPPSemantics {
}
}
+ private static void handleStructuredBinding(ICPPASTStructuredBindingDeclaration structuredBinding, IScope scope) {
+ for (IASTName name : structuredBinding.getNames()) {
+ ASTInternal.addName(scope, name);
+ }
+ }
+
private static void handleEnumeration(ICPPASTEnumerationSpecifier enumSpec, IScope enclosingScope) {
// Add unscoped enumerators to the enclosing scope
if (!enumSpec.isScoped()) {
@@ -2647,6 +2656,11 @@ public class CPPSemantics {
return result;
}
+ /**
+ * Resolves the {@code IBinding} for given {@code LookupData} in the set of function bindings {@code fns}.
+ * It supports mixed member/non-member lookup. {@code LookupData::argContainsImpliedObject} is ignored for
+ * non-member lookup.
+ */
public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, boolean allowUDC,
boolean resolveTargetedArgumentTypes) throws DOMException {
final IASTName lookupName = data.getLookupName();
@@ -4262,6 +4276,14 @@ public class CPPSemantics {
* in the given scope.
*/
public static IBinding[] findBindingsForQualifiedName(IScope scope, String qualifiedName) {
+ return findBindingsForQualifiedName(scope, qualifiedName, null);
+ }
+
+ /**
+ * Uses C++ lookup semantics to find the possible bindings for the given qualified name starting
+ * in the given scope.
+ */
+ public static IBinding[] findBindingsForQualifiedName(IScope scope, String qualifiedName, IASTNode beforeNode) {
// Return immediately if the qualifiedName does not match a known format.
Matcher m = QUALNAME_REGEX.matcher(qualifiedName);
if (!m.matches())
@@ -4284,7 +4306,7 @@ public class CPPSemantics {
Set<IBinding> bindings = new HashSet<>();
// Look for the name in the given scope.
- findBindingsForQualifiedName(scope, qualifiedName, bindings);
+ findBindingsForQualifiedName(scope, qualifiedName, bindings, beforeNode);
// If the qualified name is not rooted in the global namespace (with a leading ::), then
// look at all parent scopes.
@@ -4293,7 +4315,7 @@ public class CPPSemantics {
while (scope != null) {
scope = scope.getParent();
if (scope != null)
- findBindingsForQualifiedName(scope, qualifiedName, bindings);
+ findBindingsForQualifiedName(scope, qualifiedName, bindings, beforeNode);
}
} catch (DOMException e) {
CCorePlugin.log(e);
@@ -4303,8 +4325,8 @@ public class CPPSemantics {
return bindings.size() == 0 ? IBinding.EMPTY_BINDING_ARRAY : bindings.toArray(new IBinding[bindings.size()]);
}
- private static void findBindingsForQualifiedName(IScope scope, String qualifiedName,
- Collection<IBinding> bindings) {
+ private static void findBindingsForQualifiedName(IScope scope, String qualifiedName, Collection<IBinding> bindings,
+ IASTNode beforeNode) {
// Split the qualified name into the first part (before the first :: qualifier) and the rest. All
// bindings for the first part are found and their scope is used to find the rest of the name. When
// the call tree gets to a leaf (non-qualified name) then a simple lookup happens and all matching
@@ -4318,14 +4340,20 @@ public class CPPSemantics {
// When we're down to a single component name, then use the normal lookup method.
if (part2 == null || part2.isEmpty()) {
- bindings.addAll(Arrays.asList(findBindings(scope, part1, false)));
+ bindings.addAll(Arrays.asList(findBindings(scope, part1.toCharArray(), false, beforeNode)));
return;
}
// Find all bindings that match the first part of the name. For each such binding,
// lookup the second part of the name.
- for (IBinding binding : findBindings(scope, part1, false)) {
- findBindingsForQualifiedName(getLookupScope(binding), part2, bindings);
+ for (IBinding binding : findBindings(scope, part1.toCharArray(), false, beforeNode)) {
+ IScope lookupScope;
+ if (binding instanceof IScope) {
+ lookupScope = (IScope) binding;
+ } else {
+ lookupScope = getLookupScope(binding);
+ }
+ findBindingsForQualifiedName(lookupScope, part2, bindings, beforeNode);
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
index 6f8b4d518c..e5ee18de9f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
@@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -108,6 +109,8 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
return rwAssignmentToType(type, indirection);
}
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index bff715b23a..02d25f564e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -31,7 +31,11 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
@@ -90,6 +94,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
+import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.ILabel;
@@ -141,6 +146,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -155,6 +161,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -224,6 +231,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedef;
@@ -231,6 +239,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownTypeScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@@ -249,6 +258,10 @@ public class CPPVisitor extends ASTQueries {
private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$
private static final char[] INITIALIZER_LIST = "initializer_list".toCharArray(); //$NON-NLS-1$
private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {};
+ private static final String STD_TUPLE_SIZE_STR = STD + "::tuple_size"; //$NON-NLS-1$
+ private static final String STD_TUPLE_ELEMENT_STR = STD + "::tuple_element"; //$NON-NLS-1$
+ private static final String VALUE_STR = "value"; //$NON-NLS-1$
+ private static final String TYPE_STR = "type"; //$NON-NLS-1$
public static final IASTInitializerClause[] NO_ARGS = {};
// Flags for createType().
@@ -273,6 +286,19 @@ public class CPPVisitor extends ASTQueries {
}
};
+ public static final Predicate<IVariable> IS_STATIC_VARIABLE = IVariable::isStatic;
+ private static final Predicate<IVariable> HAS_INTEGRAL_TYPE = variable -> BuiltinOperators
+ .isIntegral(SemanticUtil.getUltimateTypeUptoPointers(variable.getType()));
+ private static final Predicate<IVariable> HAS_CONST_TYPE = field -> ExpressionTypes.isConst(field.getType());
+ private static final Predicate<IBinding> IS_NAMED_VALUE = binding -> binding.getName().equals(VALUE_STR);
+
+ /**
+ * Required until Java 9 Optional.stream()
+ */
+ private static final <E> Stream<E> toStream(Optional<E> optional) {
+ return optional.map(Stream::of).orElse(Stream.empty());
+ }
+
public static IBinding createBinding(IASTName name) {
IASTNode parent = name.getParent();
IBinding binding = null;
@@ -326,6 +352,8 @@ public class CPPVisitor extends ASTQueries {
return createBinding((IASTDeclarator) parent);
} else if (parent instanceof ICPPASTElaboratedTypeSpecifier) {
return createBinding((ICPPASTElaboratedTypeSpecifier) parent);
+ } else if (parent instanceof ICPPASTStructuredBindingDeclaration) {
+ return new CPPVariable(name);
} else if (parent instanceof IASTDeclaration) {
return createBinding((IASTDeclaration) parent);
} else if (parent instanceof ICPPASTEnumerationSpecifier) {
@@ -1641,7 +1669,8 @@ public class CPPVisitor extends ASTQueries {
case KIND_OBJ_FN:
if (prop == IASTDeclarator.DECLARATOR_NAME
|| prop == IASTEnumerationSpecifier.IASTEnumerator.ENUMERATOR_NAME
- || prop == ICPPASTUsingDeclaration.NAME) {
+ || prop == ICPPASTUsingDeclaration.NAME
+ || prop == ICPPASTStructuredBindingDeclaration.IDENTIFIER) {
break;
}
return PROCESS_CONTINUE;
@@ -1936,6 +1965,146 @@ public class CPPVisitor extends ASTQueries {
return pt;
}
+ private static boolean hasFieldNamedValue(ICPPClassSpecialization instance) {
+ return Arrays.stream(instance.getFields()).anyMatch(field -> field.getName().equals(VALUE_STR));
+ }
+
+ public static Optional<ICPPClassSpecialization> findTupleSizeWithValueMember(IType type, IScope scope,
+ IASTNode beforeNode) {
+ ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) };
+ return findClassTemplateInstance(scope, STD_TUPLE_SIZE_STR, templateArguments, beforeNode)
+ .filter(CPPVisitor::hasFieldNamedValue);
+ }
+
+ private static Optional<ICPPClassSpecialization> findClassTemplateInstance(IScope scope, String templateName,
+ ICPPTemplateArgument[] templateArguments, IASTNode point) {
+ IBinding[] tupleSizeBindings = CPPSemantics.findBindingsForQualifiedName(scope, templateName, point);
+ return Arrays.stream(tupleSizeBindings).filter(ICPPClassTemplate.class::isInstance)
+ .map(ICPPClassTemplate.class::cast)
+ .map(template -> CPPTemplates.instantiate(template, templateArguments))
+ .filter(ICPPClassSpecialization.class::isInstance).map(ICPPClassSpecialization.class::cast)
+ .filter(Objects::nonNull).findFirst();
+ }
+
+ private static IType determineTupleElementType(IType type, IScope scope, IASTName name, int index) {
+ ICPPTemplateArgument indexArgument = new CPPTemplateNonTypeArgument(IntegralValue.create(index),
+ CPPVisitor.get_SIZE_T());
+ ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { indexArgument,
+ new CPPTemplateTypeArgument(type) };
+ return toStream(findClassTemplateInstance(scope, STD_TUPLE_ELEMENT_STR, templateArguments, name))
+ .map(ICPPClassSpecialization::getCompositeScope)
+ // Look for "type" in class scope with CPPSemantics.findBindings to also consider base classes
+ .map(instanceScope -> CPPSemantics.findBindings(instanceScope, TYPE_STR.toCharArray(), false, name))
+ .flatMap(Arrays::stream).filter(IType.class::isInstance).map(IType.class::cast)
+ .map(SemanticUtil::getSimplifiedType).findFirst()
+ .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
+ }
+
+ private static ICPPASTInitializerClause getInitializerClause(ICPPASTStructuredBindingDeclaration declaration) {
+ IASTInitializer initializer = declaration.getInitializer();
+ ICPPASTInitializerClause initClause = null;
+ if (initializer != null) {
+ initClause = getInitClauseForInitializer(initializer);
+ } else {
+ IASTNode declarationParent = declaration.getParent();
+ if (declarationParent instanceof ICPPASTRangeBasedForStatement) {
+ ICPPASTRangeBasedForStatement rangeBasedForParent = (ICPPASTRangeBasedForStatement) declarationParent;
+ initClause = getAutoInitClauseForRangeBasedFor(rangeBasedForParent);
+ }
+ }
+ return initClause;
+ }
+
+ public static IType createType(ICPPASTStructuredBindingDeclaration declaration, IASTName name) {
+ ICPPASTInitializerClause initClause = getInitializerClause(declaration);
+
+ if (initClause == null) {
+ return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE;
+ }
+
+ ICPPEvaluation evaluation = initClause.getEvaluation();
+ IType eType = evaluation.getType();
+ IType unwrappedType = SemanticUtil.getNestedType(eType, TDEF | ALLCVQ);
+ IType initializerType = deduceInitializerType(declaration, name, unwrappedType);
+ if (initializerType == ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE) {
+ return initializerType;
+ }
+ IASTDeclSpecifier declSpec = declaration.getDeclSpecifier();
+ IType qualifiedType = SemanticUtil.addQualifiers(initializerType,
+ declSpec.isConst() || SemanticUtil.isConst(eType),
+ declSpec.isVolatile() || SemanticUtil.isVolatile(eType), declSpec.isRestrict());
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier == null) {
+ return qualifiedType;
+ }
+ return new CPPReferenceType(qualifiedType, shallBecomeRvalueReference(evaluation, refQualifier, declSpec));
+ }
+
+ public static boolean hasConstexprStaticIntegralValueField(ICPPClassType type, long expectedValue) {
+ return Arrays.stream(ClassTypeHelper.getFields(type)).filter(IS_STATIC_VARIABLE).filter(IS_NAMED_VALUE)
+ .filter(HAS_INTEGRAL_TYPE).filter(HAS_CONST_TYPE).filter(field -> {
+ return variableHasInitialNumberValue(field, expectedValue);
+ }).findFirst().isPresent();
+ }
+
+ private static boolean variableHasInitialNumberValue(IVariable variable, long expectedValue) {
+ IValue initialValue = variable.getInitialValue();
+ if (initialValue == null) {
+ return false;
+ }
+ Number numberValue = initialValue.numberValue();
+ if (numberValue == null) {
+ return false;
+ }
+ return numberValue.longValue() == expectedValue;
+ }
+
+ private static IType deduceInitializerType(ICPPASTStructuredBindingDeclaration declaration, IASTName name,
+ IType unwrappedType) {
+ if (unwrappedType instanceof IArrayType) {
+ IArrayType arrayType = (IArrayType) unwrappedType;
+ return arrayType.getType();
+ } else if (unwrappedType instanceof ICPPClassType) {
+ int index = Arrays.asList(declaration.getNames()).indexOf(name);
+ IScope scope = CPPSemantics.getLookupScope(name);
+ Optional<ICPPClassSpecialization> tupleSizeInstance = findTupleSizeWithValueMember(unwrappedType, scope,
+ name);
+ if (tupleSizeInstance.isPresent()) {
+ int numberOfNames = declaration.getNames().length;
+ if (hasConstexprStaticIntegralValueField(tupleSizeInstance.get(), numberOfNames)) {
+ return determineTupleElementType(unwrappedType, scope, name, index);
+ }
+ } else {
+ ICPPClassType classType = (ICPPClassType) unwrappedType;
+ return Arrays.stream(ClassTypeHelper.getFields(classType)).filter(IS_STATIC_VARIABLE.negate())
+ .skip(index).findFirst().map(IField::getType)
+ .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
+ }
+ }
+ return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE;
+ }
+
+ /**
+ *
+ * Determines the reference type of a name in a structured binding based on its {@code evaluation}, the {@code refQualifier} and the {@code declSpecifier}.
+ * It performs perfect forwarding in case of a forwarding reference, i.e. if the declaration specifier is exactly "auto &&",
+ * Otherwise it is always an rvalue reference if the declaration specifier contains &&
+ *
+ * Example:
+ * auto && [element] = get(); // element is an rvalue if get() is an rvalue, otherwise an lvalue
+ * auto const && [element] = get(); //element is always an rvalue, get() needs to be an rvalue too
+ *
+ */
+ private static boolean shallBecomeRvalueReference(ICPPEvaluation evaluation, RefQualifier refQualifier,
+ IASTDeclSpecifier declSpecifier) {
+
+ if (refQualifier == RefQualifier.RVALUE) {
+ return evaluation.getValueCategory() != ValueCategory.LVALUE || declSpecifier.isConst()
+ || declSpecifier.isVolatile();
+ }
+ return false;
+ }
+
private static IType createFunctionType(IType returnType, ICPPASTFunctionDeclarator fnDtor) {
IType[] pTypes = createParameterTypes(fnDtor);
@@ -2214,8 +2383,7 @@ public class CPPVisitor extends ASTQueries {
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
}
- private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
- IASTInitializer initClause = declarator.getInitializer();
+ private static ICPPASTInitializerClause getInitClauseForInitializer(IASTInitializer initClause) {
if (initClause instanceof IASTEqualsInitializer) {
return (ICPPASTInitializerClause) ((IASTEqualsInitializer) initClause).getInitializerClause();
} else if (initClause instanceof ICPPASTConstructorInitializer) {
@@ -2235,6 +2403,45 @@ public class CPPVisitor extends ASTQueries {
return null;
}
+ private static ICPPASTInitializerClause getAutoInitClauseForRangeBasedFor(ICPPASTRangeBasedForStatement forStmt) {
+ // See 6.5.4 The range-based for statement [stmt.ranged]
+ IASTInitializerClause forInit = forStmt.getInitializerClause();
+ IASTExpression beginExpr = null;
+ if (forInit instanceof IASTExpression) {
+ final IASTExpression expr = (IASTExpression) forInit;
+ IType type = SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE);
+ if (type instanceof IArrayType) {
+ beginExpr = expr.copy();
+ }
+ }
+ if (beginExpr == null) {
+ IASTImplicitName[] implicits = forStmt.getImplicitNames();
+ if (implicits.length > 0) {
+ IBinding b = implicits[0].getBinding();
+ CPPASTName name = new CPPASTName();
+ name.setBinding(b);
+ IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() };
+ if (b instanceof ICPPMethod && forInit instanceof IASTExpression) {
+ beginExpr = new CPPASTFunctionCallExpression(
+ new CPPASTFieldReference(name, (IASTExpression) forInit.copy()), beginCallArguments);
+ } else {
+ beginExpr = new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments);
+ }
+ } else {
+ return null;
+ }
+ }
+ ICPPASTInitializerClause autoInitClause = new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr);
+ autoInitClause.setParent(forStmt);
+ autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
+ return autoInitClause;
+ }
+
+ private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
+ IASTInitializer initClause = declarator.getInitializer();
+ return getInitClauseForInitializer(initClause);
+ }
+
private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, int flags,
PlaceholderKind placeholderKind) {
IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? ProblemType.CANNOT_DEDUCE_AUTO_TYPE
@@ -2275,39 +2482,10 @@ public class CPPVisitor extends ASTQueries {
}
}
} else if (parent instanceof ICPPASTRangeBasedForStatement) {
- // See 6.5.4 The range-based for statement [stmt.ranged]
- ICPPASTRangeBasedForStatement forStmt = (ICPPASTRangeBasedForStatement) parent;
- IASTInitializerClause forInit = forStmt.getInitializerClause();
- IASTExpression beginExpr = null;
- if (forInit instanceof IASTExpression) {
- final IASTExpression expr = (IASTExpression) forInit;
- IType type = SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE);
- if (type instanceof IArrayType) {
- beginExpr = expr.copy();
- }
- }
- if (beginExpr == null) {
- IASTImplicitName[] implicits = forStmt.getImplicitNames();
- if (implicits.length > 0) {
- IBinding b = implicits[0].getBinding();
- CPPASTName name = new CPPASTName();
- name.setBinding(b);
- IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() };
- if (b instanceof ICPPMethod && forInit instanceof IASTExpression) {
- beginExpr = new CPPASTFunctionCallExpression(
- new CPPASTFieldReference(name, (IASTExpression) forInit.copy()),
- beginCallArguments);
- } else {
- beginExpr = new CPPASTFunctionCallExpression(new CPPASTIdExpression(name),
- beginCallArguments);
- }
- } else {
- return cannotDeduce;
- }
+ autoInitClause = getAutoInitClauseForRangeBasedFor((ICPPASTRangeBasedForStatement) parent);
+ if (autoInitClause == null) {
+ return cannotDeduce;
}
- autoInitClause = new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr);
- autoInitClause.setParent(forStmt);
- autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
} else if (parent instanceof IASTCompositeTypeSpecifier
&& declSpec.getStorageClass() != IASTDeclSpecifier.sc_static) {
// Non-static auto-typed class members are not allowed.
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
index 6ab1df368c..6f307fd3e0 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
@@ -35,6 +35,10 @@ public class ExecIncomplete implements ICPPExecution {
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
- throw new UnsupportedOperationException();
+ buffer.putShort(ITypeMarshalBuffer.EXEC_INCOMPLETE);
+ }
+
+ public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) {
+ return INSTANCE;
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
index 2481dbbcb8..2f2f36c67b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
@@ -122,7 +122,7 @@ public class ExpressionTypes {
return false;
}
- private static boolean isVolatile(IType type) {
+ public static boolean isVolatile(IType type) {
if (type instanceof IQualifierType) {
return ((IQualifierType) type).isVolatile();
} else if (type instanceof IPointerType) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
index eaca924d50..f84d285bad 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
@@ -908,11 +908,22 @@ public class SemanticUtil {
if (type instanceof ICPPReferenceType) {
ICPPReferenceType refType = (ICPPReferenceType) type;
return isConst(refType.getType());
- } else if (type instanceof CPPQualifierType) {
- CPPQualifierType qualifierType = (CPPQualifierType) type;
- return qualifierType.isConst();
}
- return false;
+ return ExpressionTypes.isConst(type);
+ }
+
+ /**
+ * Returns whether a type is volatile or a reference to a volatile type.
+ *
+ * @param type the type to be checked
+ * @return true if the type is volatile, otherwise false
+ */
+ public static boolean isVolatile(IType type) {
+ if (type instanceof ICPPReferenceType) {
+ ICPPReferenceType refType = (ICPPReferenceType) type;
+ return isVolatile(refType.getType());
+ }
+ return ExpressionTypes.isVolatile(type);
}
static IType[] addImplicitParameterType(IType[] types, ICPPMethod m) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
index 9471f80791..e99d4ecfd6 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
@@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
@@ -34,6 +35,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
@@ -41,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
@@ -63,6 +66,8 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
public class DeclarationWriter extends NodeWriter {
private static final char OPEN_PAREN = '(';
private static final char CLOSE_PAREN = ')';
+ private static final char OPEN_BRACKET = '[';
+ private static final char CLOSE_BRACKET = ']';
private static final String ASM_START = "asm" + OPEN_PAREN; //$NON-NLS-1$
private static final String TEMPLATE_DECLARATION = "template<"; //$NON-NLS-1$
private static final String TEMPLATE_SPECIALIZATION = "template<> "; //$NON-NLS-1$
@@ -87,6 +92,8 @@ public class DeclarationWriter extends NodeWriter {
addNewLine = false;
} else if (declaration instanceof IASTProblemDeclaration) {
throw new ProblemRuntimeException((IASTProblemDeclaration) declaration);
+ } else if (declaration instanceof ICPPASTStructuredBindingDeclaration) {
+ writeStructuredBinding((ICPPASTStructuredBindingDeclaration) declaration, writeSemicolon);
} else if (declaration instanceof IASTSimpleDeclaration) {
writeSimpleDeclaration((IASTSimpleDeclaration) declaration);
} else if (declaration instanceof ICPPASTExplicitTemplateInstantiation) {
@@ -123,6 +130,28 @@ public class DeclarationWriter extends NodeWriter {
}
}
+ private void writeStructuredBinding(ICPPASTStructuredBindingDeclaration declaration, boolean writeSemicolon) {
+ writeAttributes(declaration, EnumSet.of(SpaceLocation.AFTER));
+ declaration.getDeclSpecifier().accept(visitor);
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier != null) {
+ writeRefQualifier(refQualifier);
+ }
+ scribe.printSpace();
+
+ scribe.print(OPEN_BRACKET);
+ writeNodeList(declaration.getNames());
+ scribe.print(CLOSE_BRACKET);
+
+ IASTInitializer initializer = declaration.getInitializer();
+ if (initializer != null) {
+ initializer.accept(visitor);
+ }
+ if (writeSemicolon) {
+ printSemicolon();
+ }
+ }
+
private void writeAliasDeclaration(ICPPASTAliasDeclaration aliasDeclaration) {
scribe.printStringSpace(Keywords.USING);
IASTName alias = aliasDeclaration.getAlias();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
index 97d9006210..86eb87683a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
@@ -159,16 +159,7 @@ public class DeclaratorWriter extends NodeWriter {
scribe.print(Keywords.VOLATILE);
}
RefQualifier refQualifier = funcDec.getRefQualifier();
- if (refQualifier != null) {
- switch (refQualifier) {
- case LVALUE:
- scribe.print(Keywords.cpAMPER);
- break;
- case RVALUE:
- scribe.print(Keywords.cpAND);
- break;
- }
- }
+ writeRefQualifier(refQualifier);
if (funcDec.isMutable()) {
scribe.printSpace();
scribe.print(Keywords.MUTABLE);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
index 5d9fa84b3a..085d25f212 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
@@ -23,8 +23,10 @@ import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.gnu.IGCCASTAttributeList;
import org.eclipse.cdt.core.dom.parser.cpp.ICPPASTAttributeSpecifier;
+import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
@@ -157,4 +159,17 @@ public class NodeWriter {
scribe.printSpace();
}
}
+
+ protected void writeRefQualifier(RefQualifier refQualifier) {
+ if (refQualifier != null) {
+ switch (refQualifier) {
+ case LVALUE:
+ scribe.print(Keywords.cpAMPER);
+ break;
+ case RVALUE:
+ scribe.print(Keywords.cpAND);
+ break;
+ }
+ }
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
index 4752e5e0ab..05b9367d2f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
@@ -154,6 +154,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecDo;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecExpressionStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecFor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIf;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIncomplete;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecRangeBasedFor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecReturn;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclaration;
@@ -1768,6 +1769,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return ExecSwitch.unmarshal(firstBytes, buffer);
case ITypeMarshalBuffer.EXEC_CONSTRUCTOR_CHAIN:
return ExecConstructorChain.unmarshal(firstBytes, buffer);
+ case ITypeMarshalBuffer.EXEC_INCOMPLETE:
+ return ExecIncomplete.unmarshal(firstBytes, buffer);
}
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an execution, first bytes=" + firstBytes)); //$NON-NLS-1$
}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
index a4cfe65934..2557328d2e 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -2470,6 +2470,84 @@ public class DefaultCodeFormatterConstants {
+ ".formatter.insert_space_between_empty_parens_in_exception_specification"; //$NON-NLS-1$
/**
* <pre>
+ * FORMATTER / Option to insert a space before the opening bracket of the name list in a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_before_opening_structured_binding_name_list"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_before_opening_structured_binding_name_list"; //$NON-NLS-1$
+ /**
+ * <pre>
+ * FORMATTER / Option to insert a space after the opening bracket of the name list in a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_after_opening_structured_binding_name_list"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: DO_NOT_INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_after_opening_structured_binding_name_list"; //$NON-NLS-1$
+ /**
+ * <pre>
+ * FORMATTER / Option to insert a space before the closing bracket of the name list in a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_before_closing_structured_binding_name_list"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: DO_NOT_INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_before_closing_structured_binding_name_list"; //$NON-NLS-1$
+ /**
+ * <pre>
+ * FORMATTER / Option to insert a space before a comma in the name list of a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_before_comma_in_structured_binding_name_list"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: DO_NOT_INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_before_comma_in_structured_binding_name_list"; //$NON-NLS-1$
+ /**
+ * <pre>
+ * FORMATTER / Option to insert a space after a comma in the name list of a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_after_comma_in_structured_binding_name_list"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_after_comma_in_structured_binding_name_list"; //$NON-NLS-1$
+ /**
+ * <pre>
+ * FORMATTER / Option to insert a space before a reference qualifier in a structured binding declaration
+ * - option id: "org.eclipse.cdt.core.formatter.insert_space_before_ref_qualifier_in_structured_binding"
+ * - possible values: { INSERT, DO_NOT_INSERT }
+ * - default: INSERT
+ * </pre>
+ * @see CCorePlugin#INSERT
+ * @see CCorePlugin#DO_NOT_INSERT
+ * @since 6.9
+ */
+ public static final String FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING = CCorePlugin.PLUGIN_ID
+ + ".formatter.insert_space_before_ref_qualifier_in_structured_binding"; //$NON-NLS-1$
+ /**
+ * <pre>
* FORMATTER / Option to keep else statement on the same line
* - option id: "org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line"
* - possible values: { TRUE, FALSE }
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
index 2db0bbd129..dc6868739f 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
@@ -301,6 +301,18 @@ public class DefaultCodeFormatterOptions {
public boolean insert_space_between_empty_parens_in_method_declaration;
public boolean insert_space_between_empty_parens_in_method_invocation;
public boolean insert_space_between_empty_parens_in_exception_specification;
+ /** @since 6.9 */
+ public boolean insert_space_before_opening_structured_binding_name_list;
+ /** @since 6.9 */
+ public boolean insert_space_after_opening_structured_binding_name_list;
+ /** @since 6.9 */
+ public boolean insert_space_before_closing_structured_binding_name_list;
+ /** @since 6.9 */
+ public boolean insert_space_before_comma_in_structured_binding_name_list;
+ /** @since 6.9 */
+ public boolean insert_space_after_comma_in_structured_binding_name_list;
+ /** @since 6.9 */
+ public boolean insert_space_before_ref_qualifier_in_structured_binding;
public boolean compact_else_if;
public boolean keep_guardian_clause_on_one_line;
public boolean keep_else_statement_on_same_line;
@@ -788,6 +800,24 @@ public class DefaultCodeFormatterOptions {
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BETWEEN_EMPTY_PARENS_IN_EXCEPTION_SPECIFICATION,
this.insert_space_between_empty_parens_in_exception_specification ? CCorePlugin.INSERT
: CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ this.insert_space_before_opening_structured_binding_name_list ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ this.insert_space_after_opening_structured_binding_name_list ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST,
+ this.insert_space_before_closing_structured_binding_name_list ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ this.insert_space_before_comma_in_structured_binding_name_list ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ this.insert_space_after_comma_in_structured_binding_name_list ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
+ options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING,
+ this.insert_space_before_ref_qualifier_in_structured_binding ? CCorePlugin.INSERT
+ : CCorePlugin.DO_NOT_INSERT);
options.put(DefaultCodeFormatterConstants.FORMATTER_COMPACT_ELSE_IF,
this.compact_else_if ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_GUARDIAN_CLAUSE_ON_ONE_LINE,
@@ -2130,6 +2160,42 @@ public class DefaultCodeFormatterOptions {
this.insert_space_between_empty_parens_in_exception_specification = CCorePlugin.INSERT
.equals(insertSpaceBetweenEmptyParensInExceptionSpecificationOption);
}
+ final Object insertSpaceBeforeOpeningStructuredBindingNameList = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST);
+ if (insertSpaceBeforeOpeningStructuredBindingNameList != null) {
+ this.insert_space_before_opening_structured_binding_name_list = CCorePlugin.INSERT
+ .equals(insertSpaceBeforeOpeningStructuredBindingNameList);
+ }
+ final Object insertSpaceAfterOpeningStructuredBindingNameList = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST);
+ if (insertSpaceAfterOpeningStructuredBindingNameList != null) {
+ this.insert_space_after_opening_structured_binding_name_list = CCorePlugin.INSERT
+ .equals(insertSpaceAfterOpeningStructuredBindingNameList);
+ }
+ final Object insertSpaceBeforeClosingStructuredBindingNameList = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST);
+ if (insertSpaceBeforeClosingStructuredBindingNameList != null) {
+ this.insert_space_before_closing_structured_binding_name_list = CCorePlugin.INSERT
+ .equals(insertSpaceBeforeClosingStructuredBindingNameList);
+ }
+ final Object insertSpaceBeforeCommaInStructuredBindingNameList = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST);
+ if (insertSpaceBeforeCommaInStructuredBindingNameList != null) {
+ this.insert_space_before_comma_in_structured_binding_name_list = CCorePlugin.INSERT
+ .equals(insertSpaceBeforeCommaInStructuredBindingNameList);
+ }
+ final Object insertSpaceAfterCommaInStructuredBindingNameList = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST);
+ if (insertSpaceAfterCommaInStructuredBindingNameList != null) {
+ this.insert_space_after_comma_in_structured_binding_name_list = CCorePlugin.INSERT
+ .equals(insertSpaceAfterCommaInStructuredBindingNameList);
+ }
+ final Object insertSpaceBeforeRefQualifierInStructuredBinding = settings
+ .get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING);
+ if (insertSpaceBeforeRefQualifierInStructuredBinding != null) {
+ this.insert_space_before_ref_qualifier_in_structured_binding = CCorePlugin.INSERT
+ .equals(insertSpaceBeforeRefQualifierInStructuredBinding);
+ }
final Object compactElseIfOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_COMPACT_ELSE_IF);
if (compactElseIfOption != null) {
this.compact_else_if = DefaultCodeFormatterConstants.TRUE.equals(compactElseIfOption);
@@ -2441,6 +2507,12 @@ public class DefaultCodeFormatterOptions {
this.insert_space_between_empty_parens_in_method_declaration = false;
this.insert_space_between_empty_parens_in_method_invocation = false;
this.insert_space_between_empty_parens_in_exception_specification = false;
+ this.insert_space_before_opening_structured_binding_name_list = true;
+ this.insert_space_after_opening_structured_binding_name_list = false;
+ this.insert_space_before_closing_structured_binding_name_list = false;
+ this.insert_space_before_comma_in_structured_binding_name_list = false;
+ this.insert_space_after_comma_in_structured_binding_name_list = true;
+ this.insert_space_before_ref_qualifier_in_structured_binding = false;
this.compact_else_if = true;
this.keep_guardian_clause_on_one_line = false;
this.keep_else_statement_on_same_line = false;
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
index 40ecad720d..af013b73cf 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
@@ -131,6 +131,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
@@ -149,6 +150,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -1948,7 +1950,48 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
return PROCESS_SKIP;
}
+ private int visit(ICPPASTStructuredBindingDeclaration node) {
+ formatLeadingAttributes(node);
+ IASTDeclSpecifier declSpec = node.getDeclSpecifier();
+ declSpec.accept(this);
+
+ RefQualifier refQualifier = node.getRefQualifier();
+ if (refQualifier != null) {
+ int expectedToken = refQualifier == RefQualifier.LVALUE ? Token.tAMPER : Token.tAND;
+ if (peekNextToken() == expectedToken) {
+ scribe.printNextToken(expectedToken,
+ preferences.insert_space_before_ref_qualifier_in_structured_binding);
+ }
+ }
+
+ IASTInitializer initializer = node.getInitializer();
+ if (peekNextToken() == Token.tLBRACKET) {
+ List<IASTName> names = Arrays.asList(node.getNames());
+ final ListOptions options = new ListOptions(preferences.alignment_for_declarator_list);
+ options.leftToken = Token.tLBRACKET;
+ options.rightToken = Token.tRBRACKET;
+ options.fSpaceBeforeOpeningParen = preferences.insert_space_before_opening_structured_binding_name_list;
+ options.fSpaceAfterOpeningParen = preferences.insert_space_after_opening_structured_binding_name_list;
+ options.fSpaceBeforeClosingParen = preferences.insert_space_before_closing_structured_binding_name_list;
+ options.fSpaceAfterSeparator = preferences.insert_space_after_comma_in_structured_binding_name_list;
+ options.fSpaceBeforeSeparator = preferences.insert_space_before_comma_in_structured_binding_name_list;
+ formatList(names, options, true, false, null);
+ } else if (initializer != null) {
+ skipToNode(initializer);
+ }
+ if (initializer != null) {
+ initializer.accept(this);
+ }
+ if (fExpectSemicolonAfterDeclaration && peekNextToken() == Token.tSEMI) {
+ scribe.printNextToken(Token.tSEMI);
+ }
+ return PROCESS_SKIP;
+ }
+
private int visit(IASTSimpleDeclaration node) {
+ if (node instanceof ICPPASTStructuredBindingDeclaration) {
+ return visit((ICPPASTStructuredBindingDeclaration) node);
+ }
formatLeadingAttributes(node);
IASTDeclSpecifier declSpec = node.getDeclSpecifier();
declSpec.accept(this);
@@ -2585,11 +2628,12 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
}
private void formatInlineDeclaration(final IASTDeclaration decl) {
+ boolean previousExpectSemicolonAfterDeclaration = fExpectSemicolonAfterDeclaration;
fExpectSemicolonAfterDeclaration = false;
try {
decl.accept(this);
} finally {
- fExpectSemicolonAfterDeclaration = true;
+ fExpectSemicolonAfterDeclaration = previousExpectSemicolonAfterDeclaration;
}
}
@@ -3660,7 +3704,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
scribe.space();
}
IASTDeclaration declaration = node.getDeclaration();
- declaration.accept(this);
+ formatInlineDeclaration(declaration);
scribe.printNextToken(Token.tCOLON, true /* preferences.insert_space_before_colon_in_for */);
final IASTInitializerClause initializer = node.getInitializerClause();
if (true /*preferences.insert_space_after_colon_in_for*/) {
diff --git a/core/org.eclipse.cdt.ui.tests/resources/ceditor/occurrences.cpp b/core/org.eclipse.cdt.ui.tests/resources/ceditor/occurrences.cpp
index c63250e4f5..a0e7f2e463 100644
--- a/core/org.eclipse.cdt.ui.tests/resources/ceditor/occurrences.cpp
+++ b/core/org.eclipse.cdt.ui.tests/resources/ceditor/occurrences.cpp
@@ -133,4 +133,15 @@ void functionWithLabelReferenceGoto() {
goto *labelPointer;
referencedLabel:
return;
+}
+
+void localOccurrencesInStructuredBinding() {
+ int decompArr[2]{1, 2};
+ auto [decomposedF, decomposedS] = decompArr;
+ decomposedF;
+ decomposedS;
+ auto [decomposedF2, decomposedS2](decompArr);
+ auto [decomposedF3, decomposedS3]{decompArr};
+ auto & [decomposedF4, decomposedS4] = decompArr;
+ auto const & [decomposedF5,decomposedS5] = decompArr;
} \ No newline at end of file
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
index 7fb8106301..f7f52b193a 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
@@ -4517,4 +4517,186 @@ public class CodeFormatterTest extends BaseUITestCase {
public void testWrappingLambdaExpression_Bug549653() throws Exception {
assertFormatterResult();
}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto[l,r]=s;
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto [l, r] = s;
+ //}
+ public void testStructuredBindingSimpleDeclaration() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto&[l0,r0]=s;
+ // auto&&[l1,r1]=S{1,1.0};
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto& [l0, r0] = s;
+ // auto&& [l1, r1] = S { 1, 1.0 };
+ //}
+ public void testStructuredBindingWithRefQualifiers() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto[l0,r0]=s;
+ // auto&[l1,r1]=s;
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // auto[ l0 ,r0 ] = s;
+ // auto &[ l1 ,r1 ] = s;
+ //}
+ public void testStructuredBindingSimpleDeclarationInvertedFormat() throws Exception {
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING,
+ CCorePlugin.INSERT);
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ CCorePlugin.DO_NOT_INSERT);
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ CCorePlugin.INSERT);
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST,
+ CCorePlugin.INSERT);
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ CCorePlugin.INSERT);
+ fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ CCorePlugin.DO_NOT_INSERT);
+ assertFormatterResult();
+ }
+
+ //#define SB(F, S, I) auto[F,S] = I
+ //#define LIST(F, S) [F,S]
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // SB(l0,r0,s);
+ // auto LIST(l1,r1)=s;
+ //}
+
+ //#define SB(F, S, I) auto[F,S] = I
+ //#define LIST(F, S) [F,S]
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // SB(l0, r0, s);
+ // auto LIST(l1,r1) = s;
+ //}
+ public void testStructuredBindingSimpleDeclarationFromMacro() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} esses[] { { 1, 1.0 } };
+ //void foo() {
+ // for (auto[l,r]: esses) {
+ // }
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} esses[] { { 1, 1.0 } };
+ //void foo() {
+ // for (auto [l, r] : esses) {
+ // }
+ //}
+ public void testStructuredBindingInRangeBasedForLoop() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // for(auto[l,r]=s;l<10;l++){
+ // }
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // for (auto [l, r] = s; l < 10; l++) {
+ // }
+ //}
+ public void testStructuredBindingInForLoop() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // if(auto[l,r]=s;l==1){
+ // }
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // if (auto [l, r] = s; l == 1) {
+ // }
+ //}
+ public void testStructuredBindingInIfInitStatement() throws Exception {
+ assertFormatterResult();
+ }
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // switch(auto[l,r]=s;l){
+ // }
+ //}
+
+ //struct S {
+ // int i;
+ // double d;
+ //} s { 1, 1.0 };
+ //void foo() {
+ // switch (auto [l, r] = s; l) {
+ // }
+ //}
+ public void testStructuredBindingInSwitchInitStatement() throws Exception {
+ assertFormatterResult();
+ }
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/MarkOccurrenceTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/MarkOccurrenceTest.java
index aa4a5a9c59..a301f5ce5e 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/MarkOccurrenceTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/MarkOccurrenceTest.java
@@ -557,6 +557,32 @@ public class MarkOccurrenceTest extends BaseUITestCase {
assertOccurrencesInWidget();
}
+ public void testMarkReferencedStructuredBindingDefinition() {
+ try {
+ fMatch = fFindReplaceDocumentAdapter.find(0, "decomposedF", true, true, true, false);
+ } catch (BadLocationException e) {
+ fail();
+ }
+
+ fEditor.selectAndReveal(fMatch.getOffset(), fMatch.getLength());
+
+ assertOccurrences(2, 1);
+ assertOccurrencesInWidget();
+ }
+
+ public void testMarkReferencedStructuredBindingInitializer() {
+ try {
+ fMatch = fFindReplaceDocumentAdapter.find(0, "decompArr", true, true, true, false);
+ } catch (BadLocationException e) {
+ fail();
+ }
+
+ fEditor.selectAndReveal(fMatch.getOffset(), fMatch.getLength());
+
+ assertOccurrences(6, 2);
+ assertOccurrencesInWidget();
+ }
+
private void assertOccurrencesInWidget() {
EditorTestHelper.runEventQueue(100);
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java
index fec4270ace..a66e622f1d 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java
@@ -1380,4 +1380,38 @@ public class CPPSelectionTestsIndexer extends BaseSelectionTestsIndexer {
assertInstance(target, IASTName.class);
assertEquals(IASTNameOwner.r_definition, ((IASTName) target).getRoleOfName(false));
}
+
+ // template <typename E>
+ // struct Node {
+ // Node * next;
+ // E value;
+ // };
+ // Node<int> head{nullptr, 42};
+ // auto [h, v] = head;
+
+ // #include "SBTestHeader.hpp"
+ // auto myH = h;
+ // auto myV = v;
+ public void testNavigationToStructuredBinding_522200() throws Exception {
+ StringBuilder[] buffers = getContents(2);
+ String header = buffers[0].toString();
+ IFile headerFile = importFile("SBTestHeader.hpp", header);
+ String source = buffers[1].toString();
+ IFile sourceFile = importFile("SBTestSource.cpp", source);
+ waitUntilFileIsIndexed(index, sourceFile);
+
+ IASTNode targetH = testF3(sourceFile, source.indexOf("myH = h") + 6);
+ assertInstance(targetH, IASTName.class);
+ assertEquals(IASTNameOwner.r_definition, ((IASTName) targetH).getRoleOfName(false));
+ IASTFileLocation locationH = targetH.getFileLocation();
+ int targetHOffset = locationH.getNodeOffset();
+ assertEquals(header.indexOf("auto [h") + 6, targetHOffset);
+
+ IASTNode targetV = testF3(sourceFile, source.indexOf("myV = v") + 6);
+ assertInstance(targetV, IASTName.class);
+ assertEquals(IASTNameOwner.r_definition, ((IASTName) targetV).getRoleOfName(false));
+ IASTFileLocation locationV = targetV.getFileLocation();
+ int targetVOffset = locationV.getNodeOffset();
+ assertEquals(header.indexOf("[h, v") + 4, targetVOffset);
+ }
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java
index 6e2d290a75..6a96df10ae 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java
@@ -1418,4 +1418,33 @@ public class CPPSelectionTestsNoIndexer extends BaseSelectionTests {
assertInstance(target, IASTName.class);
assertEquals(IASTNameOwner.r_definition, ((IASTName) target).getRoleOfName(false));
}
+
+ //int arr[2]{1, 2};
+ //auto [e1, e2] = arr;
+ //auto r1 = e1;
+ //auto r2 = e2;
+ public void testOpenDeclarationForStructuredBinding_522200() throws Exception {
+ String code = getAboveComment();
+ IFile file = importFile("testSB_.cpp", code); //$NON-NLS-1$
+
+ int offsetE1Reference = code.indexOf("e1;"); //$NON-NLS-1$
+ IASTNode e1Declaration = testF3(file, offsetE1Reference);
+ assertTrue(e1Declaration instanceof IASTName);
+
+ String expectedE1Name = "e1"; //$NON-NLS-1$
+ assertEquals(expectedE1Name, ((IASTName) e1Declaration).toString());
+ assertEquals(code.indexOf(expectedE1Name), ((ASTNode) e1Declaration).getOffset());
+ assertEquals(expectedE1Name.length(), ((ASTNode) e1Declaration).getLength());
+ assertEquals(IASTNameOwner.r_definition, ((IASTName) e1Declaration).getRoleOfName(false));
+
+ int offsetE2Reference = code.indexOf("e2;"); //$NON-NLS-1$
+ IASTNode e2Declaration = testF3(file, offsetE2Reference);
+ assertTrue(e2Declaration instanceof IASTName);
+
+ String expectedE2Name = "e2"; //$NON-NLS-1$
+ assertEquals(expectedE2Name, ((IASTName) e2Declaration).toString());
+ assertEquals(code.indexOf(expectedE2Name), ((ASTNode) e2Declaration).getOffset());
+ assertEquals(expectedE2Name.length(), ((ASTNode) e2Declaration).getLength());
+ assertEquals(IASTNameOwner.r_definition, ((IASTName) e2Declaration).getRoleOfName(false));
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
index f3f5ed0232..7deb8d1086 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
@@ -78,6 +78,7 @@ final class FormatterMessages extends NLS {
public static String WhiteSpaceTabPage_if;
public static String WhiteSpaceTabPage_for;
public static String WhiteSpaceTabPage_labels;
+ public static String WhiteSpaceTabPage_structured_bindings;
public static String WhiteSpaceTabPage_template_arguments;
public static String WhiteSpaceTabPage_template_parameters;
public static String WhiteSpaceTabPage_conditionals;
@@ -204,6 +205,13 @@ final class FormatterMessages extends NLS {
public static String WhiteSpaceOptions_after_semicolon;
public static String WhiteSpaceOptions_before_question_mark;
public static String WhiteSpaceOptions_after_question_mark;
+ public static String WhiteSpaceOptions_structured_binding_declarations;
+ public static String WhiteSpaceOptions_structured_binding_before_ref_qualifier;
+ public static String WhiteSpaceOptions_structured_binding_before_name_list_opening_bracket;
+ public static String WhiteSpaceOptions_structured_binding_before_first_name_in_list;
+ public static String WhiteSpaceOptions_structured_binding_before_comma_in_name_list;
+ public static String WhiteSpaceOptions_structured_binding_after_comma_in_name_list;
+ public static String WhiteSpaceOptions_structured_binding_before_name_list_closing_bracket;
// public static String WhiteSpaceOptions_before_ellipsis;
// public static String WhiteSpaceOptions_after_ellipsis;
// public static String WhiteSpaceOptions_return_with_parenthesized_expression;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
index 4bdc8611c3..6921dc869e 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
@@ -79,6 +79,7 @@ WhiteSpaceTabPage_for='for'
#WhiteSpaceTabPage_for_after_comma_inc=after comma in increments
WhiteSpaceTabPage_labels=Labels
+WhiteSpaceTabPage_structured_bindings=Structured bindings
WhiteSpaceTabPage_template_arguments=Template arguments
WhiteSpaceTabPage_template_parameters=Template parameters
@@ -235,6 +236,14 @@ WhiteSpaceOptions_after_semicolon=After semicolon
WhiteSpaceOptions_before_question_mark=Before question mark
WhiteSpaceOptions_after_question_mark=After question mark
+WhiteSpaceOptions_structured_binding_declarations=Structured binding declarations
+WhiteSpaceOptions_structured_binding_before_ref_qualifier=Before reference qualifier
+WhiteSpaceOptions_structured_binding_before_name_list_opening_bracket=Before opening bracket
+WhiteSpaceOptions_structured_binding_before_name_list_closing_bracket=Before closing bracket
+WhiteSpaceOptions_structured_binding_before_first_name_in_list=Before first name
+WhiteSpaceOptions_structured_binding_before_comma_in_name_list=Before comma
+WhiteSpaceOptions_structured_binding_after_comma_in_name_list=After comma
+
#WhiteSpaceOptions_before_ellipsis=Before Ellipsis
#WhiteSpaceOptions_after_ellipsis=After Ellipsis
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
index 7336a30e56..95e938b5ff 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
@@ -236,6 +236,10 @@ public final class WhiteSpaceOptions {
"map<int,int> m;" //$NON-NLS-1$
);
+ private final PreviewSnippet STRUCTURED_BINDING_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
+ "auto & [first, second, third] = init;" //$NON-NLS-1$
+ );
+
/**
* Create the tree, in this order: syntax element - position - abstract element
* @param workingValues
@@ -477,6 +481,7 @@ public final class WhiteSpaceOptions {
createMethodDeclTree(workingValues, declarations);
createExceptionSpecificationTree(workingValues, declarations);
createLabelTree(workingValues, declarations);
+ createStructuredBindingTree(workingValues, declarations);
final InnerNode statements = new InnerNode(null, workingValues, FormatterMessages.WhiteSpaceTabPage_statements);
createOption(statements, workingValues, FormatterMessages.WhiteSpaceOptions_before_semicolon,
@@ -582,6 +587,10 @@ public final class WhiteSpaceOptions {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_exception_specification,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_METHOD_DECLARATION_THROWS,
METHOD_DECL_PREVIEW);
+
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createBeforeOperatorTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -602,6 +611,9 @@ public final class WhiteSpaceOptions {
private void createBeforeClosingBracketTree(Map<String, String> workingValues, final InnerNode parent) {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_arrays,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_BRACKET, ARRAY_PREVIEW);
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createBeforeClosingAngleBracketTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -616,6 +628,9 @@ public final class WhiteSpaceOptions {
private void createBeforeOpenBracketTree(Map<String, String> workingValues, final InnerNode parent) {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_arrays,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACKET, ARRAY_PREVIEW);
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createBeforeOpenAngleBracketTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -703,6 +718,9 @@ public final class WhiteSpaceOptions {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_declarator_list,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_POINTER_IN_DECLARATOR_LIST,
DECLARATOR_LIST_PREVIEW);
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createAfterPointerTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -814,6 +832,10 @@ public final class WhiteSpaceOptions {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_exception_specification,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_METHOD_DECLARATION_THROWS,
METHOD_DECL_PREVIEW);
+
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createAfterOperatorTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -835,6 +857,9 @@ public final class WhiteSpaceOptions {
private void createAfterOpenBracketTree(Map<String, String> workingValues, final InnerNode parent) {
createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_arrays,
DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_BRACKET, ARRAY_PREVIEW);
+ createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_declarations,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
}
private void createAfterOpenAngleBracketTree(Map<String, String> workingValues, final InnerNode parent) {
@@ -1268,6 +1293,33 @@ public final class WhiteSpaceOptions {
return root;
}
+ private void createStructuredBindingTree(Map<String, String> workingValues, InnerNode parent) {
+ InnerNode root = new InnerNode(parent, workingValues, FormatterMessages.WhiteSpaceTabPage_structured_bindings);
+ createOption(root, workingValues, FormatterMessages.WhiteSpaceOptions_structured_binding_before_ref_qualifier,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_REF_QUALIFIER_IN_STRUCTURED_BINDING,
+ STRUCTURED_BINDING_PREVIEW);
+ createOption(root, workingValues,
+ FormatterMessages.WhiteSpaceOptions_structured_binding_before_name_list_opening_bracket,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
+ createOption(root, workingValues,
+ FormatterMessages.WhiteSpaceOptions_structured_binding_before_name_list_closing_bracket,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
+ createOption(root, workingValues,
+ FormatterMessages.WhiteSpaceOptions_structured_binding_before_first_name_in_list,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
+ createOption(root, workingValues,
+ FormatterMessages.WhiteSpaceOptions_structured_binding_before_comma_in_name_list,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
+ createOption(root, workingValues,
+ FormatterMessages.WhiteSpaceOptions_structured_binding_after_comma_in_name_list,
+ DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_STRUCTURED_BINDING_NAME_LIST,
+ STRUCTURED_BINDING_PREVIEW);
+ }
+
private InnerNode createTemplateArgumentTree(Map<String, String> workingValues, InnerNode parent) {
final InnerNode root = new InnerNode(parent, workingValues,
FormatterMessages.WhiteSpaceTabPage_template_arguments);

Back to the top