1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-11 10:15:39 +02:00

Bug 516338 - Introduce alias template specializations

We previously modelled alias template specializations as alias template
instances, which was conceptually incorrect and problematic for a number
of reasons.

Change-Id: Ibca8b87bb3d54cd3ae312254a02e8522e446331d
This commit is contained in:
Nathan Ridge 2017-05-09 22:35:32 -04:00
parent 3e0853ae0c
commit 8d6cab41e7
9 changed files with 254 additions and 54 deletions

View file

@ -0,0 +1,61 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
/**
* Specialization of an alias template.
*/
public class CPPAliasTemplateSpecialization extends CPPSpecialization implements ICPPAliasTemplate {
private ICPPTemplateParameter[] fParameters;
private IType fAliasedType;
public CPPAliasTemplateSpecialization(ICPPAliasTemplate specialized, IBinding owner,
ICPPTemplateParameterMap argumentMap, IType aliasedType) {
super(specialized, owner, argumentMap);
fAliasedType = aliasedType;
}
public void setTemplateParameters(ICPPTemplateParameter[] parameters) {
fParameters = parameters;
}
@Override
public boolean isSameType(IType type) {
if (type == null) {
return false;
}
return type.isSameType(fAliasedType);
}
@Override
public ICPPTemplateParameter[] getTemplateParameters() {
return fParameters;
}
@Override
public IType getType() {
return fAliasedType;
}
@Override
public Object clone() {
IType t = null;
try {
t = (IType) super.clone();
} catch (CloneNotSupportedException e) {
// Not going to happen
}
return t;
}
}

View file

@ -134,6 +134,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplateInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplateInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization;
@ -316,35 +317,6 @@ public class CPPTemplates {
} }
} }
/**
* Instantiate a specialization of an alias template with the given arguments.
*
* TODO(nathanridge): The reason we have this method is that we (incorrectly) represent
* specializations of alias templates as alias template instances. A specialization of
* an alias template is an alias template, so it needs to be instantiated to produce
* an actual alias template instance. Actual alias template instances do not need to be
* instantiated.
*/
public static IBinding instantiateAliasTemplateInstance(ICPPAliasTemplateInstance aliasTemplateInstance,
ICPPTemplateArgument[] args, IASTNode point) {
ICPPAliasTemplate aliasTemplate = aliasTemplateInstance.getTemplateDefinition();
try {
args = addDefaultArguments(aliasTemplate, args, point);
if (args == null) {
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
}
ICPPTemplateParameterMap parameterMap = createParameterMap(aliasTemplate, args, point);
if (parameterMap == null) {
return createProblem(aliasTemplate, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, point);
}
IType aliasedType = aliasTemplateInstance.getType();
IBinding owner = aliasTemplateInstance.getOwner();
return createAliasTemplaceInstance(aliasTemplate, args, parameterMap, aliasedType, owner, point);
} catch (DOMException e) {
return e.getProblem();
}
}
private static IBinding createProblem(ICPPTemplateDefinition template, int id, IASTNode point) { private static IBinding createProblem(ICPPTemplateDefinition template, int id, IASTNode point) {
return new ProblemBinding(point, id, template.getNameCharArray()); return new ProblemBinding(point, id, template.getNameCharArray());
} }
@ -797,16 +769,6 @@ public class CPPTemplates {
return instantiateAliasTemplate(aliasTemplate, args, id); return instantiateAliasTemplate(aliasTemplate, args, id);
} }
// Alias template instance.
if (template instanceof ICPPAliasTemplateInstance) {
// TODO(nathanridge): Remove this branch once we properly represent
// specializations of alias templates (which will then implement
// ICPPAliasTemplate and be caught by the previous branch).
ICPPAliasTemplateInstance aliasTemplateInstance = (ICPPAliasTemplateInstance) template;
ICPPTemplateArgument[] args = createTemplateArgumentArray(id);
return instantiateAliasTemplateInstance(aliasTemplateInstance, args, id);
}
// Class or variable template. // Class or variable template.
if (template instanceof ICPPConstructor) { if (template instanceof ICPPConstructor) {
template= template.getOwner(); template= template.getOwner();
@ -1120,7 +1082,12 @@ public class CPPTemplates {
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) decl; ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) decl;
InstantiationContext context = createInstantiationContext(tpMap, owner, point); InstantiationContext context = createInstantiationContext(tpMap, owner, point);
IType type= instantiateType(aliasTemplate.getType(), context); IType type= instantiateType(aliasTemplate.getType(), context);
spec = new CPPAliasTemplateInstance(decl.getNameCharArray(), aliasTemplate, type); CPPAliasTemplateSpecialization aliasSpec =
new CPPAliasTemplateSpecialization(aliasTemplate, owner, tpMap, type);
aliasSpec.setTemplateParameters(specializeTemplateParameters(aliasSpec,
(ICPPScope) aliasSpec.getScope(), aliasTemplate.getTemplateParameters(), classOwner,
point));
spec = aliasSpec;
} else if (decl instanceof ICPPEnumeration && classOwner != null) { } else if (decl instanceof ICPPEnumeration && classOwner != null) {
// TODO: Handle local enumerations // TODO: Handle local enumerations
spec = CPPEnumerationSpecialization.createInstance((ICPPEnumeration) decl, classOwner, tpMap, point); spec = CPPEnumerationSpecialization.createInstance((ICPPEnumeration) decl, classOwner, tpMap, point);
@ -3045,12 +3012,6 @@ public class CPPTemplates {
} else if (result instanceof ICPPAliasTemplate) { } else if (result instanceof ICPPAliasTemplate) {
result = instantiateAliasTemplate((ICPPAliasTemplate) result, args1, result = instantiateAliasTemplate((ICPPAliasTemplate) result, args1,
context.getPoint()); context.getPoint());
} else if (result instanceof ICPPAliasTemplateInstance) {
// TODO(nathanridge): Remove this branch once we properly represent
// specializations of alias templates (which will then implement
// ICPPAliasTemplate and be caught by the previous branch).
result = instantiateAliasTemplateInstance((ICPPAliasTemplateInstance) result,
args1, context.getPoint());
} }
} }
} }

