blob: a49d2873f243c4d2cf6edfe343cca349f0338b67 [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 com.google.eclipse.protobuf.scoping.OptionType.typeOf;
import static java.util.Collections.emptySet;
import java.util.*;
import org.eclipse.emf.ecore.*;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.*;
import com.google.eclipse.protobuf.model.util.*;
import com.google.eclipse.protobuf.protobuf.*;
import com.google.eclipse.protobuf.protobuf.Enum;
import com.google.inject.Inject;
/**
* Custom scoping description.
*
* @author alruiz@google.com (Alex Ruiz)
*
* @see <a href="http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping">Xtext Scoping</a>
*/
public class ProtobufScopeProvider extends AbstractDeclarativeScopeProvider implements Scoping {
private static final boolean DO_NOT_IGNORE_CASE = false;
@Inject private AstWalker astWalker;
@Inject private CustomOptionFieldScopeFinder customOptionFieldScopeFinder;
@Inject private CustomOptionScopeFinder customOptionScopeFinder;
@Inject private ProtoDescriptorProvider descriptorProvider;
@Inject private FieldNotationScopeFinder fieldNotationScopeFinder;
@Inject private ModelFinder modelFinder;
@Inject private LiteralDescriptions literalDescriptions;
@Inject private NativeOptionDescriptions nativeOptionDescriptions;
@Inject private Options options;
@Inject private TypeScopeFinder typeScopeFinder;
@SuppressWarnings("unused") public IScope scope_ComplexTypeLink_target(ComplexTypeLink link, EReference r) {
EObject c = link.eContainer();
if (c instanceof MessageField) { return createScope(allPossibleTypesFor((MessageField) c)); }
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
}
@Override public Collection<IEObjectDescription> allPossibleTypesFor(MessageField field) {
return astWalker.traverseAst(field, typeScopeFinder, ComplexType.class);
}
@SuppressWarnings("unused") public IScope scope_ExtensibleTypeLink_target(ExtensibleTypeLink link, EReference r) {
return createScope(extensibleTypesFor(link));
}
@Override public Collection<IEObjectDescription> allPossibleTypesFor(TypeExtension extension) {
return extensibleTypesFor(extension);
}
private Collection<IEObjectDescription> extensibleTypesFor(EObject o) {
Protobuf root = modelFinder.rootOf(o);
return astWalker.traverseAst(root, typeScopeFinder, ExtensibleType.class);
}
@SuppressWarnings("unused") public IScope scope_MessageLink_target(MessageLink link, EReference r) {
return createScope(messagesFor(link));
}
@Override public Collection<IEObjectDescription> allPossibleMessagesFor(Rpc rpc) {
return messagesFor(rpc);
}
private Collection<IEObjectDescription> messagesFor(EObject o) {
Protobuf root = modelFinder.rootOf(o);
return astWalker.traverseAst(root, typeScopeFinder, Message.class);
}
@SuppressWarnings("unused") public IScope scope_LiteralLink_target(LiteralLink link, EReference r) {
EObject container = link.eContainer();
Enum anEnum = null;
if (container instanceof DefaultValueFieldOption) {
container = container.eContainer();
}
if (container instanceof NativeOption) {
ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
IndexedElement e = options.rootSourceOf((Option) container);
anEnum = descriptor.enumTypeOf((MessageField) e);
}
if (container instanceof CustomOption) {
CustomOption option = (CustomOption) container;
container = options.sourceOf(option);
}
if (container instanceof NativeFieldOption) {
ProtoDescriptor descriptor = descriptorProvider.primaryDescriptor();
IndexedElement c = options.rootSourceOf((FieldOption) container);
anEnum = descriptor.enumTypeOf((MessageField) c);
}
if (container instanceof CustomFieldOption) {
CustomFieldOption option = (CustomFieldOption) container;
container = options.sourceOf(option);
}
if (container instanceof SimpleValueField) {
SimpleValueField field = (SimpleValueField) container;
container = field.getName().getTarget();
}
if (container instanceof MessageField) {
anEnum = modelFinder.enumTypeOf((MessageField) container);
}
return createScope(literalDescriptions.literalsOf(anEnum));
}
@SuppressWarnings("unused") public IScope scope_OptionSource_target(OptionSource source, EReference r) {
EObject c = source.eContainer();
if (c instanceof NativeOption) {
NativeOption option = (NativeOption) c;
return createScope(nativeOptionDescriptions.sources(option));
}
if (c instanceof NativeFieldOption) {
NativeFieldOption option = (NativeFieldOption) c;
return createScope(nativeOptionDescriptions.sources(option));
}
if (c instanceof CustomOption) {
CustomOption option = (CustomOption) c;
return createScope(allPossibleSourcesOf(option));
}
if (c instanceof CustomFieldOption) {
CustomFieldOption option = (CustomFieldOption) c;
return createScope(allPossibleSourcesOf(option));
}
Set<IEObjectDescription> descriptions = emptySet();
return createScope(descriptions);
}
@Override public Collection<IEObjectDescription> allPossibleSourcesOf(CustomOption option) {
OptionType optionType = typeOf(option);
Collection<IEObjectDescription> descriptions = emptySet();
if (optionType != null) {
descriptions = astWalker.traverseAst(option, customOptionScopeFinder, optionType);
}
return descriptions;
}
@Override public Collection<IEObjectDescription> allPossibleSourcesOf(CustomFieldOption option) {
OptionType optionType = typeOf(option);
Collection<IEObjectDescription> descriptions = emptySet();
if (optionType != null) {
descriptions = astWalker.traverseAst(option, customOptionScopeFinder, optionType);
}
return descriptions;
}
@SuppressWarnings("unused") public IScope scope_OptionField_target(OptionField field, EReference r) {
return createScope(allPossibleSourcesOf(field));
}
private Collection<IEObjectDescription> allPossibleSourcesOf(OptionField field) {
if (field == null) {
return emptySet();
}
EObject container = field.eContainer();
if (container instanceof CustomOption) {
CustomOption option = (CustomOption) container;
if (field instanceof MessageOptionField) { return findSources(option, (MessageOptionField) field); }
return findSources(option, (ExtensionOptionField) field);
}
if (container instanceof CustomFieldOption) {
CustomFieldOption option = (CustomFieldOption) container;
if (field instanceof MessageOptionField) { return findSources(option, (MessageOptionField) field); }
return findSources(option, (ExtensionOptionField) field);
}
return emptySet();
}
@Override public Collection<IEObjectDescription> allPossibleNormalFieldsOf(CustomOption option) {
return findSources(option, (MessageOptionField) null);
}
@Override public Collection<IEObjectDescription> allPossibleNormalFieldsOf(CustomFieldOption option) {
return findSources(option, (MessageOptionField) null);
}
@Override public Collection<IEObjectDescription> allPossibleExtensionFieldsOf(CustomOption option) {
return findSources(option, (ExtensionOptionField) null);
}
@Override public Collection<IEObjectDescription> allPossibleExtensionFieldsOf(CustomFieldOption option) {
return findSources(option, (ExtensionOptionField) null);
}
private Collection<IEObjectDescription> findSources(CustomOption option, MessageOptionField field) {
return customOptionFieldScopeFinder.findScope(option, field);
}
private Collection<IEObjectDescription> findSources(CustomOption option, ExtensionOptionField field) {
return customOptionFieldScopeFinder.findScope(option, field);
}
private Collection<IEObjectDescription> findSources(CustomFieldOption option, MessageOptionField field) {
return customOptionFieldScopeFinder.findScope(option, field);
}
private Collection<IEObjectDescription> findSources(CustomFieldOption option, ExtensionOptionField field) {
return customOptionFieldScopeFinder.findScope(option, field);
}
@SuppressWarnings("unused") public IScope scope_FieldName_target(FieldName name, EReference r) {
return createScope(findSources(name));
}
private Collection<IEObjectDescription> findSources(FieldName name) {
ComplexValue value = container(name);
if (value == null) {
return emptySet();
}
if (name instanceof NormalFieldName) { return allPossibleNamesOfNormalFieldsOf(value); }
return allPossibleNamesOfExtensionFieldsOf(value);
}
private ComplexValue container(FieldName name) {
EObject container = name;
while (container != null) {
if (container instanceof ComplexValue) { return (ComplexValue) container; }
container = container.eContainer();
}
return null;
}
@Override public Collection<IEObjectDescription> allPossibleNamesOfNormalFieldsOf(ComplexValue value) {
return fieldNotationScopeFinder.sourceOfNormalFieldNamesOf(value);
}
@Override public Collection<IEObjectDescription> allPossibleNamesOfExtensionFieldsOf(ComplexValue value) {
return fieldNotationScopeFinder.sourceOfExtensionFieldNamesOf(value);
}
private static IScope createScope(Iterable<IEObjectDescription> descriptions) {
return new SimpleScope(descriptions, DO_NOT_IGNORE_CASE);
}
}