Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Corbat2018-05-23 11:02:03 +0000
committerThomas Corbat2019-08-05 07:00:35 +0000
commitacbceb04ee9e472119ef3255a47986c833fcf4c2 (patch)
treec27f6cf457270d83047b8c01a9c790c2d0d5ef7b /core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core
parentaf88842969b538dc3a33eab84b3b9631194bd9a3 (diff)
downloadorg.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.tar.gz
org.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.tar.xz
org.eclipse.cdt-acbceb04ee9e472119ef3255a47986c833fcf4c2.zip
Bug 522200: [C++17] Add support for structured binding declarations
Adds support for structured bindings: - Parser updated - Semantics updated - Tests for parser and bindings added Change-Id: I1de7b760041ac4ce4601f1b5032fdb0a197212a1 Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch> Signed-off-by: Thomas Corbat <tcorbat@hsr.ch>
Diffstat (limited to 'core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core')
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java34
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java15
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java5
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java210
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java53
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java13
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java239
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java59
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java78
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java46
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java3
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java248
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java6
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java19
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java29
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java11
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java15
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java3
23 files changed, 1014 insertions, 88 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
index f5aaab64105..9698bfac8e5 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java
@@ -132,6 +132,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
public IASTDeclarator fDtor2;
public IToken fDtorToken1;
+ public boolean isAtStartOfStructuredBinding = false;
+
public Decl set(IASTDeclSpecifier declspec, IASTDeclarator dtor, IToken dtorToken) {
fDeclSpec1 = declspec;
fDtor1 = dtor;
@@ -1676,6 +1678,24 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
/**
+ * Checks whether the type specified by the {@code declSpecifier} is "auto" and
+ * the subsequent token, when looking beyond potential ref-qualifiers (& and &&),
+ * will be a single opening bracket ([) followed by an identifier.
+ */
+ protected boolean isAtStartOfStructuredBinding(IASTDeclSpecifier declSpecifier) {
+ if (!isAutoType(declSpecifier)) {
+ return false;
+ }
+ int expectedBracketOffset = 1;
+ int nextToken = LTcatchEOF(expectedBracketOffset);
+ if (nextToken == IToken.tAMPER || nextToken == IToken.tAND) {
+ expectedBracketOffset++;
+ }
+ return LTcatchEOF(expectedBracketOffset) == IToken.tLBRACKET
+ && LTcatchEOF(expectedBracketOffset + 1) == IToken.tIDENTIFIER;
+ }
+
+ /**
* Parses for two alternatives of a declspec sequence followed by a initDeclarator.
* A second alternative is accepted only, if it ends at the same point of the first alternative. Otherwise the
* longer alternative is selected.
@@ -1689,6 +1709,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (lt1 == IToken.tEOC)
return result;
+ // support for structured bindings
+ if (isAtStartOfStructuredBinding(result.fDeclSpec1)) {
+ result.isAtStartOfStructuredBinding = true;
+ return result;
+ }
+
// support simple declarations without declarators
final boolean acceptEmpty = acceptCompoundWithoutDtor && isLegalWithoutDtor(result.fDeclSpec1);
if (acceptEmpty) {
@@ -2056,6 +2082,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return false;
}
+ protected static boolean isAutoType(IASTDeclSpecifier declSpec) {
+ if (declSpec instanceof IASTSimpleDeclSpecifier) {
+ IASTSimpleDeclSpecifier simpleDeclSpecifier = (IASTSimpleDeclSpecifier) declSpec;
+ return simpleDeclSpecifier.getType() == IASTSimpleDeclSpecifier.t_auto;
+ }
+ return false;
+ }
+
protected abstract IASTAmbiguousStatement createAmbiguousStatement();
protected IASTStatement parseLabelStatement() throws EndOfFileException, BacktrackException {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
index fab7f546028..cc215747ed2 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java
@@ -52,7 +52,7 @@ public interface ITypeMarshalBuffer {
EXEC_DECLARATION_STATEMENT = 0x05, EXEC_DECLARATOR = 0x06, EXEC_DEFAULT = 0x07,
EXEC_SIMPLE_DECLARATION = 0x08, EXEC_RETURN = 0x09, EXEC_EXPRESSION_STATEMENT = 0x0A, EXEC_IF = 0x0B,
EXEC_WHILE = 0x0C, EXEC_DO = 0x0D, EXEC_FOR = 0x0E, EXEC_RANGE_BASED_FOR = 0x0F, EXEC_SWITCH = 0x10,
- EXEC_CONSTRUCTOR_CHAIN = 0x11;
+ EXEC_CONSTRUCTOR_CHAIN = 0x11, EXEC_INCOMPLETE = 0x12;
// Can add more executions up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
static final short KIND_MASK = 0x001F;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
index e2a026f862a..24eeb562e32 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java
@@ -27,6 +27,8 @@ public class ProblemType implements IProblemType, ISerializableType {
public static final IType AUTO_FOR_VIRTUAL_METHOD = new ProblemType(TYPE_AUTO_FOR_VIRTUAL_METHOD);
public static final IType CANNOT_DEDUCE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_AUTO_TYPE);
public static final IType CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE);
+ public static final IType CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE = new ProblemType(
+ TYPE_CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
public static final IType ENUMERATION_EXPECTED = new ProblemType(TYPE_ENUMERATION_EXPECTED);
public static final IType NO_NAME = new ProblemType(TYPE_NO_NAME);
public static final IType NOT_PERSISTED = new ProblemType(TYPE_NOT_PERSISTED);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
index d693071b73a..fb757d85f89 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/VariableReadWriteFlags.java
@@ -51,8 +51,10 @@ import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
@@ -96,6 +98,8 @@ public abstract class VariableReadWriteFlags {
if (binding instanceof IVariable) {
return rwAssignmentToType(((IVariable) binding).getType(), indirection);
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
@@ -113,10 +117,21 @@ public abstract class VariableReadWriteFlags {
}
}
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
+ protected int rwInStructuredBinding(ICPPASTStructuredBindingDeclaration declaration) {
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier != null && !declaration.getDeclSpecifier().isConst()) {
+ return READ | WRITE;
+ } else {
+ return READ;
+ }
+ }
+
protected int rwInExpression(IASTExpression expr, IASTNode node, int indirection) {
if (expr instanceof IASTIdExpression) {
return rwAnyNode(expr, indirection);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
index e8d638ce2b9..b15def18a0f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTImplicitName.java
@@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.Keywords;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTNodeSearch;
@@ -35,6 +36,10 @@ public class CPPASTImplicitName extends CPPASTName implements IASTImplicitName {
private boolean isOperator;
private boolean isDefinition;
+ public CPPASTImplicitName(IASTNode parent) {
+ this(CharArrayUtils.EMPTY, parent);
+ }
+
public CPPASTImplicitName(char[] name, IASTNode parent) {
super(name);
setParent(parent);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
index a7d76c5f1ff..5ab051c26a3 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleDeclaration.java
@@ -46,11 +46,15 @@ public class CPPASTSimpleDeclaration extends CPPASTAttributeOwner implements IAS
@Override
public CPPASTSimpleDeclaration copy(CopyStyle style) {
CPPASTSimpleDeclaration copy = new CPPASTSimpleDeclaration();
+ return copy(copy, style);
+ }
+
+ protected <T extends CPPASTSimpleDeclaration> T copy(T copy, CopyStyle style) {
copy.setDeclSpecifier(declSpecifier == null ? null : declSpecifier.copy(style));
for (IASTDeclarator declarator : getDeclarators()) {
copy.addDeclarator(declarator == null ? null : declarator.copy(style));
}
- return copy(copy, style);
+ return super.copy(copy, style);
}
@Override
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java
new file mode 100644
index 00000000000..41779d21ff6
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTStructuredBindingDeclaration.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import java.util.Arrays;
+
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
+import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecDeclarator;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIncomplete;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclaration;
+import org.eclipse.jdt.annotation.NonNull;
+
+public class CPPASTStructuredBindingDeclaration extends CPPASTSimpleDeclaration
+ implements ICPPASTStructuredBindingDeclaration {
+
+ private RefQualifier refQualifier;
+ private IASTName[] names;
+ private IASTInitializer initializer;
+ private IASTImplicitName implicitInitializerName;
+
+ public CPPASTStructuredBindingDeclaration() {
+ }
+
+ public CPPASTStructuredBindingDeclaration(IASTDeclSpecifier declSpecifier, RefQualifier refQualifier,
+ IASTName[] names, IASTInitializer initializer) {
+ super(declSpecifier);
+ this.refQualifier = refQualifier;
+ for (IASTName name : names) {
+ addName(name);
+ }
+ setInitializer(initializer);
+ }
+
+ @Override
+ public RefQualifier getRefQualifier() {
+ return refQualifier;
+ }
+
+ public void setRefQualifier(RefQualifier refQualifier) {
+ assertNotFrozen();
+ this.refQualifier = refQualifier;
+ }
+
+ @Override
+ public IASTName[] getNames() {
+ if (names == null) {
+ return IASTName.EMPTY_NAME_ARRAY;
+ }
+ names = ArrayUtil.trim(names);
+ return names;
+ }
+
+ @Override
+ public IASTInitializer getInitializer() {
+ return initializer;
+ }
+
+ @Override
+ public boolean accept(ASTVisitor action) {
+ if (action.shouldVisitDeclarations) {
+ switch (action.visit(this)) {
+ case ASTVisitor.PROCESS_ABORT:
+ return false;
+ case ASTVisitor.PROCESS_SKIP:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ IASTDeclSpecifier declSpecifier = getDeclSpecifier();
+ if (declSpecifier != null && !declSpecifier.accept(action)) {
+ return false;
+ }
+
+ for (IASTName name : getNames()) {
+ if (!name.accept(action)) {
+ return false;
+ }
+ }
+
+ if (initializer != null && !initializer.accept(action)) {
+ return false;
+ }
+
+ if (action.shouldVisitImplicitNames && !getImplicitNames()[0].accept(action)) {
+ return false;
+ }
+
+ if (action.shouldVisitDeclarations) {
+ switch (action.leave(this)) {
+ case ASTVisitor.PROCESS_ABORT:
+ return false;
+ case ASTVisitor.PROCESS_SKIP:
+ return true;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
+ protected void addName(IASTName name) {
+ assertNotFrozen();
+ if (name != null) {
+ names = ArrayUtil.append(IASTName.class, names, name);
+ name.setParent(this);
+ name.setPropertyInParent(IDENTIFIER);
+ }
+ }
+
+ protected void setInitializer(IASTInitializer initializer) {
+ assertNotFrozen();
+ if (initializer != null) {
+ this.initializer = initializer;
+ initializer.setParent(this);
+ initializer.setPropertyInParent(INITIALIZER);
+ }
+ }
+
+ @Override
+ public CPPASTStructuredBindingDeclaration copy() {
+ return copy(CopyStyle.withoutLocations);
+ }
+
+ @Override
+ public CPPASTStructuredBindingDeclaration copy(CopyStyle style) {
+ CPPASTStructuredBindingDeclaration copy = new CPPASTStructuredBindingDeclaration();
+ return copy(copy, style);
+ }
+
+ protected <T extends CPPASTStructuredBindingDeclaration> T copy(@NonNull T copy, CopyStyle style) {
+ copy.setRefQualifier(refQualifier);
+ if (initializer != null) {
+ copy.setInitializer(initializer.copy(style));
+ }
+
+ for (IASTName name : names) {
+ if (name == null) {
+ break;
+ }
+ copy.addName(name.copy(style));
+ }
+ return super.copy(copy, style);
+ }
+
+ @Override
+ public ICPPExecution getExecution() {
+ IASTName[] names = getNames();
+ ICPPExecution[] nameExecutions = Arrays.stream(names).map(name -> {
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof CPPVariable) {
+ CPPVariable variable = (CPPVariable) binding;
+ ICPPEvaluation initializerEval = variable.getInitializerEvaluation();
+ return new ExecDeclarator((ICPPBinding) binding, initializerEval);
+ }
+ return ExecIncomplete.INSTANCE;
+ }).toArray(ICPPExecution[]::new);
+ return new ExecSimpleDeclaration(nameExecutions);
+ }
+
+ @Override
+ public int getRoleForName(IASTName name) {
+ return r_definition;
+ }
+
+ @Override
+ public IASTImplicitName[] getImplicitNames() {
+ if (implicitInitializerName == null) {
+ ICPPEvaluation initializerEvaluation = CPPVariable.evaluationOfInitializer(initializer);
+ if (initializerEvaluation == null) {
+ initializerEvaluation = EvalFixed.INCOMPLETE;
+ }
+ CPPASTImplicitName implicitName = new CPPASTImplicitName(this);
+ implicitName.setIsDefinition(true);
+ if (initializer != null) {
+ implicitName.setOffsetAndLength((ASTNode) initializer);
+ }
+ implicitInitializerName = implicitName;
+ CPPStructuredBindingComposite implicitInitializerVariable = new CPPStructuredBindingComposite(
+ implicitInitializerName, initializerEvaluation);
+ implicitInitializerName.setBinding(implicitInitializerVariable);
+ }
+ return new IASTImplicitName[] { implicitInitializerName };
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java
new file mode 100644
index 00000000000..c4ec33b459a
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitVariable.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.IValue;
+
+/**
+ * Represents a variable implicitly created in C++ code.
+ * For example the initializer of a structured binding decomposition [dcl.struct.bind]:
+ * <code>auto [first, second] = decomposed;</code>
+ *
+ * The <code>initializerEvaluation</code> has to be supplied.
+ *
+ */
+public class CPPImplicitVariable extends CPPVariable {
+
+ private ICPPEvaluation initializerEvaluation;
+
+ public CPPImplicitVariable(IASTImplicitName name, ICPPEvaluation initializerEvaluation) {
+ super(name);
+ this.initializerEvaluation = initializerEvaluation;
+ }
+
+ @Override
+ public ICPPEvaluation getInitializerEvaluation() {
+ return initializerEvaluation;
+ }
+
+ @Override
+ public IType getType() {
+ return initializerEvaluation.getType();
+ }
+
+ @Override
+ public IValue getInitialValue() {
+ return initializerEvaluation.getValue();
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
index 176335f6c0b..b659a58cc17 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java
@@ -91,6 +91,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
@@ -119,6 +120,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -914,4 +916,15 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory {
public ICPPASTWhileStatement newWhileStatement(IASTExpression condition, IASTStatement body) {
return new CPPASTWhileStatement(condition, body);
}
+
+ @Override
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration() {
+ return new CPPASTStructuredBindingDeclaration();
+ }
+
+ @Override
+ public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration(ICPPASTSimpleDeclSpecifier declSpecifier,
+ RefQualifier refQualifier, IASTName[] names, IASTInitializer initializer) {
+ return new CPPASTStructuredBindingDeclaration(declSpecifier, refQualifier, names, initializer);
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java
new file mode 100644
index 00000000000..e9c1bbc85b1
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPStructuredBindingComposite.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Institute for Software, HSR Hochschule fuer Technik
+ * Rapperswil, University of applied sciences.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Thomas Corbat (IFS) - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core.dom.parser.cpp;
+
+import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor.IS_STATIC_VARIABLE;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IArrayType;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.ICompositeType;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IScope;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
+import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinary;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinding;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionCall;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalMemberAccess;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.LookupData;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
+
+/**
+ * Represents the implicit object created for the initializer of a structured binding declaration.
+ * It is used for caching the evaluation strategy used to determine the <code>ICPPEvaluation</code> of
+ * the names introduced by the declaration.
+ *
+ */
+public class CPPStructuredBindingComposite extends CPPImplicitVariable {
+
+ private static final char[] GET_NAME = "get".toCharArray(); //$NON-NLS-1$
+ private static final IStructuredBindingNameEvaluationStrategy INCOMPLETE_INITIALIZER = new IStructuredBindingNameEvaluationStrategy() {
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ return EvalFixed.INCOMPLETE;
+ }
+ };
+
+ private IStructuredBindingNameEvaluationStrategy evaluationStrategy = null;
+ private ICPPASTStructuredBindingDeclaration declaration;
+
+ public CPPStructuredBindingComposite(IASTImplicitName name, ICPPEvaluation initializerEvaluation) {
+ super(name, initializerEvaluation);
+ IASTNode nameParent = name.getParent();
+ assert (nameParent instanceof ICPPASTStructuredBindingDeclaration);
+ this.declaration = (ICPPASTStructuredBindingDeclaration) nameParent;
+ }
+
+ public ICPPEvaluation getEvaluationForName(IASTName name) {
+ int index = ArrayUtil.indexOf(declaration.getNames(), name);
+ return getNameEvaluationStrategy().getEvaluation(index);
+ }
+
+ private IStructuredBindingNameEvaluationStrategy getNameEvaluationStrategy() {
+ if (evaluationStrategy == null) {
+ evaluationStrategy = createEvaluationStrategy(declaration);
+ }
+ return evaluationStrategy;
+ }
+
+ private IStructuredBindingNameEvaluationStrategy createEvaluationStrategy(
+ ICPPASTStructuredBindingDeclaration structuredBinding) {
+ IASTInitializer initializer = structuredBinding.getInitializer();
+ ICPPEvaluation initializerEvaluation = getInitializerEvaluation();
+ if (initializer != null && initializerEvaluation != null) {
+ IType initializerType = getType();
+ IType unwrappedType = SemanticUtil.getNestedType(initializerType, SemanticUtil.ALLCVQ | SemanticUtil.REF);
+ if (unwrappedType instanceof IArrayType) {
+ return new ArrayElement(initializer, initializerEvaluation);
+ }
+ if (unwrappedType instanceof ICPPClassType) {
+ IASTName[] definedNames = structuredBinding.getNames();
+ long numberOfNames = definedNames.length;
+ ICPPClassType classType = (ICPPClassType) unwrappedType;
+ if (numberOfNames > 0) {
+ IScope scope = CPPSemantics.getLookupScope(definedNames[0]);
+ Optional<ICPPClassSpecialization> tupleSizeInstance = CPPVisitor
+ .findTupleSizeWithValueMember(unwrappedType, scope, structuredBinding);
+ if (tupleSizeInstance.isPresent()) {
+ if (CPPVisitor.hasConstexprStaticIntegralValueField(tupleSizeInstance.get(), numberOfNames)) {
+ return new TupleElement(initializer, initializerEvaluation, classType);
+ }
+ } else {
+ return new MemberElement(initializer, initializerEvaluation, classType);
+ }
+ }
+ }
+ }
+ return INCOMPLETE_INITIALIZER;
+ }
+
+ private abstract static class IStructuredBindingNameEvaluationStrategy {
+ abstract public ICPPEvaluation getEvaluation(int nameIndex);
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has array type.
+ */
+ private class ArrayElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+
+ private ArrayElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ EvalFixed indexEvaluation = new EvalFixed(CPPBasicType.UNSIGNED_INT, ValueCategory.PRVALUE,
+ IntegralValue.create(nameIndex));
+ return new EvalBinary(EvalBinary.op_arrayAccess, initializerEvaluation, indexEvaluation, initializer);
+ }
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has class type for which std::tuple_size is specialized.
+ */
+ private class TupleElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+ private ICPPClassType initializerType;
+
+ private TupleElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation,
+ ICPPClassType initializerType) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ this.initializerType = initializerType;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ EvalFixed indexEvaluation = new EvalFixed(CPPBasicType.UNSIGNED_INT, ValueCategory.PRVALUE,
+ IntegralValue.create(nameIndex));
+ IBinding resolvedFunction = resolveGetFunction(initializerType, initializer, initializerEvaluation,
+ indexEvaluation);
+ if (resolvedFunction instanceof ICPPMethod) {
+ ICPPEvaluation eExpressionEvaluation = new EvalMemberAccess(initializerType,
+ initializerEvaluation.getValueCategory(), resolvedFunction, initializerEvaluation, false,
+ initializer);
+ return new EvalFunctionCall(new ICPPEvaluation[] { eExpressionEvaluation }, null, initializer);
+ } else if (resolvedFunction instanceof ICPPFunction) {
+ EvalBinding functionEvaluation = new EvalBinding(resolvedFunction,
+ ((ICPPFunction) resolvedFunction).getType(), initializer);
+ return new EvalFunctionCall(new ICPPEvaluation[] { functionEvaluation, initializerEvaluation }, null,
+ initializer);
+ }
+ return EvalFixed.INCOMPLETE;
+ }
+
+ /**
+ *
+ * Resolves the member or non-member get() function template for a type and given arguments.
+ *
+ * Returns {@code null} if the function cannot be resolved
+ */
+ private IBinding resolveGetFunction(ICompositeType classType, IASTNode point, ICPPEvaluation argument,
+ ICPPEvaluation index) {
+ //find member and non-member get() bindings in class scope and all parent scopes
+ IBinding[] allGetBindings = CPPSemantics.findBindings(classType.getCompositeScope(), GET_NAME, false,
+ point);
+ ICPPFunction[] functions = Arrays.stream(allGetBindings).filter(IFunction.class::isInstance)
+ .map(IFunction.class::cast).toArray(ICPPFunction[]::new);
+ ICPPTemplateArgument[] arguments = new ICPPTemplateArgument[] { new CPPTemplateNonTypeArgument(index) };
+ LookupData lookupGet = new LookupData(GET_NAME, arguments, point);
+ //LookupData::containsImpliedObject is ignored for non-member functions in CPPSemantics.resolveFunction
+ //and will therefore find the the free get function using the arguments
+ lookupGet.setFunctionArguments(true, argument);
+ try {
+ return CPPSemantics.resolveFunction(lookupGet, functions, true, true);
+ } catch (DOMException e) {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Name evaluation strategy for the case in which the initializer has class type with public members.
+ */
+ private class MemberElement extends IStructuredBindingNameEvaluationStrategy {
+ private IASTInitializer initializer;
+ private ICPPEvaluation initializerEvaluation;
+ private ICPPClassType initializerType;
+
+ private MemberElement(IASTInitializer initializer, ICPPEvaluation initializerEvaluation,
+ ICPPClassType initializerType) {
+ this.initializer = initializer;
+ this.initializerEvaluation = initializerEvaluation;
+ this.initializerType = initializerType;
+ }
+
+ @Override
+ public ICPPEvaluation getEvaluation(int nameIndex) {
+ IField[] nonStaticFields = Arrays.stream(ClassTypeHelper.getFields(initializerType))
+ .filter(IS_STATIC_VARIABLE.negate()).toArray(IField[]::new);
+ //TODO (tcorbat): Further restrictions to structured bindings that are not checked. Maybe add a Codan checker.
+ // * Add further check that all members origin from the same class/base class
+ // * classType must not have an anonymous union member
+ // * Check accessibility of the members
+ if (nameIndex >= 0 && nameIndex < nonStaticFields.length) {
+ IField boundField = nonStaticFields[nameIndex];
+ return new EvalMemberAccess(initializerType, initializerEvaluation.getValueCategory(), boundField,
+ initializerEvaluation, false, initializer);
+ }
+ return EvalFixed.INCOMPLETE;
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
index 9bce0ccd1fe..b77e1b87038 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java
@@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
@@ -41,6 +42,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -52,7 +54,6 @@ import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConstructor;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalUtil;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.core.runtime.PlatformObject;
@@ -258,7 +259,7 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
IValue initialValue = null;
final IType nestedType = SemanticUtil.getNestedType(getType(), TDEF | REF | CVTYPE);
if (nestedType instanceof ICPPClassType || (initialValue = VariableHelpers.getInitialValue(fDefinition,
- fDeclarations, getType())) == IntegralValue.UNKNOWN) {
+ fDeclarations, getType())) == IntegralValue.UNKNOWN || getStructuredBindingDeclaration() != null) {
ICPPEvaluation initEval = getInitializerEvaluation();
if (initEval == null) {
return null;
@@ -319,21 +320,48 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
if (constructor != null) {
ICPPEvaluation[] arguments = EvalConstructor.extractArguments(initializer, constructor);
return new EvalConstructor(getType(), constructor, arguments, declarator);
- } else if (initializer instanceof IASTEqualsInitializer) {
- IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
- ICPPASTInitializerClause clause = (ICPPASTInitializerClause) equalsInitializer.getInitializerClause();
- return clause.getEvaluation();
- } else if (initializer instanceof ICPPASTInitializerList) {
- return ((ICPPASTInitializerClause) initializer).getEvaluation();
- } else if (initializer instanceof ICPPASTConstructorInitializer) {
- ICPPASTConstructorInitializer ctorInitializer = (ICPPASTConstructorInitializer) initializer;
- ICPPASTInitializerClause evalOwner = (ICPPASTInitializerClause) ctorInitializer.getArguments()[0];
- return evalOwner.getEvaluation();
- } else if (initializer == null) {
- return null;
}
+ return evaluationOfInitializer(initializer);
}
- return EvalFixed.INCOMPLETE;
+
+ ICPPASTStructuredBindingDeclaration structuredBinding = getStructuredBindingDeclaration();
+ if (structuredBinding != null) {
+ return evaluationOfStructuredBindingInitializer(structuredBinding);
+ }
+ return null;
+ }
+
+ private ICPPEvaluation evaluationOfStructuredBindingInitializer(
+ ICPPASTStructuredBindingDeclaration structuredBinding) {
+ IASTImplicitName implicitName = structuredBinding.getImplicitNames()[0];
+ CPPStructuredBindingComposite variable = (CPPStructuredBindingComposite) implicitName.getBinding();
+ return variable.getEvaluationForName(fDefinition);
+ }
+
+ public static ICPPEvaluation evaluationOfInitializer(IASTInitializer initializer) {
+ if (initializer instanceof IASTEqualsInitializer) {
+ IASTEqualsInitializer equalsInitializer = (IASTEqualsInitializer) initializer;
+ ICPPASTInitializerClause clause = (ICPPASTInitializerClause) equalsInitializer.getInitializerClause();
+ return clause.getEvaluation();
+ } else if (initializer instanceof ICPPASTInitializerList) {
+ return ((ICPPASTInitializerClause) initializer).getEvaluation();
+ } else if (initializer instanceof ICPPASTConstructorInitializer) {
+ ICPPASTConstructorInitializer ctorInitializer = (ICPPASTConstructorInitializer) initializer;
+ ICPPASTInitializerClause evalOwner = (ICPPASTInitializerClause) ctorInitializer.getArguments()[0];
+ return evalOwner.getEvaluation();
+ }
+ return null;
+ }
+
+ private ICPPASTStructuredBindingDeclaration getStructuredBindingDeclaration() {
+ IASTNode definition = getDefinition();
+ if (definition != null) {
+ IASTNode parent = definition.getParent();
+ if (parent instanceof ICPPASTStructuredBindingDeclaration) {
+ return (ICPPASTStructuredBindingDeclaration) parent;
+ }
+ }
+ return null;
}
private static ICPPConstructor getImplicitlyCalledCtor(ICPPASTDeclarator declarator) {
@@ -350,4 +378,5 @@ public class CPPVariable extends PlatformObject implements ICPPInternalDeclaredV
public void allDeclarationsDefinitionsAdded() {
fAllResolved = true;
}
+
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
index cf8815ba4fd..ebdf710df1d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java
@@ -134,6 +134,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -2886,6 +2887,51 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return super.isLegalWithoutDtor(declSpec);
}
+ private RefQualifier optionalRefQualifier() throws EndOfFileException {
+ int nextToken = LT(1);
+ switch (nextToken) {
+ case IToken.tAMPER:
+ consume();
+ return RefQualifier.LVALUE;
+
+ case IToken.tAND:
+ consume();
+ return RefQualifier.RVALUE;
+
+ default:
+ return null;
+ }
+ }
+
+ private ICPPASTStructuredBindingDeclaration structuredBinding(ICPPASTSimpleDeclSpecifier simpleDeclSpecifier,
+ List<IASTAttributeSpecifier> attributes) throws BacktrackException, EndOfFileException {
+ RefQualifier refQualifier = optionalRefQualifier();
+ consume(IToken.tLBRACKET);
+ IASTName[] identifiers = identifierList();
+ int endOffset = consume(IToken.tRBRACKET).getEndOffset();
+
+ IASTInitializer initializer = null;
+ if (LT(1) != IToken.tCOLON) {
+ switch (LT(1)) {
+ case IToken.tASSIGN:
+ initializer = equalsInitalizerClause(false);
+ break;
+ case IToken.tLBRACE:
+ case IToken.tLPAREN:
+ initializer = bracedOrCtorStyleInitializer();
+ break;
+ }
+
+ endOffset = consume(IToken.tSEMI).getEndOffset();
+ }
+
+ ICPPASTStructuredBindingDeclaration structuredBinding = getNodeFactory()
+ .newStructuredBindingDeclaration(simpleDeclSpecifier, refQualifier, identifiers, initializer);
+ setRange(structuredBinding, simpleDeclSpecifier, endOffset);
+ addAttributeSpecifiers(attributes, structuredBinding);
+ return structuredBinding;
+ }
+
/**
* Parses a declaration with the given options.
*/
@@ -2903,6 +2949,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IASTDeclSpecifier altDeclSpec = null;
IASTDeclarator altDtor = null;
IToken markBeforDtor = null;
+ boolean isAtStartOfStructuredBinding = false;
try {
Decl decl = declSpecifierSequence_initDeclarator(declOption, true);
markBeforDtor = decl.fDtorToken1;
@@ -2910,6 +2957,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
dtor = decl.fDtor1;
altDeclSpec = decl.fDeclSpec2;
altDtor = decl.fDtor2;
+ isAtStartOfStructuredBinding = decl.isAtStartOfStructuredBinding;
} catch (FoundAggregateInitializer lie) {
declSpec = lie.fDeclSpec;
// scalability: don't keep references to tokens, initializer may be large
@@ -2925,6 +2973,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throw e;
}
+ if (isAtStartOfStructuredBinding && declSpec instanceof ICPPASTSimpleDeclSpecifier) {
+ ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec;
+ return structuredBinding(simpleDeclSpecifier, attributes);
+ }
+
IASTDeclarator[] declarators = IASTDeclarator.EMPTY_DECLARATOR_ARRAY;
if (dtor != null) {
declarators = new IASTDeclarator[] { dtor };
@@ -4765,17 +4818,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
// ref-qualifiers
- switch (LT(1)) {
- case IToken.tAMPER:
- fc.setRefQualifier(RefQualifier.LVALUE);
- endOffset = consume().getEndOffset();
- break;
- case IToken.tAND:
- fc.setRefQualifier(RefQualifier.RVALUE);
- endOffset = consume().getEndOffset();
- break;
- default:
- break;
+ RefQualifier refQualifier = optionalRefQualifier();
+ if (refQualifier != null) {
+ fc.setRefQualifier(refQualifier);
+ endOffset = getEndOffset();
}
// throws clause
@@ -5673,4 +5719,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
IASTAlignmentSpecifier typeId) {
return new CPPASTAmbiguousAlignmentSpecifier(expression, typeId);
}
+
+ protected IASTName[] identifierList() throws EndOfFileException, BacktrackException {
+ List<IASTName> result = new ArrayList<>();
+ result.add(identifier());
+ while (LT(1) == IToken.tCOMMA) {
+ consume();
+ result.add(identifier());
+ }
+ return result.toArray(new IASTName[result.size()]);
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
index df7c37954fd..34adee0f83b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/VariableHelpers.java
@@ -31,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
@@ -120,6 +121,9 @@ public class VariableHelpers {
if (firstCandidate == null) {
firstCandidate = (IArrayType) t;
}
+ } else if (node instanceof ICPPASTStructuredBindingDeclaration) {
+ ICPPASTStructuredBindingDeclaration parent = (ICPPASTStructuredBindingDeclaration) node;
+ return CPPVisitor.createType(parent, n);
}
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
index 6728e38cb71..bcb87fc8d92 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java
@@ -141,6 +141,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -938,7 +939,7 @@ public class CPPSemantics {
}
}
- static ICPPScope getLookupScope(IASTName name) throws DOMException {
+ public static ICPPScope getLookupScope(IASTName name) {
IASTNode parent = name.getParent();
IScope scope = null;
if (parent instanceof ICPPASTBaseSpecifier) {
@@ -1822,7 +1823,9 @@ public class CPPSemantics {
return;
}
- if (declaration instanceof IASTSimpleDeclaration) {
+ if (declaration instanceof ICPPASTStructuredBindingDeclaration) {
+ handleStructuredBinding((ICPPASTStructuredBindingDeclaration) declaration, scope);
+ } else if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration;
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
IASTDeclarator[] declarators = simpleDeclaration.getDeclarators();
@@ -1944,6 +1947,12 @@ public class CPPSemantics {
}
}
+ private static void handleStructuredBinding(ICPPASTStructuredBindingDeclaration structuredBinding, IScope scope) {
+ for (IASTName name : structuredBinding.getNames()) {
+ ASTInternal.addName(scope, name);
+ }
+ }
+
private static void handleEnumeration(ICPPASTEnumerationSpecifier enumSpec, IScope enclosingScope) {
// Add unscoped enumerators to the enclosing scope
if (!enumSpec.isScoped()) {
@@ -2647,6 +2656,11 @@ public class CPPSemantics {
return result;
}
+ /**
+ * Resolves the {@code IBinding} for given {@code LookupData} in the set of function bindings {@code fns}.
+ * It supports mixed member/non-member lookup. {@code LookupData::argContainsImpliedObject} is ignored for
+ * non-member lookup.
+ */
public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, boolean allowUDC,
boolean resolveTargetedArgumentTypes) throws DOMException {
final IASTName lookupName = data.getLookupName();
@@ -4262,6 +4276,14 @@ public class CPPSemantics {
* in the given scope.
*/
public static IBinding[] findBindingsForQualifiedName(IScope scope, String qualifiedName) {
+ return findBindingsForQualifiedName(scope, qualifiedName, null);
+ }
+
+ /**
+ * Uses C++ lookup semantics to find the possible bindings for the given qualified name starting
+ * in the given scope.
+ */
+ public static IBinding[] findBindingsForQualifiedName(IScope scope, String qualifiedName, IASTNode beforeNode) {
// Return immediately if the qualifiedName does not match a known format.
Matcher m = QUALNAME_REGEX.matcher(qualifiedName);
if (!m.matches())
@@ -4284,7 +4306,7 @@ public class CPPSemantics {
Set<IBinding> bindings = new HashSet<>();
// Look for the name in the given scope.
- findBindingsForQualifiedName(scope, qualifiedName, bindings);
+ findBindingsForQualifiedName(scope, qualifiedName, bindings, beforeNode);
// If the qualified name is not rooted in the global namespace (with a leading ::), then
// look at all parent scopes.
@@ -4293,7 +4315,7 @@ public class CPPSemantics {
while (scope != null) {
scope = scope.getParent();
if (scope != null)
- findBindingsForQualifiedName(scope, qualifiedName, bindings);
+ findBindingsForQualifiedName(scope, qualifiedName, bindings, beforeNode);
}
} catch (DOMException e) {
CCorePlugin.log(e);
@@ -4303,8 +4325,8 @@ public class CPPSemantics {
return bindings.size() == 0 ? IBinding.EMPTY_BINDING_ARRAY : bindings.toArray(new IBinding[bindings.size()]);
}
- private static void findBindingsForQualifiedName(IScope scope, String qualifiedName,
- Collection<IBinding> bindings) {
+ private static void findBindingsForQualifiedName(IScope scope, String qualifiedName, Collection<IBinding> bindings,
+ IASTNode beforeNode) {
// Split the qualified name into the first part (before the first :: qualifier) and the rest. All
// bindings for the first part are found and their scope is used to find the rest of the name. When
// the call tree gets to a leaf (non-qualified name) then a simple lookup happens and all matching
@@ -4318,14 +4340,20 @@ public class CPPSemantics {
// When we're down to a single component name, then use the normal lookup method.
if (part2 == null || part2.isEmpty()) {
- bindings.addAll(Arrays.asList(findBindings(scope, part1, false)));
+ bindings.addAll(Arrays.asList(findBindings(scope, part1.toCharArray(), false, beforeNode)));
return;
}
// Find all bindings that match the first part of the name. For each such binding,
// lookup the second part of the name.
- for (IBinding binding : findBindings(scope, part1, false)) {
- findBindingsForQualifiedName(getLookupScope(binding), part2, bindings);
+ for (IBinding binding : findBindings(scope, part1.toCharArray(), false, beforeNode)) {
+ IScope lookupScope;
+ if (binding instanceof IScope) {
+ lookupScope = (IScope) binding;
+ } else {
+ lookupScope = getLookupScope(binding);
+ }
+ findBindingsForQualifiedName(lookupScope, part2, bindings, beforeNode);
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
index 6f8b4d518c0..e5ee18de9fa 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java
@@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -108,6 +109,8 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
return rwAssignmentToType(type, indirection);
}
}
+ } else if (grand instanceof ICPPASTStructuredBindingDeclaration) {
+ return rwInStructuredBinding((ICPPASTStructuredBindingDeclaration) grand);
}
return READ | WRITE; // fallback
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index bff715b23a8..02d25f564e8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -31,7 +31,11 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
@@ -90,6 +94,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
+import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.ILabel;
@@ -141,6 +146,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
@@ -155,6 +161,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -224,6 +231,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedef;
@@ -231,6 +239,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownTypeScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
@@ -249,6 +258,10 @@ public class CPPVisitor extends ASTQueries {
private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$
private static final char[] INITIALIZER_LIST = "initializer_list".toCharArray(); //$NON-NLS-1$
private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {};
+ private static final String STD_TUPLE_SIZE_STR = STD + "::tuple_size"; //$NON-NLS-1$
+ private static final String STD_TUPLE_ELEMENT_STR = STD + "::tuple_element"; //$NON-NLS-1$
+ private static final String VALUE_STR = "value"; //$NON-NLS-1$
+ private static final String TYPE_STR = "type"; //$NON-NLS-1$
public static final IASTInitializerClause[] NO_ARGS = {};
// Flags for createType().
@@ -273,6 +286,19 @@ public class CPPVisitor extends ASTQueries {
}
};
+ public static final Predicate<IVariable> IS_STATIC_VARIABLE = IVariable::isStatic;
+ private static final Predicate<IVariable> HAS_INTEGRAL_TYPE = variable -> BuiltinOperators
+ .isIntegral(SemanticUtil.getUltimateTypeUptoPointers(variable.getType()));
+ private static final Predicate<IVariable> HAS_CONST_TYPE = field -> ExpressionTypes.isConst(field.getType());
+ private static final Predicate<IBinding> IS_NAMED_VALUE = binding -> binding.getName().equals(VALUE_STR);
+
+ /**
+ * Required until Java 9 Optional.stream()
+ */
+ private static final <E> Stream<E> toStream(Optional<E> optional) {
+ return optional.map(Stream::of).orElse(Stream.empty());
+ }
+
public static IBinding createBinding(IASTName name) {
IASTNode parent = name.getParent();
IBinding binding = null;
@@ -326,6 +352,8 @@ public class CPPVisitor extends ASTQueries {
return createBinding((IASTDeclarator) parent);
} else if (parent instanceof ICPPASTElaboratedTypeSpecifier) {
return createBinding((ICPPASTElaboratedTypeSpecifier) parent);
+ } else if (parent instanceof ICPPASTStructuredBindingDeclaration) {
+ return new CPPVariable(name);
} else if (parent instanceof IASTDeclaration) {
return createBinding((IASTDeclaration) parent);
} else if (parent instanceof ICPPASTEnumerationSpecifier) {
@@ -1641,7 +1669,8 @@ public class CPPVisitor extends ASTQueries {
case KIND_OBJ_FN:
if (prop == IASTDeclarator.DECLARATOR_NAME
|| prop == IASTEnumerationSpecifier.IASTEnumerator.ENUMERATOR_NAME
- || prop == ICPPASTUsingDeclaration.NAME) {
+ || prop == ICPPASTUsingDeclaration.NAME
+ || prop == ICPPASTStructuredBindingDeclaration.IDENTIFIER) {
break;
}
return PROCESS_CONTINUE;
@@ -1936,6 +1965,146 @@ public class CPPVisitor extends ASTQueries {
return pt;
}
+ private static boolean hasFieldNamedValue(ICPPClassSpecialization instance) {
+ return Arrays.stream(instance.getFields()).anyMatch(field -> field.getName().equals(VALUE_STR));
+ }
+
+ public static Optional<ICPPClassSpecialization> findTupleSizeWithValueMember(IType type, IScope scope,
+ IASTNode beforeNode) {
+ ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) };
+ return findClassTemplateInstance(scope, STD_TUPLE_SIZE_STR, templateArguments, beforeNode)
+ .filter(CPPVisitor::hasFieldNamedValue);
+ }
+
+ private static Optional<ICPPClassSpecialization> findClassTemplateInstance(IScope scope, String templateName,
+ ICPPTemplateArgument[] templateArguments, IASTNode point) {
+ IBinding[] tupleSizeBindings = CPPSemantics.findBindingsForQualifiedName(scope, templateName, point);
+ return Arrays.stream(tupleSizeBindings).filter(ICPPClassTemplate.class::isInstance)
+ .map(ICPPClassTemplate.class::cast)
+ .map(template -> CPPTemplates.instantiate(template, templateArguments))
+ .filter(ICPPClassSpecialization.class::isInstance).map(ICPPClassSpecialization.class::cast)
+ .filter(Objects::nonNull).findFirst();
+ }
+
+ private static IType determineTupleElementType(IType type, IScope scope, IASTName name, int index) {
+ ICPPTemplateArgument indexArgument = new CPPTemplateNonTypeArgument(IntegralValue.create(index),
+ CPPVisitor.get_SIZE_T());
+ ICPPTemplateArgument[] templateArguments = new ICPPTemplateArgument[] { indexArgument,
+ new CPPTemplateTypeArgument(type) };
+ return toStream(findClassTemplateInstance(scope, STD_TUPLE_ELEMENT_STR, templateArguments, name))
+ .map(ICPPClassSpecialization::getCompositeScope)
+ // Look for "type" in class scope with CPPSemantics.findBindings to also consider base classes
+ .map(instanceScope -> CPPSemantics.findBindings(instanceScope, TYPE_STR.toCharArray(), false, name))
+ .flatMap(Arrays::stream).filter(IType.class::isInstance).map(IType.class::cast)
+ .map(SemanticUtil::getSimplifiedType).findFirst()
+ .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
+ }
+
+ private static ICPPASTInitializerClause getInitializerClause(ICPPASTStructuredBindingDeclaration declaration) {
+ IASTInitializer initializer = declaration.getInitializer();
+ ICPPASTInitializerClause initClause = null;
+ if (initializer != null) {
+ initClause = getInitClauseForInitializer(initializer);
+ } else {
+ IASTNode declarationParent = declaration.getParent();
+ if (declarationParent instanceof ICPPASTRangeBasedForStatement) {
+ ICPPASTRangeBasedForStatement rangeBasedForParent = (ICPPASTRangeBasedForStatement) declarationParent;
+ initClause = getAutoInitClauseForRangeBasedFor(rangeBasedForParent);
+ }
+ }
+ return initClause;
+ }
+
+ public static IType createType(ICPPASTStructuredBindingDeclaration declaration, IASTName name) {
+ ICPPASTInitializerClause initClause = getInitializerClause(declaration);
+
+ if (initClause == null) {
+ return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE;
+ }
+
+ ICPPEvaluation evaluation = initClause.getEvaluation();
+ IType eType = evaluation.getType();
+ IType unwrappedType = SemanticUtil.getNestedType(eType, TDEF | ALLCVQ);
+ IType initializerType = deduceInitializerType(declaration, name, unwrappedType);
+ if (initializerType == ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE) {
+ return initializerType;
+ }
+ IASTDeclSpecifier declSpec = declaration.getDeclSpecifier();
+ IType qualifiedType = SemanticUtil.addQualifiers(initializerType,
+ declSpec.isConst() || SemanticUtil.isConst(eType),
+ declSpec.isVolatile() || SemanticUtil.isVolatile(eType), declSpec.isRestrict());
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier == null) {
+ return qualifiedType;
+ }
+ return new CPPReferenceType(qualifiedType, shallBecomeRvalueReference(evaluation, refQualifier, declSpec));
+ }
+
+ public static boolean hasConstexprStaticIntegralValueField(ICPPClassType type, long expectedValue) {
+ return Arrays.stream(ClassTypeHelper.getFields(type)).filter(IS_STATIC_VARIABLE).filter(IS_NAMED_VALUE)
+ .filter(HAS_INTEGRAL_TYPE).filter(HAS_CONST_TYPE).filter(field -> {
+ return variableHasInitialNumberValue(field, expectedValue);
+ }).findFirst().isPresent();
+ }
+
+ private static boolean variableHasInitialNumberValue(IVariable variable, long expectedValue) {
+ IValue initialValue = variable.getInitialValue();
+ if (initialValue == null) {
+ return false;
+ }
+ Number numberValue = initialValue.numberValue();
+ if (numberValue == null) {
+ return false;
+ }
+ return numberValue.longValue() == expectedValue;
+ }
+
+ private static IType deduceInitializerType(ICPPASTStructuredBindingDeclaration declaration, IASTName name,
+ IType unwrappedType) {
+ if (unwrappedType instanceof IArrayType) {
+ IArrayType arrayType = (IArrayType) unwrappedType;
+ return arrayType.getType();
+ } else if (unwrappedType instanceof ICPPClassType) {
+ int index = Arrays.asList(declaration.getNames()).indexOf(name);
+ IScope scope = CPPSemantics.getLookupScope(name);
+ Optional<ICPPClassSpecialization> tupleSizeInstance = findTupleSizeWithValueMember(unwrappedType, scope,
+ name);
+ if (tupleSizeInstance.isPresent()) {
+ int numberOfNames = declaration.getNames().length;
+ if (hasConstexprStaticIntegralValueField(tupleSizeInstance.get(), numberOfNames)) {
+ return determineTupleElementType(unwrappedType, scope, name, index);
+ }
+ } else {
+ ICPPClassType classType = (ICPPClassType) unwrappedType;
+ return Arrays.stream(ClassTypeHelper.getFields(classType)).filter(IS_STATIC_VARIABLE.negate())
+ .skip(index).findFirst().map(IField::getType)
+ .orElse(ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE);
+ }
+ }
+ return ProblemType.CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE;
+ }
+
+ /**
+ *
+ * Determines the reference type of a name in a structured binding based on its {@code evaluation}, the {@code refQualifier} and the {@code declSpecifier}.
+ * It performs perfect forwarding in case of a forwarding reference, i.e. if the declaration specifier is exactly "auto &&",
+ * Otherwise it is always an rvalue reference if the declaration specifier contains &&
+ *
+ * Example:
+ * auto && [element] = get(); // element is an rvalue if get() is an rvalue, otherwise an lvalue
+ * auto const && [element] = get(); //element is always an rvalue, get() needs to be an rvalue too
+ *
+ */
+ private static boolean shallBecomeRvalueReference(ICPPEvaluation evaluation, RefQualifier refQualifier,
+ IASTDeclSpecifier declSpecifier) {
+
+ if (refQualifier == RefQualifier.RVALUE) {
+ return evaluation.getValueCategory() != ValueCategory.LVALUE || declSpecifier.isConst()
+ || declSpecifier.isVolatile();
+ }
+ return false;
+ }
+
private static IType createFunctionType(IType returnType, ICPPASTFunctionDeclarator fnDtor) {
IType[] pTypes = createParameterTypes(fnDtor);
@@ -2214,8 +2383,7 @@ public class CPPVisitor extends ASTQueries {
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
}
- private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
- IASTInitializer initClause = declarator.getInitializer();
+ private static ICPPASTInitializerClause getInitClauseForInitializer(IASTInitializer initClause) {
if (initClause instanceof IASTEqualsInitializer) {
return (ICPPASTInitializerClause) ((IASTEqualsInitializer) initClause).getInitializerClause();
} else if (initClause instanceof ICPPASTConstructorInitializer) {
@@ -2235,6 +2403,45 @@ public class CPPVisitor extends ASTQueries {
return null;
}
+ private static ICPPASTInitializerClause getAutoInitClauseForRangeBasedFor(ICPPASTRangeBasedForStatement forStmt) {
+ // See 6.5.4 The range-based for statement [stmt.ranged]
+ IASTInitializerClause forInit = forStmt.getInitializerClause();
+ IASTExpression beginExpr = null;
+ if (forInit instanceof IASTExpression) {
+ final IASTExpression expr = (IASTExpression) forInit;
+ IType type = SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE);
+ if (type instanceof IArrayType) {
+ beginExpr = expr.copy();
+ }
+ }
+ if (beginExpr == null) {
+ IASTImplicitName[] implicits = forStmt.getImplicitNames();
+ if (implicits.length > 0) {
+ IBinding b = implicits[0].getBinding();
+ CPPASTName name = new CPPASTName();
+ name.setBinding(b);
+ IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() };
+ if (b instanceof ICPPMethod && forInit instanceof IASTExpression) {
+ beginExpr = new CPPASTFunctionCallExpression(
+ new CPPASTFieldReference(name, (IASTExpression) forInit.copy()), beginCallArguments);
+ } else {
+ beginExpr = new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments);
+ }
+ } else {
+ return null;
+ }
+ }
+ ICPPASTInitializerClause autoInitClause = new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr);
+ autoInitClause.setParent(forStmt);
+ autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
+ return autoInitClause;
+ }
+
+ private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
+ IASTInitializer initClause = declarator.getInitializer();
+ return getInitClauseForInitializer(initClause);
+ }
+
private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, int flags,
PlaceholderKind placeholderKind) {
IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? ProblemType.CANNOT_DEDUCE_AUTO_TYPE
@@ -2275,39 +2482,10 @@ public class CPPVisitor extends ASTQueries {
}
}
} else if (parent instanceof ICPPASTRangeBasedForStatement) {
- // See 6.5.4 The range-based for statement [stmt.ranged]
- ICPPASTRangeBasedForStatement forStmt = (ICPPASTRangeBasedForStatement) parent;
- IASTInitializerClause forInit = forStmt.getInitializerClause();
- IASTExpression beginExpr = null;
- if (forInit instanceof IASTExpression) {
- final IASTExpression expr = (IASTExpression) forInit;
- IType type = SemanticUtil.getNestedType(expr.getExpressionType(), TDEF | CVTYPE);
- if (type instanceof IArrayType) {
- beginExpr = expr.copy();
- }
- }
- if (beginExpr == null) {
- IASTImplicitName[] implicits = forStmt.getImplicitNames();
- if (implicits.length > 0) {
- IBinding b = implicits[0].getBinding();
- CPPASTName name = new CPPASTName();
- name.setBinding(b);
- IASTInitializerClause[] beginCallArguments = new IASTInitializerClause[] { forInit.copy() };
- if (b instanceof ICPPMethod && forInit instanceof IASTExpression) {
- beginExpr = new CPPASTFunctionCallExpression(
- new CPPASTFieldReference(name, (IASTExpression) forInit.copy()),
- beginCallArguments);
- } else {
- beginExpr = new CPPASTFunctionCallExpression(new CPPASTIdExpression(name),
- beginCallArguments);
- }
- } else {
- return cannotDeduce;
- }
+ autoInitClause = getAutoInitClauseForRangeBasedFor((ICPPASTRangeBasedForStatement) parent);
+ if (autoInitClause == null) {
+ return cannotDeduce;
}
- autoInitClause = new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr);
- autoInitClause.setParent(forStmt);
- autoInitClause.setPropertyInParent(ICPPASTRangeBasedForStatement.INITIALIZER);
} else if (parent instanceof IASTCompositeTypeSpecifier
&& declSpec.getStorageClass() != IASTDeclSpecifier.sc_static) {
// Non-static auto-typed class members are not allowed.
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
index 6ab1df368c3..6f307fd3e0e 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIncomplete.java
@@ -35,6 +35,10 @@ public class ExecIncomplete implements ICPPExecution {
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
- throw new UnsupportedOperationException();
+ buffer.putShort(ITypeMarshalBuffer.EXEC_INCOMPLETE);
+ }
+
+ public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) {
+ return INSTANCE;
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
index 2481dbbcb82..2f2f36c67b7 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java
@@ -122,7 +122,7 @@ public class ExpressionTypes {
return false;
}
- private static boolean isVolatile(IType type) {
+ public static boolean isVolatile(IType type) {
if (type instanceof IQualifierType) {
return ((IQualifierType) type).isVolatile();
} else if (type instanceof IPointerType) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
index eaca924d507..f84d285bad6 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
@@ -908,11 +908,22 @@ public class SemanticUtil {
if (type instanceof ICPPReferenceType) {
ICPPReferenceType refType = (ICPPReferenceType) type;
return isConst(refType.getType());
- } else if (type instanceof CPPQualifierType) {
- CPPQualifierType qualifierType = (CPPQualifierType) type;
- return qualifierType.isConst();
}
- return false;
+ return ExpressionTypes.isConst(type);
+ }
+
+ /**
+ * Returns whether a type is volatile or a reference to a volatile type.
+ *
+ * @param type the type to be checked
+ * @return true if the type is volatile, otherwise false
+ */
+ public static boolean isVolatile(IType type) {
+ if (type instanceof ICPPReferenceType) {
+ ICPPReferenceType refType = (ICPPReferenceType) type;
+ return isVolatile(refType.getType());
+ }
+ return ExpressionTypes.isVolatile(type);
}
static IType[] addImplicitParameterType(IType[] types, ICPPMethod m) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
index 9471f80791d..e99d4ecfd68 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
@@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
@@ -34,6 +35,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
@@ -41,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
@@ -63,6 +66,8 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
public class DeclarationWriter extends NodeWriter {
private static final char OPEN_PAREN = '(';
private static final char CLOSE_PAREN = ')';
+ private static final char OPEN_BRACKET = '[';
+ private static final char CLOSE_BRACKET = ']';
private static final String ASM_START = "asm" + OPEN_PAREN; //$NON-NLS-1$
private static final String TEMPLATE_DECLARATION = "template<"; //$NON-NLS-1$
private static final String TEMPLATE_SPECIALIZATION = "template<> "; //$NON-NLS-1$
@@ -87,6 +92,8 @@ public class DeclarationWriter extends NodeWriter {
addNewLine = false;
} else if (declaration instanceof IASTProblemDeclaration) {
throw new ProblemRuntimeException((IASTProblemDeclaration) declaration);
+ } else if (declaration instanceof ICPPASTStructuredBindingDeclaration) {
+ writeStructuredBinding((ICPPASTStructuredBindingDeclaration) declaration, writeSemicolon);
} else if (declaration instanceof IASTSimpleDeclaration) {
writeSimpleDeclaration((IASTSimpleDeclaration) declaration);
} else if (declaration instanceof ICPPASTExplicitTemplateInstantiation) {
@@ -123,6 +130,28 @@ public class DeclarationWriter extends NodeWriter {
}
}
+ private void writeStructuredBinding(ICPPASTStructuredBindingDeclaration declaration, boolean writeSemicolon) {
+ writeAttributes(declaration, EnumSet.of(SpaceLocation.AFTER));
+ declaration.getDeclSpecifier().accept(visitor);
+ RefQualifier refQualifier = declaration.getRefQualifier();
+ if (refQualifier != null) {
+ writeRefQualifier(refQualifier);
+ }
+ scribe.printSpace();
+
+ scribe.print(OPEN_BRACKET);
+ writeNodeList(declaration.getNames());
+ scribe.print(CLOSE_BRACKET);
+
+ IASTInitializer initializer = declaration.getInitializer();
+ if (initializer != null) {
+ initializer.accept(visitor);
+ }
+ if (writeSemicolon) {
+ printSemicolon();
+ }
+ }
+
private void writeAliasDeclaration(ICPPASTAliasDeclaration aliasDeclaration) {
scribe.printStringSpace(Keywords.USING);
IASTName alias = aliasDeclaration.getAlias();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
index 97d90062102..86eb87683a4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
@@ -159,16 +159,7 @@ public class DeclaratorWriter extends NodeWriter {
scribe.print(Keywords.VOLATILE);
}
RefQualifier refQualifier = funcDec.getRefQualifier();
- if (refQualifier != null) {
- switch (refQualifier) {
- case LVALUE:
- scribe.print(Keywords.cpAMPER);
- break;
- case RVALUE:
- scribe.print(Keywords.cpAND);
- break;
- }
- }
+ writeRefQualifier(refQualifier);
if (funcDec.isMutable()) {
scribe.printSpace();
scribe.print(Keywords.MUTABLE);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
index 5d9fa84b3a6..085d25f2129 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
@@ -23,8 +23,10 @@ import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier;
import org.eclipse.cdt.core.dom.ast.gnu.IGCCASTAttributeList;
import org.eclipse.cdt.core.dom.parser.cpp.ICPPASTAttributeSpecifier;
+import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
@@ -157,4 +159,17 @@ public class NodeWriter {
scribe.printSpace();
}
}
+
+ protected void writeRefQualifier(RefQualifier refQualifier) {
+ if (refQualifier != null) {
+ switch (refQualifier) {
+ case LVALUE:
+ scribe.print(Keywords.cpAMPER);
+ break;
+ case RVALUE:
+ scribe.print(Keywords.cpAND);
+ break;
+ }
+ }
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
index 4752e5e0ab5..05b9367d2f2 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java
@@ -154,6 +154,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecDo;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecExpressionStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecFor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIf;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecIncomplete;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecRangeBasedFor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecReturn;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclaration;
@@ -1768,6 +1769,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return ExecSwitch.unmarshal(firstBytes, buffer);
case ITypeMarshalBuffer.EXEC_CONSTRUCTOR_CHAIN:
return ExecConstructorChain.unmarshal(firstBytes, buffer);
+ case ITypeMarshalBuffer.EXEC_INCOMPLETE:
+ return ExecIncomplete.unmarshal(firstBytes, buffer);
}
throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an execution, first bytes=" + firstBytes)); //$NON-NLS-1$
}

Back to the top