In progress: [Issue 199] Add ability to navigate to proto element from
generated C++ code.

* Made creation of pattern more efficient.
* Code cleanup.
diff --git a/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF
index 09d731b..3b08b5f 100644
--- a/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.cdt.test/META-INF/MANIFEST.MF
@@ -7,4 +7,6 @@
 Fragment-Host: com.google.eclipse.protobuf.cdt;bundle-version="1.0.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Require-Bundle: org.junit;bundle-version="4.8.2",
- org.mockito;bundle-version="1.8.5"
+ org.mockito;bundle-version="1.8.5",
+ org.hamcrest;bundle-version="1.1.0",
+ org.hamcrest.library;bundle-version="1.1.0"
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java
new file mode 100644
index 0000000..ffe207e
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder_patternToMatchFrom_Test.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.cdt.matching;
+
+import static com.google.eclipse.protobuf.cdt.matching.PatternMatcher.matches;
+import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.xtext.naming.IQualifiedNameConverter;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.cdt.mapping.CppToProtobufMapping;
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.inject.Inject;
+
+/**
+ * Tests for <code>{@link PatternBuilder#patternToMatchFrom(CppToProtobufMapping)}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class PatternBuilder_patternToMatchFrom_Test {
+  @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule());
+
+  @Inject private PatternBuilder builder;
+  @Inject private IQualifiedNameConverter converter;
+
+  @Test public void should_escape_dots() {
+    CppToProtobufMapping mapping = createMessageMapping("com.google.proto.test.Person");
+    Pattern pattern = builder.patternToMatchFrom(mapping);
+    assertThat(pattern.pattern(), equalTo("com\\.google\\.proto\\.test\\.Person"));
+    assertThat("com.google.proto.test.Person", matches(pattern));
+  }
+
+  @Test public void should_escape_underscore() {
+    CppToProtobufMapping mapping = createMessageMapping("com.google.proto.test.Person_PhoneType");
+    Pattern pattern = builder.patternToMatchFrom(mapping);
+    assertThat(pattern.pattern(), equalTo("com\\.google\\.proto\\.test\\.Person(\\.|_)PhoneType"));
+    assertThat("com.google.proto.test.Person.PhoneType", matches(pattern));
+    assertThat("com.google.proto.test.Person_PhoneType", matches(pattern));
+  }
+
+  private CppToProtobufMapping createMessageMapping(String qualifiedNameAsText) {
+    return new CppToProtobufMapping(converter.toQualifiedName(qualifiedNameAsText), MESSAGE);
+  }
+}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java
new file mode 100644
index 0000000..c7d4f07
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/PatternMatcher.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.cdt.matching;
+
+import java.util.regex.Pattern;
+
+import org.hamcrest.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class PatternMatcher extends TypeSafeMatcher<String> {
+  private final Pattern pattern;
+
+  static PatternMatcher matches(Pattern pattern) {
+    return new PatternMatcher(pattern);
+  }
+
+  private PatternMatcher(Pattern pattern) {
+    super(String.class);
+    this.pattern = pattern;
+  }
+
+  @Override public boolean matchesSafely(String item) {
+    return pattern.matcher(item).matches();
+  }
+
+  @Override public void describeTo(Description description) {
+    description.appendValue(pattern.pattern());
+  }
+
+}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher_findUriOfMatchingProtobufElement_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher_findUriOfMatchingProtobufElement_Test.java
index ac4e225..15f9ec1 100644
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher_findUriOfMatchingProtobufElement_Test.java
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher_findUriOfMatchingProtobufElement_Test.java
@@ -10,6 +10,7 @@
 
 import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
 import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE;
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.*;
 
@@ -105,7 +106,7 @@
 
   private CppToProtobufMapping messageMapping(String qualifiedNameAsText) {
     QualifiedName qualifiedName = fqnConverter.toQualifiedName(qualifiedNameAsText);
-    return new CppToProtobufMapping(qualifiedName, Message.class);
+    return new CppToProtobufMapping(qualifiedName, MESSAGE);
   }
 
   private URI uriOfMessageWithName(String name) {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/cpplang/CppKeywords.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/cpplang/CppKeywords.java
new file mode 100644
index 0000000..87604a6
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/cpplang/CppKeywords.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.cdt.cpplang;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.List;
+
+import com.google.inject.Singleton;
+
+/**
+ * C++ keywords.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton public class CppKeywords {
+
+  private static final List<String> KEYWORDS = newArrayList("and", "and_eq", "asm", "auto", "bitand", "bitor", "bool",
+      "break", "case", "catch", "char", "class", "compl", "const", "const_cast", "continue", "default", "delete",
+      "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend",
+      "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", "operator", "or", "or_eq",
+      "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof",
+      "static", "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", "typedef", "typeid",
+      "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq");
+
+  @SuppressWarnings("unused")
+  private static final List<String> CPP11_KEYWORDS = newArrayList("alignas", "alignof", "char16_t", "char32_t",
+      "constexpr", "decltype", "noexcept", "nullptr", "static_assert", "thread_local");
+
+  /**
+   * Indicates whether the content of the given {@code String} is a C++ keyword.
+   * @param s the given {@code String}.
+   * @return {@code true} if the content of the given {@code String} is a C++ keyword, {@code false} otherwise.
+   */
+  public boolean isKeyword(String s) {
+    return KEYWORDS.contains(s);
+  }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
index 00dacf4..2b9a1f5 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/ClassMappingStrategy.java
@@ -8,13 +8,14 @@
  */
 package com.google.eclipse.protobuf.cdt.mapping;
 
