mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-05 08:46:02 +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:
parent
01589f6297
commit
c6dc02c94d
3 changed files with 132 additions and 8 deletions
|
@ -15,6 +15,7 @@
|
||||||
* Nathan Ridge
|
* Nathan Ridge
|
||||||
* Thomas Corbat (IFS)
|
* Thomas Corbat (IFS)
|
||||||
* Michael Woski
|
* Michael Woski
|
||||||
|
* Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.ui.tests.text.contentassist2;
|
package org.eclipse.cdt.ui.tests.text.contentassist2;
|
||||||
|
|
||||||
|
@ -855,7 +856,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
// Printer::/*cursor*/
|
// Printer::/*cursor*/
|
||||||
public void testPrivateStaticMember_109480() throws Exception {
|
public void testPrivateStaticMember_109480() throws Exception {
|
||||||
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=109480
|
// 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);
|
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,7 +1262,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
// }
|
// }
|
||||||
//};
|
//};
|
||||||
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
|
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
|
||||||
final String[] expected= { "add()" };
|
final String[] expected= { "add(tOther)" };
|
||||||
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1428,7 +1429,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
// }
|
// }
|
||||||
// using N::f/*cursor*/
|
// using N::f/*cursor*/
|
||||||
public void testUsingDeclaration_379631() throws Exception {
|
public void testUsingDeclaration_379631() throws Exception {
|
||||||
final String[] expected= { "foo;" };
|
final String[] expected= { "foo()" };
|
||||||
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1575,7 +1576,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
// }
|
// }
|
||||||
// using N::fo/*cursor*/;
|
// using N::fo/*cursor*/;
|
||||||
public void testUsingCompletionWithFollowingSemicolon() throws Exception {
|
public void testUsingCompletionWithFollowingSemicolon() throws Exception {
|
||||||
final String[] expected = { "foo" };
|
final String[] expected = { "foo()" };
|
||||||
assertContentAssistResults(fCursorOffset, expected, true, REPLACEMENT);
|
assertContentAssistResults(fCursorOffset, expected, true, REPLACEMENT);
|
||||||
final String[] expectedInformation = { "null" };
|
final String[] expectedInformation = { "null" };
|
||||||
assertContentAssistResults(fCursorOffset, expectedInformation, true, CONTEXT);
|
assertContentAssistResults(fCursorOffset, expectedInformation, true, CONTEXT);
|
||||||
|
@ -1613,7 +1614,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
setDisplayDefaultArguments(true);
|
setDisplayDefaultArguments(true);
|
||||||
final String[] expectedDisplay = { "default_argument(int i = 23) : void" };
|
final String[] expectedDisplay = { "default_argument(int i = 23) : void" };
|
||||||
assertContentAssistResults(fCursorOffset, expectedDisplay, true, DISPLAY);
|
assertContentAssistResults(fCursorOffset, expectedDisplay, true, DISPLAY);
|
||||||
final String[] expectedReplacement = { "default_argument()" };
|
final String[] expectedReplacement = { "default_argument(i)" };
|
||||||
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
|
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,8 @@ public class ContentAssist2TestSuite extends TestSuite {
|
||||||
addTest(CompletionTests.suite());
|
addTest(CompletionTests.suite());
|
||||||
addTest(CompletionTests_PlainC.suite());
|
addTest(CompletionTests_PlainC.suite());
|
||||||
addTest(ParameterHintTests.suite());
|
addTest(ParameterHintTests.suite());
|
||||||
// addTest(CPPParameterGuessingTests.suite());
|
addTest(CPPParameterGuessingTests.suite());
|
||||||
// addTest(CParameterGuessingTests.suite());
|
addTest(CParameterGuessingTests.suite());
|
||||||
|
|
||||||
addTest(ShowCamelCasePreferenceTest.suite());
|
addTest(ShowCamelCasePreferenceTest.suite());
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,15 @@
|
||||||
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
|
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
|
||||||
* Nathan Ridge
|
* Nathan Ridge
|
||||||
* Thomas Corbat (IFS)
|
* Thomas Corbat (IFS)
|
||||||
|
* Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.ui.text.contentassist;
|
package org.eclipse.cdt.internal.ui.text.contentassist;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jface.preference.IPreferenceStore;
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
import org.eclipse.jface.resource.ImageDescriptor;
|
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 TEMPLATE_PARAMETER_PATTERN = "template<{0}> class"; //$NON-NLS-1$;
|
||||||
private static final String TYPENAME = "typename"; //$NON-NLS-1$;
|
private static final String TYPENAME = "typename"; //$NON-NLS-1$;
|
||||||
private static final String ELLIPSIS = "..."; //$NON-NLS-1$;
|
private static final String ELLIPSIS = "..."; //$NON-NLS-1$;
|
||||||
|
private String fPrefix;
|
||||||
|
private ArrayList<IBinding> fAvailableElements;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor is required (executable extension).
|
* Default constructor is required (executable extension).
|
||||||
*/
|
*/
|
||||||
public DOMCompletionProposalComputer() {
|
public DOMCompletionProposalComputer() {
|
||||||
|
fPrefix = ""; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<ICompletionProposal> computeCompletionProposals(
|
protected List<ICompletionProposal> computeCompletionProposals(
|
||||||
CContentAssistInvocationContext context,
|
CContentAssistInvocationContext context,
|
||||||
IASTCompletionNode completionNode, String prefix) {
|
IASTCompletionNode completionNode, String prefix) {
|
||||||
|
fPrefix = prefix;
|
||||||
|
initializeDefinedElements(context);
|
||||||
List<ICompletionProposal> proposals = new ArrayList<>();
|
List<ICompletionProposal> proposals = new ArrayList<>();
|
||||||
|
|
||||||
if (inPreprocessorDirective(context)) {
|
if (inPreprocessorDirective(context)) {
|
||||||
|
@ -587,7 +595,122 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
|
||||||
proposal.setContextInformation(info);
|
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) {
|
private boolean skipDefaultedParameter(IParameter param) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue