1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

Revert "Bug 438549. Add mechanism for parameter guessing."

This reverts commit 69aa2d0bf0.
This commit is contained in:
Sergey Prigogin 2015-02-06 14:12:55 -08:00
parent 1b6b3f0f06
commit 3042d38e0d
11 changed files with 9 additions and 1695 deletions

View file

@ -11,15 +11,12 @@
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
* Thomas Corbat (IFS)
* Mentor Graphics (Mohamed Azab) - added the API to CDT
*******************************************************************************/
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;
@ -47,7 +44,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.CContentAssistProcessor;
import org.eclipse.cdt.internal.ui.text.contentassist.ParameterGuessingProposal;
import org.eclipse.cdt.internal.ui.text.contentassist.RelevanceConstants;
public abstract class AbstractContentAssistTest extends BaseUITestCase {
@ -101,20 +97,7 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
super.tearDown();
}
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;
}
}
private ContentAssistResult invokeContentAssist(int offset, int length, boolean isCompletion, boolean isTemplate, boolean filterResults) throws Exception {
protected void assertContentAssistResults(int offset, int length, String[] expected, boolean isCompletion, boolean isTemplate, boolean filterResults, CompareType compareType) throws Exception {
if (CTestPlugin.getDefault().isDebugging()) {
System.out.println("\n\n\n\n\nTesting "+this.getClass().getName());
}
@ -140,18 +123,12 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
results= filterResults(results, isCode);
}
}
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);
String[] resultStrings= toStringArray(results, compareType);
Arrays.sort(expected);
Arrays.sort(resultStrings);
if (CTestPlugin.getDefault().isDebugging()) {
System.out.println("Time (ms): " + (r.endTime-r.startTime));
System.out.println("Time (ms): " + (endTime-startTime));
for (String proposal : resultStrings) {
System.out.println("Result: " + proposal);
}
@ -185,59 +162,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 (ms): " + (r.endTime-r.startTime));
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();
}
boolean allFound = true; // for the time being, let's be optimistic
for (String proposal : expected.keySet()) {
String [][] result = resultMap.get(proposal);
if (result == null) {
allFound = false;
break;
} else {
String [][] expectedGuesses = expected.get(proposal);
if (expectedGuesses.length != result.length) {
allFound = false;
} else {
for (int i=0; i< expectedGuesses.length; i++) {
String [] exp = expectedGuesses[i];
Arrays.sort(exp);
String [] guess = result[i];
Arrays.sort(guess);
for (int j=0; j< exp.length; j++) {
if (!exp[j].equals(guess[j])) {
allFound = false;
break;
}
}
if (!allFound)
break;
}
}
}
}
if (!allFound) {
fail("Wrong parameters guesses!");
}
}
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);
}
@ -246,35 +170,6 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
assertContentAssistResults(offset, 0, expected, isCompletion, false, compareType);
}
private Map<String, String[][]> toMap(Object[] results, CompareType compareType) {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
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][0];
}
resultsMap.put(pName, p);
}
break;
}
}
return resultsMap;
}
/**
* Filter out template and keyword proposals.
* @param results

View file

@ -15,7 +15,6 @@
* Nathan Ridge
* Thomas Corbat (IFS)
* Michael Woski
* Mentor Graphics (Mohamed Azab) - Update tests for parameter guessing
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text.contentassist2;
@ -833,7 +832,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)", "port" };
final String[] expected= { "InitPrinter()", "port" };
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
@ -1239,7 +1238,7 @@ public class CompletionTests extends AbstractContentAssistTest {
// }
//};
public void testContentAssistInDeferredClassInstance_194592() throws Exception {
final String[] expected= { "add(tOther)" };
final String[] expected= { "add()" };
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
@ -1399,7 +1398,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);
}
@ -1527,7 +1526,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);
@ -1565,7 +1564,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(i)" };
final String[] expectedReplacement = { "default_argument()" };
assertContentAssistResults(fCursorOffset, expectedReplacement, true, REPLACEMENT);
}

View file

@ -9,7 +9,6 @@
* Norbert Ploett - Initial implementation
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Mentor Graphics (Mohamed Azab) - Add parameter guessing tests
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text.contentassist2;
@ -72,8 +71,6 @@ public class ContentAssist2TestSuite extends TestSuite {
addTest(CompletionTests.suite());
addTest(CompletionTests_PlainC.suite());
addTest(ParameterHintTests.suite());
addTest(ParameterGuessingTests.suite());
addTest(ParameterGuessingTests_PlainC.suite());
addTest(ShowCamelCasePreferenceTest.suite());

View file

@ -1,134 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 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:
* Mentor Graphics (Mohamed Azab) - 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 ParameterGuessingTests 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 ParameterGuessingTests(String name) {
super(name, true);
}
public static Test suite() {
return BaseTestCase.suite(ParameterGuessingTests.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* axPtr;
// bClass bx;
// piab(
public void testIndirectTypes() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("piab(a, b)", new String[][]{
{"a", "*axPtr", "bx"}, {"b", "bx"}
});
assertParametersGuesses(resultsMap);
}
// void foo(){
// int w;
// aClass ax;
// overload(
public void testOverloadedFunction() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("overload(x, a)", new String[][]{
{"x", "w"}, {"a", "ax"}
});
resultsMap.put("overload(x, aPtr)", new String[][]{
{"x", "w"}, {"aPtr", "&ax"}
});
assertParametersGuesses(resultsMap);
}
// void foo(){
// aClass ax;
// tFunc<aClass> (
public void testTemplateFunction() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("tFunc<aClass> (x, y)", new String[][]{
{"x"}, {"y"}
});
assertParametersGuesses(resultsMap);
}
// struct container {
// aClass* axPtr;
// };
// void foo(){
// char x, y, z;
// container c;
// c.axPtr = new aClass();
// c.axPtr->
public void testOverloadedMethod() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("aMethod(c)", new String[][]{
{"c", "x", "y", "z"}
});
resultsMap.put("aMethod(c, x)", new String[][]{
{"c", "x", "y", "z"}, {"x", "x", "y", "z"}
});
assertParametersGuesses(resultsMap);
}
// class cClass : bClass {
// public:
// cClass(int inCall) {
// char x, y;
// aClass::
public void testInsideConstructor() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("aMethod(c)", new String[][]{
{"c", "x", "y", "inCall"}
});
resultsMap.put("aMethod(c, x)", new String[][]{
{"c", "x", "y", "inCall"}, {"x", "x", "y", "inCall"}
});
assertParametersGuesses(resultsMap);
}
}

View file

@ -1,82 +0,0 @@
/*******************************************************************************
* Copyright (c) 2014 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:
* Mentor Graphics (Mohamed Azab) - 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 ParameterGuessingTests_PlainC 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 piab(aStruct a, aStruct b);
public ParameterGuessingTests_PlainC(String name) {
super(name, false);
}
public static Test suite() {
return BaseTestCase.suite(ParameterGuessingTests_PlainC.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;
// piab(
public void testIndirectTypes() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("piab(a, b)", new String[][]{
{"a", "*axPtr", "ax"}, {"b", "*axPtr", "ax"}
});
assertParametersGuesses(resultsMap);
}
// void foo(){
// aStruct ax;
// ov
public void testMultipleFunctions() throws Exception {
Map<String, String[][]> resultsMap = new HashMap<String, String[][]>();
resultsMap.put("ov1(x, a)", new String[][]{
{"x"}, {"a", "ax"}
});
resultsMap.put("ov2(x, aPtr)", new String[][]{
{"x"}, {"aPtr", "&ax"}
});
assertParametersGuesses(resultsMap);
}
}

View file

@ -13,15 +13,12 @@
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
* Nathan Ridge
* Thomas Corbat (IFS)
* Mentor Graphics (Mohamed Azab) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=438549 (parameter guessing)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.contentassist;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
@ -110,20 +107,17 @@ 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;
/**
* 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;
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
if (inPreprocessorDirective(context)) {
@ -593,43 +587,9 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
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, proposal, function, fPrefix));
else
proposals.add(proposal);
}
/**
* @return 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;
// Check if the invocation is before typing any parameter names.
Pattern functionNamePattern = Pattern.compile("\\s*(<.+>)?\\s*\\(\\s*"); //$NON-NLS-1$
int startOffset = context.getParseOffset();
try {
String completePrefix = context.getDocument().get(startOffset, context.getInvocationOffset() - startOffset);
Matcher m = functionNamePattern.matcher(completePrefix);
if (m.matches() && m.group(0).equals(completePrefix)) {
return true;
}
} catch (BadLocationException e) {
return false;
}
return false;
}
private boolean skipDefaultedParameter(IParameter param) {
return !isDisplayDefaultedParameters() && param instanceof ICPPParameter && ((ICPPParameter)param).hasDefaultValue();
}

View file

@ -1,135 +0,0 @@
/*******************************************************************************
* Copyright (c) 2005, 2011 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
* Mentor Graphics (Mohamed Azab) - added the API to CDT and made the necessary changes
*******************************************************************************/
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.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= false;
private boolean fHasParameters;
protected IParameter [] fFunctionParameters;
protected CContentAssistInvocationContext fContext;
public FunctionCompletionProposal(String replacementString, int replacementOffset, int replacementLength,
Image image, String displayString, String idString, int relevance, ITextViewer viewer, IFunction function, CContentAssistInvocationContext context) {
super(replacementString, replacementOffset, replacementLength, image, displayString, idString, relevance,
viewer);
fFunctionParameters = function.getParameters();
fContext = context;
}
@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, ';');
}
}
/**
* @return <code>true</code> if the method has any parameters, <code>false</code> 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;
}
/*
* @see org.eclipse.jdt.internal.ui.text.link.LinkedPositionUI.ExitPolicy#doExit(org.eclipse.jdt.internal.ui.text.link.LinkedPositionManager, org.eclipse.swt.events.VerifyEvent, int, int)
*/
@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 offset = fContext.getInvocationOffset();
int exit= getReplacementOffset() + getReplacementString().length();
try {
LinkedPositionGroup group= new LinkedPositionGroup();
group.addPosition(new LinkedPosition(document, offset, 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);
}
}
}
}

