In progress: [Issue 199] Add ability to navigate to proto element from
generated C++ code.
* Added support for enums.
* Made retrieval of alternative qualified names lazy.
* Code cleanup.
* Added tests.
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java
deleted file mode 100644
index f21019f..0000000
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory_createQualifiedNamesForComplexType_Test.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2012 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.cdt.actions;
-
-import static com.google.eclipse.protobuf.cdt.junit.QualifiedNamesContain.containOnly;
-import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
-import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
-import static org.junit.Assert.assertThat;
-
-import java.util.List;
-
-import org.eclipse.xtext.naming.QualifiedName;
-import org.junit.*;
-
-import com.google.eclipse.protobuf.cdt.ProtobufCdtModule;
-import com.google.eclipse.protobuf.junit.core.XtextRule;
-import com.google.inject.Inject;
-
-/**
- * Tests for <code>{@link QualifiedNameFactory#createQualifiedNamesForComplexType(String[])}</code>
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class QualifiedNameFactory_createQualifiedNamesForComplexType_Test {
- @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new ProtobufCdtModule());
-
- @Inject private QualifiedNameFactory qualifiedNameFactory;
-
- @Test public void should_return_single_qualified_name_for_top_level_type() {
- String[] segments = { "com", "google", "proto", "Test" };
- List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
- assertThat(qualifiedNames, containOnly("com.google.proto.Test"));
- }
-
- @Test public void should_split_in_underscore_for_one_level_nesting() {
- String[] segments = { "com", "google", "proto", "Test_Inner" };
- List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
- assertThat(qualifiedNames, containOnly("com.google.proto.Test_Inner", "com.google.proto.Test.Inner"));
- }
-
- @Test public void should_split_in_underscore_for_multiple_level_nesting() {
- String[] segments = { "com", "google", "proto", "Test_Inner_Inner" };
- List<QualifiedName> qualifiedNames = qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
- assertThat(qualifiedNames, containOnly("com.google.proto.Test_Inner_Inner", "com.google.proto.Test.Inner.Inner"));
- }}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy_qualifiedNamesFrom_Test.java
similarity index 69%
rename from com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java
rename to com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy_qualifiedNamesFrom_Test.java
index 1fcc16d..469f454 100644
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test.java
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy_qualifiedNamesFrom_Test.java
@@ -6,17 +6,15 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.cdt.actions;
+package com.google.eclipse.protobuf.cdt.fqn;
+import static com.google.eclipse.protobuf.cdt.fqn.IsQualifiedNameSource.isQualifiedNameSourceWith;
import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
-import static java.util.Collections.singletonList;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-import java.util.List;
-
+import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.internal.core.dom.parser.c.CASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
@@ -28,25 +26,23 @@
import com.google.inject.Inject;
/**
- * Tests for <code>{@link ClassTypeQualifiedNameBuilder#createQualifiedNamesFrom(CPPClassType)}</code>
+ * Tests for <code>{@link ClassTypeQualifiedNameProviderStrategy#qualifiedNamesFrom(IBinding)}</code>
*
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
-public class ClassTypeQualifiedNameBuilder_createQualifiedNamesFrom_Test {
+public class ClassTypeQualifiedNameProviderStrategy_qualifiedNamesFrom_Test {
@Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new ProtobufCdtModule(), new TestModule());
@Inject private CPPClassType classType;
- @Inject private QualifiedNameFactory qualifiedNameFactory;
- @Inject private ClassTypeQualifiedNameBuilder nameBuilder;
+ @Inject private ClassTypeQualifiedNameProviderStrategy nameBuilder;
- @Test public void should_return_qualified_names_for_class_type() {
+ @Test public void should_return_qualified_names_for_class_type_if_it_extends_proto_file() {
expectClassTypeToExtendProtoMessage();
String[] segments = { "com", "google", "proto", "Test" };
when(classType.getQualifiedName()).thenReturn(segments);
- List<QualifiedName> expected = singletonList(QualifiedName.create(segments));
- when(qualifiedNameFactory.createQualifiedNamesForComplexType(segments)).thenReturn(expected);
- assertThat(nameBuilder.createQualifiedNamesFrom(classType), equalTo(expected));
+ Iterable<QualifiedName> qualifiedNames = nameBuilder.qualifiedNamesFrom(classType);
+ assertThat(qualifiedNames, isQualifiedNameSourceWith(segments));
}
private void expectClassTypeToExtendProtoMessage() {
@@ -64,10 +60,15 @@
return qualifiedName;
}
+ @Test public void should_return_null_if_class_type_does_not_extend_proto_message() {
+ when(classType.getBases()).thenReturn(new ICPPBase[0]);
+ Iterable<QualifiedName> qualifiedNames = nameBuilder.qualifiedNamesFrom(classType);
+ assertNull(qualifiedNames);
+ }
+
private static class TestModule extends AbstractTestModule {
@Override protected void configure() {
mockAndBind(CPPClassType.class);
- mockAndBind(QualifiedNameFactory.class);
}
}
}
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/IsQualifiedNameSource.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/IsQualifiedNameSource.java
new file mode 100644
index 0000000..a5417d1
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/fqn/IsQualifiedNameSource.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 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.cdt.fqn;
+
+import org.eclipse.xtext.naming.QualifiedName;
+import org.hamcrest.*;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class IsQualifiedNameSource extends BaseMatcher<Iterable<QualifiedName>> {
+
+ private final QualifiedName original;
+
+ public static IsQualifiedNameSource isQualifiedNameSourceWith(String[] segments) {
+ return new IsQualifiedNameSource(segments);
+ }
+
+ private IsQualifiedNameSource(String[] segments) {
+ original = QualifiedName.create(segments);
+ }
+
+ @Override public boolean matches(Object item) {
+ if (!(item instanceof QualifiedNameSource)) {
+ return false;
+ }
+ QualifiedNameSource source = (QualifiedNameSource) item;
+ return original.equals(source.original());
+ }
+
+ @Override public void describeTo(Description description) {
+ description.appendValue(QualifiedNameSource.class.getSimpleName() + " with original qualified name: " + original);
+ }
+}
diff --git a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java b/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java
deleted file mode 100644
index e2f213a..0000000
--- a/com.google.eclipse.protobuf.cdt.test/src/com/google/eclipse/protobuf/cdt/junit/QualifiedNamesContain.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2012 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.cdt.junit;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-import java.util.List;
-
-import org.eclipse.xtext.naming.QualifiedName;
-import org.hamcrest.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class QualifiedNamesContain extends BaseMatcher<List<QualifiedName>> {
- private final List<String> qualifiedNames;
-
- public static QualifiedNamesContain containOnly(String...qualifiedNames) {
- return new QualifiedNamesContain(qualifiedNames);
- }
-
- private QualifiedNamesContain(String[] qualifiedNames) {
- this.qualifiedNames = newArrayList(qualifiedNames);
- }
-
- @SuppressWarnings("unchecked")
- @Override public boolean matches(Object item) {
- if (!(item instanceof List)) {
- return false;
- }
- List<String> copy = newArrayList(qualifiedNames);
- List<QualifiedName> actualNames = (List<QualifiedName>) item;
- for (QualifiedName actual : actualNames) {
- String expected = actual.toString();
- copy.remove(expected);
- }
- return copy.isEmpty();
- }
-
- @Override public void describeTo(Description description) {
- description.appendValue(qualifiedNames);
- }
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/ProtobufCdtModule.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/ProtobufCdtModule.java
index 2774df5..5a4ee54 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/ProtobufCdtModule.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/ProtobufCdtModule.java
@@ -21,8 +21,8 @@
*/
public class ProtobufCdtModule extends AbstractGenericModule {
public void configureModelObjectDefinitionNavigator(Binder binder) {
- bindToProtobufPluginObject(ModelObjectDefinitionNavigator.class, binder);
bindToProtobufPluginObject(IPreferenceStoreAccess.class, binder);
+ bindToProtobufPluginObject(ModelObjectDefinitionNavigator.class, binder);
}
private <T> void bindToProtobufPluginObject(Class<T> type, Binder binder) {
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectLookupQueryBuilder.java
similarity index 64%
rename from com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java
rename to com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectLookupQueryBuilder.java
index c5f9320..61e11a3 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectDefinitionQueryBuilder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ModelObjectLookupQueryBuilder.java
@@ -8,25 +8,26 @@
*/
package com.google.eclipse.protobuf.cdt.actions;
-import static com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query.query;
-import static java.lang.Math.max;
import static org.eclipse.cdt.internal.ui.editor.ASTProvider.WAIT_NO;
import static org.eclipse.core.runtime.Status.*;
-import java.util.Collection;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.cdt.core.dom.ast.*;
import org.eclipse.cdt.core.model.*;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType;
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
import org.eclipse.cdt.internal.ui.editor.ASTProvider;
import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.*;
import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.xtext.naming.QualifiedName;
+import com.google.eclipse.protobuf.cdt.fqn.QualifiedNameProvider;
+import com.google.eclipse.protobuf.cdt.path.ProtoFilePathFinder;
import com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query;
import com.google.inject.Inject;
@@ -34,12 +35,17 @@
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
-class ModelObjectDefinitionQueryBuilder {
- @Inject private ClassTypeQualifiedNameBuilder nameBuilder;
+class ModelObjectLookupQueryBuilder {
+ @Inject private QualifiedNameProvider qualifiedNameProvider;
@Inject private ProtoFilePathFinder pathFinder;
- Query buildQuery(final IEditorPart editor, final ITextSelection selection) {
- final IPath protoFilePath = pathFinder.findProtoFilePath(editor);
+ Query buildQuery(IEditorPart editor) {
+ final int offset = selectionOffsetOf(editor);
+ if (offset < 0) {
+ return null;
+ }
+ IFile file = (IFile) editor.getEditorInput().getAdapter(IFile.class);
+ final IPath protoFilePath = pathFinder.findProtoFilePath(file);
if (protoFilePath == null) {
return null;
}
@@ -54,21 +60,16 @@
if (ast == null) {
return CANCEL_STATUS;
}
- int offset = selection.getOffset();
- int length = max(1, selection.getLength());
IASTNodeSelector nodeSelector= ast.getNodeSelector(null);
- IASTName selectedName = nodeSelector.findEnclosingName(offset, length);
+ IASTName selectedName = nodeSelector.findEnclosingName(offset, 1);
if (selectedName == null) {
return CANCEL_STATUS;
}
if (selectedName.isDefinition()) {
IBinding binding = selectedName.resolveBinding();
- if (binding instanceof CPPClassType) {
- Collection<QualifiedName> qualifiedNames = nameBuilder.createQualifiedNamesFrom((CPPClassType) binding);
- if (qualifiedNames.isEmpty()) {
- return CANCEL_STATUS;
- }
- queriesReference.set(query(qualifiedNames, protoFilePath));
+ Iterable<QualifiedName> qualifiedNames = qualifiedNameProvider.qualifiedNamesFrom(binding);
+ if (qualifiedNames != null) {
+ queriesReference.set(Query.newQuery(qualifiedNames, protoFilePath));
return OK_STATUS;
}
}
@@ -80,4 +81,14 @@
}
return queriesReference.get();
}
+
+ private int selectionOffsetOf(IEditorPart editor) {
+ ISelectionProvider selectionProvider = ((ITextEditor) editor).getSelectionProvider();
+ ISelection selection = selectionProvider.getSelection();
+ if (selection instanceof ITextSelection) {
+ ITextSelection textSelection = (ITextSelection) selection;
+ return textSelection.getOffset();
+ }
+ return -1;
+ }
}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
index 25201bc..0c390f6 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/OpenProtoDeclarationAction.java
@@ -9,7 +9,6 @@
package com.google.eclipse.protobuf.cdt.actions;
import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.*;
@@ -23,30 +22,23 @@
*/
public class OpenProtoDeclarationAction implements IEditorActionDelegate {
private IEditorPart editor;
- private ITextSelection selection;
- @Inject private ModelObjectDefinitionQueryBuilder queryBuilder;
+ @Inject private ModelObjectLookupQueryBuilder queryBuilder;
@Inject private NavigationJobs navigationJobs;
@Override public void run(IAction action) {
- if (editor == null || selection == null) {
+ if (editor == null) {
return;
}
- Query query = queryBuilder.buildQuery(editor, selection);
+ Query query = queryBuilder.buildQuery(editor);
if (query != null) {
navigationJobs.scheduleUsing(query);
}
}
- @Override public void selectionChanged(IAction action, ISelection selection) {
- if (selection instanceof ITextSelection) {
- this.selection = (ITextSelection) selection;
- return;
- }
- this.selection = null;
- }
-
@Override public void setActiveEditor(IAction action, IEditorPart editor) {
this.editor = editor;
}
+
+ @Override public void selectionChanged(IAction action, ISelection selection) {}
}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ProtoFilePathFinder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ProtoFilePathFinder.java
deleted file mode 100644
index 9ee947e..0000000
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ProtoFilePathFinder.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2012 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.cdt.actions;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences.compilerPreferences;
-import static org.eclipse.core.runtime.IPath.SEPARATOR;
-import static org.eclipse.xtext.util.Strings.*;
-
-import java.util.List;
-
-import org.eclipse.core.resources.*;
-import org.eclipse.core.runtime.*;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
-
-import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
-import com.google.inject.Inject;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-class ProtoFilePathFinder {
- private static final String PATH_SEPARATOR = new String(new char[] { SEPARATOR });
-
- @Inject private IPreferenceStoreAccess storeAccess;
-
- IPath findProtoFilePath(IEditorPart editor) {
- IFile file = (IFile) editor.getEditorInput().getAdapter(IFile.class);
- IPath headerFilePath = file.getFullPath();
- if (!"h".equals(headerFilePath.getFileExtension())) {
- return null;
- }
- String cppOutputDirectory = cppOutputDirectory(file.getProject());
- if (isEmpty(cppOutputDirectory)) {
- return null;
- }
- List<String> segments = newArrayList(headerFilePath.segments());
- for (int i = 0; i < headerFilePath.segmentCount() - 1; i++) {
- segments.remove(0);
- if (headerFilePath.segment(i).equals(cppOutputDirectory)) {
- break;
- }
- }
- String headerFileName = headerFilePath.lastSegment();
- segments.set(segments.size() - 1, headerFileName.replace("pb.h", "proto"));
- String protoFilePath = concat(PATH_SEPARATOR, segments);
- return new Path(protoFilePath);
- }
-
- private String cppOutputDirectory(IProject project) {
- CompilerPreferences preferences = compilerPreferences(storeAccess, project);
- if (!preferences.compileProtoFiles().getValue() && !preferences.cppCodeGenerationEnabled().getValue()) {
- return null;
- }
- return preferences.cppOutputDirectory().getValue();
- }
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java
deleted file mode 100644
index 98389a8..0000000
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/QualifiedNameFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2012 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.cdt.actions;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Collections.unmodifiableList;
-
-import java.util.List;
-
-import org.eclipse.xtext.naming.QualifiedName;
-
-import com.google.eclipse.protobuf.model.util.QualifiedNames;
-import com.google.inject.*;
-
-/**
- * @author alruiz@google.com (Alex Ruiz)
- */
-@Singleton class QualifiedNameFactory {
- @Inject private QualifiedNames qualifiedNames;
-
- List<QualifiedName> createQualifiedNamesForComplexType(String[] segments) {
- List<QualifiedName> names = newArrayList();
- names.add(QualifiedName.create(segments));
- int lastSegmentIndex = segments.length - 1;
- String messageName = segments[lastSegmentIndex];
- if (messageName.contains("_")) {
- String[] hierarchicalNames = messageName.split("_");
- List<String> newSegments = newArrayList(segments);
- newSegments.remove(lastSegmentIndex);
- newSegments.addAll(newArrayList(hierarchicalNames));
- names.add(qualifiedNames.createFqn(newSegments));
- }
- return unmodifiableList(names);
- }
-}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy.java
similarity index 68%
rename from com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java
rename to com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy.java
index 907fa26..34fe592 100644
--- a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/actions/ClassTypeQualifiedNameBuilder.java
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/ClassTypeQualifiedNameProviderStrategy.java
@@ -6,32 +6,28 @@
*
* http://www.eclipse.org/legal/epl-v10.html
*/
-package com.google.eclipse.protobuf.cdt.actions;
-
-import static java.util.Collections.emptyList;
-
-import java.util.List;
+package com.google.eclipse.protobuf.cdt.fqn;
import org.eclipse.cdt.core.dom.IName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.*;
import org.eclipse.xtext.naming.QualifiedName;
-import com.google.inject.*;
+import com.google.inject.Singleton;
/**
* @author alruiz@google.com (Alex Ruiz)
*/
@SuppressWarnings("restriction")
-@Singleton class ClassTypeQualifiedNameBuilder {
- @Inject QualifiedNameFactory qualifiedNameFactory;
-
- public List<QualifiedName> createQualifiedNamesFrom(CPPClassType classType) {
+@Singleton class ClassTypeQualifiedNameProviderStrategy implements QualifiedNameProviderStrategy<CPPClassType> {
+ @Override public Iterable<QualifiedName> qualifiedNamesFrom(IBinding binding) {
+ CPPClassType classType = supportedBindingType().cast(binding);
if (isMessage(classType)) {
String[] segments = classType.getQualifiedName();
- return qualifiedNameFactory.createQualifiedNamesForComplexType(segments);
+ return new QualifiedNameSource(segments);
}
- return emptyList();
+ return null;
}
private boolean isMessage(CPPClassType classType) {
@@ -50,4 +46,8 @@
String qualifiedNameAsText = qualifiedName.toString();
return "::google::protobuf::Message".equals(qualifiedNameAsText);
}
+
+ @Override public Class<CPPClassType> supportedBindingType() {
+ return CPPClassType.class;
+ }
}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/EnumQualifiedNameProviderStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/EnumQualifiedNameProviderStrategy.java
new file mode 100644
index 0000000..d904428
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/EnumQualifiedNameProviderStrategy.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 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.cdt.fqn;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration;
+import org.eclipse.xtext.naming.QualifiedName;
+
+import com.google.inject.Singleton;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@SuppressWarnings("restriction")
+@Singleton class EnumQualifiedNameProviderStrategy implements QualifiedNameProviderStrategy<CPPEnumeration> {
+ @Override public Iterable<QualifiedName> qualifiedNamesFrom(IBinding binding) {
+ CPPEnumeration enumeration = supportedBindingType().cast(binding);
+ String[] segments = enumeration.getQualifiedName();
+ return new QualifiedNameSource(segments);
+ }
+
+ @Override public Class<CPPEnumeration> supportedBindingType() {
+ return CPPEnumeration.class;
+ }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProvider.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProvider.java
new file mode 100644
index 0000000..03438b0
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 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.cdt.fqn;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.xtext.naming.QualifiedName;
+
+import com.google.inject.Singleton;
+
+/**
+ * Provides all the possible qualified names of the protocol buffer element used to generate a C++ element.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton public class QualifiedNameProvider {
+ private final Map<Class<?>, QualifiedNameProviderStrategy<?>> strategies = newHashMap();
+
+ public QualifiedNameProvider() {
+ add(new ClassTypeQualifiedNameProviderStrategy());
+ add(new EnumQualifiedNameProviderStrategy());
+ }
+
+ private void add(QualifiedNameProviderStrategy<?> strategy) {
+ strategies.put(strategy.supportedBindingType(), strategy);
+ }
+
+ /**
+ * Returns a lazy-loaded <code>{@link Iterable}</code> containing all the possible qualified names of the protocol
+ * buffer element used to generate a C++ element.
+ * @param binding specifies the semantics of the name of the generated C++ element.
+ * @return a lazy-loaded {@code Iterable} containing all the possible qualified names, or {@code null} if qualified
+ * names cannot be obtained from the given {@code IBinding}.
+ */
+ public Iterable<QualifiedName> qualifiedNamesFrom(IBinding binding) {
+ QualifiedNameProviderStrategy<? extends IBinding> strategy = strategies.get(binding.getClass());
+ return (strategy != null) ? strategy.qualifiedNamesFrom(binding) : null;
+ }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProviderStrategy.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProviderStrategy.java
new file mode 100644
index 0000000..44816d0
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameProviderStrategy.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 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.cdt.fqn;
+
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.xtext.naming.QualifiedName;
+
+/**
+ * Provides all the possible qualified names of the protocol buffer element used to generate a C++ element described
+ * by a specific type of <code>{@link IBinding}</code>.
+ * @param <T> the type of {@code IBinding} this strategy supports.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+interface QualifiedNameProviderStrategy<T extends IBinding> {
+ Iterable<QualifiedName> qualifiedNamesFrom(IBinding binding);
+
+ Class<T> supportedBindingType();
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameSource.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameSource.java
new file mode 100644
index 0000000..062e1ac
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/fqn/QualifiedNameSource.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 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.cdt.fqn;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.util.*;
+
+import org.eclipse.xtext.naming.QualifiedName;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.AbstractIterator;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+class QualifiedNameSource implements Iterable<QualifiedName> {
+ private final QualifiedName original;
+
+ public QualifiedNameSource(String[] segments) {
+ original = QualifiedName.create(segments);
+ }
+
+ @VisibleForTesting QualifiedName original() {
+ return original;
+ }
+
+ @Override public Iterator<QualifiedName> iterator() {
+ return new QualifiedNameIterator();
+ }
+
+ private class QualifiedNameIterator extends AbstractIterator<QualifiedName> {
+ private int sentCount;
+
+ @Override protected QualifiedName computeNext() {
+ switch (sentCount++) {
+ case 0:
+ return original;
+ case 1:
+ return nested();
+ default:
+ return endOfData();
+ }
+ }
+
+ private QualifiedName nested() {
+ String name = original.getLastSegment();
+ if (!name.contains("_")) {
+ return endOfData();
+ }
+ String[] nestedNames = name.split("_");
+ List<String> newSegments = newArrayList(original.getSegments());
+ newSegments.remove(newSegments.size() - 1);
+ newSegments.addAll(newArrayList(nestedNames));
+ String[] segments = newSegments.toArray(new String[newSegments.size()]);
+ return QualifiedName.create(segments);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/path/ProtoFilePathFinder.java b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/path/ProtoFilePathFinder.java
new file mode 100644
index 0000000..fd25b97
--- /dev/null
+++ b/com.google.eclipse.protobuf.cdt/src/com/google/eclipse/protobuf/cdt/path/ProtoFilePathFinder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 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.cdt.path;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences.compilerPreferences;
+import static com.google.eclipse.protobuf.ui.util.Paths.segmentsOf;
+import static org.eclipse.core.runtime.IPath.SEPARATOR;
+import static org.eclipse.xtext.util.Strings.*;
+
+import java.util.List;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+
+import com.google.eclipse.protobuf.ui.preferences.compiler.core.CompilerPreferences;
+import com.google.inject.Inject;
+
+/**
+ * Finds the path of a .proto file, given the path of the generated C++ header file.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class ProtoFilePathFinder {
+ private static final String PATH_SEPARATOR = new String(new char[] { SEPARATOR });
+
+ @Inject private IPreferenceStoreAccess storeAccess;
+
+ /**
+ * Returns the path of the .proto file used as source of the generated C++ header file.
+ * @param file the given file.
+ * @return the path of the .proto file used as source of the generated C++ header file, or {@code null} if the given
+ * file is not a C++ header file or if C++ code generation is not enabled in the proto editor.
+ */
+ public IPath findProtoFilePath(IFile file) {
+ IPath headerFilePath = file.getFullPath();
+ if (!"h".equals(headerFilePath.getFileExtension())) {
+ return null;
+ }
+ IPath cppOutputDirectory = cppOutputDirectory(file.getProject());
+ if (cppOutputDirectory == null) {
+ return null;
+ }
+ List<String> newPathSegments = newArrayList(headerFilePath.segments());
+ for (int i = 0; i < headerFilePath.segmentCount() - 1; i++) {
+ newPathSegments.remove(0);
+ if (headerFilePath.segment(i).equals(cppOutputDirectory.lastSegment())) {
+ break;
+ }
+ }
+ int fileNameIndex = newPathSegments.size() - 1;
+ String fileName = newPathSegments.get(fileNameIndex);
+ newPathSegments.set(fileNameIndex, fileName.replace("pb.h", "proto"));
+ return new Path(concat(PATH_SEPARATOR, newPathSegments));
+ }
+
+ private IPath cppOutputDirectory(IProject project) {
+ CompilerPreferences preferences = compilerPreferences(storeAccess, project);
+ if (!preferences.compileProtoFiles().getValue() && !preferences.cppCodeGenerationEnabled().getValue()) {
+ return null;
+ }
+ String directoryName = preferences.cppOutputDirectory().getValue();
+ if (isEmpty(directoryName)) {
+ return null;
+ }
+ IFolder directory = null;
+ String[] segments = segmentsOf(directoryName);
+ StringBuilder pathBuilder = new StringBuilder();
+ for (String segment : segments) {
+ pathBuilder.append(segment);
+ directory = project.getFolder(pathBuilder.toString());
+ if (!directory.exists()) {
+ return null;
+ }
+ pathBuilder.append(SEPARATOR);
+ }
+ if (directory == null) {
+ return null;
+ }
+ return directory.getFullPath();
+ }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/IndexLookup_resourceIn_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/IndexLookup_resourceIn_Test.java
new file mode 100644
index 0000000..a6cb9b5
--- /dev/null
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/IndexLookup_resourceIn_Test.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012 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.resource;
+
+import static com.google.eclipse.protobuf.junit.core.IntegrationTestModule.integrationTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.resource.*;
+import org.eclipse.xtext.resource.impl.ResourceSetBasedResourceDescriptions;
+import org.junit.*;
+
+import com.google.eclipse.protobuf.junit.core.XtextRule;
+import com.google.inject.Inject;
+
+/**
+ * Tests for <code>{@link IndexLookup#resourceIn(IPath)}</code>.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class IndexLookup_resourceIn_Test {
+ @Rule public XtextRule xtext = overrideRuntimeModuleWith(integrationTestModule());
+
+ @Inject private IndexLookup lookup;
+
+ // syntax = "proto2";
+ // package com.google.proto;
+ //
+ // message Person {}
+ @Test public void should_find_resource_if_URIs_are_exact_match() {
+ XtextResource resource = xtext.resource();
+ addToXtextIndex(resource);
+ URI resourceUri = resource.getURI();
+ IResourceDescription description = lookup.resourceIn(new Path(resourceUri.path()));
+ assertThat(description.getURI(), equalTo(resourceUri));
+ }
+
+ // syntax = "proto2";
+ // package com.google.proto;
+ //
+ // message Person {}
+ @Test public void should_find_resource_matching_segments_if_URIs_are_not_exact_match() {
+ XtextResource resource = xtext.resource();
+ addToXtextIndex(resource);
+ URI resourceUri = resource.getURI();
+ String[] segments = resourceUri.segments();
+ int segmentCount = segments.length;
+ String path = segments[segmentCount - 2] + "/" + segments[segmentCount - 1]; // last two segments.
+ IResourceDescription description = lookup.resourceIn(new Path(path));
+ assertThat(description.getURI(), equalTo(resourceUri));
+ }
+
+ // syntax = "proto2";
+ // package com.google.proto;
+ //
+ // message Person {}
+ @Test public void should_return_null_if_matching_URI_was_not_found() {
+ XtextResource resource = xtext.resource();
+ addToXtextIndex(resource);
+ IResourceDescription description = lookup.resourceIn(new Path("some/crazy/path"));
+ assertNull(description);
+ }
+
+ private void addToXtextIndex(XtextResource resource) {
+ IResourceDescriptions xtextIndex = lookup.getXtextIndex();
+ if (xtextIndex instanceof ResourceSetBasedResourceDescriptions) {
+ ((ResourceSetBasedResourceDescriptions) xtextIndex).setContext(resource);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ResourceDescriptions_modelObjectUri_Test.java
similarity index 60%
rename from com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java
rename to com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ResourceDescriptions_modelObjectUri_Test.java
index afa5d16..0d680f5 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup_findModelObjectUri_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/resource/ResourceDescriptions_modelObjectUri_Test.java
@@ -10,14 +10,12 @@
import static com.google.eclipse.protobuf.junit.core.IntegrationTestModule.integrationTestModule;
import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
-import static java.util.Collections.singletonList;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
-import org.eclipse.core.runtime.*;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.naming.*;
-import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.*;
import org.eclipse.xtext.resource.impl.ResourceSetBasedResourceDescriptions;
import org.junit.*;
@@ -27,15 +25,17 @@
import com.google.inject.Inject;
/**
- * Tests for <code>{@link ModelObjectLocationLookup#findModelObjectUri(Iterable, IPath)}</code>
+ * Tests for <code>{@link ResourceDescriptions#modelObjectUri(IResourceDescription, QualifiedName)}</code>
*
* @author alruiz@google.com (Alex Ruiz)
*/
-public class ModelObjectLocationLookup_findModelObjectUri_Test {
+public class ResourceDescriptions_modelObjectUri_Test {
@Rule public XtextRule xtext = overrideRuntimeModuleWith(integrationTestModule());
@Inject private IQualifiedNameConverter fqnConverter;
- @Inject private ModelObjectLocationLookup lookup;
+ @Inject private ResourceSetBasedResourceDescriptions index;
+ @Inject private ResourceDescriptions resourceDescriptions;
+
// syntax = "proto2";
// package com.google.proto;
@@ -46,34 +46,26 @@
// }
@Test public void should_find_URI_of_model_object_given_its_qualified_name() {
XtextResource resource = xtext.resource();
- addToXtextIndex(resource);
- Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Type"));
- URI foundUri = lookup.findModelObjectUri(qualifiedNames, pathOf(resource));
+ QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Type");
+ URI foundUri = resourceDescriptions.modelObjectUri(describe(resource), qualifiedName);
Enum anEnum = xtext.find("Type", Enum.class);
String fragment = resource.getURIFragment(anEnum);
URI expectedUri = resource.getURI().appendFragment(fragment);
assertThat(foundUri, equalTo(expectedUri));
}
- private IPath pathOf(XtextResource resource) {
- return new Path(resource.getURI().path());
- }
-
// syntax = "proto2";
// package com.google.proto;
//
// message Person {}
@Test public void should_return_null_if_file_name_is_equal_but_file_path_is_not() {
- addToXtextIndex(xtext.resource());
- Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Person"));
- URI foundUri = lookup.findModelObjectUri(qualifiedNames, new Path("/test/src/protos/mytestmodel.proto"));
+ QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Type");
+ URI foundUri = resourceDescriptions.modelObjectUri(describe(xtext.resource()), qualifiedName);
assertNull(foundUri);
}
- private void addToXtextIndex(XtextResource resource) {
- IResourceDescriptions xtextIndex = lookup.getXtextIndex();
- if (xtextIndex instanceof ResourceSetBasedResourceDescriptions) {
- ((ResourceSetBasedResourceDescriptions) xtextIndex).setContext(resource);
- }
+ private IResourceDescription describe(Resource resource) {
+ index.setContext(resource);
+ return index.getResourceDescription(resource.getURI());
}
}
diff --git a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
index 6213098..75ce83f 100644
--- a/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
+++ b/com.google.eclipse.protobuf.ui.test/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator_navigateToDefinition_Test.java
@@ -10,7 +10,7 @@
import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
-import static com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query.query;
+import static com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query.newQuery;
import static java.util.Collections.singletonList;
import static org.eclipse.core.runtime.Status.*;
import static org.eclipse.emf.common.util.URI.createURI;
@@ -22,11 +22,12 @@
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.naming.*;
import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
import org.junit.*;
import com.google.eclipse.protobuf.junit.core.*;
-import com.google.eclipse.protobuf.resource.ModelObjectLocationLookup;
+import com.google.eclipse.protobuf.resource.*;
import com.google.eclipse.protobuf.ui.editor.ModelObjectDefinitionNavigator.Query;
import com.google.inject.Inject;
@@ -38,38 +39,48 @@
public class ModelObjectDefinitionNavigator_navigateToDefinition_Test {
private static IPath filePath;
- @BeforeClass public static void setUp() {
+ @BeforeClass public static void setUpOnce() {
filePath = new Path("/src/protos/test.proto");
}
@Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new TestModule());
- @Inject private IQualifiedNameConverter fqnConverter;
- @Inject private ModelObjectLocationLookup locationLookup;
@Inject private IURIEditorOpener editorOpener;
+ @Inject private IQualifiedNameConverter fqnConverter;
+ @Inject private IndexLookup indexLookup;
+ @Inject private ResourceDescriptions resources;
@Inject private ModelObjectDefinitionNavigator navigator;
+ private IResourceDescription resource;
+
+ @Before public void setUp() {
+ resource = mock(IResourceDescription.class);
+ }
+
@Test public void should_navigate_to_model_object_if_URI_is_found() {
+ when(indexLookup.resourceIn(filePath)).thenReturn(resource);
+ QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Type");
URI uri = createURI("file:/usr/local/project/src/protos/test.proto");
- Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Type"));
- when(locationLookup.findModelObjectUri(qualifiedNames, filePath)).thenReturn(uri);
- IStatus result = navigator.navigateToDefinition(query(qualifiedNames, filePath));
+ when(resources.modelObjectUri(resource, qualifiedName)).thenReturn(uri);
+ IStatus result = navigator.navigateToDefinition(newQuery(singletonList(qualifiedName), filePath));
assertThat(result, equalTo(OK_STATUS));
verify(editorOpener).open(uri, true);
}
@Test public void should_not_navigate_to_model_object_if_URI_is_not_found() {
- Iterable<QualifiedName> qualifiedNames = singletonList(fqnConverter.toQualifiedName("com.google.proto.Person"));
- when(locationLookup.findModelObjectUri(qualifiedNames, filePath)).thenReturn(null);
- IStatus result = navigator.navigateToDefinition(query(qualifiedNames, filePath));
+ when(indexLookup.resourceIn(filePath)).thenReturn(resource);
+ QualifiedName qualifiedName = fqnConverter.toQualifiedName("com.google.proto.Person");
+ when(resources.modelObjectUri(resource, qualifiedName)).thenReturn(null);
+ IStatus result = navigator.navigateToDefinition(newQuery(singletonList(qualifiedName), filePath));
assertThat(result, equalTo(CANCEL_STATUS));
verifyZeroInteractions(editorOpener);
}
private static class TestModule extends AbstractTestModule {
@Override protected void configure() {
- mockAndBind(ModelObjectLocationLookup.class);
mockAndBind(IURIEditorOpener.class);
+ mockAndBind(IndexLookup.class);
+ mockAndBind(ResourceDescriptions.class);
}
}
}
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java
index 67cbaf6..75cd929 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/builder/protoc/OutputDirectory.java
@@ -9,7 +9,7 @@
package com.google.eclipse.protobuf.ui.builder.protoc;
import static com.google.eclipse.protobuf.ui.util.Paths.segmentsOf;
-import static java.io.File.separator;
+import static org.eclipse.core.runtime.IPath.SEPARATOR;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
@@ -41,7 +41,7 @@
if (!directory.exists()) {
directory.create(true, true, NO_MONITOR);
}
- path.append(separator);
+ path.append(SEPARATOR);
}
}
return directory;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
index f0393c7..3cec964 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/editor/ModelObjectDefinitionNavigator.java
@@ -14,9 +14,10 @@
import org.eclipse.core.runtime.*;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.ui.editor.IURIEditorOpener;
-import com.google.eclipse.protobuf.resource.ModelObjectLocationLookup;
+import com.google.eclipse.protobuf.resource.*;
import com.google.inject.Inject;
/**
@@ -25,8 +26,9 @@
* @author alruiz@google.com (Alex Ruiz)
*/
public class ModelObjectDefinitionNavigator {
- @Inject private ModelObjectLocationLookup locationLookup;
+ @Inject private IndexLookup lookup;
@Inject private IURIEditorOpener editorOpener;
+ @Inject private ResourceDescriptions resources;
/**
* Navigates to the definition of the model object whose qualified name matches any of the given ones. This method
@@ -35,10 +37,16 @@
* @return the result of the operation.
*/
public IStatus navigateToDefinition(Query query) {
- URI uri = locationLookup.findModelObjectUri(query.qualifiedNames, query.filePath);
- if (uri != null) {
- editorOpener.open(uri, true);
- return OK_STATUS;
+ IResourceDescription resource = lookup.resourceIn(query.filePath);
+ if (resource == null) {
+ return CANCEL_STATUS;
+ }
+ for (QualifiedName qualifiedName : query.qualifiedNames) {
+ URI uri = resources.modelObjectUri(resource, qualifiedName);
+ if (uri != null) {
+ editorOpener.open(uri, true);
+ return OK_STATUS;
+ }
}
return CANCEL_STATUS;
}
@@ -59,7 +67,7 @@
* @param filePath the path and name of the file where to perform the lookup.
* @return the created {@code Query}.
*/
- public static Query query(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
+ public static Query newQuery(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
return new Query(qualifiedNames, filePath);
}
@@ -67,5 +75,10 @@
this.qualifiedNames = newLinkedList(qualifiedNames);
this.filePath = filePath;
}
+
+ @Override public String toString() {
+ String format = "%s[qualifiedNames=%s, filePath=%s]";
+ return String.format(format, getClass().getSimpleName(), qualifiedNames, filePath);
+ }
}
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Resources.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Resources.java
index 108152a..1627d2c 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Resources.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Resources.java
@@ -11,9 +11,6 @@
import static org.eclipse.emf.common.util.URI.createURI;
import static org.eclipse.emf.ecore.util.EcoreUtil.getAllContents;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.inject.Inject;
-
import org.eclipse.emf.common.util.*;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.*;
@@ -21,6 +18,9 @@
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.scoping.impl.ImportUriResolver;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
+
/**
* Utility methods related to <code>{@link Resource}</code>
*
@@ -36,6 +36,7 @@
* @return the resource referred by the URI of the given import, or {@code null} is the given {@code ResourceSet} does
* not contain the resource.
*/
+ // TODO move to class ResourceSets
public Resource importedResource(Import anImport, ResourceSet resourceSet) {
try {
URI importUri = createURI(uriResolver.apply(anImport));
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/IndexLookup.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/IndexLookup.java
new file mode 100644
index 0000000..65668fd
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/IndexLookup.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012 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.resource;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.resource.*;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.eclipse.protobuf.util.IPaths;
+import com.google.inject.Inject;
+
+/**
+ * Simplified Xtext index lookups.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class IndexLookup {
+ @Inject private IPaths paths;
+ @Inject private IResourceDescriptions xtextIndex;
+
+ /**
+ * Finds the resource description for the given path.
+ * @param path the given path.
+ * @return the found resource description, or {@code null} if a resource description with a matching path could not be
+ * found.
+ */
+ public IResourceDescription resourceIn(IPath path) {
+ IResourceDescription description = lookup(path);
+ if (description != null) {
+ return description;
+ }
+ return segmentMatching(path);
+ }
+
+ private IResourceDescription lookup(IPath path) {
+ URI uri = URI.createPlatformResourceURI(path.toOSString(), false);
+ return xtextIndex.getResourceDescription(uri);
+ }
+
+ private IResourceDescription segmentMatching(IPath path) {
+ for (IResourceDescription description : xtextIndex.getAllResourceDescriptions()) {
+ URI resourceUri = description.getURI();
+ if (paths.areReferringToSameFile(path, resourceUri)) {
+ return description;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting IResourceDescriptions getXtextIndex() {
+ return xtextIndex;
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java
deleted file mode 100644
index 4c82a51..0000000
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ModelObjectLocationLookup.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2012 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.resource;
-
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.xtext.naming.QualifiedName;
-import org.eclipse.xtext.resource.*;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.eclipse.protobuf.util.IPaths;
-import com.google.inject.Inject;
-
-/**
- * Looks up the location of model objects in the Xtext index.
- *
- * @author alruiz@google.com (Alex Ruiz)
- */
-public class ModelObjectLocationLookup {
- @Inject private IPaths paths;
- @Inject private IResourceDescriptions xtextIndex;
-
- /**
- * Finds the URI of a model object whose qualified name matches any of the given ones.
- * @param qualifiedNames all the possible qualified names the model object to look for may have.
- * @param filePath the path and name of the file where to perform the lookup.
- * @return the URI of a model object whose qualified name matches any of the given ones, or {@code null} if a
- * matching model object cannot be found.
- */
- public URI findModelObjectUri(Iterable<QualifiedName> qualifiedNames, IPath filePath) {
- for (IResourceDescription resourceDescription : xtextIndex.getAllResourceDescriptions()) {
- URI resourceUri = resourceDescription.getURI();
- if (paths.areReferringToSameFile(filePath, resourceUri)) {
- // we found the resource we are looking for.
- for (IEObjectDescription exported : resourceDescription.getExportedObjects()) {
- QualifiedName modelObjectQualifiedName = exported.getQualifiedName();
- for (QualifiedName qualifiedName : qualifiedNames) {
- if (qualifiedName.equals(modelObjectQualifiedName)) {
- return exported.getEObjectURI();
- }
- }
- }
- break;
- }
- }
- return null;
- }
-
- @VisibleForTesting IResourceDescriptions getXtextIndex() {
- return xtextIndex;
- }
-}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java
new file mode 100644
index 0000000..14a93f6
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/resource/ResourceDescriptions.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012 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.resource;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.*;
+
+import com.google.inject.Singleton;
+
+/**
+ * Utility methods related to <code>{@link IResourceDescription}</code>s.
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+@Singleton public class ResourceDescriptions {
+ /**
+ * Finds the URI of a model object in the given resource whose qualified name matches the given one.
+ * @param resource the given resource.
+ * @param qualifiedName the qualified name to match.
+ * @return the URI of the found model object, or {@code null} if a model object with a matching URI could not be
+ * found.
+ */
+ public URI modelObjectUri(IResourceDescription resource, QualifiedName qualifiedName) {
+ for (IEObjectDescription exported : resource.getExportedObjects()) {
+ QualifiedName modelObjectQualifiedName = exported.getQualifiedName();
+ if (qualifiedName.equals(modelObjectQualifiedName)) {
+ return exported.getEObjectURI();
+ }
+ }
+ return null;
+ }
+}