Fixed caching of qualified names and compiled patterns.
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/semicolon/CommentNodesFinder.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/semicolon/CommentNodesFinder.java
index 059a2c6..86494d5 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/semicolon/CommentNodesFinder.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/commands/semicolon/CommentNodesFinder.java
@@ -8,31 +8,39 @@
  */
 package com.google.eclipse.protobuf.ui.commands.semicolon;
 
+import static com.google.common.cache.CacheBuilder.newBuilder;
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.eclipse.protobuf.util.Strings.quote;
 import static com.google.eclipse.protobuf.util.SystemProperties.lineSeparator;
 import static java.util.regex.Pattern.CASE_INSENSITIVE;
 import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.getNode;
 import static org.eclipse.xtext.util.Strings.isEmpty;
 import static org.eclipse.xtext.util.Tuples.pair;
 
-import java.util.List;
-import java.util.regex.*;
-
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.xtext.nodemodel.*;
-import org.eclipse.xtext.util.*;
-
+import com.google.common.cache.*;
 import com.google.eclipse.protobuf.model.util.INodes;
 import com.google.inject.*;
 
+import org.apache.log4j.Logger;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.nodemodel.*;
+import org.eclipse.xtext.util.Pair;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.*;
+
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
 @Singleton class CommentNodesFinder {
   private static final String MATCH_ANYTHING = ".*";
 
+  private static Logger logger = Logger.getLogger(CommentNodesFinder.class);
+
   @Inject private INodes nodes;
-  @Inject private final IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE;
+
+  private final Cache<String, Pattern> patternCache = newBuilder().maximumSize(20).build(new PatternCacheLoader());
 
   Pair<INode, Matcher> matchingCommentNode(EObject target, String... patternsToMatch) {
     ICompositeNode node = getNode(target);
@@ -48,7 +56,9 @@
       for (String line : comment) {
         for (Pattern pattern : compile(patternsToMatch, target)) {
           Matcher matcher = pattern.matcher(line);
-          if (matcher.matches()) { return pair(currentNode, matcher); }
+          if (matcher.matches()) {
+            return pair(currentNode, matcher);
+          }
         }
       }
     }
@@ -58,13 +68,25 @@
   private List<Pattern> compile(String[] patterns, EObject target) {
     List<Pattern> compiled = newArrayList();
     for (final String s : patterns) {
-      Pattern p = cache.get(s, target.eResource(), new Provider<Pattern>() {
-        @Override public Pattern get() {
-          return Pattern.compile(MATCH_ANYTHING + s + MATCH_ANYTHING, CASE_INSENSITIVE);
-        }
-      });
+      Pattern p = null;
+      try {
+        p = patternCache.get(s);
+      } catch (ExecutionException e) {
+        logger.error("Unable to obtain pattern from cache for " + quote(s), e);
+        p = PatternCacheLoader.compile(s);
+      }
       compiled.add(p);
     }
     return compiled;
   }
+
+  private static class PatternCacheLoader extends CacheLoader<String, Pattern> {
+    @Override public Pattern load(String key) throws Exception {
+      return compile(key);
+    }
+
+    static Pattern compile(String s) {
+      return Pattern.compile(MATCH_ANYTHING + s + MATCH_ANYTHING, CASE_INSENSITIVE);
+    }
+  }
 }
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/documentation/MLCommentDocumentationProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/documentation/MLCommentDocumentationProvider.java
index 9994bd5..ef9347e 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/documentation/MLCommentDocumentationProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/documentation/MLCommentDocumentationProvider.java
@@ -12,14 +12,14 @@
 import static java.util.regex.Pattern.compile;
 import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.getNode;
 
-import java.util.regex.Pattern;
+import com.google.eclipse.protobuf.model.util.INodes;
+import com.google.inject.*;
 
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.xtext.documentation.IEObjectDocumentationProvider;
 import org.eclipse.xtext.nodemodel.*;
 