+import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE;
+
 import org.eclipse.cdt.core.dom.IName;
 import org.eclipse.cdt.core.dom.ast.IBinding;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
 import org.eclipse.xtext.naming.QualifiedName;
 
-import com.google.eclipse.protobuf.protobuf.Message;
 import com.google.inject.Singleton;
 
 /**
@@ -28,7 +29,7 @@
     if (isMessage(classType)) {
       String[] segments = classType.getQualifiedName();
       QualifiedName qualifiedName = QualifiedName.create(segments);
-      return new CppToProtobufMapping(qualifiedName, Message.class);
+      return new CppToProtobufMapping(qualifiedName, MESSAGE);
     }
     return null;
   }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
index 35df4c4..b600a3b 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/CppToProtobufMapping.java
@@ -8,7 +8,7 @@
  */
 package com.google.eclipse.protobuf.cdt.mapping;
 
-import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EClass;
 import org.eclipse.xtext.naming.QualifiedName;
 
 /**
@@ -18,9 +18,9 @@
  */
 public class CppToProtobufMapping {
   private final QualifiedName qualifiedName;
-  private final Class<? extends EObject> type;
+  private final EClass type;
 
-  public CppToProtobufMapping(QualifiedName qualifiedName, Class<? extends EObject> type) {
+  public CppToProtobufMapping(QualifiedName qualifiedName, EClass type) {
     this.qualifiedName = qualifiedName;
     this.type = type;
   }
@@ -37,7 +37,7 @@
    * Returns the type of the protocol buffer element.
    * @return the type of the protocol buffer element.
    */
-  public Class<? extends EObject> type() {
+  public EClass type() {
     return type;
   }
 }
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
index 9c0edef..5c30caf 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/EnumMappingStrategy.java
@@ -8,11 +8,12 @@
  */
 package com.google.eclipse.protobuf.cdt.mapping;
 
+import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.ENUM;
+
 import org.eclipse.cdt.core.dom.ast.IBinding;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration;
 import org.eclipse.xtext.naming.QualifiedName;
 
-import com.google.eclipse.protobuf.protobuf.Enum;
 import com.google.inject.Singleton;
 
 /**
@@ -25,7 +26,7 @@
     CPPEnumeration enumeration = typeOfSupportedBinding().cast(binding);
     String[] segments = enumeration.getQualifiedName();
     QualifiedName qualifiedName = QualifiedName.create(segments);
-    return new CppToProtobufMapping(qualifiedName, Enum.class);
+    return new CppToProtobufMapping(qualifiedName, ENUM);
   }
 
   @Override public Class<CPPEnumeration> typeOfSupportedBinding() {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
index db5150a..5dce848 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/mapping/MethodMappingStrategy.java
@@ -8,13 +8,13 @@
  */
 package com.google.eclipse.protobuf.cdt.mapping;
 
+import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.MESSAGE_FIELD;
+
 import org.eclipse.cdt.core.dom.ast.*;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod;
 import org.eclipse.xtext.naming.QualifiedName;
 
-import com.google.eclipse.protobuf.protobuf.MessageField;
-
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
@@ -32,7 +32,7 @@
       return null;
     }
     QualifiedName qualifiedName = QualifiedName.create(method.getQualifiedName());
-    return new CppToProtobufMapping(qualifiedName, MessageField.class);
+    return new CppToProtobufMapping(qualifiedName, MESSAGE_FIELD);
   }
 
   @Override public Class<CPPMethod> typeOfSupportedBinding() {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java
new file mode 100644
index 0000000..f080950
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/PatternBuilder.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.cdt.matching;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.xtext.naming.IQualifiedNameConverter;
+
+import com.google.eclipse.protobuf.cdt.mapping.CppToProtobufMapping;
+import com.google.inject.Inject;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class PatternBuilder {
+  @Inject private IQualifiedNameConverter converter;
+
+  Pattern patternToMatchFrom(CppToProtobufMapping mapping) {
+    String qualifiedNameAsText = converter.toString(mapping.qualifiedName());
+    StringBuilder regex = new StringBuilder();
+    int size = qualifiedNameAsText.length();
+    // escape existing "."
+    // replace "_" with "(\.|_)"
+    for (int i = 0; i < size; i++) {
+      char c = qualifiedNameAsText.charAt(i);
+      switch (c) {
+        case '.':
+          regex.append("\\.");
+          break;
+        case '_':
+          regex.append("(\\.|_)");
+          break;
+        default:
+          regex.append(c);
+      }
+    }
+    return Pattern.compile(regex.toString());
+  }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher.java
index f7a254b..94655af 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/matching/ProtobufElementMatcher.java
@@ -8,13 +8,15 @@
  */
 package com.google.eclipse.protobuf.cdt.matching;
 
+import static com.google.eclipse.protobuf.resource.filter.MatchingQualifiedNameAndTypeFilter.matchingQualifiedNameAndType;
+
 import java.util.List;
 import java.util.regex.Pattern;
 
 import org.eclipse.emf.common.util.URI;
-import org.eclipse.xtext.naming.*;
 import org.eclipse.xtext.resource.*;
 
+import com.google.common.base.Predicate;
 import com.google.eclipse.protobuf.cdt.mapping.CppToProtobufMapping;
 import com.google.eclipse.protobuf.resource.ResourceDescriptions;
 import com.google.inject.Inject;
@@ -23,7 +25,7 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class ProtobufElementMatcher {
-  @Inject private IQualifiedNameConverter converter;
+  @Inject private PatternBuilder patternBuilder;
   @Inject private ResourceDescriptions descriptions;
 
   /**
@@ -34,21 +36,12 @@
    * @return the found URI, or {@code null} if it was not possible to find a matching protocol buffer element.
    */
   public URI findUriOfMatchingProtobufElement(IResourceDescription resource, CppToProtobufMapping mapping) {
-    QualifiedName qualifiedName = mapping.qualifiedName();
-    Pattern pattern = patternToMatchFrom(qualifiedName);
-    List<IEObjectDescription> matches = descriptions.matchingQualifiedNames(resource, pattern, mapping.type());
+    Pattern pattern = patternBuilder.patternToMatchFrom(mapping);
+    Predicate<IEObjectDescription> filter = matchingQualifiedNameAndType(pattern, mapping.type());
+    List<IEObjectDescription> matches = descriptions.filterModelObjects(resource, filter);
     if (!matches.isEmpty()) {
       return matches.get(0).getEObjectURI();
     }
     return null;
   }
-
-  private Pattern patternToMatchFrom(QualifiedName qualifiedName) {
-    String qualifiedNameAsText = converter.toString(qualifiedName);
-    // escape existing "."
-    // replace "_" with "(\.|_)"
-    String regex = qualifiedNameAsText.replaceAll("\\.", "\\\\.")
-                                      .replaceAll("_", "\\(\\\\.|_\\)");
-    return Pattern.compile(regex);
-  }
 }
diff --git a/com.google.eclipse.protobuf.integration.test/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.integration.test/META-INF/MANIFEST.MF
index 3136f73..5726298 100644
--- a/com.google.eclipse.protobuf.integration.test/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.integration.test/META-INF/MANIFEST.MF
@@ -9,5 +9,7 @@
  org.eclipse.xtext.junit;bundle-version="2.0.0",
  org.eclipse.xtext.junit4;bundle-version="2.0.0",
  org.mockito;bundle-version="1.8.5",
- org.eclipse.core.resources;bundle-version="3.7.100"
+ org.eclipse.core.resources;bundle-version="3.7.100",
+ org.hamcrest;bundle-version="1.1.0",
+ org.hamcrest.library;bundle-version="1.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFields.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFields.java
index 18b486c..83db9ee 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFields.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFields.java
@@ -23,7 +23,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ContainAllFields extends BaseMatcher<IEObjectDescriptions> {
+public class ContainAllFields extends TypeSafeMatcher<IEObjectDescriptions> {
   private final Collection<MessageField> fields = newArrayList();
 
   public static ContainAllFields containAll(Collection<MessageField> fields) {
@@ -31,20 +31,17 @@
   }
 
   private ContainAllFields(Collection<MessageField> fields) {
+    super(IEObjectDescriptions.class);
     this.fields.addAll(fields);
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof IEObjectDescriptions)) {
-      return false;
-    }
-    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
-    if (descriptions.size() != fields.size()) {
+  @Override public boolean matchesSafely(IEObjectDescriptions item) {
+    if (item.size() != fields.size()) {
       return false;
     }
     for (MessageField field : fields) {
       String name = field.getName();
-      EObject described = descriptions.objectDescribedAs(name);
+      EObject described = item.objectDescribedAs(name);
       if (described != field) {
         return false;
       }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFieldsInMessage.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFieldsInMessage.java
index a4fb223..670969c 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFieldsInMessage.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllFieldsInMessage.java
@@ -23,7 +23,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ContainAllFieldsInMessage extends BaseMatcher<IEObjectDescriptions> {
+public class ContainAllFieldsInMessage extends TypeSafeMatcher<IEObjectDescriptions> {
   private final EObject container;
 
   public static ContainAllFieldsInMessage containAllFieldsIn(Group group) {
@@ -35,21 +35,18 @@
   }
 
   private ContainAllFieldsInMessage(EObject container) {
+    super(IEObjectDescriptions.class);
     this.container = container;
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof IEObjectDescriptions)) {
-      return false;
-    }
-    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
+  @Override public boolean matchesSafely(IEObjectDescriptions item) {
     List<IndexedElement> elements = allIndexedElements();
-    if (descriptions.size() != elements.size()) {
+    if (item.size() != elements.size()) {
       return false;
     }
     for (IndexedElement e : elements) {
       String name = nameOf(e);
-      EObject described = descriptions.objectDescribedAs(name);
+      EObject described = item.objectDescribedAs(name);
       if (described != e) {
         return false;
       }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllLiteralsInEnum.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllLiteralsInEnum.java
index 40312dd..89ded43 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllLiteralsInEnum.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllLiteralsInEnum.java
@@ -24,7 +24,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ContainAllLiteralsInEnum extends BaseMatcher<IEObjectDescriptions> {
+public class ContainAllLiteralsInEnum extends TypeSafeMatcher<IEObjectDescriptions> {
   private final Enum anEnum;
 
   public static ContainAllLiteralsInEnum containAllLiteralsIn(Enum anEnum) {
@@ -32,21 +32,18 @@
   }
 
   private ContainAllLiteralsInEnum(Enum anEnum) {
+    super(IEObjectDescriptions.class);
     this.anEnum = anEnum;
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof IEObjectDescriptions)) {
-      return false;
-    }
-    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
+  @Override public boolean matchesSafely(IEObjectDescriptions item) {
     List<Literal> literals = allLiterals();
-    if (descriptions.size() != literals.size()) {
+    if (item.size() != literals.size()) {
       return false;
     }
     for (Literal literal : literals) {
       String name = literal.getName();
-      EObject described = descriptions.objectDescribedAs(name);
+      EObject described = item.objectDescribedAs(name);
       if (described != literal) {
         return false;
       }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllNames.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllNames.java
index 2fb0457..b26569f 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllNames.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainAllNames.java
@@ -19,7 +19,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ContainAllNames extends BaseMatcher<IEObjectDescriptions> {
+public class ContainAllNames extends TypeSafeMatcher<IEObjectDescriptions> {
   private final String[] expectedNames;
 
   public static ContainAllNames containAll(String... names) {
@@ -27,15 +27,12 @@
   }
 
   private ContainAllNames(String... names) {
+    super(IEObjectDescriptions.class);
     expectedNames = names;
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof IEObjectDescriptions)) {
-      return false;
-    }
-    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
-    List<String> names = newArrayList(descriptions.names());
+  @Override public boolean matchesSafely(IEObjectDescriptions item) {
+    List<String> names = newArrayList(item.names());
     if (names.size() != expectedNames.length) {
       return false;
     }
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainNames.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainNames.java
index 456e079..3dfc2af 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainNames.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/junit/matchers/ContainNames.java
@@ -10,7 +10,7 @@
 
 import static java.util.Arrays.asList;
 
-import java.util.List;
+import java.util.*;
 
 import org.hamcrest.*;
 
@@ -19,7 +19,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class ContainNames extends BaseMatcher<IEObjectDescriptions> {
+public class ContainNames extends TypeSafeMatcher<IEObjectDescriptions> {
   private final List<String> expectedNames;
 
   public static ContainNames contain(String... names) {
@@ -27,15 +27,13 @@
   }
 
   private ContainNames(String... names) {
+    super(IEObjectDescriptions.class);
     expectedNames = asList(names);
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof IEObjectDescriptions)) {
-      return false;
-    }
-    IEObjectDescriptions descriptions = (IEObjectDescriptions) arg;
-    return descriptions.names().containsAll(expectedNames);
+  @Override public boolean matchesSafely(IEObjectDescriptions item) {
+    Collection<String> names = item.names();
+    return names.containsAll(expectedNames);
   }
 
   @Override public void describeTo(Description description) {
diff --git a/com.google.eclipse.protobuf.test/.gitignore b/com.google.eclipse.protobuf.test/.gitignore
new file mode 100644
index 0000000..42859ab
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/.gitignore
@@ -0,0 +1 @@
+/test-protos
diff --git a/com.google.eclipse.protobuf.test/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.test/META-INF/MANIFEST.MF
index dbf6497..4d98f42 100644
--- a/com.google.eclipse.protobuf.test/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.test/META-INF/MANIFEST.MF
@@ -9,7 +9,9 @@
  org.eclipse.xtext.junit;bundle-version="2.0.0",
  org.eclipse.xtext.junit4;bundle-version="2.0.0",
  org.mockito;bundle-version="1.8.5",
- org.eclipse.core.resources;bundle-version="3.7.100"
+ org.eclipse.core.resources;bundle-version="3.7.100",
+ org.hamcrest;bundle-version="1.1.0",
+ org.hamcrest.library;bundle-version="1.1.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Export-Package: com.google.eclipse.protobuf.junit.core,
  com.google.eclipse.protobuf.junit.matchers,
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/EnumHasLiterals.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/EnumHasLiterals.java
index ba26024..21ef88d 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/EnumHasLiterals.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/EnumHasLiterals.java
@@ -23,7 +23,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class EnumHasLiterals extends BaseMatcher<Enum> {
+public class EnumHasLiterals extends TypeSafeMatcher<Enum> {
   private final String[] literalNames;
 
   public static EnumHasLiterals hasLiterals(String... literalNames) {
@@ -31,15 +31,12 @@
   }
 
   private EnumHasLiterals(String... literalNames) {
+    super(Enum.class);
     this.literalNames = literalNames;
   }
 
-  @Override public boolean matches(Object item) {
-    if (!(item instanceof Enum)) {
-      return false;
-    }
-    Enum anEnum = (Enum) item;
-    List<String> actualNames = newArrayList(literalNames(anEnum));
+  @Override public boolean matchesSafely(Enum item) {
+    List<String> actualNames = newArrayList(literalNames(item));
     for (String name : literalNames) {
       actualNames.remove(name);
     }
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/FieldHasType.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/FieldHasType.java
index c02ed9f..9996ded 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/FieldHasType.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/matchers/FieldHasType.java
@@ -15,7 +15,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class FieldHasType extends BaseMatcher<MessageField> {
+public class FieldHasType extends TypeSafeMatcher<MessageField> {
   private final String typeName;
 
   public static FieldHasType isBool() {
@@ -31,15 +31,12 @@
   }
 
   private FieldHasType(String typeName) {
+    super(MessageField.class);
     this.typeName = typeName;
   }
 
-  @Override public boolean matches(Object arg) {
-    if (!(arg instanceof MessageField)) {
-      return false;
-    }
-    MessageField field = (MessageField) arg;
-    return typeName.equals(typeNameOf(field));
+  @Override public boolean matchesSafely(MessageField item) {
+    return typeName.equals(typeNameOf(item));
   }
 
   private String typeNameOf(MessageField field) {
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnosticMatcher.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnosticMatcher.java
index 162a5e4..9b35c37 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnosticMatcher.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnosticMatcher.java
@@ -18,7 +18,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-class ProtobufDiagnosticMatcher extends BaseMatcher<ProtobufDiagnostic> {
+class ProtobufDiagnosticMatcher extends TypeSafeMatcher<ProtobufDiagnostic> {
   private final DiagnosticMessage message;
 
   static ProtobufDiagnosticMatcher wasCreatedFrom(DiagnosticMessage message) {
@@ -26,16 +26,14 @@
   }
 
   private ProtobufDiagnosticMatcher(DiagnosticMessage message) {
+    super(ProtobufDiagnostic.class);
     this.message = message;
   }
 
-  @Override public boolean matches(Object item) {
-    if (!(item instanceof ProtobufDiagnostic)) {
-      return false;
-    }
-    ProtobufDiagnostic d = (ProtobufDiagnostic) item;
-    return equal(message.getIssueCode(), d.getCode()) && Arrays.equals(message.getIssueData(), d.getData())
-        && equal(message.getMessage(), d.getMessage());
+  @Override public boolean matchesSafely(ProtobufDiagnostic item) {
+    return equal(message.getIssueCode(), item.getCode()) &&
+        Arrays.equals(message.getIssueData(), item.getData()) &&
+        equal(message.getMessage(), item.getMessage());
   }
 
   @Override public void describeTo(Description description) {
diff --git a/com.google.eclipse.protobuf.ui.test/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.ui.test/META-INF/MANIFEST.MF
index a90dbbd..5af6725 100644
--- a/com.google.eclipse.protobuf.ui.test/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.ui.test/META-INF/MANIFEST.MF
@@ -10,4 +10,6 @@
  org.eclipse.xtext.junit;bundle-version="2.0.0",
  org.eclipse.xtext.junit4;bundle-version="2.0.0",
  org.eclipse.xtext.ui.junit;bundle-version="2.0.0",
- org.mockito;bundle-version="1.8.5"
+ org.mockito;bundle-version="1.8.5",
+ org.hamcrest;bundle-version="1.1.0",
+ org.hamcrest.library;bundle-version="1.1.0"
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/contentassist/IEObjectDescriptionsHaveNames.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/contentassist/IEObjectDescriptionsHaveNames.java
index 392b247..7d2b688 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/contentassist/IEObjectDescriptionsHaveNames.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/contentassist/IEObjectDescriptionsHaveNames.java
@@ -19,7 +19,7 @@
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-public class IEObjectDescriptionsHaveNames extends BaseMatcher<Collection<IEObjectDescription>> {
+public class IEObjectDescriptionsHaveNames extends TypeSafeMatcher<Collection<IEObjectDescription>> {
   private final List<String> qualifiedNames;
 
   public static IEObjectDescriptionsHaveNames containOnly(String...names) {
@@ -30,18 +30,12 @@
     this.qualifiedNames = newArrayList(qualifiedNames);
   }
 
-  /** {@inheritDoc} */
-  @Override @SuppressWarnings("unchecked")
-  public boolean matches(Object arg) {
-    if (!(arg instanceof Collection)) {
-      return false;
-    }
-    Collection<IEObjectDescription> descriptions = (Collection<IEObjectDescription>) arg;
+  @Override public boolean matchesSafely(Collection<IEObjectDescription> item) {
     List<String> copyOfNames = newArrayList(qualifiedNames);
-    if (copyOfNames.size() != descriptions.size()) {
+    if (copyOfNames.size() != item.size()) {
       return false;
     }
-    for (IEObjectDescription description : descriptions) {
+    for (IEObjectDescription description : item) {
       QualifiedName qualifiedName = description.getName();
       if (qualifiedName == null) {
         continue;
diff --git a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
index caafc24..d306d0f 100644
--- a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
@@ -33,6 +33,7 @@
  com.google.eclipse.protobuf.protobuf.impl,

  com.google.eclipse.protobuf.protobuf.util,

  com.google.eclipse.protobuf.resource,

+ com.google.eclipse.protobuf.resource.filter,

  com.google.eclipse.protobuf.scoping,

  com.google.eclipse.protobuf.serializer,

  com.google.eclipse.protobuf.services,

diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java
index ae13715..61b72a2 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java
@@ -8,19 +8,18 @@
  */
 package com.google.eclipse.protobuf.resource;
 
-import static com.google.common.base.Objects.equal;
+import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Lists.newArrayList;
 import static java.util.Collections.unmodifiableList;
 
 import java.util.List;
-import java.util.regex.*;
 
 import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.*;
-import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.naming.QualifiedName;
 import org.eclipse.xtext.resource.*;
 
-import com.google.inject.*;
+import com.google.common.base.Predicate;
+import com.google.inject.Singleton;
 
 /**
  * Utility methods related to <code>{@link IResourceDescription}</code>s.
@@ -28,8 +27,6 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 @Singleton public class ResourceDescriptions {
-  @Inject private IQualifiedNameConverter converter;
-
   /**
    * Finds the URI of a model object, in the given resource, whose qualified name matches the given one.
    * @param resource the given resource.
@@ -48,30 +45,13 @@
   }
 
   /**
-   * Finds the URIs of the model objects, in the given resource, that:
-   * <ol>
-   * <li>have a qualified name that match the given pattern, and</li>
-   * <li>have an {@code EClass} whose name is equal to the simple name of the given type.
-   * </ol>
-   * @param resource the given resource.
-   * @param pattern the pattern to match.
-   * @param type the type of model object we are looking for.
-   * @return the URI of the matching object models, or an empty list if matches could not be found.
+   * Returns the model objects that match the criteria specified in the given filter.
+   * @param resource the resource containing model objects.
+   * @param filter the filter to use.
+   * @return  the model objects that match the criteria specified in the given filter.
    */
-  public List<IEObjectDescription> matchingQualifiedNames(IResourceDescription resource, Pattern pattern,
-      Class<? extends EObject> type) {
-    List<IEObjectDescription> descriptions = newArrayList();
-    for (IEObjectDescription exported : resource.getExportedObjects()) {
-      QualifiedName qualifiedName = exported.getQualifiedName();
-      Matcher matcher = pattern.matcher(converter.toString(qualifiedName));
-      if (haveMatchingNames(exported.getEClass(), type) && matcher.matches()) {
-        descriptions.add(exported);
-      }
-    }
-    return unmodifiableList(descriptions);
-  }
-
-  private boolean haveMatchingNames(EClass eClass, Class<? extends EObject> type) {
-    return equal(eClass.getName(), type.getSimpleName());
+  public List<IEObjectDescription> filterModelObjects(IResourceDescription resource, Predicate<IEObjectDescription> filter) {
+    List<IEObjectDescription> filtered = newArrayList(filter(resource.getExportedObjects(), filter));
+    return unmodifiableList(filtered);
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/filter/MatchingQualifiedNameAndTypeFilter.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/filter/MatchingQualifiedNameAndTypeFilter.java
new file mode 100644
index 0000000..3bdac63
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/filter/MatchingQualifiedNameAndTypeFilter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.resource.filter;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IEObjectDescription;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Indicates whether the qualified name and {@code EClass} of a <code>{@link IEObjectDescription}</code> match the given
+ * pattern and type, respectively.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class MatchingQualifiedNameAndTypeFilter implements Predicate<IEObjectDescription> {
+  private final Pattern pattern;
+  private final EClass type;
+
+  /**
+   * Creates a new <code>{@link MatchingQualifiedNameAndTypeFilter}</code>.
+   * @param pattern the pattern that qualified names should match.
+   * @param type the type of model object to match.
+   * @return the created filter.
+   */
+  public static MatchingQualifiedNameAndTypeFilter matchingQualifiedNameAndType(Pattern pattern, EClass type) {
+    return new MatchingQualifiedNameAndTypeFilter(pattern, type);
+  }
+
+  private MatchingQualifiedNameAndTypeFilter(Pattern pattern, EClass type) {
+    this.pattern = pattern;
+    this.type = type;
+  }
+
+  @Override public boolean apply(IEObjectDescription input) {
+    if (!type.equals(input.getEClass())) {
+      return false;
+    }
+    QualifiedName qualifiedName = input.getQualifiedName();
+    return pattern.matcher(qualifiedName.toString()).matches();
+  }
+}