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);
 	}