/*
* 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.naming;
import static java.util.Collections.emptyList;
import static org.eclipse.xtext.util.Strings.isEmpty;
import static org.eclipse.xtext.util.Tuples.pair;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.eclipse.protobuf.naming.NameType.NORMAL;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.util.IResourceScopeCache;
import org.eclipse.xtext.util.Pair;
import com.google.eclipse.protobuf.model.util.ModelObjects;
import com.google.eclipse.protobuf.model.util.Packages;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Provides alternative qualified names for protobuf elements.
* <p>
* For example, given the following proto element:
*
* <pre>
* package test.alternative.names;
*
* message Person {
* optional string name = 1;
*
* enum PhoneType {
* HOME = 0;
* WORK = 1;
* }
* }
* </pre>
*
* The default qualified name for {@code PhoneType} is {@code alternative.names.Person.PhoneType}. The problem is that
* protoc also recognizes the following as qualified names:
* <ul>
* <li>{@code PhoneType}</li>
* <li>{@code Person.PhoneType}</li>
* <li>{@code names.Person.PhoneType}</li>
* <li>{@code test.names.Person.PhoneType}</li>
* </ul>
* </p>
*
* @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(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);
}
});
return cached.getSecond();
}
}