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
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPAliasTemplateSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPAliasTemplateSpecialization.java
new file mode 100644
index 0000000..84398bd
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPAliasTemplateSpecialization.java
@@ -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;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
index 75a83d7..0c9591d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
@@ -134,6 +134,7 @@
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.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.CPPClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization;
@@ -316,35 +317,6 @@
}
}
- /**
- * 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) {
return new ProblemBinding(point, id, template.getNameCharArray());
}
@@ -797,16 +769,6 @@
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.
if (template instanceof ICPPConstructor) {
template= template.getOwner();
@@ -1120,7 +1082,12 @@
ICPPAliasTemplate aliasTemplate = (ICPPAliasTemplate) decl;
InstantiationContext context = createInstantiationContext(tpMap, owner, point);
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) {
// TODO: Handle local enumerations
spec = CPPEnumerationSpecialization.createInstance((ICPPEnumeration) decl, classOwner, tpMap, point);
@@ -3045,12 +3012,6 @@
} else if (result instanceof ICPPAliasTemplate) {
result = instantiateAliasTemplate((ICPPAliasTemplate) result, args1,
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());
}
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java
index 1b51d0b..366d32c 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/HeuristicResolver.java
@@ -26,7 +26,6 @@
import org.eclipse.cdt.core.dom.ast.IType;
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.ICPPAliasTemplateInstance;
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.ICPPClassTemplate;
@@ -451,12 +450,6 @@
} else if (result instanceof ICPPAliasTemplate) {
result = (IType) CPPTemplates.instantiateAliasTemplate((ICPPAliasTemplate) result,
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;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java
index cc005df..8e42260 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java
@@ -73,4 +73,5 @@
int CPP_VARIABLE_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 59;
int CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 60;
int CPP_DEFERRED_VARIABLE_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 61;
+ int CPP_ALIAS_TEMPLATE_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 62;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java
index 16b3ac2..a90d939 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java
@@ -595,6 +595,8 @@
return new CompositeCPPMethodTemplateSpecialization(this, (ICPPMethod) binding);
} else if (binding instanceof ICPPFunction) {
return new CompositeCPPFunctionTemplateSpecialization(this, (ICPPFunction) binding);
+ } else if (binding instanceof ICPPAliasTemplate) {
+ return new CompositeCPPAliasTemplateSpecialization(this, (ICPPAliasTemplate) binding);
} else {
throw new CompositingNotImplementedError("Composite binding unavailable for " + binding + " " + binding.getClass()); //$NON-NLS-1$ //$NON-NLS-2$
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPAliasTemplateSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPAliasTemplateSpecialization.java
new file mode 100644
index 0000000..868ff5b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPAliasTemplateSpecialization.java
@@ -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;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPAliasTemplateSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPAliasTemplateSpecialization.java
new file mode 100644
index 0000000..8d3b588
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPAliasTemplateSpecialization.java
@@ -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;
+ }
+}
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 a61e669..8ced089 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
@@ -515,6 +515,32 @@
}
}
+ 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 {
PDOMCPPSpecialization fInstance;
@@ -933,6 +959,8 @@
result= new PDOMCPPClassTemplateSpecialization(this, parent, (ICPPClassTemplate) special, orig);
} else if (special instanceof ICPPClassType) {
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) {
result= new PDOMCPPTypedefSpecialization(this, parent, (ITypedef) special, orig);
} else if (special instanceof ICPPUsingDeclaration) {
@@ -1023,6 +1051,8 @@
return CPP_CLASS_TEMPLATE_SPECIALIZATION;
} else if (binding instanceof ICPPClassType) {
return CPP_CLASS_SPECIALIZATION;
+ } else if (binding instanceof ICPPAliasTemplate) {
+ return CPP_ALIAS_TEMPLATE_SPECIALIZATION;
} else if (binding instanceof ITypedef) {
return CPP_TYPEDEF_SPECIALIZATION;
}
@@ -1329,6 +1359,8 @@
return new PDOMCPPVariableTemplatePartialSpecialization(this, record);
case CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION:
return new PDOMCPPFieldTemplatePartialSpecialization(this, record);
+ case CPP_ALIAS_TEMPLATE_SPECIALIZATION:
+ return new PDOMCPPAliasTemplateSpecialization(this, record);
}
assert false : "nodeid= " + nodeType; //$NON-NLS-1$
return null;
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java
index 3917fbb..978719a 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java
@@ -625,7 +625,7 @@
// C<A>::/*cursor*/
// }
public void testAliasTemplate_418479() throws Exception {
- final String[] expected = { "D", "E" };
+ final String[] expected = { "D", "E<typename T>" };
assertCompletionResults(fCursorOffset, expected, ID);
}