blob: 698c6566cd59fa940c0649bfd059067ce78f687a [file] [log] [blame]
/*
* Copyright (c) 2011 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.scoping;
import static java.util.Collections.*;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
import java.util.*;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.*;
import org.eclipse.xtext.resource.IEObjectDescription;
import com.google.eclipse.protobuf.model.util.*;
import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Package;
import com.google.inject.Inject;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
class AstWalker {
@Inject private ModelFinder modelFinder;
@Inject private Imports imports;
@Inject private Packages packages;
@Inject private Protobufs protobufs;
@Inject private Resources resources;
Collection<IEObjectDescription> traverseAst(EObject start, ScopeFinder scopeFinder, Object criteria) {
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
EObject current = start.eContainer();
while (current != null) {
descriptions.addAll(local(current, scopeFinder, criteria));
current = current.eContainer();
}
Protobuf root = modelFinder.rootOf(start);
descriptions.addAll(imported(root, scopeFinder, criteria));
return unmodifiableSet(descriptions);
}
Collection<IEObjectDescription> traverseAst(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
descriptions.addAll(local(start, scopeFinder, criteria));
descriptions.addAll(imported(start, scopeFinder, criteria));
return unmodifiableSet(descriptions);
}
private Collection<IEObjectDescription> local(EObject start, ScopeFinder scopeFinder, Object criteria) {
return local(start, scopeFinder, criteria, 0);
}
private Collection<IEObjectDescription> local(EObject start, ScopeFinder scopeFinder, Object criteria, int level) {
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
for (EObject element : start.eContents()) {
descriptions.addAll(scopeFinder.local(element, criteria, level));
if (element instanceof Message || element instanceof Group) {
descriptions.addAll(local(element, scopeFinder, criteria, level + 1));
}
}
return descriptions;
}
private Collection<IEObjectDescription> imported(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
List<Import> allImports = modelFinder.importsIn(start);
if (allImports.isEmpty()) return emptyList();
ResourceSet resourceSet = start.eResource().getResourceSet();
return imported(allImports, modelFinder.packageOf(start), resourceSet, scopeFinder, criteria);
}
private Collection<IEObjectDescription> imported(List<Import> allImports, Package fromImporter,
ResourceSet resourceSet, ScopeFinder scopeFinder, Object criteria) {
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
for (Import anImport : allImports) {
if (imports.isImportingDescriptor(anImport)) {
descriptions.addAll(scopeFinder.inDescriptor(anImport, criteria));
continue;
}
Resource imported = resources.importedResource(anImport, resourceSet);
if (imported == null) continue;
Protobuf rootOfImported = modelFinder.rootOf(imported);
if (!protobufs.isProto2(rootOfImported)) continue;
if (rootOfImported != null) {
descriptions.addAll(publicImported(rootOfImported, scopeFinder, criteria));
if (arePackagesRelated(fromImporter, rootOfImported)) {
descriptions.addAll(local(rootOfImported, scopeFinder, criteria));
continue;
}
Package packageOfImported = modelFinder.packageOf(rootOfImported);
descriptions.addAll(imported(fromImporter, packageOfImported, imported, scopeFinder, criteria));
}
}
return descriptions;
}
private Collection<IEObjectDescription> publicImported(Protobuf start, ScopeFinder scopeFinder, Object criteria) {
if (!protobufs.isProto2(start)) return emptySet();
List<Import> allImports = modelFinder.publicImportsIn(start);
if (allImports.isEmpty()) return emptyList();
ResourceSet resourceSet = start.eResource().getResourceSet();
return imported(allImports, modelFinder.packageOf(start), resourceSet, scopeFinder, criteria);
}
private boolean arePackagesRelated(Package aPackage, EObject root) {
Package p = modelFinder.packageOf(root);
return packages.areRelated(aPackage, p);
}
private Collection<IEObjectDescription> imported(Package fromImporter, Package fromImported, Resource resource,
ScopeFinder scopeFinder, Object criteria) {
Set<IEObjectDescription> descriptions = new HashSet<IEObjectDescription>();
TreeIterator<Object> contents = getAllContents(resource, true);
while (contents.hasNext()) {
Object next = contents.next();
descriptions.addAll(scopeFinder.imported(fromImporter, fromImported, next, criteria));
}
return descriptions;
}
}