-import com.google.eclipse.protobuf.model.util.INodes;
-import com.google.inject.*;
+import java.util.regex.Pattern;
 
 /**
  * Provides multiple-line comments of a protobuf element as its documentation
@@ -42,7 +42,9 @@
   private String findComment(EObject o) {
     String returnValue = null;
     ICompositeNode node = getNode(o);
-    if (node == null) { return null; }
+    if (node == null) {
+      return null;
+    }
     // get the last multiple-line comment before a non hidden leaf node
     for (INode currentNode : node.getAsTreeIterable()) {
       if (!nodes.isHiddenLeafNode(currentNode)) {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/misc/core/MiscellaneousPreferenceStoreInitializer.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/misc/core/MiscellaneousPreferenceStoreInitializer.java
index 0d394fe..f768584 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/misc/core/MiscellaneousPreferenceStoreInitializer.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/preferences/misc/core/MiscellaneousPreferenceStoreInitializer.java
@@ -18,6 +18,6 @@
 public class MiscellaneousPreferenceStoreInitializer implements IPreferenceStoreInitializer {
   @Override public void initialize(IPreferenceStoreAccess storeAccess) {
     MiscellaneousPreferences preferences = new MiscellaneousPreferences(storeAccess);
-    preferences.isGoogleInternal().setDefaultValue(false);
+    preferences.isGoogleInternal().setDefaultValue(true);
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/IProtobufQualifiedNameProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/IProtobufQualifiedNameProvider.java
index c2f8020..0042599 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/IProtobufQualifiedNameProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/IProtobufQualifiedNameProvider.java
@@ -21,8 +21,8 @@
   /**
    * Returns the qualified name of the given model object.
    * @param e the given model object.
-   * @param namingStrategy gets the name of the model object.
+   * @param strategy gets the name of the model object.
    * @return the qualified name of the given model object.
    */
-  QualifiedName getFullyQualifiedName(EObject e, NamingStrategy namingStrategy);
+  QualifiedName getFullyQualifiedName(EObject e, NamingStrategy strategy);
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/LocalNamesProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/LocalNamesProvider.java
index f9b2881..5d7b9bf 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/LocalNamesProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/LocalNamesProvider.java
@@ -9,16 +9,19 @@
 package com.google.eclipse.protobuf.naming;
 
 import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Collections.*;
+import static com.google.eclipse.protobuf.naming.NameType.NORMAL;
+import static java.util.Collections.emptyList;
 import static org.eclipse.xtext.util.Strings.isEmpty;
+import static org.eclipse.xtext.util.Tuples.pair;
 