View file

@ -26,7 +26,6 @@ import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; 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.ICPPClassTemplate;
@ -451,12 +450,6 @@ public class HeuristicResolver {
} else if (result instanceof ICPPAliasTemplate) { } else if (result instanceof ICPPAliasTemplate) {
result = (IType) CPPTemplates.instantiateAliasTemplate((ICPPAliasTemplate) result, result = (IType) CPPTemplates.instantiateAliasTemplate((ICPPAliasTemplate) result,
args, point); args, point);
} else if (result instanceof ICPPAliasTemplateInstance) {
// TODO(nathanridge): Remove this branch once we properly represent
// specializations of alias templates (which will then implement
// ICPPAliasTemplate and be caught by the previous branch).
result = (IType) CPPTemplates.instantiateAliasTemplateInstance(
(ICPPAliasTemplateInstance) result, args, point);
} }
} }
return result; return result;

View file

@ -73,4 +73,5 @@ public interface IIndexCPPBindingConstants {
int CPP_VARIABLE_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 59; int CPP_VARIABLE_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 59;
int CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 60; int CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 60;
int CPP_DEFERRED_VARIABLE_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 61; int CPP_DEFERRED_VARIABLE_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 61;
int CPP_ALIAS_TEMPLATE_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 62;
} }

View file

@ -595,6 +595,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
return new CompositeCPPMethodTemplateSpecialization(this, (ICPPMethod) binding); return new CompositeCPPMethodTemplateSpecialization(this, (ICPPMethod) binding);
} else if (binding instanceof ICPPFunction) { } else if (binding instanceof ICPPFunction) {
return new CompositeCPPFunctionTemplateSpecialization(this, (ICPPFunction) binding); return new CompositeCPPFunctionTemplateSpecialization(this, (ICPPFunction) binding);
} else if (binding instanceof ICPPAliasTemplate) {
return new CompositeCPPAliasTemplateSpecialization(this, (ICPPAliasTemplate) binding);
} else { } else {
throw new CompositingNotImplementedError("Composite binding unavailable for " + binding + " " + binding.getClass()); //$NON-NLS-1$ //$NON-NLS-2$ throw new CompositingNotImplementedError("Composite binding unavailable for " + binding + " " + binding.getClass()); //$NON-NLS-1$ //$NON-NLS-2$
} }