View file

@ -1,476 +0,0 @@
/*******************************************************************************
* Copyright (c) 2000, 2011 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
* Mentor Graphics (Mohamed Azab) - added the API to CDT and made the necessary changes
*******************************************************************************/
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.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.IASTExpression.ValueCategory;
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.util.StringMatcher;
import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
/**
* This iAPI layout is copied from org.eclipse.jdt.internal.ui.text.java.ParameterGuesser
*
* This class triggers a code-completion that will track all global, local and member variables and order them logically for later
* use as a parameter guessing proposal.
*/
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 boolean isAutoboxingMatch;
public final char[] triggerChars;
public final ImageDescriptor descriptor;
public boolean alreadyMatched;
public Variable(IType qualifiedTypeName, String name, int variableType, boolean isAutoboxMatch, 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.isAutoboxingMatch= isAutoboxMatch;
this.alreadyMatched= false;
}
/*
* @see Object#toString()
*/
@Override
public String toString() {
StringBuffer buffer= new StringBuffer();
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<Variable>();
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, false, 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;
}
/**
* @return 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;
}
/**
* @return 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;
}
/**
* @see {@link DOMCompletionProposalComputer#getImage()}
*/
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;
}
/**
*
* Copied from JDT
*
* 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);
boolean hasVarWithParamName= false;
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;
hasVarWithParamName |= displayString.equals(paramName);
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 (!fillBestGuess && !hasVarWithParamName) {
// insert a proposal with the argument name
ICompletionProposal[] extended= new ICompletionProposal[ret.length + 1];
System.arraycopy(ret, 0, extended, 1, ret.length);
extended[0]= new PositionBasedCompletionProposal(paramName, pos, replacementLength, null, paramName, null, null, isLastParameter ? null : new char[] {','});
return extended;
}
return ret;
}
/**
* Copied from JDT
*/
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);
}
/**
* 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; // since ???
int matchedScore= v.alreadyMatched ? 0 : 1;
int autoboxingScore= v.isAutoboxingMatch ? 0 : 1;
int score= autoboxingScore << 30 | variableScore << 21 | subStringScore << 11 | matchedScore << 10 | positionScore;
return score;
}
}
/**
*
* Copied from JDT
*
* Determine 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));
}
/**
*
* Copied from JDT
*
* Remove the duplicates from the list if any.
*/
private static List<Variable> removeDuplicates(List<Variable> typeMatches) {
HashSet<Variable> set = new HashSet<Variable>();
set.addAll(typeMatches);
return Arrays.asList(set.toArray(new Variable[set.size()]));
}
/**
*
* Copied from JDT
*
* Returns the longest common substring of two strings.
*
* @param first the first string
* @param second the second string
* @return the longest common substring
*/
private static String getLongestCommonSubstring(String first, String second) {
String shorter= (first.length() <= second.length()) ? first : second;
String longer= shorter == first ? second : first;
int minLength= shorter.length();
StringBuffer pattern= new StringBuffer(shorter.length() + 2);
String longestCommonSubstring= ""; //$NON-NLS-1$
for (int i= 0; i < minLength; i++) {
for (int j= i + 1; j <= minLength; j++) {
if (j - i < longestCommonSubstring.length())
continue;
String substring= shorter.substring(i, j);
pattern.setLength(0);
pattern.append('*');
pattern.append(substring);
pattern.append('*');
StringMatcher matcher= new StringMatcher(pattern.toString(), true, false);
if (matcher.match(longer))
longestCommonSubstring= substring;
}
}
return longestCommonSubstring;
}
/**
* Copied from JDT
*/
private Image getImage(ImageDescriptor descriptor) {
return (descriptor == null) ? null : CUIPlugin.getImageDescriptorRegistry().get(descriptor);
}
}

