Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormazab2015-06-23 13:51:48 +0000
committerGerrit Code Review @ Eclipse.org2015-12-03 00:14:42 +0000
commit241a60fe8a522a0b39586ec5ec93c67a77f2898d (patch)
treeacb9b35a4782e6c293dd7d23ac52638a7c447e7e
parente636b977a94cd9b00d5f5437578a08e0945d8ff5 (diff)
downloadorg.eclipse.cdt-241a60fe8a522a0b39586ec5ec93c67a77f2898d.tar.gz
org.eclipse.cdt-241a60fe8a522a0b39586ec5ec93c67a77f2898d.tar.xz
org.eclipse.cdt-241a60fe8a522a0b39586ec5ec93c67a77f2898d.zip
Bug 438549 Add mechanism for parameter guessing.
Change-Id: Ib348e401932a9119185dbab8ecacaf80fd3e17ff Signed-off-by: mazab <mohamed_azab@mentor.com>
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java104
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CPPParameterGuessingTests.java141
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CParameterGuessingTests.java79
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java13
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/ContentAssist2TestSuite.java5
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java127
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/FunctionCompletionProposal.java136
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuesser.java390
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuessingProposal.java368
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/PositionBasedCompletionProposal.java169
10 files changed, 1519 insertions, 13 deletions
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java
index 99b9b83cbcb..e6c78ba6d80 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/AbstractContentAssistTest.java
@@ -12,12 +12,15 @@
* Markus Schorn (Wind River Systems)
* Thomas Corbat (IFS)
* Sergey Prigogin (Google)
+ * Mohamed Azab (Mentor Graphics)
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text.contentassist2;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@@ -49,6 +52,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposal;
import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistProcessor;
import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference;
+import org.eclipse.cdt.internal.ui.text.contentassist.ParameterGuessingProposal;
import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants;
public abstract class AbstractContentAssistTest extends BaseUITestCase {
@@ -56,6 +60,18 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
ID, DISPLAY, REPLACEMENT, CONTEXT, INFORMATION
}
+ private class ContentAssistResult {
+ long startTime;
+ long endTime;
+ Object[] results;
+
+ public ContentAssistResult(long startTime, long endTime, Object[] results) {
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.results = results;
+ }
+ }
+
protected ICProject fCProject;
private IFile fCFile;
protected ITextEditor fEditor;
@@ -107,8 +123,9 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
return CUIPlugin.getDefault().getPreferenceStore();
}
- protected void assertContentAssistResults(int offset, int length, String[] expected,
- boolean isCompletion, boolean isTemplate, boolean filterResults, CompareType compareType) throws Exception {
+ private ContentAssistResult invokeContentAssist(int offset, int length,
+ boolean isCompletion, boolean isTemplate, boolean filterResults)
+ throws Exception {
if (CTestPlugin.getDefault().isDebugging()) {
System.out.println("\n\n\n\n\nTesting " + this.getClass().getName());
}
@@ -138,12 +155,20 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
results= filterResults(results, isCode);
}
}
- String[] resultStrings= toStringArray(results, compareType);
+ return new ContentAssistResult(startTime, endTime, results);
+ }
+
+ protected void assertContentAssistResults(int offset, int length,
+ String[] expected, boolean isCompletion, boolean isTemplate,
+ boolean filterResults, CompareType compareType) throws Exception {
+ ContentAssistResult r = invokeContentAssist(offset, length, isCompletion, isTemplate, filterResults);
+
+ String[] resultStrings= toStringArray(r.results, compareType);
Arrays.sort(expected);
Arrays.sort(resultStrings);
if (CTestPlugin.getDefault().isDebugging()) {
- System.out.println("Time: " + (endTime - startTime) + " ms");
+ System.out.println("Time: " + (r.endTime - r.startTime) + " ms");
for (String proposal : resultStrings) {
System.out.println("Result: " + proposal);
}
@@ -177,6 +202,77 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
}
}
+ protected void assertContentAssistResults(int offset, int length, Map<String, String[][]> expected,
+ boolean isCompletion, boolean isTemplate, boolean filterResults, CompareType compareType)
+ throws Exception {
+ ContentAssistResult r = invokeContentAssist(offset, length, isCompletion, isTemplate, filterResults);
+ Map<String, String[][]> resultMap = toMap(r.results, compareType);
+
+ if (CTestPlugin.getDefault().isDebugging()) {
+ System.out.println("Time : " + (r.endTime - r.startTime) + " ms");
+ for (String proposal : resultMap.keySet()) {
+ System.out.println("Result: " + proposal);
+ String[][] result = resultMap.get(proposal);
+ for (String[] row : result) {
+ for (String s : row) {
+ System.out.print(s + " ");
+ }
+ System.out.println();
+ }
+ }
+ System.out.println();
+ }
+
+ for (String proposal : expected.keySet()) {
+ String[][] result = resultMap.get(proposal);
+ assertNotNull(result);
+ String[][] expectedGuesses = expected.get(proposal);
+ String exp = "";
+ String guess = "";
+ int minLength = expectedGuesses.length < result.length ? expectedGuesses.length : result.length;
+ for (int i = 0; i < minLength; i++) {
+ String[] tmp = expectedGuesses[i];
+ Arrays.sort(tmp);
+ exp += toString(tmp) + "\n";
+ tmp = result[i];
+ Arrays.sort(tmp);
+ guess += toString(tmp) + "\n";
+ }
+ assertEquals(exp, guess);
+ }
+ }
+
+ private Map<String, String[][]> toMap(Object[] results,
+ CompareType compareType) {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ for (Object result : results) {
+ switch (compareType) {
+ case REPLACEMENT:
+ if (result instanceof ParameterGuessingProposal) {
+ ParameterGuessingProposal proposal = (ParameterGuessingProposal) result;
+ String pName = proposal.getReplacementString();
+ ICompletionProposal[][] pProposals = proposal
+ .getParametersGuesses();
+ String[][] p;
+ if (pProposals != null) {
+ p = new String[pProposals.length][];
+ for (int i = 0; i < pProposals.length; i++) {
+ p[i] = new String[pProposals[i].length];
+ for (int j = 0; j < pProposals[i].length; j++) {
+ p[i][j] = pProposals[i][j].getDisplayString();
+ }
+ }
+ } else {
+ p = new String[0][];
+ }
+ resultsMap.put(pName, p);
+ }
+ break;
+ }
+ }
+ return resultsMap;
+ }
+
protected void assertContentAssistResults(int offset, int length, String[] expected, boolean isCompletion, boolean isTemplate, CompareType compareType) throws Exception {
assertContentAssistResults(offset, length, expected, isCompletion, isTemplate, true, compareType);
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CPPParameterGuessingTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CPPParameterGuessingTests.java
new file mode 100644
index 00000000000..f6f8883afa6
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CPPParameterGuessingTests.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Mentor Graphics Corporation.
+ * 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
+ *
+ * Contributors:
+ * Mohamed Azab (Mentor Graphics) - Initial implementation.
+ *******************************************************************************/
+package org.eclipse.cdt.ui.tests.text.contentassist2;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+
+public class CPPParameterGuessingTests extends AbstractContentAssistTest {
+ private static final String HEADER_FILE_NAME = "PGTest.h";
+ private static final String SOURCE_FILE_NAME = "PGTest.cpp";
+
+ // {PGTest.h}
+ // class aClass {
+ // public:
+ // int aField;
+ // void aMethod(char c);
+ // void aMethod(char c, int x);
+ // };
+ //
+ // class bClass : aClass {
+ // };
+ //
+ // void overload(int x, aClass a);
+ // void overload(int x, aClass* aPtr);
+ // int piab(aClass a, bClass b);
+ // template<class T>void tFunc(T x, T y);
+
+ public CPPParameterGuessingTests(String name) {
+ super(name, true);
+ }
+
+ public static Test suite() {
+ return BaseTestCase.suite(CPPParameterGuessingTests.class, "_");
+ }
+
+ @Override
+ protected IFile setUpProjectContent(IProject project) throws Exception {
+ String headerContent = readTaggedComment(HEADER_FILE_NAME);
+ StringBuilder sourceContent = getContentsForTest(1)[0];
+ sourceContent.insert(0, "#include \"" + HEADER_FILE_NAME + "\"\n");
+ assertNotNull(createFile(project, HEADER_FILE_NAME, headerContent));
+ return createFile(project, SOURCE_FILE_NAME, sourceContent.toString());
+ }
+
+ protected void assertParametersGuesses(Map<String, String[][]> expected)
+ throws Exception {
+ assertContentAssistResults(getBuffer().length() - 1, 0, expected, true,
+ false, false, CompareType.REPLACEMENT);
+ }
+
+ // void foo(){
+ // aClass* aTypePtr;
+ // bClass bTypeObj;
+ // piab(
+ public void testIndirectTypes() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("piab(a, b)", new String[][] { { "*aTypePtr", "bTypeObj" },
+ { "bTypeObj" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // void foo(){
+ // int intVal;
+ // aClass aTypeObj;
+ // overload(
+ public void testOverloadedFunction() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("overload(x, a)", new String[][] { { "intVal" }, { "aTypeObj" } });
+ resultsMap.put("overload(x, aPtr)",
+ new String[][] { { "intVal" }, { "&aTypeObj" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // void foo(){
+ // aClass aTypeObj;
+ // tFunc<aClass> (
+ public void testTemplateFunction() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("tFunc<aClass> (x, y)", new String[][] { { "x" },
+ { "y" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // struct container {
+ // aClass* aTypePtr;
+ // };
+ //
+ // void foo(){
+ // char charX, charY, charZ;
+ // container containerObj;
+ // containerObj.aTypePtr = new aClass();
+ // containerObj.aTypePtr->
+ public void testOverloadedMethod() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("aMethod(c)", new String[][] { { "charX", "charY", "charZ" } });
+ resultsMap.put("aMethod(c, x)", new String[][] { { "charX", "charY", "charZ" },
+ { "charX", "charY", "charZ" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // void testParameterNameMatching(int lngName, int shrt);
+ //
+ // void foo() {
+ // int lng;
+ // int shrtNameMatch;
+ // testParameter
+ public void testParameterNameMatching() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("testParameterNameMatching(lngName, shrt)", new String[][] {
+ { "lng", "shrtNameMatch" }, { "lng", "shrtNameMatch" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // class cClass : bClass {
+ // public:
+ // cClass(int inCall) {
+ // char charX, charY;
+ // aClass::
+ public void testInsideConstructor() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("aMethod(c)", new String[][] { { "charX", "charY", "inCall" } });
+ resultsMap.put("aMethod(c, x)", new String[][] {
+ { "charX", "charY"}, { "inCall" } });
+ assertParametersGuesses(resultsMap);
+ }
+}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CParameterGuessingTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CParameterGuessingTests.java
new file mode 100644
index 00000000000..5c9b94d6345
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CParameterGuessingTests.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Mentor Graphics Corporation.
+ * 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
+ *
+ * Contributors:
+ * Mohamed Azab (Mentor Graphics) - Initial implementation.
+ *******************************************************************************/
+package org.eclipse.cdt.ui.tests.text.contentassist2;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+
+public class CParameterGuessingTests extends AbstractContentAssistTest {
+ private static final String HEADER_FILE_NAME = "PGTest_C.h";
+ private static final String SOURCE_FILE_NAME = "PGTest_C.c";
+
+ // {PGTest_C.h}
+ // typedef struct aStruct {
+ // int a;
+ // int b;
+ // } aStruct;
+ //
+ // void ov1(int x, aStruct a);
+ // void ov2(int x, aStruct* aPtr);
+ // int funWith2ATypeObjectParams(aStruct a, aStruct b);
+
+ public CParameterGuessingTests(String name) {
+ super(name, false);
+ }
+
+ public static Test suite() {
+ return BaseTestCase.suite(CParameterGuessingTests.class, "_");
+ }
+
+ @Override
+ protected IFile setUpProjectContent(IProject project) throws Exception {
+ String headerContent = readTaggedComment(HEADER_FILE_NAME);
+ StringBuilder sourceContent = getContentsForTest(1)[0];
+ sourceContent.insert(0, "#include \"" + HEADER_FILE_NAME + "\"\n");
+ assertNotNull(createFile(project, HEADER_FILE_NAME, headerContent));
+ return createFile(project, SOURCE_FILE_NAME, sourceContent.toString());
+ }
+
+ protected void assertParametersGuesses(Map<String, String[][]> expected) throws Exception {
+ assertContentAssistResults(getBuffer().length() - 1, 0, expected, true,
+ false, false, CompareType.REPLACEMENT);
+ }
+
+ // void foo(){
+ // aStruct* axPtr;
+ // aStruct ax;
+ // funWith2ATypeObjectParams(
+ public void testIndirectTypes() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("funWith2ATypeObjectParams(a, b)", new String[][] { { "ax", "*axPtr" },
+ { "ax", "*axPtr" } });
+ assertParametersGuesses(resultsMap);
+ }
+
+ // void foo(){
+ // aStruct ax;
+ // ov
+ public void testMultipleFunctions() throws Exception {
+ Map<String, String[][]> resultsMap = new HashMap<>();
+ resultsMap.put("ov1(x, a)", new String[][] { { "x" }, { "ax" } });
+ resultsMap.put("ov2(x, aPtr)", new String[][] { { "x" }, { "&ax" } });
+ assertParametersGuesses(resultsMap);
+ }
+}
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 85bcbc33ecd..a3325c6fcdd 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2014 Wind River Systems, Inc. and others.
+ * Copyright (c) 2006, 2015 Wind River Systems, Inc. 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
@@ -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);
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/ContentAssist2TestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/ContentAssist2TestSuite.java
index 7a064666c2d..354cb986d25 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/ContentAssist2TestSuite.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/ContentAssist2TestSuite.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2007 Siemens AG and others.
+ * Copyright (c) 2006, 2015 Siemens AG and others.
* All rights reserved. This content 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 @@
* Norbert Ploett - Initial implementation
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
+ * Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text.contentassist2;
@@ -71,6 +72,8 @@ public class ContentAssist2TestSuite extends TestSuite {
addTest(CompletionTests.suite());
addTest(CompletionTests_PlainC.suite());
addTest(ParameterHintTests.suite());
+ addTest(CPPParameterGuessingTests.suite());
+ addTest(CParameterGuessingTests.suite());
addTest(ShowCamelCasePreferenceTest.suite());
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 5c7323936f6..dc6367d8407 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, 2014 QNX Software Systems and others.
+ * Copyright (c) 2007, 2015 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
@@ -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<ICompletionProposal>();
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 content assist is invoked before typing
+ * any parameters. Otherwise, the normal Parameter Hint Proposal will be added.
+ */
+ if (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) {
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/FunctionCompletionProposal.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/FunctionCompletionProposal.java
new file mode 100644
index 00000000000..5c69c51dd02
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/FunctionCompletionProposal.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Tom Eicher <eclipse@tom.eicher.name> - [content assist] prefix complete casted method proposals - https://bugs.eclipse.org/bugs/show_bug.cgi?id=247547
+ * Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text.contentassist;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.link.ILinkedModeListener;
+import org.eclipse.jface.text.link.LinkedModeModel;
+import org.eclipse.jface.text.link.LinkedModeUI;
+import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags;
+import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy;
+import org.eclipse.jface.text.link.LinkedPosition;
+import org.eclipse.jface.text.link.LinkedPositionGroup;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
+
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IParameter;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+/**
+ * This is a modified version of org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal
+ *
+ * This class adds a linked mode function compilation proposal with exit policy.
+ */
+public class FunctionCompletionProposal extends CCompletionProposal {
+ private boolean fHasParametersComputed;
+ private boolean fHasParameters;
+ protected IParameter[] fFunctionParameters;
+ protected int fInvocationOffset;
+ protected int fParseOffset;
+ protected ITranslationUnit fTranslationUnit;
+ protected IDocument fDocument;
+
+ public FunctionCompletionProposal(String replacementString, int replacementOffset, int replacementLength,
+ Image image, String displayString, String idString, int relevance, ITextViewer viewer,
+ IFunction function, int invocationOffset, int parseOffset, ITranslationUnit translationUnit, IDocument document) {
+ super(replacementString, replacementOffset, replacementLength, image, displayString, idString,
+ relevance, viewer);
+ fFunctionParameters = function.getParameters();
+ fInvocationOffset = invocationOffset;
+ fParseOffset = parseOffset;
+ fTranslationUnit = translationUnit;
+ fDocument = document;
+ }
+
+ @Override
+ public void apply(IDocument document, char trigger, int offset) {
+ if (trigger == ' ' || trigger == '(')
+ trigger = '\0';
+ super.apply(document, trigger, offset);
+ if (hasParameters()) {
+ setUpLinkedMode(document, ')');
+ } else if (getReplacementString().endsWith(";")) { //$NON-NLS-1$
+ setUpLinkedMode(document, ';');
+ }
+ }
+
+ /**
+ * Returns {@code true} if the method has any parameters, {@code true} if it has no parameters
+ */
+ protected final boolean hasParameters() {
+ if (!fHasParametersComputed) {
+ fHasParametersComputed = true;
+ fHasParameters = computeHasParameters();
+ }
+ return fHasParameters;
+ }
+
+ private boolean computeHasParameters() {
+ return (fFunctionParameters != null && fFunctionParameters.length != 0);
+ }
+
+ protected static class ExitPolicy implements IExitPolicy {
+ final char fExitCharacter;
+
+ public ExitPolicy(char exitCharacter) {
+ fExitCharacter = exitCharacter;
+ }
+
+ @Override
+ public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event, int offset, int length) {
+ if (event.character == fExitCharacter) {
+ if (environment.anyPositionContains(offset)) {
+ return new ExitFlags(ILinkedModeListener.UPDATE_CARET, false);
+ } else {
+ return new ExitFlags(ILinkedModeListener.UPDATE_CARET, true);
+ }
+ }
+
+ switch (event.character) {
+ case ';':
+ return new ExitFlags(ILinkedModeListener.NONE, true);
+ default:
+ return null;
+ }
+ }
+ }
+
+ protected void setUpLinkedMode(IDocument document, char closingCharacter) {
+ if (fTextViewer != null) {
+ int exit = getReplacementOffset() + getReplacementString().length();
+ try {
+ LinkedPositionGroup group = new LinkedPositionGroup();
+ group.addPosition(new LinkedPosition(document, fInvocationOffset, 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(closingCharacter));
+ ui.setExitPosition(fTextViewer, exit, 0, Integer.MAX_VALUE);
+ ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER);
+ ui.enter();
+ } catch (BadLocationException x) {
+ CUIPlugin.log(x);
+ }
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuesser.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuesser.java
new file mode 100644
index 00000000000..828c38769c4
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuesser.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text.contentassist;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.ICompositeType;
+import org.eclipse.cdt.core.dom.ast.IEnumeration;
+import org.eclipse.cdt.core.dom.ast.IEnumerator;
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IPointerType;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.ITypedef;
+import org.eclipse.cdt.core.dom.ast.IVariable;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
+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.ICPPUsingDeclaration;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.IField;
+import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
+import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
+
+/**
+ * This class is based on org.eclipse.jdt.internal.ui.text.java.ParameterGuesser
+ *
+ * This class produces a logically-ordered list of applicable variables for later use as parameter guessing
+ * proposals for a function parameter.
+ */
+public class ParameterGuesser {
+ private final Set<String> fAlreadyMatchedNames = new HashSet<>();
+
+ /**
+ * Variable type. Used to choose the best guess based on scope (LOCAL is preferred over FIELD,
+ * which is preferred over GLOBAL).
+ */
+ static enum VariableType {
+ LOCAL(0),
+ FIELD(1),
+ GLOBAL(3); // Give the global variables a lower priority.
+
+ private final int priority;
+
+ private VariableType(int priority) {
+ this.priority = priority;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+ }
+
+ private final static class Variable {
+ public final String name;
+ public final VariableType variableType;
+ public final int positionScore;
+
+ public int totalScore;
+
+ public final char[] triggerChars;
+ public final ImageDescriptor descriptor;
+
+ public boolean alreadyMatched;
+
+ public Variable(String name, VariableType variableType, int positionScore,
+ char[] triggerChars, ImageDescriptor descriptor) {
+ this.name = name;
+ this.variableType = variableType;
+ this.positionScore = positionScore;
+ this.triggerChars = triggerChars;
+ this.descriptor = descriptor;
+ }
+ }
+
+ private Collection<Variable> evaluateVisibleMatches(IType expectedType, List<IBinding> suggestions)
+ throws CModelException {
+ Set<Variable> res = new HashSet<>();
+ int size = suggestions.size();
+ for (int i = 0; i < size; i++) {
+ Variable variable = createVariable(suggestions.get(i), expectedType, i);
+ if (variable != null) {
+ if (fAlreadyMatchedNames.contains(variable.name)) {
+ variable.alreadyMatched = true;
+ }
+ res.add(variable);
+ }
+ }
+ return res;
+ }
+
+ private boolean isAnonymousBinding(IBinding binding) {
+ char[] name = binding.getNameCharArray();
+ return name.length == 0 || name[0] == '{';
+ }
+
+ protected IType getType(IBinding binding) {
+ if (!isAnonymousBinding(binding) && binding instanceof IVariable)
+ return ((IVariable) binding).getType();
+ return null;
+ }
+
+ private Variable createVariable(IBinding element, IType enclosingType, int positionScore)
+ throws CModelException {
+ IType elementType = getType(element);
+ String elementName = element.getName();
+ if (elementType != null
+ && (elementType.toString().equals(enclosingType.toString())
+ || elementType.isSameType(enclosingType)
+ || isParent(elementType, enclosingType)
+ || isReferenceTo(enclosingType, elementType)
+ || isReferenceTo(elementType, enclosingType))) {
+ VariableType variableType = VariableType.GLOBAL;
+ if (element instanceof ICPPField) {
+ variableType = VariableType.FIELD;
+
+ } else if (element instanceof IVariable) {
+ try {
+ if (element instanceof ICPPBinding && ((ICPPBinding) element).isGloballyQualified()) {
+ variableType = VariableType.GLOBAL;
+ } else {
+ variableType = VariableType.LOCAL;
+ }
+ } catch (DOMException e) {
+ }
+ }
+
+ // Handle reference case
+ if (isReferenceTo(enclosingType, elementType))
+ elementName = "&" + elementName; //$NON-NLS-1$
+ else if (isReferenceTo(elementType, enclosingType))
+ elementName = "*" + elementName; //$NON-NLS-1$
+ return new Variable(elementName, variableType, positionScore, CharArrayUtils.EMPTY_CHAR_ARRAY,
+ getImageDescriptor(element));
+ }
+ return null;
+ }
+
+ private boolean isReferenceTo(IType ref, IType val) {
+ if (ref instanceof IPointerType) {
+ IType ptr = ((IPointerType) ref).getType();
+ if (ptr.toString().equals(val.toString()) || ptr.isSameType(val))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true, if the parent type is a direct/indirect parent of the child type
+ */
+ private boolean isParent(IType child, IType parent) {
+ if (child != null && parent != null
+ && child instanceof ICPPClassType && !(child instanceof ICPPClassSpecialization)
+ && parent instanceof ICPPClassType && !(parent instanceof ICPPClassSpecialization)) {
+ ICPPBase[] bases = ((ICPPClassType) child).getBases();
+ for (ICPPBase base : bases) {
+ IType tmpType = base.getBaseClassType();
+ if (tmpType.toString().equals(parent.toString()) || tmpType.isSameType(parent)
+ || isParent(tmpType, parent))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private ImageDescriptor getImageDescriptor(IBinding binding) {
+ ImageDescriptor imageDescriptor = null;
+
+ if (binding instanceof ITypedef) {
+ imageDescriptor = CElementImageProvider.getTypedefImageDescriptor();
+ } else if (binding instanceof ICompositeType) {
+ if (((ICompositeType) binding).getKey() == ICPPClassType.k_class
+ || binding instanceof ICPPClassTemplate)
+ imageDescriptor = CElementImageProvider.getClassImageDescriptor();
+ else if (((ICompositeType) binding).getKey() == ICompositeType.k_struct)
+ imageDescriptor = CElementImageProvider.getStructImageDescriptor();
+ else if (((ICompositeType) binding).getKey() == ICompositeType.k_union)
+ imageDescriptor = CElementImageProvider.getUnionImageDescriptor();
+ } else if (binding instanceof ICPPMethod) {
+ switch (((ICPPMethod) binding).getVisibility()) {
+ case ICPPMember.v_private:
+ imageDescriptor = CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PRIVATE);
+ break;
+ case ICPPMember.v_protected:
+ imageDescriptor =
+ CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PROTECTED);
+ break;
+ default:
+ imageDescriptor = CElementImageProvider.getMethodImageDescriptor(ASTAccessVisibility.PUBLIC);
+ break;
+ }
+ } else if (binding instanceof IFunction) {
+ imageDescriptor = CElementImageProvider.getFunctionImageDescriptor();
+ } else if (binding instanceof ICPPField) {
+ switch (((ICPPField) binding).getVisibility()) {
+ case ICPPMember.v_private:
+ imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PRIVATE);
+ break;
+ case ICPPMember.v_protected:
+ imageDescriptor =
+ CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PROTECTED);
+ break;
+ default:
+ imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PUBLIC);
+ break;
+ }
+ } else if (binding instanceof IField) {
+ imageDescriptor = CElementImageProvider.getFieldImageDescriptor(ASTAccessVisibility.PUBLIC);
+ } else if (binding instanceof IVariable) {
+ imageDescriptor = CElementImageProvider.getVariableImageDescriptor();
+ } else if (binding instanceof IEnumeration) {
+ imageDescriptor = CElementImageProvider.getEnumerationImageDescriptor();
+ } else if (binding instanceof IEnumerator) {
+ imageDescriptor = CElementImageProvider.getEnumeratorImageDescriptor();
+ } else if (binding instanceof ICPPNamespace) {
+ imageDescriptor = CElementImageProvider.getNamespaceImageDescriptor();
+ } else if (binding instanceof ICPPFunctionTemplate) {
+ imageDescriptor = CElementImageProvider.getFunctionImageDescriptor();
+ } else if (binding instanceof ICPPUsingDeclaration) {
+ IBinding[] delegates = ((ICPPUsingDeclaration) binding).getDelegates();
+ if (delegates.length > 0)
+ return getImageDescriptor(delegates[0]);
+ }
+ return imageDescriptor;
+ }
+
+ /**
+ * Returns the matches for the type and name argument, ordered by match quality.
+ *
+ * @param expectedType the qualified type of the parameter we are trying to match
+ * @param paramName the name of the parameter (used to find similarly named matches)
+ * @param pos the position
+ * @param suggestions the suggestions or <code>null</code>
+ * @param isLastParameter <code>true</code> iff this proposal is for the last parameter of a method
+ * @return returns the name of the best match, or <code>null</code> if no match found
+ */
+ public ICompletionProposal[] parameterProposals(IType expectedType, String paramName, Position pos,
+ List<IBinding> suggestions, boolean isLastParameter)
+ throws CModelException {
+ List<Variable> typeMatches = new ArrayList<>(evaluateVisibleMatches(expectedType, suggestions));
+ orderMatches(typeMatches, paramName);
+
+ ICompletionProposal[] ret = new ICompletionProposal[typeMatches.size()];
+ int i = 0;
+ int replacementLength = 0;
+ for (Variable v : typeMatches) {
+ if (i == 0) {
+ fAlreadyMatchedNames.add(v.name);
+ replacementLength = v.name.length();
+ }
+
+ String displayString = v.name;
+
+ final char[] triggers;
+ if (isLastParameter) {
+ triggers = v.triggerChars;
+ } else {
+ triggers = new char[v.triggerChars.length + 1];
+ System.arraycopy(v.triggerChars, 0, triggers, 0, v.triggerChars.length);
+ triggers[triggers.length - 1] = ',';
+ }
+ ret[i++] = new PositionBasedCompletionProposal(v.name, pos, replacementLength,
+ getImage(v.descriptor), displayString, null, null, triggers);
+ }
+ return ret;
+ }
+
+ private static class MatchComparator implements Comparator<Variable> {
+ @Override
+ public int compare(Variable one, Variable two) {
+ return two.totalScore - one.totalScore;
+ }
+ }
+
+ /**
+ * Determines the best match of all possible type matches. The input into this method is all possible
+ * completions that match the type of the argument. The purpose of this method is to choose among them
+ * based on the following simple rules:
+ *
+ * 1) Local Variables > Instance/Class Variables > Inherited Instance/Class Variables
+ *
+ * 2) A longer case insensitive substring match will prevail
+ *
+ * 3) Variables that have not been used already during this completion will prevail over those that have
+ * already been used (this avoids the same String/int/char from being passed in for multiple arguments)
+ *
+ * 4) A better source position score will prevail (the declaration point of the variable, or
+ * "how close to the point of completion?"
+ *
+ * @param typeMatches
+ * the list of type matches
+ * @param paramName
+ * the parameter name
+ */
+ private static void orderMatches(List<Variable> typeMatches, String paramName) {
+ if (typeMatches != null) {
+ calculateVariablesScores(paramName, typeMatches);
+ Collections.sort(typeMatches, new MatchComparator());
+ }
+ }
+
+ /**
+ * Set the replacement scores of the variables with respect to the parameter name.
+ */
+ private static void calculateVariablesScores(String parameterName, List<Variable> variables) {
+ for (Variable v : variables) {
+ v.totalScore = score(v, parameterName);
+ }
+ }
+
+ /**
+ * The four order criteria as described below - put already used into bit 10, all others into bits
+ * 0-9, 11-20, 21-30; 31 is sign - always 0
+ *
+ * @param v the variable
+ * @param parameterName the name of the parameter to be replaced.
+ * @return the score for <code>v</code>
+ */
+ private static int score(Variable v, String parameterName) {
+ int variableScore = 100 - v.variableType.getPriority(); // since these are increasing with distance
+ int subStringScore = getContainedString(v.name, parameterName).length();
+ // Substring scores under 60% are not considered.
+ // This prevents marginal matches like a - ba and false - isBool that will
+ // destroy the sort order.
+ int shorter = Math.min(v.name.length(), parameterName.length());
+ if (subStringScore < 0.6 * shorter)
+ subStringScore = 0;
+
+ int positionScore = v.positionScore;
+ int matchedScore = v.alreadyMatched ? 0 : 1;
+
+ int score = variableScore << 21 | subStringScore << 11 | matchedScore << 10 | positionScore;
+
+ return score;
+ }
+
+ /**
+ * Returns the shorter string if it is a substring of the longer string, or an empty
+ * string otherwise.
+ * @param first the first string
+ * @param second the second string
+ */
+ private static String getContainedString(String first, String second) {
+ // Now only considering the case where shorter string is part of longer string.
+ // TODO: Use a more efficient technique to get the common string (i.e. suffix tree).
+ String shorterStr = first.length() < second.length() ? first : second;
+ String longerStr = first == shorterStr ? second : first;
+ if (longerStr.contains(shorterStr)) {
+ return shorterStr;
+ } else {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ private static Image getImage(ImageDescriptor descriptor) {
+ return descriptor == null ? null : CUIPlugin.getImageDescriptorRegistry().get(descriptor);
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuessingProposal.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuessingProposal.java
new file mode 100644
index 00000000000..b4d94a9e238
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ParameterGuessingProposal.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew McCullough - initial API and implementation
+ * IBM Corporation - general improvement and bug fixes, partial reimplementation
+ * Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text.contentassist;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IPositionUpdater;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.link.ILinkedModeListener;
+import org.eclipse.jface.text.link.InclusivePositionUpdater;
+import org.eclipse.jface.text.link.LinkedModeModel;
+import org.eclipse.jface.text.link.LinkedModeUI;
+import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags;
+import org.eclipse.jface.text.link.LinkedPosition;
+import org.eclipse.jface.text.link.LinkedPositionGroup;
+import org.eclipse.jface.text.link.ProposalPosition;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IParameter;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+import org.eclipse.cdt.internal.ui.editor.CEditor;
+import org.eclipse.cdt.internal.ui.editor.EditorHighlightingSynchronizer;
+
+/**
+ * This class is based on org.eclipse.jdt.internal.ui.text.java.ParameterGuessingProposal
+ *
+ * Extents the basic Function Completion Proposal to add a linked mode for each of the function parameters
+ * with a list of suggestions for each parameter.
+ */
+public class ParameterGuessingProposal extends FunctionCompletionProposal {
+ private ICompletionProposal[][] fChoices; // initialized by guessParameters()
+ private Position[] fPositions; // initialized by guessParameters()
+ private IRegion fSelectedRegion; // initialized by apply()
+ private IPositionUpdater fUpdater;
+ private String fFullPrefix; // The string from the start of the statement to the invocation offset.
+ private CEditor fCEditor;
+ private char[][] fParametersNames;
+ private IType[] fParametersTypes;
+ private ArrayList<IBinding> fAssignableElements;
+
+ public static ParameterGuessingProposal createProposal(CContentAssistInvocationContext context,
+ ArrayList<IBinding> availableElements, CCompletionProposal proposal, IFunction function,
+ String prefix) {
+ String replacement = getParametersList(function);
+ String fullPrefix = function.getName() + "("; //$NON-NLS-1$
+ int replacementOffset = proposal.getReplacementOffset();
+ int replacementLength = 0;
+ int invocationOffset = context.getInvocationOffset();
+ int parseOffset = context.getParseOffset();
+ IDocument document = context.getDocument();
+ /*
+ * Adjust the replacement offset, the replacement string and the replacement length for the case of
+ * invoking after '('. - The replacement offset will be calculated to point to the start of the
+ * function call statement, as in that case the proposal.getReplacementOffset() doesn't point to that.
+ * - The replacement string will contain the in-editor prefix instead of the function name only, to
+ * handle the case of C++ function templates. - The length will be updated after changing the
+ * replacement string.
+ */
+ if (isInsideBracket(invocationOffset, parseOffset)) {
+ replacementOffset = parseOffset - prefix.length();
+ try {
+ fullPrefix = document.get(replacementOffset, invocationOffset - replacementOffset);
+ replacement = fullPrefix + replacement + ")"; //$NON-NLS-1$
+ } catch (BadLocationException e1) {
+ }
+ try {
+ // remove ')' from the replacement string if it is auto appended.
+ if (document.getChar(invocationOffset) == ')')
+ replacement = replacement.substring(0, replacement.length() - 1);
+ } catch (BadLocationException e) {
+ }
+ } else {
+ replacement = fullPrefix + replacement + ")"; //$NON-NLS-1$
+ replacementOffset = proposal.getReplacementOffset();
+ }
+ replacementLength = replacement.length();
+ ParameterGuessingProposal ret = new ParameterGuessingProposal(replacement, replacementOffset,
+ replacementLength, proposal.getImage(), proposal.getDisplayString(), proposal.getIdString(),
+ proposal.getRelevance(), context.getViewer(), function, invocationOffset, parseOffset,
+ context.getTranslationUnit(), document);
+ ret.setContextInformation(proposal.getContextInformation());
+ ret.fFullPrefix = fullPrefix;
+ ret.fCEditor = getCEditor(context.getEditor());
+ /*
+ * Get all defined elements before the start of the statement. ex: 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*)".
+ */
+ ret.fAssignableElements = availableElements;
+ return ret;
+ }
+
+ /**
+ * Returns a comma-separated list of parameters
+ */
+ private static String getParametersList(IFunction method) {
+ StringBuilder params = new StringBuilder();
+ for (IParameter param : method.getParameters()) {
+ if (params.length() != 0)
+ params.append(", "); //$NON-NLS-1$
+ params.append(param.getName());
+ }
+ return params.toString();
+ }
+
+ public ParameterGuessingProposal(String replacementString, int replacementOffset, int replacementLength,
+ Image image, String displayString, String idString, int relevance, ITextViewer viewer,
+ IFunction function, int invocationOffset, int parseOffset, ITranslationUnit tu, IDocument document) {
+ super(replacementString, replacementOffset, replacementLength, image, displayString, idString,
+ relevance, viewer, function, invocationOffset, parseOffset, tu, document);
+ }
+
+ /**
+ * Checks if the invocation of content assist was after open bracket.
+ */
+ private static boolean isInsideBracket(int invocationOffset, int parseOffset) {
+ return invocationOffset - parseOffset != 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
+ if (isInsideBracket(fInvocationOffset, fParseOffset)) {
+ try {
+ return fDocument.get(getReplacementOffset(), fInvocationOffset - getReplacementOffset());
+ } catch (BadLocationException e) {
+ }
+ }
+ return super.getPrefixCompletionText(document, completionOffset);
+ }
+
+ @Override
+ public void apply(final IDocument document, char trigger, int offset) {
+ super.apply(document, trigger, offset);
+
+ // Initialize necessary fields
+ fParametersNames = getFunctionParametersNames(fFunctionParameters);
+ fParametersTypes = getFunctionParametersTypes(fFunctionParameters);
+
+ try {
+ guessParameters();
+ } catch (Exception e) {
+ CUIPlugin.log(e);
+ return;
+ }
+
+ int baseOffset = getReplacementOffset();
+ String replacement = getReplacementString();
+ try {
+ if (fPositions != null && fTextViewer != null) {
+ LinkedModeModel model = new LinkedModeModel();
+
+ for (int i = 0; i < fPositions.length; i++) {
+ LinkedPositionGroup group = new LinkedPositionGroup();
+ int positionOffset = fPositions[i].getOffset();
+ int positionLength = fPositions[i].getLength();
+
+ if (fChoices[i].length == 0) {
+ group.addPosition(new LinkedPosition(document, positionOffset, positionLength,
+ LinkedPositionGroup.NO_STOP));
+ } else {
+ ensurePositionCategoryInstalled(document, model);
+ document.addPosition(getCategory(), fPositions[i]);
+ group.addPosition(new ProposalPosition(document, positionOffset, positionLength,
+ LinkedPositionGroup.NO_STOP, fChoices[i]));
+ }
+ model.addGroup(group);
+ }
+
+ model.forceInstall();
+ if (fCEditor != null) {
+ model.addLinkingListener(new EditorHighlightingSynchronizer(fCEditor));
+ }
+
+ LinkedModeUI ui = new EditorLinkedModeUI(model, fTextViewer);
+ ui.setExitPosition(fTextViewer, baseOffset + replacement.length(), 0, Integer.MAX_VALUE);
+ // exit character can be either ')' or ';'
+ final char exitChar = replacement.charAt(replacement.length() - 1);
+ ui.setExitPolicy(new ExitPolicy(exitChar) {
+ @Override
+ public ExitFlags doExit(LinkedModeModel model2, VerifyEvent event, int offset2, int length) {
+ if (event.character == ',') {
+ for (int i = 0; i < fPositions.length - 1; i++) { // not for the last one
+ Position position = fPositions[i];
+ if (position.offset <= offset2
+ && offset2 + length <= position.offset + position.length) {
+ event.character = '\t';
+ event.keyCode = SWT.TAB;
+ return null;
+ }
+ }
+ } else if (event.character == ')' && exitChar != ')') {
+ // exit from link mode when user is in the last ')' position.
+ Position position = fPositions[fPositions.length - 1];
+ if (position.offset <= offset2
+ && offset2 + length <= position.offset + position.length) {
+ return new ExitFlags(ILinkedModeListener.UPDATE_CARET, false);
+ }
+ }
+ return super.doExit(model2, event, offset2, length);
+ }
+ });
+ ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT);
+ ui.setDoContextInfo(true);
+ ui.enter();
+ fSelectedRegion = ui.getSelectedRegion();
+ } else {
+ fSelectedRegion = new Region(baseOffset + replacement.length(), 0);
+ }
+ } catch (Exception e) {
+ ensurePositionCategoryRemoved(document);
+ CUIPlugin.log(e);
+ }
+ }
+
+ @Override
+ public Point getSelection(IDocument document) {
+ if (fSelectedRegion == null)
+ return new Point(getReplacementOffset(), 0);
+
+ return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
+ }
+
+ private void guessParameters() throws Exception {
+ int count = fParametersNames.length;
+ fPositions = new Position[count];
+ fChoices = new ICompletionProposal[count][];
+
+ ParameterGuesser guesser = new ParameterGuesser();
+
+ for (int i = 0; i < count; i++) {
+ String paramName = new String(fParametersNames[i]);
+ Position position = new Position(0, 0);
+
+ boolean isLastParameter = i == count - 1;
+ ArrayList<ICompletionProposal> allProposals = new ArrayList<>();
+ ICompletionProposal[] argumentProposals = guesser.parameterProposals(fParametersTypes[i],
+ paramName, position, fAssignableElements, isLastParameter);
+ allProposals.addAll(Arrays.asList(argumentProposals));
+ fPositions[i] = position;
+ fChoices[i] = argumentProposals;
+ }
+ updateProposalsPossitions();
+ }
+
+ private void updateProposalsPossitions() throws Exception {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(fFullPrefix);
+ setCursorPosition(buffer.length());
+
+ int count = fParametersNames.length;
+ int replacementOffset = getReplacementOffset();
+
+ for (int i = 0; i < count; i++) {
+ if (i != 0)
+ buffer.append(", "); //$NON-NLS-1$
+
+ String argument = new String(fParametersNames[i]);
+
+ Position position = fPositions[i];
+ position.setOffset(replacementOffset + buffer.length());
+ position.setLength(argument.length());
+
+ buffer.append(argument);
+ }
+ }
+
+ private static IType[] getFunctionParametersTypes(IParameter[] functionParameters) {
+ IType[] ret = new IType[functionParameters.length];
+ for (int i = 0; i < functionParameters.length; i++) {
+ ret[i] = functionParameters[i].getType();
+ }
+ return ret;
+ }
+
+ private static char[][] getFunctionParametersNames(IParameter[] functionParameters) {
+ char[][] parameterNames = new char[functionParameters.length][];
+ for (int i = 0; i < functionParameters.length; i++) {
+ parameterNames[i] = functionParameters[i].getNameCharArray();
+ }
+ return parameterNames;
+ }
+
+ private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) {
+ if (!document.containsPositionCategory(getCategory())) {
+ document.addPositionCategory(getCategory());
+ fUpdater = new InclusivePositionUpdater(getCategory());
+ document.addPositionUpdater(fUpdater);
+
+ model.addLinkingListener(new ILinkedModeListener() {
+ @Override
+ public void left(LinkedModeModel environment, int flags) {
+ ensurePositionCategoryRemoved(document);
+ }
+
+ @Override
+ public void suspend(LinkedModeModel environment) {
+ }
+
+ @Override
+ public void resume(LinkedModeModel environment, int flags) {
+ }
+ });
+ }
+ }
+
+ private void ensurePositionCategoryRemoved(IDocument document) {
+ if (document.containsPositionCategory(getCategory())) {
+ try {
+ document.removePositionCategory(getCategory());
+ } catch (BadPositionCategoryException e) {
+ // ignore
+ }
+ document.removePositionUpdater(fUpdater);
+ }
+ }
+
+ private String getCategory() {
+ return "ParameterGuessingProposal_" + toString(); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the c editor, or <code>null</code> if it cannot be determined.
+ */
+ private static CEditor getCEditor(IEditorPart editorPart) {
+ if (editorPart instanceof CEditor) {
+ return (CEditor) editorPart;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the guesses for each parameter
+ */
+ public ICompletionProposal[][] getParametersGuesses() {
+ return fChoices;
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/PositionBasedCompletionProposal.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/PositionBasedCompletionProposal.java
new file mode 100644
index 00000000000..bc809cc195f
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/PositionBasedCompletionProposal.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Mohamed Azab (Mentor Graphics) - Bug 438549. Add mechanism for parameter guessing.
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text.contentassist;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+
+/**
+ * An enhanced implementation of the <code>ICompletionProposal</code> interface implementing all the extension interfaces.
+ * It uses a position to track its replacement offset and length. The position must be set up externally.
+ */
+public class PositionBasedCompletionProposal implements ICompletionProposal, ICompletionProposalExtension, ICompletionProposalExtension2 {
+ /** The string to be displayed in the completion proposal popup */
+ private String fDisplayString;
+ /** The replacement string */
+ private String fReplacementString;
+ /** The replacement position. */
+ private Position fReplacementPosition;
+ /** The cursor position after this proposal has been applied */
+ private int fCursorPosition;
+ /** The image to be displayed in the completion proposal popup */
+ private Image fImage;
+ /** The context information of this proposal */
+ private IContextInformation fContextInformation;
+ /** The additional info of this proposal */
+ private String fAdditionalProposalInfo;
+ /** The trigger characters */
+ private char[] fTriggerCharacters;
+
+ /**
+ * Creates a new completion proposal based on the provided information. The replacement string is
+ * considered being the display string too. All remaining fields are set to <code>null</code>.
+ *
+ * @param replacementString the actual string to be inserted into the document
+ * @param replacementPosition the position of the text to be replaced
+ * @param cursorPosition the position of the cursor following the insert relative to replacementOffset
+ */
+ public PositionBasedCompletionProposal(String replacementString, Position replacementPosition, int cursorPosition) {
+ this(replacementString, replacementPosition, cursorPosition, null, null, null, null, null);
+ }
+
+ /**
+ * Creates a new completion proposal. All fields are initialized based on the provided information.
+ *
+ * @param replacementString the actual string to be inserted into the document
+ * @param replacementPosition the position of the text to be replaced
+ * @param cursorPosition the position of the cursor following the insert relative to replacementOffset
+ * @param image the image to display for this proposal
+ * @param displayString the string to be displayed for the proposal
+ * @param contextInformation the context information associated with this proposal
+ * @param additionalProposalInfo the additional information associated with this proposal
+ * @param triggers the trigger characters
+ */
+ public PositionBasedCompletionProposal(String replacementString, Position replacementPosition, int cursorPosition, Image image, String displayString, IContextInformation contextInformation, String additionalProposalInfo, char[] triggers) {
+ Assert.isNotNull(replacementString);
+ Assert.isTrue(replacementPosition != null);
+
+ fReplacementString= replacementString;
+ fReplacementPosition= replacementPosition;
+ fCursorPosition= cursorPosition;
+ fImage= image;
+ fDisplayString= displayString;
+ fContextInformation= contextInformation;
+ fAdditionalProposalInfo= additionalProposalInfo;
+ fTriggerCharacters= triggers;
+ }
+
+ @Override
+ public void apply(IDocument document) {
+ try {
+ document.replace(fReplacementPosition.getOffset(), fReplacementPosition.getLength(), fReplacementString);
+ } catch (BadLocationException x) {
+ // ignore
+ }
+ }
+
+ @Override
+ public Point getSelection(IDocument document) {
+ return new Point(fReplacementPosition.getOffset() + fCursorPosition, 0);
+ }
+
+ @Override
+ public IContextInformation getContextInformation() {
+ return fContextInformation;
+ }
+
+ @Override
+ public Image getImage() {
+ return fImage;
+ }
+
+ @Override
+ public String getDisplayString() {
+ if (fDisplayString != null)
+ return fDisplayString;
+ return fReplacementString;
+ }
+
+ @Override
+ public String getAdditionalProposalInfo() {
+ return fAdditionalProposalInfo;
+ }
+
+ @Override
+ public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
+ apply(viewer.getDocument());
+ }
+
+ @Override
+ public void selected(ITextViewer viewer, boolean smartToggle) {
+ }
+
+ @Override
+ public void unselected(ITextViewer viewer) {
+ }
+
+ @Override
+ public boolean validate(IDocument document, int offset, DocumentEvent event) {
+ try {
+ String content= document.get(fReplacementPosition.getOffset(), offset - fReplacementPosition.getOffset());
+ if (fReplacementString.startsWith(content))
+ return true;
+ } catch (BadLocationException e) {
+ // ignore concurrently modified document
+ }
+ return false;
+ }
+
+ @Override
+ public void apply(IDocument document, char trigger, int offset) {
+ // not called any more
+ }
+
+ @Override
+ public boolean isValidFor(IDocument document, int offset) {
+ // not called any more
+ return false;
+ }
+
+ @Override
+ public char[] getTriggerCharacters() {
+ return fTriggerCharacters;
+ }
+
+ @Override
+ public int getContextInformationPosition() {
+ return fReplacementPosition.getOffset();
+ }
+}
+

Back to the top