diff options
author | Thomas Corbat | 2018-05-23 11:02:03 +0000 |
---|---|---|
committer | Thomas Corbat | 2019-08-05 07:00:35 +0000 |
commit | acbceb04ee9e472119ef3255a47986c833fcf4c2 (patch) | |
tree | c27f6cf457270d83047b8c01a9c790c2d0d5ef7b /core/org.eclipse.cdt.core/parser/org | |
parent | af88842969b538dc3a33eab84b3b9631194bd9a3 (diff) | |
download | org.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')
26 files changed, 1136 insertions, 88 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java index 4e5f33bcb4c..3134e58fad9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java @@ -50,6 +50,8 @@ public interface ISemanticProblem { int TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = 10007; /** @since 6.3 */ int TYPE_AUTO_FOR_VIRTUAL_METHOD = 10008; + /** @since 6.9 */ + int TYPE_CANNOT_DEDUCE_STRUCTURED_BINDING_TYPE = 10009; /** * Returns the ID of the problem. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java new file mode 100644 index 00000000000..8eff34af474 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTStructuredBindingDeclaration.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik + * Rapperswil, University of applied sciences. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Thomas Corbat (IFS) - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.core.dom.ast.cpp; + +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; +import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; +import org.eclipse.cdt.core.dom.ast.IASTInitializer; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier; +import org.eclipse.jdt.annotation.Nullable; + +/** + * This is a structured binding declaration which contains a sequence names, + * in square brackets, that decompose an initializer. + * <p> + * Examples: + * <ul> + * <li><code>auto [x, y]{coordinate};</code></li> + * <li><code>auto & [x, y](coordinate);</code></li> + * <li><code>auto && [x, y] = createCoordinte();</code></li> + * </ul> + * + * @since 6.9 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ICPPASTStructuredBindingDeclaration + extends IASTSimpleDeclaration, IASTNameOwner, IASTImplicitNameOwner { + /** + * <code>IDENTIFIER</code> represents the relationship between an + * <code>ICPPASTStructuredBindingDeclaration</code> and its + * <code>IASTName</code>s. + */ + public static final ASTNodeProperty IDENTIFIER = new ASTNodeProperty( + "ICPPASTStructuredBindingDeclaration.IDENTIFIER - IASTName for ICPPASTStructuredBindingDeclaration"); //$NON-NLS-1$ + + /** + * <code>INITIALIZER</code> represents the relationship between an + * <code>ICPPASTStructuredBindingDeclaration</code> and its <code>IASTInitializer</code>. + */ + public static final ASTNodeProperty INITIALIZER = new ASTNodeProperty( + "ICPPASTStructuredBindingDeclaration.INITIALIZER - IASTInitializer for ICPPASTStructuredBindingDeclaration"); //$NON-NLS-1$ + + /** + * Returns the <code>RefQualifier</code> of the structured binding. For either lvalue or + * rvalue reference qualifiers. + * <p> + * Examples: + * <ul> + * <li>For <code>auto [x, y] = coordinate;</code> it returns the empty <code>Optional</code></li> + * <li>For <code>auto & [x, y] = coordinate;</code> it returns <code>Optional.of(RefQualifier.LVALUE)</code></li> + * <li>For <code>auto && [x, y] = createCoordinte();</code> it returns <code>Optional.of(RefQualifier.RVALUE)</code></li> + * </ul> + * + * @return The returned <code>RefQualifier</code> of the C++ declaration or <code>null</code> if there is no reference qualifier. + * if the structured binding does not have a reference qualifier. + * @see RefQualifier + */ + @Nullable + RefQualifier getRefQualifier(); + + /** + * Returns the list of names declared by this structured binding declaration. + * <p> + * Example: For <code>auto & [x, y] = coordinate;</code> it returns the names <code>x</code> and <code>y</code>. + * + * @return All declared names of the structured binding as<code>IASTName[]</code> + * @see IASTName + */ + IASTName[] getNames(); + + /** + * Returns the initializer of the structured binding declaration. + * + * This will not be present if the structured binding is part of a range-based for loop. + * + * * Examples: + * <ul> + * <li>For <code>auto [x, y]{coordinate};</code> it returns an <code>ICPPASTInitializerList</code></li> + * <li>For <code>auto & [x, y](coordinate);</code> it returns an <code>ICPPASTConstructorInitializer</code></li> + * <li>For <code>auto && [x, y] = createCoordinte();</code> it returns an <code>IASTEqualsInitializer</code></li> + * </ul> + * + * @return The <code>IASTInitializer</code> of this structured binding. It can be <code>null</code> if the C++ declaration is lacking an initializer. + * @see IASTInitializer + * @see ICPPASTInitializerList + * @see ICPPASTConstructorInitializer + * @see IASTEqualsInitializer + */ + @Nullable + IASTInitializer getInitializer(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java index 995be0308b9..11af18db9fb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java @@ -34,6 +34,7 @@ import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier.ScopeStyle; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation.Operator; import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPASTArrayRangeDesignator; import org.eclipse.cdt.core.dom.parser.cpp.ICPPASTAttributeSpecifier; @@ -503,4 +504,15 @@ public interface ICPPNodeFactory extends INodeFactory { */ @Deprecated public ICPPASTAttributeSpecifier newAttributeSpecifier(); + + /** + * @since 6.9 + */ + public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration(); + + /** + * @since 6.9 + */ + public ICPPASTStructuredBindingDeclaration newStructuredBindingDeclaration(ICPPASTSimpleDeclSpecifier declSpecifier, + RefQualifier refQualifier, IASTName[] names, IASTInitializer initializer); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 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$ } |