Fixed issue where real unresolved references were shown as warnings when
having unresolved imports only.
diff --git a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/validation/ImportValidator_checkNonProto2Imports_Test.java b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/validation/ImportValidator_checkNonProto2Imports_Test.java
index 5b9a99b..f60840b 100644
--- a/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/validation/ImportValidator_checkNonProto2Imports_Test.java
+++ b/com.google.eclipse.protobuf.integration.test/src/com/google/eclipse/protobuf/validation/ImportValidator_checkNonProto2Imports_Test.java
@@ -12,13 +12,13 @@
import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
import static org.mockito.Mockito.*;
-import org.eclipse.xtext.validation.ValidationMessageAcceptor;
-import org.junit.*;
-
import com.google.eclipse.protobuf.junit.core.XtextRule;
import com.google.eclipse.protobuf.protobuf.Protobuf;
import com.google.inject.Inject;
+import org.eclipse.xtext.validation.ValidationMessageAcceptor;
+import org.junit.*;
+
/**
* Tests for <code>{@link ImportValidator#checkNonProto2Imports(Protobuf)}</code>
*
@@ -74,4 +74,12 @@
validator.checkNonProto2Imports(xtext.root());
verifyNoMoreInteractions(messageAcceptor);
}
+
+ // syntax = "proto2";
+ //
+ // import "093651b0-5676-11e1-b86c-0800200c9a66.proto";
+ @Test public void should_not_add_warnings_if_imported_file_does_not_exist() {
+ validator.checkNonProto2Imports(xtext.root());
+ verifyNoMoreInteractions(messageAcceptor);
+ }
}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/IntegrationTestModule.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/IntegrationTestModule.java
index beafd75..c714463 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/IntegrationTestModule.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/IntegrationTestModule.java
@@ -46,7 +46,7 @@
}
File file = protoFile(importUri);
if (!file.exists()) {
- throw new IllegalArgumentException("File: " + importUri + " does not exist.");
+ return; // file does not exist.
}
String resolvedUri = file.toURI().toString();
anImport.setImportURI(resolvedUri);
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic_constructor_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic_constructor_Test.java
index dbcb6cb..3e03766 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic_constructor_Test.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic_constructor_Test.java
@@ -35,7 +35,7 @@
new ProtobufDiagnostic("1000", null, "message", node);
}
- @Test(expected = NullPointerException.class)
+ @Test(expected = IllegalArgumentException.class)
public void should_throw_exception_if_data_contains_nulls() {
new ProtobufDiagnostic("1000", new String[] { null }, "message", node);
}
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/Imports_resolvedUriOf_Test.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/Imports_resolvedUriOf_Test.java
new file mode 100644
index 0000000..f94fb74
--- /dev/null
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/model/util/Imports_resolvedUriOf_Test.java
@@ -0,0 +1,59 @@
+/*
+ * 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.model.util;
+
+import static com.google.eclipse.protobuf.junit.core.UnitTestModule.unitTestModule;
+import static com.google.eclipse.protobuf.junit.core.XtextRule.overrideRuntimeModuleWith;
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import com.google.eclipse.protobuf.junit.core.*;
+import com.google.eclipse.protobuf.protobuf.Import;
+import com.google.inject.Inject;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.xtext.scoping.impl.ImportUriResolver;
+import org.junit.*;
+
+/**
+ * Tests for <code>{@link Imports#resolvedUriOf(Import)}</code>
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public class Imports_resolvedUriOf_Test {
+ @Rule public XtextRule xtext = overrideRuntimeModuleWith(unitTestModule(), new TestModule());
+
+ @Inject private ImportUriResolver uriResolver;
+ @Inject private Imports imports;
+
+ private Import anImport;
+
+ @Before public void setUp() {
+ anImport = mock(Import.class);
+ }
+
+ @Test public void should_return_resolved_URI() {
+ when(uriResolver.apply(anImport)).thenReturn("file:/protos/test.proto");
+ URI uri = imports.resolvedUriOf(anImport);
+ assertThat(uri.path(), equalTo("/protos/test.proto"));
+ }
+
+ @Test public void should_return_null_if_URI_cannot_be_resolved() {
+ when(uriResolver.apply(anImport)).thenReturn(null);
+ URI uri = imports.resolvedUriOf(anImport);
+ assertNull(uri);
+ }
+
+ private static class TestModule extends AbstractTestModule {
+ @Override protected void configure() {
+ mockAndBind(ImportUriResolver.class);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic.java
index 80a5387..d6591a5 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/linking/ProtobufDiagnostic.java
@@ -12,11 +12,11 @@
import static java.util.Arrays.copyOf;
import static org.eclipse.xtext.util.Arrays.contains;
+import com.google.common.base.Objects;
+
import org.eclipse.xtext.diagnostics.*;
import org.eclipse.xtext.nodemodel.INode;
-import com.google.common.base.Objects;
-
/**
* <code>{@link Diagnostic}</code> that supports appending text to its message.
*
@@ -29,9 +29,14 @@
private final INode node;
public ProtobufDiagnostic(String code, String[] data, String message, INode node) {
- validate(data);
+ if (data == null) {
+ throw new NullPointerException("The given array should not be null");
+ }
+ if (contains(data, null)) {
+ throw new IllegalArgumentException("The given array should not contain null elements");
+ }
if (node == null) {
- throw new NullPointerException("node should not be null");
+ throw new NullPointerException("The given node should not be null");
}
this.code = code;
this.data = copyOf(data, data.length);
@@ -40,15 +45,6 @@
this.node = node;
}
- private static void validate(String[] data) {
- if (data == null) {
- throw new NullPointerException("data should not be a null array");
- }
- if (contains(data, null)) {
- throw new NullPointerException("data should not contain null");
- }
- }
-
@Override public String getCode() {
return code;
}
@@ -66,7 +62,7 @@
}
/**
- * Appends the given text to the message of this diagnostic.
+ * Appends the given text to this diagnostic's message.
* @param s the text to append.
*/
public void appendToMessage(String s) {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Imports.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Imports.java
index 408118c..d308b3f 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Imports.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/Imports.java
@@ -12,16 +12,16 @@
import static com.google.eclipse.protobuf.util.Strings.*;
import static org.eclipse.xtext.util.Strings.*;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.resource.*;
-import org.eclipse.xtext.nodemodel.INode;
-import org.eclipse.xtext.scoping.impl.ImportUriResolver;
-
import com.google.eclipse.protobuf.protobuf.Import;
import com.google.eclipse.protobuf.resource.ResourceSets;
import com.google.eclipse.protobuf.scoping.ProtoDescriptorProvider;
import com.google.inject.Inject;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.*;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.scoping.impl.ImportUriResolver;
+
/**
* Utility methods related to imports.
*
@@ -90,10 +90,10 @@
* @return {@code true} if the URI of the given {@code Import} has been resolved, {@code false} otherwise.
*/
public boolean isResolved(Import anImport) {
- String importUri = anImport.getImportURI();
- if (!isEmpty(importUri)) {
- URI uri = URI.createURI(importUri);
- if (!isEmpty(uri.scheme())) {
+ String uriAsText = anImport.getImportURI();
+ if (!isEmpty(uriAsText)) {
+ URI uri = URI.createURI(uriAsText);
+ if (isResolved(uri)) {
return true;
}
}
@@ -122,6 +122,14 @@
*/
public URI resolvedUriOf(Import anImport) {
String resolvedUri = uriResolver.apply(anImport);
- return (isEmpty(resolvedUri)) ? null : URI.createURI(resolvedUri);
+ if (isEmpty(resolvedUri)) {
+ return null;
+ }
+ URI uri = URI.createURI(resolvedUri);
+ return (isResolved(uri)) ? uri : null;
+ }
+
+ private boolean isResolved(URI uri) {
+ return !isEmpty(uri.scheme());
}
}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ImportValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ImportValidator.java
index d852659..878ae52 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ImportValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ImportValidator.java
@@ -15,16 +15,16 @@
import static java.lang.String.format;
import static org.eclipse.xtext.util.Tuples.pair;
-import java.util.*;
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.protobuf.*;
+import com.google.inject.Inject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.scoping.impl.ImportUriResolver;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.validation.*;
-import com.google.eclipse.protobuf.model.util.*;
-import com.google.eclipse.protobuf.protobuf.*;
-import com.google.inject.Inject;
+import java.util.*;
/**
* Verifies that "imports" contain correct values.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
index f161e5a..648bc90 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
@@ -18,7 +18,7 @@
import static org.eclipse.xtext.validation.CheckType.FAST;
import static org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator.DISABLE_CONCRETE_SYNTAX_EVALIDATOR;
-import java.util.*;
+import com.google.eclipse.protobuf.linking.ProtobufDiagnostic;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.Diagnostic;
@@ -29,7 +29,7 @@
import org.eclipse.xtext.util.*;
import org.eclipse.xtext.validation.*;
-import com.google.eclipse.protobuf.linking.ProtobufDiagnostic;
+import java.util.*;
/**
* Adds support for converting scoping errors into warnings if non-proto2 files are imported.
@@ -48,51 +48,18 @@
List<Issue> result = newArrayListWithExpectedSize(resource.getErrors().size() + resource.getWarnings().size());
try {
IAcceptor<Issue> acceptor = createAcceptor(result);
- boolean hasNonProto2Import = false;
- for (EObject element : resource.getContents()) {
- try {
- if (monitor.isCanceled()) {
- return null;
- }
- Diagnostic diagnostic = getDiagnostician().validate(element, validationOptions(resource, mode, monitor));
- if (!diagnostic.getChildren().isEmpty()) {
- for (Diagnostic child : diagnostic.getChildren()) {
- if (importingNonProto2.equals(child.getMessage())) {
- hasNonProto2Import = true;
- }
- issueFromEValidatorDiagnostic(child, acceptor);
- }
- } else {
- issueFromEValidatorDiagnostic(diagnostic, acceptor);
- }
- } catch (RuntimeException e) {
- log.error(e.getMessage(), e);
- }
+ Status status = delegateValidationToDiagnostician(resource, mode, monitor, acceptor);
+ if (status.isCanceled()) {
+ return null;
}
if (mode.shouldCheck(FAST)) {
- for (Resource.Diagnostic error : resource.getErrors()) {
- if (monitor.isCanceled()) {
- return null;
- }
- Severity severity = ERROR;
- if (hasNonProto2Import && isUnresolveReferenceError(error)) {
- severity = WARNING;
- ProtobufDiagnostic d = (ProtobufDiagnostic) error;
- if (!d.getMessage().endsWith(scopingError)) {
- if (!d.getMessage().endsWith(".")) {
- d.appendToMessage(".");
- }
- d.appendToMessage(" ");
- d.appendToMessage(scopingError);
- }
- }
- issueFromXtextResourceDiagnostic(error, severity, acceptor);
+ status = createErrors(resource, status.hasProto1Imports(), acceptor, monitor);
+ if (status.isCanceled()) {
+ return null;
}
- for (Resource.Diagnostic warning : resource.getWarnings()) {
- if (monitor.isCanceled()) {
- return null;
- }
- issueFromXtextResourceDiagnostic(warning, WARNING, acceptor);
+ status = createWarnings(resource, acceptor, monitor);
+ if (status.isCanceled()) {
+ return null;
}
}
} catch (RuntimeException e) {
@@ -101,6 +68,21 @@
return result;
}
+ private Status delegateValidationToDiagnostician(Resource resource, CheckMode mode,
+ CancelIndicator monitor, IAcceptor<Issue> acceptor) {
+ Status hasNonProto2Import = Status.OK;
+ for (EObject element : resource.getContents()) {
+ if (monitor.isCanceled()) {
+ return Status.CANCELED;
+ }
+ Diagnostic diagnostic = getDiagnostician().validate(element, validationOptions(resource, mode, monitor));
+ if (convertIssuesToMarkers(acceptor, diagnostic) == Status.PROTO1_IMPORTS_FOUND) {
+ hasNonProto2Import = Status.PROTO1_IMPORTS_FOUND;
+ }
+ }
+ return hasNonProto2Import;
+ }
+
private Map<Object, Object> validationOptions(Resource resource, CheckMode mode, CancelIndicator monitor) {
Map<Object, Object> options = newHashMap();
options.put(KEY, mode);
@@ -113,14 +95,76 @@
return options;
}
- private boolean isUnresolveReferenceError(Resource.Diagnostic error) {
+ private Status convertIssuesToMarkers(IAcceptor<Issue> acceptor, Diagnostic diagnostic) {
+ Status hasNonProto2Import = Status.OK;
+ if (diagnostic.getChildren().isEmpty()) {
+ issueFromEValidatorDiagnostic(diagnostic, acceptor);
+ return hasNonProto2Import;
+ }
+ for (Diagnostic child : diagnostic.getChildren()) {
+ if (importingNonProto2.equals(child.getMessage())) {
+ hasNonProto2Import = Status.PROTO1_IMPORTS_FOUND;
+ }
+ issueFromEValidatorDiagnostic(child, acceptor);
+ }
+ return hasNonProto2Import;
+ }
+
+ private Status createErrors(Resource resource, boolean proto1ImportsFound, IAcceptor<Issue> acceptor,
+ CancelIndicator monitor) {
+ for (Resource.Diagnostic error : resource.getErrors()) {
+ if (monitor.isCanceled()) {
+ return Status.CANCELED;
+ }
+ Severity severity = ERROR;
+ if (proto1ImportsFound && isUnresolvedReferenceError(error)) {
+ severity = WARNING;
+ ProtobufDiagnostic d = (ProtobufDiagnostic) error;
+ String message = d.getMessage();
+ if (message.endsWith(scopingError)) {
+ continue;
+ }
+ if (!message.endsWith(".")) {
+ d.appendToMessage(".");
+ }
+ d.appendToMessage(" ");
+ d.appendToMessage(scopingError);
+ }
+ issueFromXtextResourceDiagnostic(error, severity, acceptor);
+ }
+ return Status.OK;
+ }
+
+ private boolean isUnresolvedReferenceError(Resource.Diagnostic error) {
if (!(error instanceof ProtobufDiagnostic)) {
return false;
}
ProtobufDiagnostic d = (ProtobufDiagnostic) error;
- if (!"org.eclipse.xtext.diagnostics.Diagnostic.Linking".equals(d.getCode())) {
- return false;
+ if ("org.eclipse.xtext.diagnostics.Diagnostic.Linking".equals(d.getCode())) {
+ return error.getMessage().startsWith("Couldn't resolve");
}
- return error.getMessage().startsWith("Couldn't resolve");
+ return false;
+ }
+
+ private Status createWarnings(Resource resource, IAcceptor<Issue> acceptor, CancelIndicator monitor) {
+ for (Resource.Diagnostic warning : resource.getWarnings()) {
+ if (monitor.isCanceled()) {
+ return Status.CANCELED;
+ }
+ issueFromXtextResourceDiagnostic(warning, WARNING, acceptor);
+ }
+ return Status.OK;
+ }
+
+ private static enum Status {
+ OK, CANCELED, PROTO1_IMPORTS_FOUND;
+
+ boolean hasProto1Imports() {
+ return (this == PROTO1_IMPORTS_FOUND);
+ }
+
+ boolean isCanceled() {
+ return (this == CANCELED);
+ }
}
}
\ No newline at end of file