-import java.util.List;
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.inject.*;
 
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.util.*;
 
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.inject.Inject;
+import java.util.List;
 
 /**
  * Provides alternative qualified names for protobuf elements.
@@ -54,30 +57,46 @@
  * @author alruiz@google.com (Alex Ruiz)
  */
 public class LocalNamesProvider {
+  private static Pair<NameType, List<QualifiedName>> EMPTY_NAMES = emptyNames();
+
+  private static Pair<NameType, List<QualifiedName>> emptyNames() {
+    List<QualifiedName> names = emptyList();
+    return pair(NORMAL, names);
+  }
+
+  @Inject private final IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE;
+
   @Inject private ModelObjects modelObjects;
   @Inject private NameResolver nameResolver;
   @Inject private IQualifiedNameConverter qualifiedNameConverter;
   @Inject private Packages packages;
 
-  public List<QualifiedName> localNames(EObject e, NamingStrategy namingStrategy) {
-    List<QualifiedName> allNames = newArrayList();
-    EObject current = e;
-    String name = namingStrategy.nameOf(e);
-    if (isEmpty(name)) {
-      return emptyList();
-    }
-    QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(name);
-    allNames.add(qualifiedName);
-    while (current.eContainer() != null) {
-      current = current.eContainer();
-      String containerName = nameResolver.nameOf(current);
-      if (isEmpty(containerName)) {
-        continue;
+  public List<QualifiedName> localNames(final EObject e, final NamingStrategy strategy) {
+    Pair<EObject, String> key = pair(e, "localFqns");
+    Pair<NameType, List<QualifiedName>> cached = cache.get(key, e.eResource(),
+        new Provider<Pair<NameType, List<QualifiedName>>>() {
+      @Override public Pair<NameType, List<QualifiedName>> get() {
+        List<QualifiedName> allNames = newArrayList();
+        EObject current = e;
+        Pair<NameType, String> name = strategy.nameOf(e);
+        if (name == null) {
+          return EMPTY_NAMES;
+        }
+        QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(name.getSecond());
+        allNames.add(qualifiedName);
+        while (current.eContainer() != null) {
+          current = current.eContainer();
+          String containerName = nameResolver.nameOf(current);
+          if (isEmpty(containerName)) {
+            continue;
+          }
+          qualifiedName = qualifiedNameConverter.toQualifiedName(containerName).append(qualifiedName);
+          allNames.add(qualifiedName);
+        }
+        allNames.addAll(packages.addPackageNameSegments(modelObjects.packageOf(e), qualifiedName));
+        return pair(name.getFirst(), allNames);
       }
-      qualifiedName = qualifiedNameConverter.toQualifiedName(containerName).append(qualifiedName);
-      allNames.add(qualifiedName);
-    }
-    allNames.addAll(packages.addPackageNameSegments(modelObjects.packageOf(e), qualifiedName));
-    return unmodifiableList(allNames);
+    });
+    return cached.getSecond();
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameType.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameType.java
new file mode 100644
index 0000000..bf26e49
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameType.java
@@ -0,0 +1,16 @@
+/*
+ * 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.naming;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public enum NameType {
+  NORMAL, OPTION
+}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NamingStrategy.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NamingStrategy.java
index c5dc05b..f928ca3 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NamingStrategy.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NamingStrategy.java
@@ -9,6 +9,7 @@
 package com.google.eclipse.protobuf.naming;
 
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.util.Pair;
 
 /**
  * Knows how to obtain the name of a model object.
@@ -21,5 +22,5 @@
    * @param e the given model object.
    * @return the name of the given model object.
    */
-  String nameOf(EObject e);
+  Pair<NameType, String> nameOf(EObject e);
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NormalNamingStrategy.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NormalNamingStrategy.java
index 90e63a4..e36ed52 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NormalNamingStrategy.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NormalNamingStrategy.java
@@ -8,10 +8,15 @@
  */
 package com.google.eclipse.protobuf.naming;
 
-import org.eclipse.emf.ecore.EObject;
+import static com.google.eclipse.protobuf.naming.NameType.NORMAL;
+import static org.eclipse.xtext.util.Strings.isEmpty;
+import static org.eclipse.xtext.util.Tuples.pair;
 
 import com.google.inject.*;
 
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.util.Pair;
+
 /**
  * Returns the name of a model object obtained from a <code>{@link NameResolver}</code>.
  *
@@ -21,7 +26,11 @@
   @Inject private NameResolver nameResolver;
 
   /** {@inheritDoc} */
-  @Override public String nameOf(EObject e) {
-    return nameResolver.nameOf(e);
+  @Override public Pair<NameType, String> nameOf(EObject e) {
+    String value = nameResolver.nameOf(e);
+    if (isEmpty(value)) {
+      return null;
+    }
+    return pair(NORMAL, value);
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/OptionNamingStrategy.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/OptionNamingStrategy.java
index 2dc421c..196c29e 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/OptionNamingStrategy.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/OptionNamingStrategy.java
@@ -1,19 +1,25 @@
 /*
  * 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
+ * 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.naming;
 
-import org.eclipse.emf.ecore.EObject;
+import static com.google.eclipse.protobuf.naming.NameType.OPTION;
+import static org.eclipse.xtext.util.Strings.isEmpty;
+import static org.eclipse.xtext.util.Tuples.create;
 
 import com.google.eclipse.protobuf.model.util.Options;
 import com.google.eclipse.protobuf.protobuf.IndexedElement;
 import com.google.inject.*;
 
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.util.Pair;
+
 /**
  * Returns the name of a model object, to be used as the name of an option.
  *
@@ -23,7 +29,7 @@
  * @see Options#nameForOption(IndexedElement)
  */
 @Singleton public class OptionNamingStrategy implements NamingStrategy {
-  @Inject private NameResolver nameResolver;
+  @Inject private NormalNamingStrategy delegate;
   @Inject private Options options;
 
   /**
@@ -31,10 +37,14 @@
    * @param e the given model object.
    * @return the name of the given model object, to be used as the name of an option.
    */
-  @Override public String nameOf(EObject e) {
-    if (e instanceof IndexedElement) {
-      return options.nameForOption((IndexedElement) e);
+  @Override public Pair<NameType, String> nameOf(EObject e) {
+    if (!(e instanceof IndexedElement)) {
+      return delegate.nameOf(e);
     }
-    return nameResolver.nameOf(e);
+    String value = options.nameForOption((IndexedElement) e);
+    if (isEmpty(value)) {
+      return null;
+    }
+    return create(OPTION, value);
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
index 73f3668..fa070a7 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/ProtobufQualifiedNameProvider.java
@@ -8,16 +8,18 @@
  */
 package com.google.eclipse.protobuf.naming;
 
-import static org.eclipse.xtext.util.Strings.isEmpty;
-
-import java.util.List;
-
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.xtext.naming.*;
+import static com.google.eclipse.protobuf.naming.NameType.NORMAL;
+import static org.eclipse.xtext.util.Tuples.pair;
 
 import com.google.eclipse.protobuf.model.util.*;
 import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.inject.Inject;
+import com.google.inject.*;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.util.*;
+
+import java.util.List;
 
 /**
  * Provides fully-qualified names for protobuf elements.
@@ -26,7 +28,10 @@
  */
 public class ProtobufQualifiedNameProvider extends IQualifiedNameProvider.AbstractImpl implements
     IProtobufQualifiedNameProvider {
+  private static final Pair<NameType, QualifiedName> EMPTY_NAME = pair(NORMAL, null);
+
   @Inject private final IQualifiedNameConverter converter = new IQualifiedNameConverter.DefaultImpl();
+  @Inject private final IResourceScopeCache cache = IResourceScopeCache.NullImpl.INSTANCE;
 
   @Inject private ModelObjects modelObjects;
   @Inject private NormalNamingStrategy normalNamingStrategy;
@@ -37,21 +42,27 @@
     return getFullyQualifiedName(target, normalNamingStrategy);
   }
 
-  @Override public QualifiedName getFullyQualifiedName(EObject e, NamingStrategy namingStrategy) {
-    EObject current = e;
-    String name = namingStrategy.nameOf(e);
-    if (isEmpty(name)) {
-      return null;
-    }
-    QualifiedName qualifiedName = converter.toQualifiedName(name);
-    while (current.eContainer() != null) {
-      current = current.eContainer();
-      QualifiedName parentsQualifiedName = getFullyQualifiedName(current, namingStrategy);
-      if (parentsQualifiedName != null) {
-        return parentsQualifiedName.append(qualifiedName);
+  @Override public QualifiedName getFullyQualifiedName(final EObject e, final NamingStrategy namingStrategy) {
+    Pair<EObject, String> key = pair(e, "fqn");
+    Pair<NameType, QualifiedName> cached = cache.get(key, e.eResource(), new Provider<Pair<NameType, QualifiedName>>() {
+      @Override public Pair<NameType, QualifiedName> get() {
+        EObject current = e;
+        Pair<NameType, String> name = namingStrategy.nameOf(e);
+        if (name == null) {
+          return EMPTY_NAME;
+        }
+        QualifiedName qualifiedName = converter.toQualifiedName(name.getSecond());
+        while (current.eContainer() != null) {
+          current = current.eContainer();
+          QualifiedName parentsQualifiedName = getFullyQualifiedName(current, namingStrategy);
+          if (parentsQualifiedName != null) {
+            return pair(name.getFirst(), parentsQualifiedName.append(qualifiedName));
+          }
+        }
+        return pair(name.getFirst(), addPackage(e, qualifiedName));
       }
-    }
-    return addPackage(e, qualifiedName);
+    });
+    return cached.getSecond();
   }
 
   private QualifiedName addPackage(EObject obj, QualifiedName qualifiedName) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
index 9dac7b3..8af80df 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
@@ -12,10 +12,6 @@
 import static com.google.eclipse.protobuf.validation.Messages.*;
 import static java.lang.String.format;
 
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.xtext.naming.*;
-import org.eclipse.xtext.validation.*;
-
 import com.google.eclipse.protobuf.grammar.Syntaxes;
 import com.google.eclipse.protobuf.model.util.*;
 import com.google.eclipse.protobuf.naming.NameResolver;
@@ -23,11 +19,15 @@
 import com.google.eclipse.protobuf.protobuf.Package;
 import com.google.inject.Inject;
 
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.naming.*;
+import org.eclipse.xtext.validation.*;
+
 /**
  * @author alruiz@google.com (Alex Ruiz)
  */
-@ComposedChecks(validators = { DataTypeValidator.class, ImportValidator.class }) public class ProtobufJavaValidator
-    extends AbstractProtobufJavaValidator {
+@ComposedChecks(validators = { DataTypeValidator.class, ImportValidator.class })
+public class ProtobufJavaValidator extends AbstractProtobufJavaValidator {
   public static final String SYNTAX_IS_NOT_PROTO2_ERROR = "syntaxIsNotProto2";
   public static final String INVALID_FIELD_TAG_NUMBER_ERROR = "invalidFieldTagNumber";
   public static final String MORE_THAN_ONE_PACKAGE_ERROR = "moreThanOnePackage";
@@ -53,8 +53,7 @@
   }
 
   @Check public void checkTagNumberIsUnique(IndexedElement e) {
-    if (isNameNull(e))
-     {
+    if (isNameNull(e)) {
       return; // we already show an error if name is null, no need to go further.
     }
     long index = indexedElements.indexOf(e);