diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java
new file mode 100644
index 00000000000..f5888e9a8e8
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContentAssistMatcherFactoryTest.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tomasz Wesolowski 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:
+ * Jens Elmenthaler - initial implementation
+ * http://bugs.eclipse.org/173458 (camel case completion)
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.parser.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.CCorePreferenceConstants;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
+import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+
+public class ContentAssistMatcherFactoryTest extends TestCase {
+
+ @Override
+ protected void tearDown() throws Exception {
+ InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).remove(
+ CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES);
+ super.tearDown();
+ }
+
+ public void testCamelCasePreference() {
+ // Default is show camel case matches on
+ assertTrue(match("foo", "fooBar"));
+ assertTrue(match("fB", "fooBar"));
+
+ setShowCamelCaseMatches(false);
+
+ assertTrue(match("foo", "fooBar"));
+ assertFalse(match("fB", "fooBar"));
+
+ setShowCamelCaseMatches(true);
+
+ assertTrue(match("foo", "fooBar"));
+ assertTrue(match("fB", "fooBar"));
+ }
+
+ public void testCamelCaseMatcher() {
+ setShowCamelCaseMatches(true);
+ IContentAssistMatcher matcher = ContentAssistMatcherFactory
+ .getInstance().createMatcher("fB");
+
+ assertEquals("f", String.valueOf(matcher.getPrefixForBinarySearch()));
+ assertTrue(matcher.matchRequiredAfterBinarySearch());
+ }
+
+ public void testPrefixMatcher() {
+ setShowCamelCaseMatches(true);
+ IContentAssistMatcher matcher = ContentAssistMatcherFactory
+ .getInstance().createMatcher("foo");
+
+ assertEquals("foo", String.valueOf(matcher.getPrefixForBinarySearch()));
+ assertFalse(matcher.matchRequiredAfterBinarySearch());
+ }
+
+ private void setShowCamelCaseMatches(boolean enabled) {
+ InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).putBoolean(
+ CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES, enabled);
+ }
+
+ private boolean match(String pattern, String name) {
+ return ContentAssistMatcherFactory.getInstance().match(
+ pattern.toCharArray(), name.toCharArray());
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java
index 654a6775e51..44e607345d4 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ParserTestSuite.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2002, 2008 IBM Corporation and others.
+ * Copyright (c) 2002, 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
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Rational Software - Initial API and implementation
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests;
@@ -29,6 +30,8 @@ public class ParserTestSuite extends TestCase {
TestSuite suite= new TestSuite(ParserTestSuite.class.getName());
suite.addTestSuite(ArrayUtilsTest.class);
suite.addTestSuite(CharArrayUtilsTest.class);
+ suite.addTestSuite(SegmentMatcherTest.class);
+ suite.addTestSuite(ContentAssistMatcherFactoryTest.class);
suite.addTestSuite(CModelElementsTests.class);
suite.addTestSuite(StructuralCModelElementsTests.class);
suite.addTestSuite(ObjectMapTest.class);
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java
new file mode 100644
index 00000000000..ef76fdb36cf
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/SegmentMatcherTest.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tomasz Wesolowski 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:
+ * Tomasz Wesolowski - initial API and implementation
+ * Jens Elmenthaler - further tweaking
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.parser.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.cdt.core.parser.util.SegmentMatcher;
+
+public class SegmentMatcherTest extends TestCase {
+
+
+ public void testSimple() {
+
+ assertTrue(matchSegments("", "fooBarBaz"));
+ assertTrue(matchSegments("fBB", "fooBarBaz"));
+ assertTrue(matchSegments("fooBB", "fooBarBaz"));
+ assertTrue(matchSegments("foBaBaz", "fooBarBaz"));
+ assertTrue(matchSegments("fBBaz", "fooBarBaz"));
+ assertTrue(matchSegments("fooBarBaz", "fooBarBaz"));
+ assertTrue(matchSegments("foo", "fooBarBaz"));
+ assertTrue(matchSegments("fooB", "fooBarBaz"));
+ assertTrue(matchSegments("fBBaz", "fooBarBaz"));
+ assertTrue(matchSegments("fooB", "fooBarBaz"));
+ assertTrue(matchSegments("fBBaz", "fooBarBaz"));
+ // Improvement compared to JDT: an all upper case abbreviation should
+ // also match as a single segment.
+ assertTrue(matchSegments("fBBaz", "fooBARBaz"));
+ // Improvement compared to JDT: you don't need to specify all segments
+ // in between.
+ assertTrue(matchSegments("fBaz", "fooBARBaz"));
+
+ assertFalse(matchSegments("FooBarBaz", "fooBarBaz"));
+ assertFalse(matchSegments("fooBARBaz", "fooBarBaz"));
+ assertTrue(matchSegments("fooBarbaz", "fooBarBaz"));
+ assertFalse(matchSegments("barBaz", "fooBarBaz"));
+ assertFalse(matchSegments("BarBaz", "fooBarBaz"));
+ assertTrue(matchSegments("fBaz", "fooBarBaz"));
+ assertFalse(matchSegments("fBaBar", "fooBarBaz"));
+ assertFalse(matchSegments("fBBB", "fooBarBaz"));
+ assertFalse(matchSegments("fBBBarBaz", "fooBarBaz"));
+ assertFalse(matchSegments("foooBarBaz", "fooBarBaz"));
+ assertFalse(matchSegments("foBrBaz", "fooBarBaz"));
+
+ }
+
+ public void testSuffix() {
+
+ assertTrue(matchSegments("fooBar", "fooBar123"));
+ assertTrue(matchSegments("fooBar", "fooBarrr"));
+ assertTrue(matchSegments("fooBar", "fooBarr__"));
+
+ }
+
+ public void testNumeric() {
+
+ assertTrue(matchSegments("fBBaz", "foo29BarBaz"));
+ assertTrue(matchSegments("fBBaz", "fooBar100Baz10"));
+ assertTrue(matchSegments("fB100Baz1", "fooBar100Baz10"));
+ assertTrue(matchSegments("fB100Baz10", "fooBar100Baz10"));
+ assertTrue(matchSegments("fooBar100Baz10", "fooBar100Baz10"));
+
+ assertFalse(matchSegments("fBar100Ba", "fooBarBaz"));
+ assertTrue(matchSegments("f100Baz", "fooBar100Baz10"));
+ assertFalse(matchSegments("fB1000Baz", "fooBar100Baz"));
+ assertFalse(matchSegments("sV", "seed48"));
+
+ }
+
+ public void testSeparator() {
+
+ assertTrue(matchSegments("fBB", "foo_Bar_Baz"));
+ assertTrue(matchSegments("fBB", "foo_BarBaz"));
+ assertTrue(matchSegments("fBB", "foo_bar_baz"));
+ // Improvement compared to JDT:
+ assertTrue(matchSegments("FBB", "FOO_BAR_BAZ"));
+
+ assertTrue(matchSegments("fBB", "foo__barBaz"));
+ assertTrue(matchSegments("fBB", "foo__bar__baz"));
+ assertTrue(matchSegments("fB_B", "foo__bar__Baz"));
+ assertTrue(matchSegments("f__b", "foo__bar"));
+
+ assertFalse(matchSegments("fB_B", "foo__bar__baz"));
+ assertFalse(matchSegments("f___b", "foo__bar"));
+ assertFalse(matchSegments("f__bb", "foo__bar__baz"));
+
+ assertFalse(matchSegments("f_B_B", "fooBarBaz"));
+ assertFalse(matchSegments("f_B", "foo_bar"));
+ assertFalse(matchSegments("foo_B", "foo_bar"));
+ assertFalse(matchSegments("foo_Bar", "foo_bar"));
+ assertFalse(matchSegments("fO_bar", "foo_bar"));
+ assertFalse(matchSegments("f__b", "foo_bar"));
+
+ }
+
+ public void testPrefixChars() {
+
+ assertFalse(matchSegments("$asd","_asd"));
+ assertFalse(matchSegments("_$$","__"));
+ assertFalse(matchSegments("__$","__"));
+
+ // require everything to be exactly the same from start up until the first section
+ assertTrue(matchSegments("__f", "__fooBar"));
+ assertTrue(matchSegments("__fooB", "__fooBar"));
+ assertFalse(matchSegments("_fooB", "__fooBar"));
+ assertFalse(matchSegments("_FooB", "__fooBar"));
+ assertFalse(matchSegments("_$fooB", "__fooBar"));
+
+ assertTrue(matchSegments("___", "___"));
+ assertFalse(matchSegments("$__", "___"));
+ assertFalse(matchSegments("__$", "___"));
+ assertTrue(matchSegments("__", "___"));
+ assertFalse(matchSegments("____", "___"));
+
+ }
+
+ public void testAbbreviations() {
+ assertTrue(matchSegments("IFB", "IFooBar"));
+ assertTrue(matchSegments("IFoB", "IFooBar"));
+ assertTrue(matchSegments("XYZ", "XYZFooBar"));
+ }
+
+ public void testSingleSegment() {
+ assertTrue(matchSegments("foo", "fooBar"));
+ assertFalse(matchSegments("bar", "fooBar"));
+ }
+
+ public void testGetPrefixForBinarySearch() {
+ // Segments can be skipped, because of that the first letter as well
+ // as the leading separator must not be added to the binary search prefix.
+ assertEquals("foo", getPrefixForBinarySearch("fooBar"));
+ assertEquals("foo", getPrefixForBinarySearch("foo6"));
+ assertEquals("foo", getPrefixForBinarySearch("foo_"));
+ assertEquals("foo", getPrefixForBinarySearch("foo$"));
+ assertEquals("___", getPrefixForBinarySearch("___"));
+ assertEquals("___foo", getPrefixForBinarySearch("___fooBar"));
+ assertEquals("___foo", getPrefixForBinarySearch("___foo3"));
+ assertEquals("___foo", getPrefixForBinarySearch("___foo_"));
+ assertEquals("___foo", getPrefixForBinarySearch("___foo$"));
+ assertEquals("$__", getPrefixForBinarySearch("$__"));
+ assertEquals("$__foo", getPrefixForBinarySearch("$__fooBar"));
+ assertEquals("$__foo", getPrefixForBinarySearch("$__foo3"));
+ assertEquals("$__foo", getPrefixForBinarySearch("$__foo_"));
+ }
+
+ /**
+ * Only checks segment matching (i.e. without case-insensitive prefix matching)
+ */
+ private boolean matchSegments(String pattern, String name) {
+ SegmentMatcher matcher = new SegmentMatcher(pattern.toCharArray());
+ return matcher.matchSegments(name.toCharArray());
+ }
+
+ private String getPrefixForBinarySearch(String pattern) {
+ SegmentMatcher matcher = new SegmentMatcher(pattern.toCharArray());
+ return String.valueOf(matcher.getPrefixForBinarySearch());
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java
index ddeafdc6bf3..a93c278b44c 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/prefix/BasicCompletionTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.prefix;
@@ -296,4 +297,44 @@ public class BasicCompletionTest extends CompletionTestBase {
checkNonPrefixCompletion(code, true, expected);
}
+ // typedef int FooBar;
+ // typedef int Foo_Bar;
+ // FB
+ public void testCamelCaseCompletion_CScope() throws Exception {
+ String code = getAboveComment();
+ String[] expected= {"FooBar", "Foo_Bar"};
+ checkCompletion(code, false, expected);
+ }
+
+ // typedef int FooBar;
+ // typedef int Foo_Bar;
+ // FB
+ public void testCamelCaseCompletion_CPPScope() throws Exception {
+ String code = getAboveComment();
+ String[] expected= {"FooBar", "Foo_Bar"};
+ checkCompletion(code, true, expected);
+ }
+
+ // class FooBar {
+ // FooBar();
+ // }
+ // FooBar::FB
+ public void testCamelCaseCompletion_CPPASTQualifiedName_CPPClassScope() throws Exception {
+ String code = getAboveComment();
+ String[] expected= {"FooBar", "FooBar"};
+ checkCompletion(code, true, expected);
+ }
+
+ // struct s1 {
+ // int fooBar;
+ // int foo_bar;
+ // };
+ // void test() {
+ // struct s1 s;
+ // s.
+ public void testCamelCaseCompletion_CVisitor() throws Exception {
+ String code = getAboveComment();
+ String[] expected= {"fooBar", "foo_bar"};
+ checkCompletion(code, false, expected);
+ }
}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java
index 3f098b03fac..aa1a2b965dd 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Symbian Software Ltd. and others.
+ * Copyright (c) 2007, 2011 Symbian Software Ltd. 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
@@ -9,6 +9,7 @@
* Andrew Ferguson (Symbian) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.index.tests;
@@ -68,6 +69,12 @@ public class EmptyIndexFragment implements IIndexFragment {
return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY;
}
+ public IIndexFragmentBinding[] findBindingsForContentAssist(char[] prefix,
+ boolean filescope, IndexFilter filter, IProgressMonitor monitor)
+ throws CoreException {
+ return IIndexFragmentBinding.EMPTY_INDEX_BINDING_ARRAY;
+ }
+
public IIndexMacro[] findMacros(char[] name, boolean isPrefix, boolean caseSensitive, IndexFilter filter, IProgressMonitor monitor) {
return IIndexMacro.EMPTY_INDEX_MACRO_ARRAY;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java
index 9cc4978e387..9ae50211c0d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2006, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
* Andrew Ferguson (Symbian)
* Bryan Wilkinson (QNX)
* Sergey Prigogin (Google)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.core.index;
@@ -326,7 +327,19 @@ public interface IIndex {
* @throws CoreException
*/
public IIndexBinding[] findBindingsForPrefix(char[] prefix, boolean fileScopeOnly, IndexFilter filter, IProgressMonitor monitor) throws CoreException;
-
+
+ /**
+ * Searches for all bindings that are valid completions to the given prefix.
+ * @param prefix the text to be completed.
+ * @param fileScopeOnly if true, only bindings at file scope are returned
+ * @param filter a filter that allows for skipping parts of the index
+ * @param monitor a monitor for progress reporting and cancellation, may be null
+ * @return an array of bindings that complete the given text
+ * @throws CoreException
+ * @since 5.3
+ */
+ public IIndexBinding[] findBindingsForContentAssist(char[] prefix, boolean fileScopeOnly, IndexFilter filter, IProgressMonitor monitor) throws CoreException;
+
/**
* Searches for all names that resolve to the given binding. You can limit the result to references, declarations
* or definitions, or a combination of those.
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java
new file mode 100644
index 00000000000..8bf2566751a
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ContentAssistMatcherFactory.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Jens Elmenthaler 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:
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.util;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.CCorePreferenceConstants;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+
+
+/**
+ * The facade to the pattern matching algorithms of content assist.
+ *
+ * @author Jens Elmenthaler
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @since 5.3
+ */
+public class ContentAssistMatcherFactory {
+
+ private static ContentAssistMatcherFactory instance = null;
+
+ private boolean showCamelCaseMatches;
+
+ private final IPreferenceChangeListener preferencesListener = new IPreferenceChangeListener() {
+
+ public void preferenceChange(PreferenceChangeEvent event) {
+ String prop = event.getKey();
+ if (prop.equals(CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES)) {
+ updateOnPreferences();
+ }
+ }
+ };
+
+ private static class CamelCaseMatcher implements IContentAssistMatcher {
+
+ private final SegmentMatcher matcher;
+
+ public CamelCaseMatcher(char[] pattern) {
+ matcher = new SegmentMatcher(pattern);
+ }
+
+ public char[] getPrefixForBinarySearch() {
+ return matcher.getPrefixForBinarySearch();
+ }
+
+ public boolean matchRequiredAfterBinarySearch() {
+ return matcher.matchRequiredAfterBinarySearch();
+ }
+
+ public boolean match(char[] name) {
+ return matcher.match(name);
+ }
+ }
+
+ private static class PrefixMatcher implements IContentAssistMatcher {
+
+ private final char[] prefix;
+
+ public PrefixMatcher(char[] prefix) {
+ this.prefix = prefix;
+ }
+
+ public char[] getPrefixForBinarySearch() {
+ return prefix;
+ }
+
+ public boolean matchRequiredAfterBinarySearch() {
+ return false;
+ }
+
+ public boolean match(char[] name) {
+ return CharArrayUtils.equals(name, 0, prefix.length, prefix, true);
+ }
+
+ }
+
+ private ContentAssistMatcherFactory() {
+ getPreferences().addPreferenceChangeListener(
+ preferencesListener);
+ updateOnPreferences();
+ }
+
+ public static synchronized ContentAssistMatcherFactory getInstance() {
+ if (instance == null) {
+ instance = new ContentAssistMatcherFactory();
+ }
+
+ return instance;
+ }
+
+ private void shutdownInternal() {
+ getPreferences().removePreferenceChangeListener(
+ preferencesListener);
+ }
+
+ /**
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static synchronized void shutdown() {
+ if (instance != null) {
+ instance.shutdownInternal();
+ }
+ }
+
+ private static IEclipsePreferences getPreferences() {
+ return InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID);
+ }
+
+ private synchronized void updateOnPreferences() {
+ IPreferencesService prefs = Platform.getPreferencesService();
+ showCamelCaseMatches = prefs.getBoolean(CCorePlugin.PLUGIN_ID,
+ CCorePreferenceConstants.SHOW_CAMEL_CASE_MATCHES, true, null);
+ }
+
+ /**
+ * @param pattern The pattern for which to create a matcher.
+ * @return A suitable matcher.
+ */
+ public synchronized IContentAssistMatcher createMatcher(char[] pattern) {
+
+ return showCamelCaseMatches ? new CamelCaseMatcher(pattern) : new PrefixMatcher(pattern);
+ }
+
+ /**
+ * @param pattern The pattern for which to create a matcher.
+ * @return A suitable matcher.
+ */
+ public IContentAssistMatcher createMatcher(String pattern) {
+ return createMatcher(pattern.toCharArray());
+ }
+
+ /**
+ * A helper method to match a name against the pattern typed by the user.
+ * If you need to match many names at once against the same pattern, use
+ * {@link #createMatcher(char[])} and re-use the returned matcher instead.
+ *
+ * @param pattern The user provided pattern.
+ * @param name The name to match against the pattern.
+ *
+ * @return true if the name matches the given pattern.
+ */
+ public boolean match(char[] pattern, char[] name) {
+ return createMatcher(pattern).match(name);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java
new file mode 100644
index 00000000000..3d22a9f6349
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IContentAssistMatcher.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Jens Elmenthaler 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:
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.util;
+
+/**
+ * A matcher for content assist-like application to determine whether names
+ * match the user provided text.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since 5.3
+ */
+public interface IContentAssistMatcher {
+
+ /**
+ * The user provided text normally represents some kind of pattern. This pattern
+ * may not be suitable for binary searches (e.g. within the index).
+ * For each content assist pattern, however, there is a string that can be
+ * calculated and used for binary searches.
+ * In the compare method used by your binary search, return 0 for any string
+ * that starts with the returned string.
+ *
+ * @return Such a string.
+ */
+ char[] getPrefixForBinarySearch();
+
+ /**
+ * @return If false, calling @{@link #match(char[])} can be skipped if a
+ * name survived a binary search using the prefix returned by
+ * @{@link #getPrefixForBinarySearch()} as key.
+ */
+ boolean matchRequiredAfterBinarySearch();
+
+ /**
+ * Matches the given name following the rules of content assist.
+ *
+ * @param name
+ *
+ * @return True if the name matches.
+ */
+ boolean match(char[] name);
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java
new file mode 100644
index 00000000000..ed3e500d6e9
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/SegmentMatcher.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Tomasz Wesolowski 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:
+ * Tomasz Wesolowski - initial API and implementation
+ * Jens Elmenthaler - further tweaking
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A matcher for camel case matching supporting both the camel case as well as
+ * he underscore notation.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @since 5.3
+ */
+public class SegmentMatcher {
+
+ private final char[] prefixForBinarySearch;
+
+ /** The string the any prefix match has to start with. */
+ private final char[] prefixForMatching;
+
+ /** The regular expression for a segment match. */
+ private final Pattern regexp;
+
+ /** The minimum length any name must have in order to match. */
+ private final int minNameLength;
+
+ private final boolean singleSegment;
+
+ /**
+ * @param pattern
+ * The camel case or underscore pattern.
+ */
+ public SegmentMatcher(char[] pattern) {
+
+ if (pattern == null || pattern.length == 0) {
+ prefixForMatching = CharArrayUtils.EMPTY;
+ prefixForBinarySearch = CharArrayUtils.EMPTY;
+ regexp = null;
+ minNameLength = 0;
+ singleSegment = true;
+ } else {
+
+ StringBuffer regexpBuffer = new StringBuffer("^"); //$NON-NLS-1$
+ int i = 0;
+ int lengthOfFirstSegment = 0;
+ char currentChar;
+ int segmentCount = 0;
+
+ // Translate each segment
+ while (i < pattern.length) {
+
+ boolean separatorSpecified = false;
+
+ // Handle prefix, i.e. anything before the first letter or digit
+ for (; i < pattern.length; ++i) {
+ currentChar = pattern[i];
+ if (Character.isLetterOrDigit(currentChar)) {
+ break;
+ } else {
+ // Quote those characters.
+ regexpBuffer.append(Pattern.quote(String.valueOf(currentChar)));
+ separatorSpecified = true;
+ }
+ }
+
+ if (i < pattern.length) {
+ // The character here is always a letter or digit.
+ currentChar = pattern[i];
+
+ if (Character.isDigit(currentChar)) {
+
+ // Handle number segment
+ regexpBuffer.append(currentChar);
+ for (++i; i < pattern.length; ++i) {
+ currentChar = pattern[i];
+ if (Character.isDigit(currentChar)) {
+ regexpBuffer.append(currentChar);
+ } else {
+ break;
+ }
+ }
+
+ } else {
+
+ // Handle text segment
+ char lower = Character.toLowerCase(currentChar);
+ char upper = Character.toUpperCase(currentChar);
+
+ if ((segmentCount == 0) || separatorSpecified) {
+ regexpBuffer.append(currentChar);
+ } else {
+ regexpBuffer.append("(_["); //$NON-NLS-1$
+ regexpBuffer.append(lower);
+ regexpBuffer.append(upper);
+ regexpBuffer.append("]|"); //$NON-NLS-1$
+ regexpBuffer.append(upper);
+ regexpBuffer.append(')');
+ }
+
+ // Remaining letters of the segment
+ for (++i; i < pattern.length; ++i) {
+
+ currentChar = pattern[i];
+ if (Character.isLetter(currentChar)) {
+ if (Character.isUpperCase(currentChar)) {
+ break;
+ } else {
+ lower = currentChar;
+ upper = Character.toUpperCase(currentChar);
+ regexpBuffer.append('[');
+ regexpBuffer.append(lower);
+ regexpBuffer.append(upper);
+ regexpBuffer.append(']');
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ regexpBuffer.append(".*"); //$NON-NLS-1$
+
+ if (segmentCount == 0) {
+ lengthOfFirstSegment = i;
+ }
+
+ ++segmentCount;
+ }
+
+ regexp = Pattern.compile(regexpBuffer.toString());
+ singleSegment = (segmentCount == 1);
+ prefixForMatching = pattern;
+
+ // The first segment is also the binary search prefix
+ prefixForBinarySearch = CharArrayUtils.extract(pattern, 0, lengthOfFirstSegment);
+
+ minNameLength = pattern.length;
+ }
+ }
+
+ /**
+ * Matches the given name by prefix and segment matching.
+ *
+ * @return true if the associated pattern is a prefix-based or segment-based abbreviation of name.
+ */
+ public boolean match(char[] name) {
+ if (matchPrefix(name)) {
+ return true;
+ }
+
+ // If there is only a single segment given and prefix match failed,
+ // the segment match cannot pass either. So skip it.
+ if (singleSegment) {
+ return false;
+ }
+
+ return matchSegments(name);
+ }
+
+ /**
+ * Matches the given name by prefix matching.
+ *
+ * @return true if the associated pattern is a prefix-based abbreviation of name.
+ */
+ public boolean matchPrefix(char[] name) {
+ return (CharArrayUtils.equals(name, 0, prefixForMatching.length, prefixForMatching, true));
+ }
+
+ /**
+ * Matches the given name by segment matching.
+ *
+ * @return true if the associated pattern is a segment-based abbreviation of name.
+ */
+ public boolean matchSegments(char[] name) {
+
+ if (name == null) {
+ return false;
+ }
+
+ if (name.length < minNameLength) {
+ return false;
+ }
+
+ if (regexp == null) {
+ return true;
+ }
+
+ Matcher matcher = regexp.matcher(String.valueOf(name));
+
+ return matcher.find();
+ }
+
+ /**
+ * Matches pattern to name by prefix and segment matching. If you have to match
+ * against the same pattern repeatedly, create a {@link SegmentMatcher} instead
+ * and re-use it all the time, because this is much faster.
+ *
+ * @return true if pattern is a prefix-based or segment-based abbreviation of name
+ */
+ public static boolean match(char[] pattern, char[] name) {
+ return (new SegmentMatcher(pattern)).match(name);
+ }
+
+ /**
+ * The pattern used by this matcher is not suitable for binary searches
+ * (e.g. within the index).
+ * However, there can be calculated a string that can be used in the
+ * context of binary searches.
+ * In the compare method used by your binary search, return 0 for any string
+ * that starts with the returned string.
+ *
+ * @return Such a string.
+ */
+ public char[] getPrefixForBinarySearch() {
+ return prefixForBinarySearch;
+ }
+
+ /**
+ * @return If false, calling @{@link #match(char[])} can be skipped if a
+ * name survived a binary search using the prefix returned by
+ * @{@link #getPrefixForBinarySearch()} as key.
+ */
+ boolean matchRequiredAfterBinarySearch() {
+ return !singleSegment;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java
index 1f3ca719b5e..a9aecb7005a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -10,6 +10,7 @@
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
@@ -56,6 +57,8 @@ import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
+import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousParameterDeclaration;
@@ -327,10 +330,11 @@ public class CScope implements ICScope, IASTInternalScope {
populateCache();
for (CharArrayObjectMap map : mapsToNameOrBinding) {
if (prefixLookup) {
+ IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(c);
Object[] keys = map.keyArray();
for (Object key2 : keys) {
char[] key = (char[]) key2;
- if (CharArrayUtils.equals(key, 0, c.length, c, true)) {
+ if (matcher.match(key)) {
obj = ArrayUtil.append(obj, map.get(key));
}
}
@@ -344,7 +348,7 @@ public class CScope implements ICScope, IASTInternalScope {
IIndex index = tu.getIndex();
if (index != null) {
try {
- IBinding[] bindings = prefixLookup ? index.findBindingsForPrefix(name.toCharArray(), true, INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null)
+ IBinding[] bindings = prefixLookup ? index.findBindingsForContentAssist(name.toCharArray(), true, INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null)
: index.findBindings(name.toCharArray(), INDEX_FILTERS[NAMESPACE_TYPE_BOTH], null);
if (fileSet != null) {
bindings = fileSet.filterFileLocalBindings(bindings);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
index 31be5f90d60..3e6d48dd54b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * 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
@@ -10,6 +10,7 @@
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
@@ -89,6 +90,8 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
+import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
@@ -609,9 +612,10 @@ public class CVisitor extends ASTQueries {
if (prefix) {
IBinding[] result = null;
char[] p = fieldReference.getFieldName().toCharArray();
+ IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(p);
IField[] fields = ((ICompositeType) type).getFields();
for (IField field : fields) {
- if (CharArrayUtils.equals(field.getNameCharArray(), 0, p.length, p, true)) {
+ if (matcher.match(field.getNameCharArray())) {
result = (IBinding[]) ArrayUtil.append(IBinding.class, result, field);
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java
index 98ca1e8d652..01c44a1b427 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -9,6 +9,7 @@
* John Camelon (IBM) - Initial API and implementation
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@@ -41,6 +42,7 @@ import org.eclipse.cdt.core.model.IEnumeration;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@@ -329,7 +331,7 @@ public class CPPASTQualifiedName extends CPPASTNameBase
private boolean nameMatches(char[] potential, char[] name, boolean isPrefix) {
if (isPrefix)
- return CharArrayUtils.equals(potential, 0, name.length, name, true);
+ return ContentAssistMatcherFactory.getInstance().match(name, potential);
return CharArrayUtils.equals(potential, name);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java
index 62ba554c14c..1ed91896e50 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -11,6 +11,7 @@
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@@ -54,6 +55,7 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
@@ -240,7 +242,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
}
IBinding[] result = null;
if ((!prefixLookup && CharArrayUtils.equals(c, compName.getLookupKey()))
- || (prefixLookup && CharArrayUtils.equals(compName.getLookupKey(), 0, c.length, c, true))) {
+ || (prefixLookup && ContentAssistMatcherFactory.getInstance().match(c, compName.getLookupKey()))) {
if (shallReturnConstructors(name, prefixLookup)) {
result = (IBinding[]) ArrayUtil.addAll(IBinding.class, result, getConstructors(name, resolve));
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java
index 554407c43a4..3a9e06d29f4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2010, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* Markus Schorn (Wind River Systems) - initial API and implementation
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@@ -45,6 +46,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
+import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@@ -342,9 +345,10 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
private IBinding[] getPrefixBindings(char[] name) {
List result= new ArrayList();
+ IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(name);
for (ICPPMethod m : getMethods()) {
if (!(m instanceof ICPPConstructor)) {
- if (CharArrayUtils.equals(name, 0, name.length, m.getNameCharArray(), true)) {
+ if (matcher.match(m.getNameCharArray())) {
result.add(m);
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java
index 27481f95a73..635d7c46a09 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPScope.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -10,6 +10,7 @@
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
+ * Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@@ -37,6 +38,8 @@ import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.core.parser.util.ContentAssistMatcherFactory;
+import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
@@ -211,7 +214,7 @@ abstract public class CPPScope implements ICPPASTInternalScope {
IndexFilter filter = IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE;
final char[] nchars = name.getLookupKey();
IBinding[] bindings = prefixLookup ?
- index.findBindingsForPrefix(nchars, true, filter, null) :
+ index.findBindingsForContentAssist(nchars, true, filter, null) :
index.findBindings(nchars, filter, null);
if (fileSet != null) {
bindings= fileSet.filterFileLocalBindings(bindings);
@@ -253,9 +256,10 @@ abstract public class CPPScope implements ICPPASTInternalScope {
if (prefixLookup) {
Object[] keys = bindings != null ? bindings.keyArray() : new Object[0];
ObjectSet