View file

@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.index.composite.cpp;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory;
public class CompositeCPPAliasTemplateSpecialization extends CompositeCPPAliasTemplate
implements ICPPSpecialization {
public CompositeCPPAliasTemplateSpecialization(ICompositesFactory cf, ICPPAliasTemplate delegate) {
super(cf, delegate);
}
@Override
public IBinding getSpecializedBinding() {
return TemplateInstanceUtil.getSpecializedBinding(cf, rbinding);
}
@Override
public ICPPTemplateParameterMap getTemplateParameterMap() {
IBinding owner = getOwner();
if (owner instanceof ICPPSpecialization) {
return ((ICPPSpecialization) owner).getTemplateParameterMap();
}
return CPPTemplateParameterMap.EMPTY;
}
}

View file

@ -0,0 +1,114 @@
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* Rapperswil, University of applied sciences.
* 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.CoreException;
/**
* PDOM binding for alias template specializations.
*/
public class PDOMCPPAliasTemplateSpecialization extends PDOMCPPSpecialization implements ICPPAliasTemplate {
private static final int ALIASED_TYPE = PDOMCPPSpecialization.RECORD_SIZE; // TYPE_SIZE
private static final int TEMPLATE_PARAMS = ALIASED_TYPE + Database.TYPE_SIZE; // PTR_SIZE
@SuppressWarnings("hiding")
private static final int RECORD_SIZE = TEMPLATE_PARAMS + Database.PTR_SIZE;
private volatile IPDOMCPPTemplateParameter[] fParameters;
public PDOMCPPAliasTemplateSpecialization(PDOMCPPLinkage linkage, PDOMNode parent,
ICPPAliasTemplate aliasTemplateSpec, IPDOMBinding specialized)
throws CoreException, DOMException {
super(linkage, parent, (ICPPSpecialization) aliasTemplateSpec, specialized);
final ICPPTemplateParameter[] origParams = aliasTemplateSpec.getTemplateParameters();
fParameters = PDOMTemplateParameterArray.createPDOMTemplateParameters(linkage, this, origParams);
final Database db = getDB();
long rec= PDOMTemplateParameterArray.putArray(db, fParameters);
db.putRecPtr(record + TEMPLATE_PARAMS, rec);
linkage.new ConfigureAliasTemplateSpecialization(aliasTemplateSpec, this);
}
public PDOMCPPAliasTemplateSpecialization(PDOMCPPLinkage linkage, long record) {
super(linkage, record);
}
public void initData(IType aliasedType) {
try {
getLinkage().storeType(record + ALIASED_TYPE, aliasedType);
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
@Override
protected int getRecordSize() {
return RECORD_SIZE;
}
@Override
public int getNodeType() {
return IIndexCPPBindingConstants.CPP_ALIAS_TEMPLATE_SPECIALIZATION;
}
@Override
public boolean isSameType(IType type) {
if (type == null) {
return false;
}
return type.isSameType(getType());
}
@Override
public IPDOMCPPTemplateParameter[] getTemplateParameters() {
if (fParameters == null) {
try {
Database db = getDB();
long rec= db.getRecPtr(record + TEMPLATE_PARAMS);
if (rec == 0) {
fParameters= IPDOMCPPTemplateParameter.EMPTY_ARRAY;
} else {
fParameters= PDOMTemplateParameterArray.getArray(this, rec);
}
} catch (CoreException e) {
CCorePlugin.log(e);
fParameters = IPDOMCPPTemplateParameter.EMPTY_ARRAY;
}
}
return fParameters;
}
@Override
public IType getType() {
try {
return getLinkage().loadType(record + ALIASED_TYPE);
} catch (CoreException e) {
CCorePlugin.log(e);
return null;
}
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
}
return null;
}
}

View file

@ -515,6 +515,32 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
} }
} }
class ConfigureAliasTemplateSpecialization implements Runnable {
private final PDOMCPPAliasTemplateSpecialization fTemplate;
private final IPDOMCPPTemplateParameter[] fTemplateParameters;
private final ICPPTemplateParameter[] fOriginalTemplateParameters;
private final IType fOriginalAliasedType;
public ConfigureAliasTemplateSpecialization(ICPPAliasTemplate original,
PDOMCPPAliasTemplateSpecialization template) throws DOMException {
fTemplate = template;
fTemplateParameters= template.getTemplateParameters();
fOriginalTemplateParameters= original.getTemplateParameters();
fOriginalAliasedType= original.getType();
postProcesses.add(this);
}
@Override
public void run() {
for (int i = 0; i < fOriginalTemplateParameters.length; i++) {
final IPDOMCPPTemplateParameter tp = fTemplateParameters[i];
if (tp != null)
tp.configure(fOriginalTemplateParameters[i]);
}
fTemplate.initData(fOriginalAliasedType);
}
}
class ConfigureInstance implements Runnable { class ConfigureInstance implements Runnable {
PDOMCPPSpecialization fInstance; PDOMCPPSpecialization fInstance;
@ -933,6 +959,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
result= new PDOMCPPClassTemplateSpecialization(this, parent, (ICPPClassTemplate) special, orig); result= new PDOMCPPClassTemplateSpecialization(this, parent, (ICPPClassTemplate) special, orig);
} else if (special instanceof ICPPClassType) { } else if (special instanceof ICPPClassType) {
result= new PDOMCPPClassSpecialization(this, parent, (ICPPClassType) special, orig); result= new PDOMCPPClassSpecialization(this, parent, (ICPPClassType) special, orig);
} else if (special instanceof ICPPAliasTemplate) {
result= new PDOMCPPAliasTemplateSpecialization(this, parent, (ICPPAliasTemplate) special, orig);
} else if (special instanceof ITypedef) { } else if (special instanceof ITypedef) {
result= new PDOMCPPTypedefSpecialization(this, parent, (ITypedef) special, orig); result= new PDOMCPPTypedefSpecialization(this, parent, (ITypedef) special, orig);
} else if (special instanceof ICPPUsingDeclaration) { } else if (special instanceof ICPPUsingDeclaration) {
@ -1023,6 +1051,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return CPP_CLASS_TEMPLATE_SPECIALIZATION; return CPP_CLASS_TEMPLATE_SPECIALIZATION;
} else if (binding instanceof ICPPClassType) { } else if (binding instanceof ICPPClassType) {
return CPP_CLASS_SPECIALIZATION; return CPP_CLASS_SPECIALIZATION;
} else if (binding instanceof ICPPAliasTemplate) {
return CPP_ALIAS_TEMPLATE_SPECIALIZATION;
} else if (binding instanceof ITypedef) { } else if (binding instanceof ITypedef) {
return CPP_TYPEDEF_SPECIALIZATION; return CPP_TYPEDEF_SPECIALIZATION;
} }
@ -1329,6 +1359,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return new PDOMCPPVariableTemplatePartialSpecialization(this, record); return new PDOMCPPVariableTemplatePartialSpecialization(this, record);
case CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION: case CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION:
return new PDOMCPPFieldTemplatePartialSpecialization(this, record); return new PDOMCPPFieldTemplatePartialSpecialization(this, record);
case CPP_ALIAS_TEMPLATE_SPECIALIZATION:
return new PDOMCPPAliasTemplateSpecialization(this, record);
} }
assert false : "nodeid= " + nodeType; //$NON-NLS-1$ assert false : "nodeid= " + nodeType; //$NON-NLS-1$
return null; return null;

View file

@ -625,7 +625,7 @@ public class CompletionTests extends CompletionTestBase {
// C<A>::/*cursor*/ // C<A>::/*cursor*/
// } // }
public void testAliasTemplate_418479() throws Exception { public void testAliasTemplate_418479() throws Exception {
final String[] expected = { "D", "E" }; final String[] expected = { "D", "E<typename T>" };
assertCompletionResults(fCursorOffset, expected, ID); assertCompletionResults(fCursorOffset, expected, ID);
} }