Added a cache to ModelElementFinder.
- Removes the UI freeze of one second or greater when opening or editing
a proto file.
- Reduces time to lookup scopes of imported proto files.
Change-Id: Id0b665a5f9ed776deecc54c322d6597c4c5e42b9
diff --git a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
index f55ef48..e76431d 100644
--- a/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf/META-INF/MANIFEST.MF
@@ -9,15 +9,16 @@
Require-Bundle: org.antlr.runtime,
org.apache.commons.logging,
org.apache.log4j,
- org.eclipse.emf.mwe2.launch;resolution:=optional,
org.eclipse.core.resources,
org.eclipse.core.runtime,
+ org.eclipse.emf.common,
+ org.eclipse.emf.ecore,
+ org.eclipse.emf.mwe2.launch;resolution:=optional,
+ org.eclipse.jdt.annotation;resolution:=optional,
org.eclipse.xtext,
org.eclipse.xtext.generator;resolution:=optional,
- org.eclipse.emf.common,
org.eclipse.xtext.ui,
- org.eclipse.xtext.util,
- org.eclipse.emf.ecore
+ org.eclipse.xtext.util
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: com.google.eclipse.protobuf,
com.google.eclipse.protobuf.conversion,
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ModelElementFinder.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ModelElementFinder.java
index bf24be1..4520d67 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ModelElementFinder.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ModelElementFinder.java
@@ -11,22 +11,8 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
-
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import static com.google.common.collect.Sets.newHashSet;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.emf.common.util.TreeIterator;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.xtext.resource.IEObjectDescription;
-
import com.google.eclipse.protobuf.model.util.Imports;
import com.google.eclipse.protobuf.model.util.ModelObjects;
import com.google.eclipse.protobuf.model.util.Packages;
@@ -40,6 +26,23 @@
import com.google.eclipse.protobuf.resource.ResourceSets;
import com.google.inject.Inject;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.xtext.resource.IEObjectDescription;
+import org.eclipse.xtext.util.OnChangeEvictingCache;
+import org.eclipse.xtext.util.OnChangeEvictingCache.CacheAdapter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
/**
* @author alruiz@google.com (Alex Ruiz)
*/
@@ -51,16 +54,16 @@
@Inject private Resources resources;
@Inject private ResourceSets resourceSets;
- // Start at an element
<T> Collection<IEObjectDescription> find(EObject start, FinderStrategy<T> strategy, T criteria) {
- Set<IEObjectDescription> descriptions = newHashSet();
+ Set<IEObjectDescription> descriptions = new HashSet<>();
descriptions.addAll(getDescriptionsFromObjectAncestors(start, strategy, criteria));
Protobuf root = modelObjects.rootOf(start);
descriptions.addAll(getDescriptionsFromAllImports(root, strategy, criteria));
return unmodifiableSet(descriptions);
}
- private <T> Collection<IEObjectDescription> getDescriptionsFromObjectAncestors(EObject start, FinderStrategy<T> strategy, T criteria) {
+ private <T> Collection<IEObjectDescription> getDescriptionsFromObjectAncestors(
+ EObject start, FinderStrategy<T> strategy, T criteria) {
UniqueDescriptions descriptions = new UniqueDescriptions();
EObject current = start.eContainer();
while (current != null) {
@@ -71,35 +74,43 @@
}
<T> Collection<IEObjectDescription> find(Protobuf start, FinderStrategy<T> strategy, T criteria) {
- Set<IEObjectDescription> descriptions = newHashSet();
+ Set<IEObjectDescription> descriptions = new HashSet<>();
descriptions.addAll(getDescriptionsFromObjectDescendants(start, strategy, criteria, 0));
descriptions.addAll(getDescriptionsFromAllImports(start, strategy, criteria));
return unmodifiableSet(descriptions);
}
- private <T> Collection<IEObjectDescription> getDescriptionsFromObjectDescendants(EObject start, FinderStrategy<T> strategy, T criteria, int level) {
+ private <T> Collection<IEObjectDescription> getDescriptionsFromObjectDescendants(
+ EObject start, FinderStrategy<T> strategy, T criteria, int level) {
UniqueDescriptions descriptions = new UniqueDescriptions();
for (EObject element : start.eContents()) {
descriptions.addAll(strategy.local(element, criteria, level));
if (element instanceof Message || element instanceof Group) {
- descriptions.addAll(getDescriptionsFromObjectDescendants(element, strategy, criteria, level + 1));
+ descriptions.addAll(
+ getDescriptionsFromObjectDescendants(element, strategy, criteria, level + 1));
}
}
return descriptions.values();
}
- private <T> Collection<IEObjectDescription> getDescriptionsFromAllImports(Protobuf start, FinderStrategy<T> strategy, T criteria) {
+ private <T> Collection<IEObjectDescription> getDescriptionsFromAllImports(
+ Protobuf start, FinderStrategy<T> strategy, T criteria) {
List<Import> allImports = protobufs.importsIn(start);
if (allImports.isEmpty()) {
return emptyList();
}
ResourceSet resourceSet = start.eResource().getResourceSet();
- return getDescriptionsFromImports(allImports, modelObjects.packageOf(start), resourceSet, strategy, criteria);
+ return getDescriptionsFromImports(
+ allImports, modelObjects.packageOf(start), resourceSet, strategy, criteria);
}
- private <T> Collection<IEObjectDescription> getDescriptionsFromImports(List<Import> allImports, Package fromImporter,
- ResourceSet resourceSet, FinderStrategy<T> strategy, T criteria) {
- Set<IEObjectDescription> descriptions = newHashSet();
+ private <T> Collection<IEObjectDescription> getDescriptionsFromImports(
+ List<Import> allImports,
+ Package fromImporter,
+ ResourceSet resourceSet,
+ FinderStrategy<T> strategy,
+ T criteria) {
+ Set<IEObjectDescription> descriptions = new HashSet<>();
for (Import anImport : allImports) {
if (imports.isImportingDescriptor(anImport)) {
descriptions.addAll(strategy.inDescriptor(anImport, criteria));
@@ -118,23 +129,35 @@
continue;
}
if (rootOfImported != null) {
- descriptions.addAll(getDescriptionsFromPublicImports(rootOfImported, strategy, criteria));
- if (arePackagesRelated(fromImporter, rootOfImported)) {
- descriptions.addAll(getDescriptionsFromObjectDescendants(rootOfImported, strategy, criteria, 0));
- continue;
+ CacheAdapter cache = new OnChangeEvictingCache().getOrCreate(imported);
+ Set<IEObjectDescription> descriptionsFromImport =
+ getFromCache(cache, resolvedUri, strategy, criteria);
+ if (descriptionsFromImport == null) {
+ descriptionsFromImport = new HashSet<>();
+ descriptionsFromImport.addAll(
+ getDescriptionsFromPublicImports(rootOfImported, strategy, criteria));
+ if (arePackagesRelated(fromImporter, rootOfImported)) {
+ descriptionsFromImport.addAll(
+ getDescriptionsFromObjectDescendants(rootOfImported, strategy, criteria, 0));
+ } else {
+ Package packageOfImported = modelObjects.packageOf(rootOfImported);
+ TreeIterator<Object> contents = getAllContents(imported, true);
+ while (contents.hasNext()) {
+ Object next = contents.next();
+ descriptionsFromImport.addAll(
+ strategy.imported(fromImporter, packageOfImported, next, criteria));
+ }
+ }
+ putToCache(cache, resolvedUri, strategy, criteria, descriptionsFromImport);
}
- Package packageOfImported = modelObjects.packageOf(rootOfImported);
- TreeIterator<Object> contents = getAllContents(imported, true);
- while (contents.hasNext()) {
- Object next = contents.next();
- descriptions.addAll(strategy.imported(fromImporter, packageOfImported, next, criteria));
- }
+ descriptions.addAll(descriptionsFromImport);
}
}
return descriptions;
}
- private <T> Collection<IEObjectDescription> getDescriptionsFromPublicImports(Protobuf start, FinderStrategy<T> strategy, T criteria) {
+ private <T> Collection<IEObjectDescription> getDescriptionsFromPublicImports(
+ Protobuf start, FinderStrategy<T> strategy, T criteria) {
if (!protobufs.hasKnownSyntax(start)) {
return emptySet();
}
@@ -143,7 +166,36 @@
return emptyList();
}
ResourceSet resourceSet = start.eResource().getResourceSet();
- return getDescriptionsFromImports(allImports, modelObjects.packageOf(start), resourceSet, strategy, criteria);
+ return getDescriptionsFromImports(
+ allImports, modelObjects.packageOf(start), resourceSet, strategy, criteria);
+ }
+
+ private <T> @Nullable Set<IEObjectDescription> getFromCache(
+ CacheAdapter cache, URI uri, FinderStrategy<T> strategy, T criteria) {
+ Map<FinderStrategy<T>, Map<T, Set<IEObjectDescription>>> strategyMap = cache.get(uri);
+ if (strategyMap != null) {
+ Map<T, Set<IEObjectDescription>> criteriaMap = strategyMap.get(strategy);
+ if (criteriaMap != null) {
+ return criteriaMap.get(criteria);
+ }
+ }
+ return null;
+ }
+
+ private <T> void putToCache(
+ CacheAdapter cache, URI uri, FinderStrategy<T> strategy, T criteria,
+ Set<IEObjectDescription> descriptions) {
+ Map<FinderStrategy<T>, Map<T, Set<IEObjectDescription>>> strategyMap = cache.get(uri);
+ if (strategyMap == null) {
+ strategyMap = new HashMap<>();
+ cache.set(uri, strategyMap);
+ }
+ Map<T, Set<IEObjectDescription>> criteriaMap = strategyMap.get(strategy);
+ if (criteriaMap == null) {
+ criteriaMap = new HashMap<>();
+ strategyMap.put(strategy, criteriaMap);
+ }
+ criteriaMap.put(criteria, descriptions);
}
private boolean arePackagesRelated(Package aPackage, EObject root) {
@@ -152,7 +204,8 @@
}
static interface FinderStrategy<T> {
- Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Object target, T criteria);
+ Collection<IEObjectDescription> imported(
+ Package fromImporter, Package fromImported, Object target, T criteria);
Collection<IEObjectDescription> inDescriptor(Import anImport, T criteria);