View file

@ -1,491 +0,0 @@
/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andrew McCullough - initial API and implementation
* IBM Corporation - general improvement and bug fixes, partial reimplementation
* Mentor Graphics (Mohamed Azab) - added the API to CDT and made the necessary changes
*******************************************************************************/
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.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
import org.eclipse.cdt.core.dom.ast.IASTName;
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.core.dom.parser.cpp.semantics.AccessContext;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.EditorHighlightingSynchronizer;
/**
* This API layout is copied from 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 = false;
private IRegion fSelectedRegion; // initialized by apply()
private IPositionUpdater fUpdater;
private String fPrefix; // The string from the start of the statement to the parse offset.
private String fFullPrefix; // The string from the start of the statement to the invocation offset.
private char[][] fParametersNames;
private IType [] fParametersTypes;
public static ParameterGuessingProposal createProposal(CContentAssistInvocationContext context, CCompletionProposal proposal, IFunction function, String prefix) {
String replacement = getParametersList(function);
String fullPrefix = function.getName() + "("; //$NON-NLS-1$
int replacementOffset = proposal.getReplacementOffset();
int replacementLength = 0;
/*
* 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(context)) {
replacementOffset = context.getParseOffset() - prefix.length();
try {
fullPrefix = context.getDocument().get(replacementOffset, context.getInvocationOffset() - replacementOffset);
replacement = fullPrefix + replacement + ")"; //$NON-NLS-1$
} catch (BadLocationException e1) {
}
try {
// remove ')' from the replacement string if it is auto appended.
if (context.getDocument().getChar(context.getInvocationOffset()) == ')')
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, context);
ret.setContextInformation(proposal.getContextInformation());
ret.fPrefix = prefix;
ret.fFullPrefix = fullPrefix;
return ret;
}
/**
* @return a comma-separated list of parameters
*/
private static String getParametersList(IFunction method) {
StringBuilder params = new StringBuilder();
boolean first = true;
for (IParameter param : method.getParameters()) {
if (first)
first = false;
else
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, CContentAssistInvocationContext context) {
super(replacementString, replacementOffset, replacementLength, image, displayString, idString, relevance,
viewer, function, context);
fParametersNames = getFunctionParametersNames(fFunctionParameters);
fParametersTypes = getFunctionParametersTypes(fFunctionParameters);
}
// Check if the invocation of content assist was after open bracket.
private static boolean isInsideBracket(CContentAssistInvocationContext context) {
return context.getInvocationOffset() - context.getParseOffset() != 0;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension3#getReplacementText()
*
* Add special handling for the case of invocation after open bracket.
*/
@Override
public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
if (isInsideBracket(fContext)) {
try {
return fContext.getDocument().get(getReplacementOffset(), fContext.getInvocationOffset() - getReplacementOffset());
} catch (BadLocationException e) {
}
}
return super.getPrefixCompletionText(document, completionOffset);
}
/**
* Copied from JDT
*/
@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 e) {
ensurePositionCategoryRemoved(document);
CUIPlugin.log(e);
} catch (BadPositionCategoryException e) {
ensurePositionCategoryRemoved(document);
CUIPlugin.log(e);
}
}
/**
* Copied from JDT
*/
@Override
public Point getSelection(IDocument document) {
if (fSelectedRegion == null)
return new Point(getReplacementOffset(), 0);
return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
}
/**
* Copied from JDT
*/
@Override
public String getReplacementString() {
if (!fReplacementStringComputed) {
String rep = computeReplacementString();
setReplacementString(rep);
setReplacementLength(rep.length());
}
return super.getReplacementString();
}
/**
* Copied from JDT
*/
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;
}
/**
* Copied from JDT with replacing JDT types with CDT types
*/
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();
}
/**
* Copied from JDT with replacing JDT types with CDT types
*/
private ICompletionProposal[][] guessParameters(char[][] parameterNames) throws Exception {
int count= parameterNames.length;
fPositions= new Position[count];
fChoices= new ICompletionProposal[count][];
ParameterGuesser guesser= new ParameterGuesser(fContext.getCompletionNode().getTranslationUnit());
ArrayList<IBinding> assignableElements = getAssignableElements();
for (int i= count - 1; i >= 0; i--) {
String paramName= new String(parameterNames[i]);
Position position= new Position(0,0);
boolean isLastParameter= i == count - 1;
ArrayList<ICompletionProposal> allProposals = new ArrayList<ICompletionProposal>();
CCompletionProposal proposal= new CCompletionProposal(paramName, 0, paramName.length(), null, paramName, 0);
if (isLastParameter)
proposal.setTriggerCharacters(new char[] { ',' });
allProposals.add(proposal);
ICompletionProposal[] argumentProposals= guesser.parameterProposals(fParametersTypes[i], paramName, position, assignableElements, true, isLastParameter);
allProposals.addAll(Arrays.asList(argumentProposals));
fPositions[i]= position;
fChoices[i]= allProposals.toArray(new ICompletionProposal[allProposals.size()]);
}
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;
}
/**
* @return the start offset of the statement that contains the current position.
*/
private int getStatementStartOffset() {
return fContext.getParseOffset() - fPrefix.length();
}
/**
* Returns a list of functions and variables that are defined in current context.
* @return a list of assignable elements.
*/
private ArrayList<IBinding> getAssignableElements() {
int i = getStatementStartOffset(fContext.getDocument(), getStatementStartOffset());
CContentAssistInvocationContext c = new CContentAssistInvocationContext(fTextViewer, i, getCEditor(), true, false);
IASTCompletionNode node = c.getCompletionNode();
IASTName [] names = node.getNames();
ArrayList<IBinding> allBindings = new ArrayList<IBinding>();
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))
allBindings.add(binding);
}
}
}
}
return allBindings;
}
/**
* Get the beginning of statement index.
* The beginning of statement could be:
* - Index after ;
* - Index after {
* - Index after }
*/
private 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;
}
/**
* Copied from JDT
*/
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) {}
});
}
}
/**
* Copied from JDT
*/
private void ensurePositionCategoryRemoved(IDocument document) {
if (document.containsPositionCategory(getCategory())) {
try {
document.removePositionCategory(getCategory());
} catch (BadPositionCategoryException e) {
// ignore
}
document.removePositionUpdater(fUpdater);
}
}
/**
* Copied from JDT
*/
private String getCategory() {
return "ParameterGuessingProposal_" + toString(); //$NON-NLS-1$
}
/**
* Copied from JDT with replacing JDT types with CDT types.
*
* Returns the currently active C/C++ editor, or <code>null</code> if it
* cannot be determined.
*
* @return the currently active C/C++ editor, or <code>null</code>
*/
private CEditor getCEditor() {
IEditorPart part= CUIPlugin.getActivePage().getActiveEditor();
if (part instanceof CEditor)
return (CEditor) part;
else
return null;
}
/**
* @return the guesses for each parameter
*/
public ICompletionProposal[][] getParametersGuesses() {
return fChoices;
}
}

