From d159cd9545c77d98407e55407c647f078913e900 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Thu, 6 Dec 2012 23:23:59 -0500 Subject: [PATCH] Bug 379631 - code-completion of functions in using-declarations Change-Id: Ifae9e0e790629e03c1ad93988ea535e42373d448 Reviewed-on: https://git.eclipse.org/r/9066 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../text/contentassist2/CompletionTests.java | 15 ++++- .../internal/ui/text/CHeuristicScanner.java | 30 ++++++++- .../DOMCompletionProposalComputer.java | 65 ++++++++++++++++--- 3 files changed, 97 insertions(+), 13 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 49b0c3e24b3..da4abfe8443 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 @@ -12,10 +12,9 @@ * IBM Corporation * Sergey Prigogin (Google) * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) + * Nathan Ridge *******************************************************************************/ -package org.eclipse.cdt.ui.tests.text.contentassist2; - -import java.io.File; +package org.eclipse.cdt.ui.tests.text.contentassist2;import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Set; @@ -28,6 +27,7 @@ import org.eclipse.jface.text.IDocument; import org.eclipse.cdt.core.testplugin.TestScannerProvider; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +; /** * A collection of code completion tests. @@ -1365,4 +1365,13 @@ public class CompletionTests extends AbstractContentAssistTest { final String[] expected= { "__builtin_va_arg(ap, type)" }; assertCompletionResults(fCursorOffset, expected, COMPARE_ID_STRINGS); } + + // namespace N { + // void foo(int); + // } + // using N::f/*cursor*/ + public void testUsingDeclaration_Bug379631() throws Exception { + final String[] expected= { "foo;" }; + assertCompletionResults(fCursorOffset, expected, COMPARE_REP_STRINGS); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CHeuristicScanner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CHeuristicScanner.java index 4a8a10c2c67..db8e3f30b1c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CHeuristicScanner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CHeuristicScanner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2012 IBM Corporation 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 @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Sergey Prigogin, Google * Anton Leherbauer (Wind River Systems) + * Nathan Ridge *******************************************************************************/ package org.eclipse.cdt.internal.ui.text; @@ -1202,4 +1203,31 @@ public final class CHeuristicScanner implements Symbols { } } + /** + * A simplified interface to CHeuristicScanner's + * nextToken() and previousToken() methods. + */ + public static class TokenStream { + private CHeuristicScanner fScanner; + private int fPos; + private final int fDocumentLength; + + public TokenStream(IDocument document, int startPos) { + fScanner = new CHeuristicScanner(document); + fPos = startPos; + fDocumentLength = document.getLength(); + } + + public int nextToken() { + int result = fScanner.nextToken(fPos, fDocumentLength); + fPos = fScanner.getPosition(); + return result; + } + + public int previousToken() { + int result = fScanner.previousToken(fPos, 0); + fPos = fScanner.getPosition(); + return result; + } + } } 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 1fdb266723d..54dacc3d7f5 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, 2011 QNX Software Systems and others. + * Copyright (c) 2007, 2012 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 @@ -11,6 +11,7 @@ * Anton Leherbauer (Wind River Systems) * Sergey Prigogin (Google) * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion) + * Nathan Ridge *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.contentassist; @@ -83,6 +84,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.AccessContext; import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory; +import org.eclipse.cdt.internal.ui.text.CHeuristicScanner; +import org.eclipse.cdt.internal.ui.text.Symbols; import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider; /** @@ -91,7 +94,6 @@ import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider; * @author Bryan Wilkinson */ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer { - /** * Default constructor is required (executable extension). */ @@ -152,6 +154,40 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer return proposals; } + /** + * Checks whether the invocation offset is inside a using-declaration. + * + * @param context the invocation context + * @return {@code true} if the invocation offset is inside a using-declaration + */ + private boolean inUsingDeclaration(CContentAssistInvocationContext context) { + IDocument doc = context.getDocument(); + int offset = context.getInvocationOffset(); + + // Look at the tokens preceding the invocation offset. + CHeuristicScanner.TokenStream tokenStream = new CHeuristicScanner.TokenStream(doc, offset); + int token = tokenStream.previousToken(); + + // There may be a partially typed identifier which is being completed. + if (token == Symbols.TokenIDENT) + token = tokenStream.previousToken(); + + // Before that, there may be any number of "namespace::" token pairs. + while (token == Symbols.TokenDOUBLECOLON) { + token = tokenStream.previousToken(); + if (token == Symbols.TokenUSING) { // there could also be a leading "::" for global namespace + return true; + } else if (token != Symbols.TokenIDENT) { + return false; + } else { + token = tokenStream.previousToken(); + } + } + + // Before that, there must be a "using" token. + return token == Symbols.TokenUSING; + } + /** * Test whether the invocation offset is inside or before the preprocessor directive keyword. * @@ -377,10 +413,11 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer StringBuilder repStringBuff = new StringBuilder(); repStringBuff.append(function.getName()); + repStringBuff.append('('); StringBuilder dispargs = new StringBuilder(); // for the dispargString - StringBuilder idargs = new StringBuilder(); // for the idargString + StringBuilder idargs = new StringBuilder(); // for the idargString boolean hasArgs = true; String returnTypeStr = null; IParameter[] params = function.getParameters(); @@ -388,12 +425,12 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer for (int i = 0; i < params.length; ++i) { IType paramType = params[i].getType(); if (i > 0) { - dispargs.append(','); - idargs.append(','); - } + dispargs.append(','); + idargs.append(','); + } dispargs.append(ASTTypeUtil.getType(paramType, false)); - idargs.append(ASTTypeUtil.getType(paramType, false)); + idargs.append(ASTTypeUtil.getType(paramType, false)); String paramName = params[i].getName(); if (paramName != null && paramName.length() > 0) { dispargs.append(' '); @@ -439,7 +476,17 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer idStringBuff.append(')'); String idString = idStringBuff.toString(); - repStringBuff.append(')'); + // In a using declaration, emitting parentheses after the function + // name is useless, since the user will just have to delete them. + // Instead, emitting a semicolon is useful. + boolean inUsingDeclaration = inUsingDeclaration(context); + if (inUsingDeclaration) { + repStringBuff.setLength(repStringBuff.length() - 1); // Remove opening parenthesis + repStringBuff.append(';'); + } else { + repStringBuff.append(')'); + } + String repString = repStringBuff.toString(); final int relevance = function instanceof ICPPMethod ? @@ -447,7 +494,7 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer CCompletionProposal proposal = createProposal(repString, dispString, idString, context.getCompletionNode().getLength(), image, baseRelevance + relevance, context); if (!context.isContextInformationStyle()) { - int cursorPosition = hasArgs ? (repString.length() - 1) : repString.length(); + int cursorPosition = (!inUsingDeclaration && hasArgs) ? (repString.length() - 1) : repString.length(); proposal.setCursorPosition(cursorPosition); }