From 875e21efb09bf13ce4c04e894e906a44cd9e11d5 Mon Sep 17 00:00:00 2001 From: Thomas Corbat Date: Mon, 10 Mar 2014 11:23:36 +0100 Subject: [PATCH] Bug 430342 - Completion of template arguments. Change-Id: Iaf1c43ce826f6676b941689f39fc81ea5e25daa8 Reviewed-on: https://git.eclipse.org/r/29440 Tested-by: Hudson CI Reviewed-by: Thomas Corbat Tested-by: Thomas Corbat --- .../text/contentassist2/CompletionTests.java | 18 ++- .../contentassist/CCompletionProposal.java | 38 +++--- .../DOMCompletionProposalComputer.java | 111 +++++++++++++++--- 3 files changed, 133 insertions(+), 34 deletions(-) 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 967333ca142..5d2ba9620b0 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 @@ -172,6 +172,16 @@ public class CompletionTests extends AbstractContentAssistTest { // namespace _B_331056 { // using ::_A_331056::Reference; // } + // + // template + // struct Specialization { + // }; + // template + // struct Specialization { + // }; + // template<> + // struct Specialization { + // }; public CompletionTests(String name) { super(name, true); @@ -411,7 +421,7 @@ public class CompletionTests extends AbstractContentAssistTest { //void C2::f() {T/*cursor*/ public void testTypes_MethodScope() throws Exception { - final String[] expected= { "T1", "T2", "T3", "TClass" }; + final String[] expected= { "T1", "T2", "T3", "TClass" }; assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_ID_STRINGS); } @@ -1351,4 +1361,10 @@ public class CompletionTests extends AbstractContentAssistTest { final String[] expected = { "Cat", "meow(void)" }; assertContentAssistResults(fCursorOffset, expected, true, COMPARE_ID_STRINGS); } + + // void foo() { Spec/*cursor*/ + public void testTemplateSpecialization() throws Exception { + final String[] expected = { "Specialization" }; + assertContentAssistResults(fCursorOffset, expected, true, COMPARE_ID_STRINGS); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProposal.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProposal.java index 8ca51bddd5c..5d4273452d5 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProposal.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProposal.java @@ -210,21 +210,11 @@ public class CCompletionProposal implements ICCompletionProposal, ICompletionPro if (fTextViewer != null && string != null) { int index= string.indexOf("()"); //$NON-NLS-1$ if (index != -1 && index + 1 == fCursorPosition) { - int newOffset= fReplacementOffset + fCursorPosition; - - LinkedPositionGroup group= new LinkedPositionGroup(); - group.addPosition(new LinkedPosition(document, newOffset, 0, LinkedPositionGroup.NO_STOP)); - - LinkedModeModel model= new LinkedModeModel(); - model.addGroup(group); - model.forceInstall(); - - LinkedModeUI ui= new EditorLinkedModeUI(model, fTextViewer); - ui.setSimpleMode(true); - ui.setExitPolicy(new ExitPolicy(')')); - ui.setExitPosition(fTextViewer, newOffset + 1, 0, Integer.MAX_VALUE); - ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER); - ui.enter(); + addParameterListLinkedMode(document, ')'); + } + index = string.indexOf("<>"); //$NON-NLS-1$ + if (index != -1 && index + 1 == fCursorPosition) { + addParameterListLinkedMode(document, '>'); } } } catch (BadLocationException x) { @@ -232,6 +222,24 @@ public class CCompletionProposal implements ICCompletionProposal, ICompletionPro } } + private void addParameterListLinkedMode(IDocument document, char endSymbol) throws BadLocationException { + int newOffset= fReplacementOffset + fCursorPosition; + + LinkedPositionGroup group= new LinkedPositionGroup(); + group.addPosition(new LinkedPosition(document, newOffset, 0, LinkedPositionGroup.NO_STOP)); + + LinkedModeModel model= new LinkedModeModel(); + model.addGroup(group); + model.forceInstall(); + + LinkedModeUI ui= new EditorLinkedModeUI(model, fTextViewer); + ui.setSimpleMode(true); + ui.setExitPolicy(new ExitPolicy(endSymbol)); + ui.setExitPosition(fTextViewer, newOffset + 1, 0, Integer.MAX_VALUE); + ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER); + ui.enter(); + } + /** * A class to simplify tracking a reference position in a document. */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java index 54dacc3d7f5..b2d361defe7 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 QNX Software Systems and others. + * Copyright (c) 2007, 2014 QNX Software Systems 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 @@ -12,9 +12,11 @@ * Sergey Prigogin (Google) * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) * Nathan Ridge + * Thomas Corbat (IFS) *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.contentassist; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -56,6 +58,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; @@ -64,6 +67,10 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; 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.ICPPTemplateNonTypeParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; import org.eclipse.cdt.core.parser.util.CharArrayUtils; @@ -94,6 +101,10 @@ import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider; * @author Bryan Wilkinson */ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer { + private static final String TEMPLATE_PARAMETER_PATTERN = "template<{0}> class"; //$NON-NLS-1$; + private static final String TYPENAME = "typename"; //$NON-NLS-1$; + private static final String ELLIPSIS = "..."; //$NON-NLS-1$; + /** * Default constructor is required (executable extension). */ @@ -336,7 +347,8 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer || binding instanceof CImplicitFunction || binding instanceof CImplicitTypedef || binding instanceof CBuiltinVariable - || binding instanceof CBuiltinParameter) + || binding instanceof CBuiltinParameter + || binding instanceof ICPPClassTemplatePartialSpecialization) && !(binding instanceof CPPImplicitMethod)) { return; } @@ -375,26 +387,65 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer return name.length == 0 || name[0] == '{'; } + private void addProposalForClassTemplate(ICPPClassTemplate templateType, CContentAssistInvocationContext context, + int baseRelevance, List proposals) { + int relevance = getClassTypeRelevance(templateType); + StringBuilder representation = new StringBuilder(templateType.getName()); + representation.append("<{0}>"); //$NON-NLS-1$ + + String representationString = MessageFormat.format(representation.toString(), ""); //$NON-NLS-1$ + + String templateParameterRepresentation = buildTemplateParameters(templateType); + String displayString = MessageFormat.format(representation.toString(), templateParameterRepresentation); + + CCompletionProposal proposal = createProposal(representationString, displayString, getImage(templateType), + baseRelevance + relevance, context); + + CProposalContextInformation info = + new CProposalContextInformation(getImage(templateType), displayString, templateParameterRepresentation); + info.setContextInformationPosition(context.getContextInformationOffset()); + proposal.setContextInformation(info); + proposal.setCursorPosition(representationString.length() - 1); + proposals.add(proposal); + } + + private String buildTemplateParameters(ICPPClassTemplate templateType) { + ICPPTemplateParameter[] parameters = templateType.getTemplateParameters(); + StringBuilder representation = new StringBuilder(); + + for (int i = 0; i < parameters.length; i++) { + ICPPTemplateParameter parameter = parameters[i]; + if (i > 0) { + representation.append(", "); //$NON-NLS-1$ + } + if (parameter instanceof ICPPTemplateNonTypeParameter) { + IType parameterType = ((ICPPTemplateNonTypeParameter) parameter).getType(); + String typeName = ASTTypeUtil.getType(parameterType); + representation.append(typeName); + } else if (parameter instanceof ICPPTemplateTypeParameter) { + representation.append(TYPENAME); + } else if (parameter instanceof ICPPTemplateTemplateParameter) { + String templateParameterParameters = buildTemplateParameters((ICPPTemplateTemplateParameter) parameter); + representation.append(MessageFormat.format(TEMPLATE_PARAMETER_PATTERN, templateParameterParameters)); + representation.append(templateParameterParameters); + } + if (parameter.isParameterPack()) { + representation.append(ELLIPSIS); + } + representation.append(' '); + representation.append(parameter.getName()); + } + return representation.toString(); + } + private void handleClass(ICPPClassType classType, IASTCompletionContext astContext, CContentAssistInvocationContext context, int baseRelevance, List proposals) { if (context.isContextInformationStyle()) { - ICPPConstructor[] constructors = classType.getConstructors(); - for (ICPPConstructor constructor : constructors) { - handleFunction(constructor, context, baseRelevance, proposals); - } + addProposalsForConstructors(classType, context, baseRelevance, proposals); + } else if (classType instanceof ICPPClassTemplate) { + addProposalForClassTemplate((ICPPClassTemplate) classType, context, baseRelevance, proposals); } else { - int relevance= 0; - switch (classType.getKey()) { - case ICPPClassType.k_class: - relevance= RelevanceConstants.CLASS_TYPE_RELEVANCE; - break; - case ICompositeType.k_struct: - relevance= RelevanceConstants.STRUCT_TYPE_RELEVANCE; - break; - case ICompositeType.k_union: - relevance= RelevanceConstants.UNION_TYPE_RELEVANCE; - break; - } + int relevance = getClassTypeRelevance(classType); if (astContext instanceof IASTName && !(astContext instanceof ICPPASTQualifiedName)) { IASTName name= (IASTName)astContext; if (name.getParent() instanceof IASTDeclarator) { @@ -407,6 +458,30 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer } } + private void addProposalsForConstructors(ICPPClassType classType, + CContentAssistInvocationContext context, int baseRelevance, List proposals) { + ICPPConstructor[] constructors = classType.getConstructors(); + for (ICPPConstructor constructor : constructors) { + handleFunction(constructor, context, baseRelevance, proposals); + } + } + + private int getClassTypeRelevance(ICPPClassType classType) { + int relevance= 0; + switch (classType.getKey()) { + case ICPPClassType.k_class: + relevance= RelevanceConstants.CLASS_TYPE_RELEVANCE; + break; + case ICompositeType.k_struct: + relevance= RelevanceConstants.STRUCT_TYPE_RELEVANCE; + break; + case ICompositeType.k_union: + relevance= RelevanceConstants.UNION_TYPE_RELEVANCE; + break; + } + return relevance; + } + private void handleFunction(IFunction function, CContentAssistInvocationContext context, int baseRelevance, List proposals) { Image image = getImage(function);