View file

@ -8,7 +8,6 @@
* Contributors:
* QNX - Initial API and implementation
* Anton Leherbauer (Wind River Systems)
* Mentor Graphics (Mohamed Azab) - added the API to CDT
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.contentassist;

View file

@ -1,218 +0,0 @@
/*******************************************************************************
* Copyright (c) 2000, 2008 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
* Mentor Graphics (Mohamed Azab) - added the API to CDT
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.contentassist;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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;
/**
* 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;
}
/*
* @see ICompletionProposal#apply(IDocument)
*/
@Override
public void apply(IDocument document) {
try {
document.replace(fReplacementPosition.getOffset(), fReplacementPosition.getLength(), fReplacementString);
} catch (BadLocationException x) {
// ignore
}
}
/*
* @see ICompletionProposal#getSelection(IDocument)
*/
@Override
public Point getSelection(IDocument document) {
return new Point(fReplacementPosition.getOffset() + fCursorPosition, 0);
}
/*
* @see ICompletionProposal#getContextInformation()
*/
@Override
public IContextInformation getContextInformation() {
return fContextInformation;
}
/*
* @see ICompletionProposal#getImage()
*/
@Override
public Image getImage() {
return fImage;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString()
*/
@Override
public String getDisplayString() {
if (fDisplayString != null)
return fDisplayString;
return fReplacementString;
}
/*
* @see ICompletionProposal#getAdditionalProposalInfo()
*/
@Override
public String getAdditionalProposalInfo() {
return fAdditionalProposalInfo;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, char, int, int)
*/
@Override
public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) {
apply(viewer.getDocument());
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(org.eclipse.jface.text.ITextViewer, boolean)
*/
@Override
public void selected(ITextViewer viewer, boolean smartToggle) {
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(org.eclipse.jface.text.ITextViewer)
*/
@Override
public void unselected(ITextViewer viewer) {
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument, int, org.eclipse.jface.text.DocumentEvent)
*/
@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;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#apply(org.eclipse.jface.text.IDocument, char, int)
*/
@Override
public void apply(IDocument document, char trigger, int offset) {
// not called any more
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#isValidFor(org.eclipse.jface.text.IDocument, int)
*/
@Override
public boolean isValidFor(IDocument document, int offset) {
// not called any more
return false;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#getTriggerCharacters()
*/
@Override
public char[] getTriggerCharacters() {
return fTriggerCharacters;
}
/*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension#getContextInformationPosition()
*/
@Override
public int getContextInformationPosition() {
return fReplacementPosition.getOffset();
}
}