From a8ff78b531d599ebfa99464a897bb4957ed8bf3f Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Thu, 18 May 2017 01:10:45 -0400 Subject: [PATCH] Bug 528457 - Store lambda parameters in index The special binding type CPPLambdaExpressionParameter is removed. Instead, a lambda expression parameters's are represented as regular CPPParameters owned by the closure type's generated function call operator. Change-Id: I4afeac90c2595a1f84dfa59f057d0494b64d079c --- .../ast2/cxx14/GenericLambdaIndexTests.java | 3 +- .../dom/parser/cpp/CPPASTConversionName.java | 11 ++ .../core/dom/parser/cpp/CPPClosureType.java | 41 +++- .../cpp/CPPLambdaExpressionParameter.java | 180 ------------------ .../core/dom/parser/cpp/CPPParameter.java | 13 +- .../dom/parser/cpp/semantics/CPPVisitor.java | 28 ++- .../dom/parser/cpp/semantics/EvalBinding.java | 5 +- 7 files changed, 76 insertions(+), 205 deletions(-) delete mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPLambdaExpressionParameter.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java index 65c546bc2d2..561d511f262 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java @@ -72,8 +72,7 @@ public class GenericLambdaIndexTests extends IndexBindingResolutionTestBase { // waldo(foo(L(42, 'x'))); // waldo(bar(L(42, 'x', 42.0f))); // } - public void _testVariadicAutoParameter() throws Exception { - // TODO: To pass this test, we need to store lambda parameters in the index. + public void testVariadicAutoParameter() throws Exception { checkBindings(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConversionName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConversionName.java index 477d711cb94..53b6c1c055e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConversionName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConversionName.java @@ -109,6 +109,17 @@ public class CPPASTConversionName extends CPPASTNameBase implements ICPPASTConve return fName; } + public static char[] createName(String targetName) { + StringBuilder buf = new StringBuilder(); + buf.append(Keywords.cOPERATOR); + buf.append(' '); + buf.append(targetName); + final int len= buf.length(); + char[] name= new char[len]; + buf.getChars(0, len, name, 0); + return name; + } + public static char[] createName(IType t, IASTNode typeId) { StringBuilder buf= new StringBuilder(); buf.append(Keywords.cOPERATOR); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java index 99d967081ef..492651e84bb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java @@ -67,6 +67,8 @@ import org.eclipse.core.runtime.PlatformObject; */ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICPPInternalBinding { private final ICPPASTLambdaExpression fLambdaExpression; + private IType[] fParameterTypes; + private ICPPParameter[] fParameters; private ICPPMethod[] fMethods; private ClassScope fScope; // Used for generic lambdas; null otherwise. @@ -113,10 +115,7 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP final IType[] parameterTypes= getParameterTypes(); ft= new CPPFunctionType(returnType, parameterTypes, !isMutable(), false, false, false, false); - ICPPParameter[] params = new ICPPParameter[parameterTypes.length]; - for (int i = 0; i < params.length; i++) { - params[i]= new CPPParameter(parameterTypes[i], i); - } + ICPPParameter[] params = getParameters(); char[] operatorParensName = OverloadableOperator.PAREN.toCharArray(); if (isGeneric()) { m = new CPPImplicitMethodTemplate(getInventedTemplateParameterList(), scope, operatorParensName, @@ -136,7 +135,10 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP if (needConversionOperator) { final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes); ft= new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false, false, false); - char[] conversionOperatorName = CPPASTConversionName.createName(conversionTarget, null); + // Calling CPPASTConversionName.createName(IType) would try to stringize the type to + // construct a name, which is unnecessary work (not to mention prone to recursion with + // dependent types). Since the name doesn't matter anyways, just make one up. + char[] conversionOperatorName = CPPASTConversionName.createName("__fptr"); //$NON-NLS-1$ if (isGeneric()) { ICPPTemplateParameter[] templateParams = getInventedTemplateParameterList(); // Clone the template parameters, since they are used by the function call operator, @@ -236,11 +238,32 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP } private IType[] getParameterTypes() { - ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); - if (lambdaDtor != null) { - return CPPVisitor.createParameterTypes(lambdaDtor); + if (fParameterTypes == null) { + ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); + if (lambdaDtor != null) { + fParameterTypes = CPPVisitor.createParameterTypes(lambdaDtor); + } else { + fParameterTypes = IType.EMPTY_TYPE_ARRAY; + } } - return IType.EMPTY_TYPE_ARRAY; + return fParameterTypes; + } + + public ICPPParameter[] getParameters() { + if (fParameters == null) { + final IType[] parameterTypes= getParameterTypes(); + fParameters = new ICPPParameter[parameterTypes.length]; + ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); + if (lambdaDtor != null) { + ICPPASTParameterDeclaration[] paramDecls = lambdaDtor.getParameters(); + for (int i = 0; i < fParameters.length; i++) { + CPPParameter param = new CPPParameter(parameterTypes[i], i); + param.addDeclaration(paramDecls[i].getDeclarator().getName()); + fParameters[i] = param; + } + } + } + return fParameters; } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPLambdaExpressionParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPLambdaExpressionParameter.java deleted file mode 100644 index 713b14b6bfd..00000000000 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPLambdaExpressionParameter.java +++ /dev/null @@ -1,180 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010, 2014 Wind River Systems, Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Markus Schorn (Wind River Systems) - initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.internal.core.dom.parser.cpp; - -import org.eclipse.cdt.core.dom.ILinkage; -import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; -import org.eclipse.cdt.core.dom.ast.IBinding; -import org.eclipse.cdt.core.dom.ast.IScope; -import org.eclipse.cdt.core.dom.ast.IType; -import org.eclipse.cdt.core.dom.ast.IValue; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; -import org.eclipse.cdt.internal.core.dom.Linkage; -import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; -import org.eclipse.core.runtime.PlatformObject; - -/** - * Binding for a c++ function parameter - */ -public class CPPLambdaExpressionParameter extends PlatformObject implements ICPPParameter { - private IType fType; - private IASTName fDeclaration; - - public CPPLambdaExpressionParameter(IASTName name) { - fDeclaration = name; - } - - @Override - public boolean isParameterPack() { - return getType() instanceof ICPPParameterPackType; - } - - @Override - public String getName() { - return new String(getNameCharArray()); - } - - @Override - public char[] getNameCharArray() { - return fDeclaration.getSimpleID(); - } - - @Override - public IScope getScope() { - return CPPVisitor.getContainingScope(fDeclaration); - } - - @Override - public IType getType() { - if (fType == null) { - IASTNode parent= fDeclaration.getParent(); - while (parent != null) { - if (parent instanceof ICPPASTParameterDeclaration) { - fType= CPPVisitor.createType((ICPPASTParameterDeclaration) parent, false); - break; - } - parent= parent.getParent(); - } - } - return fType; - } - - @Override - public boolean isStatic() { - return false; - } - - @Override - public String[] getQualifiedName() { - return new String[] { getName() }; - } - - @Override - public char[][] getQualifiedNameCharArray() { - return new char[][] { getNameCharArray() }; - } - - @Override - public boolean isGloballyQualified() { - return false; - } - - @Override - public boolean isExtern() { - //7.1.1-5 extern can not be used in the declaration of a parameter - return false; - } - - @Override - public boolean isMutable() { - //7.1.1-8 mutable can only apply to class members - return false; - } - - @Override - public boolean isConstexpr() { - return false; - } - - @Override - public boolean isAuto() { - return hasStorageClass(IASTDeclSpecifier.sc_auto); - } - - @Override - public boolean isRegister() { - return hasStorageClass(IASTDeclSpecifier.sc_register); - } - - private boolean hasStorageClass(int storage) { - IASTNode parent = fDeclaration.getParent(); - while (parent != null && !(parent instanceof IASTParameterDeclaration)) - parent = parent.getParent(); - if (parent != null) { - IASTDeclSpecifier declSpec = ((IASTParameterDeclaration) parent).getDeclSpecifier(); - if (declSpec.getStorageClass() == storage) - return true; - } - return false; - } - - @Override - public boolean hasDefaultValue() { - return false; - } - - @Override - public IValue getDefaultValue() { - return null; - } - - @Override - public ILinkage getLinkage() { - return Linkage.CPP_LINKAGE; - } - - @Override - public boolean isExternC() { - return false; - } - - @Override - public String toString() { - String name = getName(); - return name.length() != 0 ? name : ""; //$NON-NLS-1$ - } - - @Override - public IBinding getOwner() { - IASTNode node= fDeclaration; - while (node != null && !(node instanceof ICPPASTLambdaExpression)) - node= node.getParent(); - - if (node instanceof ICPPASTLambdaExpression) { - IType type= ((ICPPASTLambdaExpression) node).getExpressionType(); - if (type instanceof IBinding) { - return (IBinding) type; - } - } - return null; - } - - @Override - public IValue getInitialValue() { - return null; - } -} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java index e65fa986494..629daec5aa3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPParameter.java @@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; @@ -277,6 +278,10 @@ public class CPPParameter extends PlatformObject implements ICPPParameter, ICPPI ASTQueries.findAncestorWithType(fDeclarations[0], IASTFunctionDeclarator.class); if (decl == null) return null; + if (decl.getParent() instanceof ICPPASTLambdaExpression) { + CPPClosureType closure = (CPPClosureType) ((ICPPASTLambdaExpression) decl.getParent()).getExpressionType(); + return closure.getFunctionCallOperator(); + } IASTName name= decl.getName(); return name != null ? name.resolveBinding() : null; } @@ -299,9 +304,11 @@ public class CPPParameter extends PlatformObject implements ICPPParameter, ICPPI } if (node instanceof IASTFunctionDeclarator) { IASTName funcName= ASTQueries.findInnermostDeclarator((IASTFunctionDeclarator) node).getName(); - IBinding b= funcName.resolvePreBinding(); - if (b instanceof ICPPInternalFunction) { - return ((ICPPInternalFunction) b).resolveParameter(this); + if (funcName != null) { // will be null for lambda declarator + IBinding b= funcName.resolvePreBinding(); + if (b instanceof ICPPInternalFunction) { + return ((ICPPInternalFunction) b).resolveParameter(this); + } } } return this; 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 3bc98035370..e5a2c957a87 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 @@ -163,6 +163,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; @@ -207,7 +208,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLabel; -import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPLambdaExpressionParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace; @@ -744,6 +744,15 @@ public class CPPVisitor extends ASTQueries { return null; } + private static int findParameterIndex(IASTParameterDeclaration param, IASTParameterDeclaration[] params) { + int i= 0; + for (; i < params.length; i++) { + if (params[i] == param) + return i; + } + return -1; + } + private static IBinding createBinding(IASTDeclarator declarator) { IASTNode parent = findOutermostDeclarator(declarator).getParent(); declarator= findInnermostDeclarator(declarator); @@ -796,17 +805,18 @@ public class CPPVisitor extends ASTQueries { final IASTNode dtorParent= findOutermostDeclarator(fdtor).getParent(); if (dtorParent instanceof ICPPASTLambdaExpression) { - return new CPPLambdaExpressionParameter(name); + CPPClosureType closure = (CPPClosureType) + ((ICPPASTLambdaExpression) dtorParent).getExpressionType(); + ICPPParameter[] paramBindings = closure.getParameters(); + int index = findParameterIndex(param, fdtor.getParameters()); + if (index >= 0 && index < paramBindings.length) { + return paramBindings[index]; + } } if (dtorParent instanceof IASTDeclaration) { - IASTParameterDeclaration[] params = fdtor.getParameters(); - int i= 0; - for (; i < params.length; i++) { - if (params[i] == param) - break; - } - return new CPPParameter(name, i); + int index = findParameterIndex(param, fdtor.getParameters()); + return new CPPParameter(name, index); } return null; } else if (parent instanceof ICPPASTTemplateDeclaration) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java index dea9a222a87..51eca0ef32f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinding.java @@ -63,8 +63,9 @@ public class EvalBinding extends CPPDependentEvaluation { private int fParameterPosition; /** * The binding represented by this evaluation. For a function parameter binding may be computed - * lazily to avoid infinite recursion during unmarshalling of the evaluation. If #fBinding is - * {@code null}, {@link #fParameterOwner} is guaranteed to be not {@code null} and vice versa. + * lazily to avoid infinite recursion during unmarshalling of the evaluation. If + * {@link #fBinding} is {@code null}, {@link #fParameterOwner} is guaranteed to be not {@code null} + * and vice versa. */ private IBinding fBinding; private final boolean fFixedType;