1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 438549 - Fixed a regression for parameterless functions and

re-enabled parameter guessing.

Change-Id: I4b6347999d675335c8e88f4bffed37fcef2e0bc3
Signed-off-by: mazab <mohamed_azab@mentor.com>
This commit is contained in:
mazab 2015-12-13 11:50:48 +02:00 committed by Gerrit Code Review @ Eclipse.org
parent 01589f6297
commit c6dc02c94d
3 changed files with 132 additions and 8 deletions

View file

@ -15,6 +15,7 @@
* Nathan Ridge
* Thomas Corbat (IFS)
* Michael Woski
* Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text.contentassist2;
@ -855,7 +856,7 @@ public class CompletionTests extends AbstractContentAssistTest {
// Printer::/*cursor*/
public void testPrivateStaticMember_109480() throws Exception {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=109480
final String[] expected= { "InitPrinter()", "port" };
final String[] expected= { "InitPrinter(port)", "port" };
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
@ -1261,7 +1262,7 @@ public class CompletionTests extends AbstractContentAssistTest {
// }
//};
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
final String[] expected= { "add()" };
final String[] expected= { "add(tOther)" };
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
@ -1428,7 +1429,7 @@ public class CompletionTests extends AbstractContentAssistTest {
// }
// using N::f/*cursor*/
public void testUsingDeclaration_379631() throws Exception {
final String[] expected= { "foo;" };
final String[] expected= { "foo()" };
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
@ -1575,7 +1576,7 @@ public class CompletionTests extends AbstractContentAssistTest {
// }
// using N::fo/*cursor*/;
public void testUsingCompletionWithFollowingSemicolon() throws Exception {
final String[] expected = { "foo" };
final String[] expected = { "foo()" };
assertContentAssistResults(fCursorOffset, expected, true, REPLACEMENT);
final String[] expectedInformation = { "null" };
assertContentAssistResults(fCursorOffset, expectedInformation, true, CONTEXT);
@ -1613,7 +1614,7 @@ public class CompletionTests extends AbstractContentAssistTest {
setDisplayDefaultArguments(true);
final String[] expectedDisplay = { "default_argument(int i = 23) : void" };
assertContentAssistResults(fCursorOffset, expectedDisplay, true, DISPLAY);
final String[] expectedReplacement = { "default_argument()" };
final String[] expectedReplacement = { "default_argument(i)" };
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
}

View file

@ -72,8 +72,8 @@ public class ContentAssist2TestSuite extends TestSuite {
addTest(CompletionTests.suite());
addTest(CompletionTests_PlainC.suite());
addTest(ParameterHintTests.suite());
// addTest(CPPParameterGuessingTests.suite());
// addTest(CParameterGuessingTests.suite());
addTest(CPPParameterGuessingTests.suite());
addTest(CParameterGuessingTests.suite());
addTest(ShowCamelCasePreferenceTest.suite());

View file

@ -13,12 +13,15 @@
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
* Nathan Ridge
* Thomas Corbat (IFS)
* Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.contentassist;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
@ -107,17 +110,22 @@ 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$;
private String fPrefix;
private ArrayList<IBinding> fAvailableElements;
/**
* Default constructor is required (executable extension).
*/
public DOMCompletionProposalComputer() {
fPrefix = ""; //$NON-NLS-1$
}
@Override
protected List<ICompletionProposal> computeCompletionProposals(
CContentAssistInvocationContext context,
IASTCompletionNode completionNode, String prefix) {
fPrefix = prefix;
initializeDefinedElements(context);
List<ICompletionProposal> proposals = new ArrayList<>();
if (inPreprocessorDirective(context)) {
@ -587,7 +595,122 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
proposal.setContextInformation(info);
}
proposals.add(proposal);
/*
* The ParameterGuessingProposal will be active if the function accepts parameters and the content assist is
* invoked before typing any parameters. Otherwise, the normal Parameter Hint Proposal will be added.
*/
if (function.getParameters() != null && function.getParameters().length > 0 && isBeforeParameters(context)) {
proposals.add(ParameterGuessingProposal.createProposal(context, fAvailableElements, proposal, function, fPrefix));
} else {
proposals.add(proposal);
}
}
/**
* Returns true if the invocation is at the function name or before typing any parameters
*/
private boolean isBeforeParameters(CContentAssistInvocationContext context) {
/*
* Invocation offset and parse offset are the same if content assist is invoked while in the function
* name (i.e. before the '('). After that, the parse offset will indicate the end of the name part. If
* the diff. between them is zero, then we're still inside the function name part.
*/
int relativeOffset = context.getInvocationOffset() - context.getParseOffset();
if (relativeOffset == 0)
return true;
int startOffset = context.getParseOffset();
String completePrefix = context.getDocument().get().substring(startOffset,
context.getInvocationOffset());
int lastChar = getLastNonWhitespaceChar(completePrefix);
if (lastChar != -1 && completePrefix.charAt(lastChar) == '(')
return true;
return false;
}
private static int getLastNonWhitespaceChar(String str) {
char[] chars = str.toCharArray();
for (int i = chars.length - 1; i >= 0; i--) {
if (!Character.isWhitespace(chars[i]))
return i;
}
return -1;
}
/**
* Initializes the list of defined elements at the start of the current statement.
*/
private void initializeDefinedElements(CContentAssistInvocationContext context) {
/*
* Get all defined elements before the start of the statement.
* ex1: int a = foo(
* ^ --> We don't want 'a' as a suggestion.
* ex2: char* foo(int a, int b) {return NULL;}
* void bar(char* name) {}
* ...
* bar( foo(
* ^ --> If this offset is used, the only defined name will be "bar(char*)".
*/
int startOffset = getStatementStartOffset(context.getDocument(),
context.getParseOffset() - fPrefix.length());
Map<String, IBinding> elementsMap = new HashMap<>();
IASTCompletionNode node = null;
// Create a content assist context that points to the start of the statement.
CContentAssistInvocationContext newContext = new CContentAssistInvocationContext(
context.getViewer(), startOffset, context.getEditor(), true, false);
try {
node = newContext.getCompletionNode();
if (node != null) {
IASTTranslationUnit tu = node.getTranslationUnit();
IASTName[] names = node.getNames();
for (IASTName name : names) {
IASTCompletionContext astContext = name.getCompletionContext();
if (astContext != null) {
IBinding[] bindings = astContext.findBindings(name, true);
if (bindings != null) {
AccessContext accessibilityContext = new AccessContext(name);
for (IBinding binding : bindings) {
// Consider only variables that are part of the current translation unit and fields.
if (binding instanceof IVariable
&& accessibilityContext.isAccessible(binding)
&& !elementsMap.containsKey(binding.getName())) {
if (binding instanceof ICPPField) {
elementsMap.put(binding.getName(), binding);
} else {
IASTName[] declarations = tu.getDeclarationsInAST(binding);
if (declarations.length != 0)
elementsMap.put(binding.getName(), binding);
}
}
}
}
}
}
}
} finally {
fAvailableElements = new ArrayList<>(elementsMap.values());
newContext.dispose();
}
}
/**
* Returns the position after last semicolon or opening or closing brace before the given offset.
*/
private static int getStatementStartOffset(IDocument doc, int offset) {
if (offset != 0) {
String docPart;
try {
docPart = doc.get(0, offset);
int index = docPart.lastIndexOf(';');
int tmpIndex = docPart.lastIndexOf('{');
index = (index < tmpIndex) ? tmpIndex : index;
tmpIndex = docPart.lastIndexOf('}');
index = (index < tmpIndex) ? tmpIndex : index;
return index + 1;
} catch (BadLocationException e) {
CUIPlugin.log(e);
}
}
return offset;
}
private boolean skipDefaultedParameter(IParameter param) {