mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 14:12:10 +02:00
Revert "Bug 438549 Add mechanism for parameter guessing."
This reverts commit a2cff345b1
.
Reverted due to a serious performance regression.
Change-Id: I90a5b4ded9b7180cf10f1fba64bca897a2040013
This commit is contained in:
parent
0c2af8d5ce
commit
958d5a8a3d
10 changed files with 13 additions and 1595 deletions
|
@ -12,15 +12,12 @@
|
||||||
* Markus Schorn (Wind River Systems)
|
* Markus Schorn (Wind River Systems)
|
||||||
* Thomas Corbat (IFS)
|
* Thomas Corbat (IFS)
|
||||||
* Sergey Prigogin (Google)
|
* Sergey Prigogin (Google)
|
||||||
* 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;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
|
@ -52,7 +49,6 @@ 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.CCompletionProposal;
|
||||||
import org.eclipse.cdt.internal.ui.text.contentassist.CContentAssistProcessor;
|
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.ContentAssistPreference;
|
||||||
import org.eclipse.cdt.internal.ui.text.contentassist.ParameterGuessingProposal;
|
|
||||||
import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants;
|
import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants;
|
||||||
|
|
||||||
public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
||||||
|
@ -111,21 +107,8 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
||||||
return CUIPlugin.getDefault().getPreferenceStore();
|
return CUIPlugin.getDefault().getPreferenceStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ContentAssistResult {
|
protected void assertContentAssistResults(int offset, int length, String[] expected,
|
||||||
long startTime;
|
boolean isCompletion, boolean isTemplate, boolean filterResults, CompareType compareType) throws Exception {
|
||||||
long endTime;
|
|
||||||
Object[] results;
|
|
||||||
|
|
||||||
public ContentAssistResult(long startTime, long endTime, Object[] results) {
|
|
||||||
this.startTime = startTime;
|
|
||||||
this.endTime = endTime;
|
|
||||||
this.results = results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ContentAssistResult invokeContentAssist(int offset, int length,
|
|
||||||
boolean isCompletion, boolean isTemplate, boolean filterResults)
|
|
||||||
throws Exception {
|
|
||||||
if (CTestPlugin.getDefault().isDebugging()) {
|
if (CTestPlugin.getDefault().isDebugging()) {
|
||||||
System.out.println("\n\n\n\n\nTesting " + this.getClass().getName());
|
System.out.println("\n\n\n\n\nTesting " + this.getClass().getName());
|
||||||
}
|
}
|
||||||
|
@ -155,20 +138,12 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
||||||
results= filterResults(results, isCode);
|
results= filterResults(results, isCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ContentAssistResult(startTime, endTime, results);
|
String[] resultStrings= toStringArray(results, compareType);
|
||||||
}
|
|
||||||
|
|
||||||
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(expected);
|
||||||
Arrays.sort(resultStrings);
|
Arrays.sort(resultStrings);
|
||||||
|
|
||||||
if (CTestPlugin.getDefault().isDebugging()) {
|
if (CTestPlugin.getDefault().isDebugging()) {
|
||||||
System.out.println("Time: " + (r.endTime - r.startTime) + " ms");
|
System.out.println("Time: " + (endTime - startTime) + " ms");
|
||||||
for (String proposal : resultStrings) {
|
for (String proposal : resultStrings) {
|
||||||
System.out.println("Result: " + proposal);
|
System.out.println("Result: " + proposal);
|
||||||
}
|
}
|
||||||
|
@ -202,46 +177,6 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void assertContentAssistResults(int offset, int length, String[] expected, boolean isCompletion, boolean isTemplate, CompareType compareType) throws Exception {
|
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);
|
assertContentAssistResults(offset, length, expected, isCompletion, isTemplate, true, compareType);
|
||||||
}
|
}
|
||||||
|
@ -250,37 +185,6 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
|
||||||
assertContentAssistResults(offset, 0, expected, isCompletion, false, compareType);
|
assertContentAssistResults(offset, 0, expected, isCompletion, false, compareType);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter out template and keyword proposals.
|
* Filter out template and keyword proposals.
|
||||||
* @param results
|
* @param results
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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(*aTypePtr, bTypeObj)", 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(intVal, aTypeObj)", new String[][] { { "intVal" }, { "aTypeObj" } });
|
|
||||||
resultsMap.put("overload(intVal, &aTypeObj)",
|
|
||||||
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(charZ)", new String[][] { { "charX", "charY", "charZ" } });
|
|
||||||
resultsMap.put("aMethod(charZ, charY)", 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(lng, shrtNameMatch)", 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(charY)", new String[][] { { "charX", "charY", "inCall" } });
|
|
||||||
resultsMap.put("aMethod(charY, charX)", new String[][] {
|
|
||||||
{ "charX", "charY", "inCall" }, { "charX", "charY", "inCall" } });
|
|
||||||
assertParametersGuesses(resultsMap);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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(*axPtr, ax)", 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, ax)", new String[][] { { "x" }, { "ax" } });
|
|
||||||
resultsMap.put("ov2(x, &ax)", new String[][] { { "x" }, { "&ax" } });
|
|
||||||
assertParametersGuesses(resultsMap);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2006, 2015 Wind River Systems, Inc. and others.
|
* Copyright (c) 2006, 2014 Wind River Systems, Inc. and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
* 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;
|
||||||
|
|
||||||
|
@ -856,7 +855,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)", "port" };
|
final String[] expected= { "InitPrinter()", "port" };
|
||||||
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1262,7 +1261,7 @@ public class CompletionTests extends AbstractContentAssistTest {
|
||||||
// }
|
// }
|
||||||
//};
|
//};
|
||||||
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
|
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
|
||||||
final String[] expected= { "add(tOther)" };
|
final String[] expected= { "add()" };
|
||||||
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1422,7 +1421,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1569,7 +1568,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);
|
||||||
|
@ -1607,7 +1606,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(i)" };
|
final String[] expectedReplacement = { "default_argument()" };
|
||||||
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
|
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2006, 2015 Siemens AG and others.
|
* Copyright (c) 2006, 2007 Siemens AG and others.
|
||||||
* All rights reserved. This content and the accompanying materials
|
* All rights reserved. This content and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -9,7 +9,6 @@
|
||||||
* Norbert Ploett - Initial implementation
|
* Norbert Ploett - Initial implementation
|
||||||
* Bryan Wilkinson (QNX)
|
* Bryan Wilkinson (QNX)
|
||||||
* Andrew Ferguson (Symbian)
|
* Andrew Ferguson (Symbian)
|
||||||
* 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;
|
||||||
|
|
||||||
|
@ -72,8 +71,6 @@ 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(CParameterGuessingTests.suite());
|
|
||||||
|
|
||||||
addTest(ShowCamelCasePreferenceTest.suite());
|
addTest(ShowCamelCasePreferenceTest.suite());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2007, 2015 QNX Software Systems and others.
|
* Copyright (c) 2007, 2014 QNX Software Systems and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -13,7 +13,6 @@
|
||||||
* 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;
|
||||||
|
|
||||||
|
@ -29,7 +28,6 @@ import org.eclipse.jface.text.ITypedRegion;
|
||||||
import org.eclipse.jface.text.TextUtilities;
|
import org.eclipse.jface.text.TextUtilities;
|
||||||
import org.eclipse.jface.text.contentassist.ICompletionProposal;
|
import org.eclipse.jface.text.contentassist.ICompletionProposal;
|
||||||
import org.eclipse.swt.graphics.Image;
|
import org.eclipse.swt.graphics.Image;
|
||||||
import org.eclipse.ui.IEditorPart;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
@ -96,7 +94,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.AccessContext;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.AccessContext;
|
||||||
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
|
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
|
||||||
|
|
||||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
|
||||||
import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
|
import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,22 +107,17 @@ 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<ICompletionProposal>();
|
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
|
||||||
|
|
||||||
if (inPreprocessorDirective(context)) {
|
if (inPreprocessorDirective(context)) {
|
||||||
|
@ -595,117 +587,8 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
|
||||||
proposal.setContextInformation(info);
|
proposal.setContextInformation(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
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();
|
|
||||||
try {
|
|
||||||
String completePrefix = context.getDocument().get(startOffset,
|
|
||||||
context.getInvocationOffset() - startOffset);
|
|
||||||
if (completePrefix.trim().endsWith("(")) //$NON-NLS-1$
|
|
||||||
return true;
|
|
||||||
} catch (BadLocationException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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());
|
|
||||||
fAvailableElements = new ArrayList<>();
|
|
||||||
IASTCompletionNode node = null;
|
|
||||||
// Create a content assist context that points to the start of the statement.
|
|
||||||
CContentAssistInvocationContext newContext = new CContentAssistInvocationContext(
|
|
||||||
context.getViewer(), startOffset, getCEditor(), true, false);
|
|
||||||
try {
|
|
||||||
node = newContext.getCompletionNode();
|
|
||||||
if (node != null) {
|
|
||||||
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) {
|
|
||||||
if (accessibilityContext.isAccessible(binding))
|
|
||||||
fAvailableElements.add(binding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the currently active C/C++ editor, or <code>null</code> if it cannot be determined.
|
|
||||||
*/
|
|
||||||
private static CEditor getCEditor() {
|
|
||||||
IEditorPart part = CUIPlugin.getActivePage().getActiveEditor();
|
|
||||||
if (part instanceof CEditor) {
|
|
||||||
return (CEditor) part;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean skipDefaultedParameter(IParameter param) {
|
private boolean skipDefaultedParameter(IParameter param) {
|
||||||
return !isDisplayDefaultedParameters() && param instanceof ICPPParameter && ((ICPPParameter)param).hasDefaultValue();
|
return !isDisplayDefaultedParameters() && param instanceof ICPPParameter && ((ICPPParameter)param).hasDefaultValue();
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.IASTTranslationUnit;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IFunction;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IParameter;
|
|
||||||
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 IASTTranslationUnit 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, IASTTranslationUnit 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,431 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
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.IASTExpression.ValueCategory;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
|
||||||
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.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.ui.CUIPlugin;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions;
|
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
|
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
|
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost;
|
|
||||||
|
|
||||||
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 IASTTranslationUnit fTranslationUnit;
|
|
||||||
private static final char[] NO_TRIGGERS = new char[0];
|
|
||||||
private final Set<String> fAlreadyMatchedNames;
|
|
||||||
|
|
||||||
private final static class Variable {
|
|
||||||
/**
|
|
||||||
* Variable type. Used to choose the best guess based on scope (Local beats instance beats inherited
|
|
||||||
* beats global).
|
|
||||||
*/
|
|
||||||
public static final int LOCAL = 0;
|
|
||||||
public static final int FIELD = 1;
|
|
||||||
public static final int GLOBAL = 3;
|
|
||||||
|
|
||||||
public final IType qualifiedTypeName;
|
|
||||||
public final String name;
|
|
||||||
public final int variableType;
|
|
||||||
public final int positionScore;
|
|
||||||
|
|
||||||
public final char[] triggerChars;
|
|
||||||
public final ImageDescriptor descriptor;
|
|
||||||
|
|
||||||
public boolean alreadyMatched;
|
|
||||||
|
|
||||||
public Variable(IType qualifiedTypeName, String name, int variableType, int positionScore,
|
|
||||||
char[] triggerChars, ImageDescriptor descriptor) {
|
|
||||||
this.qualifiedTypeName = qualifiedTypeName;
|
|
||||||
this.name = name;
|
|
||||||
this.variableType = variableType;
|
|
||||||
this.positionScore = positionScore;
|
|
||||||
this.triggerChars = triggerChars;
|
|
||||||
this.descriptor = descriptor;
|
|
||||||
this.alreadyMatched = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder buffer = new StringBuilder();
|
|
||||||
buffer.append(qualifiedTypeName);
|
|
||||||
buffer.append(' ');
|
|
||||||
buffer.append(name);
|
|
||||||
buffer.append(" ("); //$NON-NLS-1$
|
|
||||||
buffer.append(variableType);
|
|
||||||
buffer.append(')');
|
|
||||||
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a parameter guesser
|
|
||||||
*/
|
|
||||||
public ParameterGuesser(IASTTranslationUnit translationUnit) {
|
|
||||||
fAlreadyMatchedNames = new HashSet<String>();
|
|
||||||
fTranslationUnit = translationUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Variable> evaluateVisibleMatches(IType expectedType, ArrayList<IBinding> suggestions)
|
|
||||||
throws CModelException {
|
|
||||||
ArrayList<Variable> res = new ArrayList<>();
|
|
||||||
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)) {
|
|
||||||
if (binding instanceof IVariable) {
|
|
||||||
return ((IVariable) binding).getType();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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)
|
|
||||||
|| isAutomaticCasting(enclosingType, elementType)
|
|
||||||
|| isReferenceTo(enclosingType, elementType) || isReferenceTo(elementType,
|
|
||||||
enclosingType))) {
|
|
||||||
int variableType = Variable.GLOBAL;
|
|
||||||
if (element instanceof ICPPField) {
|
|
||||||
variableType = Variable.FIELD;
|
|
||||||
|
|
||||||
} else if (element instanceof IVariable) {
|
|
||||||
try {
|
|
||||||
if (element instanceof ICPPBinding && ((ICPPBinding) element).isGloballyQualified()) {
|
|
||||||
variableType = Variable.GLOBAL;
|
|
||||||
} else {
|
|
||||||
variableType = Variable.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(elementType, elementName, variableType, positionScore, NO_TRIGGERS,
|
|
||||||
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
|
|
||||||
&& parent instanceof ICPPClassType) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the orginType can be automatically casted to the candidateType
|
|
||||||
*/
|
|
||||||
private boolean isAutomaticCasting(IType orginType, IType candidateType) {
|
|
||||||
try {
|
|
||||||
Cost cost = Conversions.checkImplicitConversionSequence(orginType, candidateType,
|
|
||||||
ValueCategory.LVALUE, UDCMode.ALLOWED, Context.ORDINARY, fTranslationUnit);
|
|
||||||
if (cost.converts())
|
|
||||||
return true;
|
|
||||||
} catch (DOMException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
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 fillBestGuess <code>true</code> if the best guess should be filled in
|
|
||||||
* @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,
|
|
||||||
ArrayList<IBinding> suggestions, boolean fillBestGuess, boolean isLastParameter)
|
|
||||||
throws CModelException {
|
|
||||||
List<Variable> typeMatches = evaluateVisibleMatches(expectedType, suggestions);
|
|
||||||
typeMatches = removeDuplicates(typeMatches);
|
|
||||||
orderMatches(typeMatches, paramName);
|
|
||||||
|
|
||||||
ICompletionProposal[] ret = new ICompletionProposal[typeMatches.size()];
|
|
||||||
int i = 0;
|
|
||||||
int replacementLength = 0;
|
|
||||||
for (Iterator<Variable> it = typeMatches.iterator(); it.hasNext();) {
|
|
||||||
Variable v = it.next();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (ret.length == 0) {
|
|
||||||
// Add the parameter name
|
|
||||||
return new ICompletionProposal[] { new PositionBasedCompletionProposal(paramName, pos,
|
|
||||||
replacementLength, null, paramName, null, null,
|
|
||||||
isLastParameter ? null : new char[] { ',' }) };
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MatchComparator implements Comparator<Variable> {
|
|
||||||
private String fParamName;
|
|
||||||
|
|
||||||
MatchComparator(String paramName) {
|
|
||||||
fParamName = paramName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Variable one, Variable two) {
|
|
||||||
return score(two) - score(one);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getLongestCommonSubstring(String first, String second) {
|
|
||||||
// Now only considering the case where shorter string is part of longer string.
|
|
||||||
// TODO: Use a more smart 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$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* @return the score for <code>v</code>
|
|
||||||
*/
|
|
||||||
private int score(Variable v) {
|
|
||||||
int variableScore = 100 - v.variableType; // since these are increasing with distance
|
|
||||||
int subStringScore = getLongestCommonSubstring(v.name, fParamName).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(), fParamName.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
Collections.sort(typeMatches, new MatchComparator(paramName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the duplicates from the list if any.
|
|
||||||
*/
|
|
||||||
private static List<Variable> removeDuplicates(List<Variable> typeMatches) {
|
|
||||||
HashSet<Variable> set = new HashSet<>();
|
|
||||||
set.addAll(typeMatches);
|
|
||||||
return Arrays.asList(set.toArray(new Variable[set.size()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Image getImage(ImageDescriptor descriptor) {
|
|
||||||
return (descriptor == null) ? null : CUIPlugin.getImageDescriptorRegistry().get(descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,408 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.IASTTranslationUnit;
|
|
||||||
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.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 Compilation 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 boolean fReplacementStringComputed;
|
|
||||||
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 char[][] fParametersNames;
|
|
||||||
private IType[] fParametersTypes;
|
|
||||||
private ArrayList<IBinding> fAssignableElemebts;
|
|
||||||
|
|
||||||
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();
|
|
||||||
IASTTranslationUnit translationUnit = context.getCompletionNode().getTranslationUnit();
|
|
||||||
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,
|
|
||||||
translationUnit, document);
|
|
||||||
ret.setContextInformation(proposal.getContextInformation());
|
|
||||||
ret.fFullPrefix = fullPrefix;
|
|
||||||
/*
|
|
||||||
* 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.fAssignableElemebts = availableElements;
|
|
||||||
ret.getReplacementString();
|
|
||||||
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, IASTTranslationUnit translationUnit,
|
|
||||||
IDocument document) {
|
|
||||||
super(replacementString, replacementOffset, replacementLength, image, displayString, idString,
|
|
||||||
relevance, viewer, function, invocationOffset, parseOffset, translationUnit, document);
|
|
||||||
fParametersNames = getFunctionParametersNames(fFunctionParameters);
|
|
||||||
fParametersTypes = getFunctionParametersTypes(fFunctionParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
try {
|
|
||||||
super.apply(document, trigger, offset);
|
|
||||||
|
|
||||||
int baseOffset = getReplacementOffset();
|
|
||||||
String replacement = getReplacementString();
|
|
||||||
|
|
||||||
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 < 2) {
|
|
||||||
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();
|
|
||||||
CEditor editor = getCEditor();
|
|
||||||
if (editor != null) {
|
|
||||||
model.addLinkingListener(new EditorHighlightingSynchronizer(editor));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (BadLocationException | BadPositionCategoryException 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());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getReplacementString() {
|
|
||||||
if (!fReplacementStringComputed) {
|
|
||||||
String rep = computeReplacementString();
|
|
||||||
setReplacementString(rep);
|
|
||||||
setReplacementLength(rep.length());
|
|
||||||
fReplacementStringComputed = true;
|
|
||||||
}
|
|
||||||
return super.getReplacementString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeReplacementString() {
|
|
||||||
if (!hasParameters())
|
|
||||||
return super.getReplacementString();
|
|
||||||
|
|
||||||
String replacement;
|
|
||||||
try {
|
|
||||||
replacement = computeGuessingCompletion();
|
|
||||||
} catch (Exception x) {
|
|
||||||
fPositions = null;
|
|
||||||
fChoices = null;
|
|
||||||
CUIPlugin.log(x);
|
|
||||||
return super.getReplacementString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeGuessingCompletion() throws Exception {
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
buffer.append(fFullPrefix);
|
|
||||||
setCursorPosition(buffer.length());
|
|
||||||
|
|
||||||
for (int i = 0; i < fFunctionParameters.length; i++) {
|
|
||||||
fParametersNames[i] = fFunctionParameters[i].getNameCharArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
fChoices = guessParameters(fParametersNames);
|
|
||||||
int count = fChoices.length;
|
|
||||||
int replacementOffset = getReplacementOffset();
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
if (i != 0)
|
|
||||||
buffer.append(", "); //$NON-NLS-1$
|
|
||||||
|
|
||||||
ICompletionProposal proposal = fChoices[i][0];
|
|
||||||
String argument = proposal.getDisplayString();
|
|
||||||
|
|
||||||
Position position = fPositions[i];
|
|
||||||
position.setOffset(replacementOffset + buffer.length());
|
|
||||||
position.setLength(argument.length());
|
|
||||||
|
|
||||||
if (proposal instanceof CCompletionProposal) // handle the "unknown" case where we only insert a
|
|
||||||
// proposal.
|
|
||||||
((CCompletionProposal) proposal).setReplacementOffset(replacementOffset + buffer.length());
|
|
||||||
buffer.append(argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.append(")"); //$NON-NLS-1$
|
|
||||||
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ICompletionProposal[][] guessParameters(char[][] parameterNames) throws Exception {
|
|
||||||
int count = parameterNames.length;
|
|
||||||
fPositions = new Position[count];
|
|
||||||
fChoices = new ICompletionProposal[count][];
|
|
||||||
|
|
||||||
ParameterGuesser guesser = new ParameterGuesser(fTranslationUnit);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
String paramName = new String(parameterNames[i]);
|
|
||||||
Position position = new Position(0, 0);
|
|
||||||
|
|
||||||
boolean isLastParameter = i == count - 1;
|
|
||||||
ArrayList<ICompletionProposal> allProposals = new ArrayList<ICompletionProposal>();
|
|
||||||
ICompletionProposal[] argumentProposals = guesser.parameterProposals(fParametersTypes[i],
|
|
||||||
paramName, position, fAssignableElemebts, true, isLastParameter);
|
|
||||||
allProposals.addAll(Arrays.asList(argumentProposals));
|
|
||||||
fPositions[i] = position;
|
|
||||||
fChoices[i] = argumentProposals;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fChoices;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 currently active C/C++ editor, or <code>null</code> if it cannot be determined.
|
|
||||||
*/
|
|
||||||
private static CEditor getCEditor() {
|
|
||||||
IEditorPart part = CUIPlugin.getActivePage().getActiveEditor();
|
|
||||||
if (part instanceof CEditor) {
|
|
||||||
return (CEditor) part;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the guesses for each parameter
|
|
||||||
*/
|
|
||||||
public ICompletionProposal[][] getParametersGuesses() {
|
|
||||||
return fChoices;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue