blob: d92fbfbdf4b6a67a1bd8e9bf756773c3c0d09752 [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.emptyList;
import static org.eclipse.emf.common.util.URI.createURI;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
import static org.eclipse.xtext.resource.EObjectDescription.create;
import java.util.*;
import org.eclipse.emf.common.util.*;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.*;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.impl.ImportUriResolver;
import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Package;
import com.google.eclipse.protobuf.util.*;
import com.google.inject.Inject;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
class OptionDescriptions {
@Inject private ProtoDescriptorProvider descriptorProvider;
@Inject private ProtobufElementFinder finder;
@Inject private ImportedNamesProvider importedNamesProvider;
@Inject private Imports imports;
@Inject private LocalNamesProvider localNamesProvider;
@Inject private PackageResolver packageResolver;
@Inject private QualifiedNameDescriptions qualifiedNamesDescriptions;
@Inject private ImportUriResolver uriResolver;
Collection <IEObjectDescription> builtInOptionProperties(BuiltInOption option) {
ProtoDescriptor descriptor = descriptorProvider.get();
Collection<Property> properties = descriptor.availableOptionPropertiesFor(option.eContainer());
if (!properties.isEmpty()) return describe(properties);
return emptyList();
}
Collection <IEObjectDescription> localCustomOptionProperties(EObject root, OptionType optionType) {
return localCustomOptionProperties(root, optionType, 0);
}
private Collection <IEObjectDescription> localCustomOptionProperties(EObject root, OptionType optionType, int level) {
if (optionType == null) return emptyList();
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
for (EObject element : root.eContents()) {
if (isExtendingOptionMessage(element, optionType)) {
ExtendMessage extend = (ExtendMessage) element;
for (MessageElement e : extend.getElements()) {
if (!(e instanceof Property)) continue;
List<QualifiedName> names = localNamesProvider.namesOf(e);
int nameCount = names.size();
for (int i = level; i < nameCount; i++) {
descriptions.add(create(names.get(i), e));
}
descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(e));
}
continue;
}
if (element instanceof Message) {
descriptions.addAll(localCustomOptionProperties(element, optionType, level + 1));
}
}
return descriptions;
}
Collection<IEObjectDescription> importedCustomOptionProperties(Protobuf root, OptionType optionType) {
List<Import> allImports = finder.importsIn(root);
if (allImports.isEmpty()) return emptyList();
ResourceSet resourceSet = root.eResource().getResourceSet();
return importedCustomOptionProperties(allImports, finder.packageOf(root), resourceSet, optionType);
}
private Collection<IEObjectDescription> importedCustomOptionProperties(List<Import> allImports, Package aPackage,
ResourceSet resourceSet, OptionType optionType) {
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
for (Import anImport : allImports) {
if (imports.isImportingDescriptor(anImport)) continue;
Resource importedResource = importedResource(anImport, resourceSet);
Protobuf importedRoot = finder.rootOf(importedResource);
if (importedRoot != null) {
descriptions.addAll(publicImportedCustomOptionProperties(importedRoot, optionType));
if (arePackagesRelated(aPackage, importedRoot)) {
descriptions.addAll(localCustomOptionProperties(importedRoot, optionType));
continue;
}
}
descriptions.addAll(localCustomOptionProperties(importedResource, optionType));
}
return descriptions;
}
private Resource importedResource(Import anImport, ResourceSet resourceSet) {
URI importUri = createURI(uriResolver.apply(anImport));
try {
return resourceSet.getResource(importUri, true);
} catch (Throwable t) {
return null;
}
}
private <T extends Type> Collection<IEObjectDescription> publicImportedCustomOptionProperties(Protobuf root,
OptionType optionType) {
List<Import> allImports = finder.publicImportsIn(root);
if (allImports.isEmpty()) return emptyList();
ResourceSet resourceSet = root.eResource().getResourceSet();
return importedCustomOptionProperties(allImports, finder.packageOf(root), resourceSet, optionType);
}
private boolean arePackagesRelated(Package aPackage, EObject root) {
Package p = finder.packageOf(root);
return packageResolver.areRelated(aPackage, p);
}
private Collection<IEObjectDescription> describe(Collection<Property> properties) {
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
for (Property p : properties) {
descriptions.add(create(p.getName(), p));
}
return descriptions;
}
private Collection<IEObjectDescription> localCustomOptionProperties(Resource resource, OptionType optionType) {
List<IEObjectDescription> descriptions = new ArrayList<IEObjectDescription>();
TreeIterator<Object> contents = getAllContents(resource, true);
while (contents.hasNext()) {
Object next = contents.next();
if (!isExtendingOptionMessage(next, optionType)) continue;
ExtendMessage extend = (ExtendMessage) next;
for (MessageElement e : extend.getElements()) {
if (!(e instanceof Property)) continue;
descriptions.addAll(qualifiedNamesDescriptions.qualifiedNames(e));
for (QualifiedName name : importedNamesProvider.namesOf(e)) {
descriptions.add(create(name, e));
}
}
}
return descriptions;
}
private boolean isExtendingOptionMessage(Object o, OptionType optionType) {
if (!(o instanceof ExtendMessage)) return false;
Message message = messageFrom((ExtendMessage) o);
if (message == null) return false;
return optionType.messageName.equals(message.getName());
}
private Message messageFrom(ExtendMessage extend) {
MessageRef ref = extend.getMessage();
return ref == null ? null : ref.getType();
}
}