mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 08:55:25 +02:00
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>
This commit is contained in:
parent
af88842969
commit
acbceb04ee
58 changed files with 3043 additions and 163 deletions
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -376,4 +376,9 @@ int __declspec(selectany)* pi2 = 0;
|
|||
|
||||
//!MS declspec attribute on simple declaration
|
||||
//%CPP GNU
|
||||
__declspec(thread) int tls_i = 1;
|
||||
__declspec(thread) int tls_i = 1;
|
||||
|
||||
//!Attributed structured binding declaration
|
||||
//%CPP
|
||||
int arr[]{1, 2, 3};
|
||||
[[nodiscard]] auto [a, b, c] = arr;
|
||||
|
|
|
@ -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{};
|
||||
|
|
|
@ -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){
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -1675,6 +1677,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
return declSpecifierSequence_initDeclarator(option, acceptCompoundWithoutDtor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
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 EvalFixed.INCOMPLETE;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ICPPConstructor getImplicitlyCalledCtor(ICPPASTDeclarator declarator) {
|
||||
|
@ -350,4 +378,5 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
|
|||
public void allDeclarationsDefinitionsAdded() {
|
||||
fAllResolved = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
autoInitClause = getAutoInitClauseForRangeBasedFor((ICPPASTRangeBasedForStatement) parent);
|
||||
if (autoInitClause == null) {
|
||||
return cannotDeduce;
|
||||
}
|
||||
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 = 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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
|
|
|
@ -2468,6 +2468,84 @@ public class DefaultCodeFormatterConstants {
|
|||
*/
|
||||
public static final String FORMATTER_INSERT_SPACE_BETWEEN_EMPTY_PARENS_IN_EXCEPTION_SPECIFICATION = CCorePlugin.PLUGIN_ID
|
||||
+ ".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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*/) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue