blob: 9f978ac7baba3b4500107390aa98f7ba809c737e [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.validation;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.IMPORT__IMPORT_URI;
import static com.google.eclipse.protobuf.validation.Messages.*;
import static java.lang.String.format;
import static org.eclipse.xtext.util.Tuples.pair;
import java.util.*;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.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.eclipse.protobuf.resource.ResourceSets;
import com.google.inject.Inject;
/**
* Verifies that "imports" contain correct values.
*
* @author alruiz@google.com (Alex Ruiz)
*/
public class ImportValidator extends AbstractDeclarativeValidator {
@Inject private Imports imports;
@Inject private Protobufs protobufs;
@Inject private Resources resources;
@Inject private ResourceSets resourceSets;
@Inject private ImportUriResolver uriResolver;
@Override public void register(EValidatorRegistrar registrar) {}
/**
* Verifies that {@code Import}s in the given root only refer to "proto2" files. If non-proto2 {@code Import}s are
* found, this validator will create warning markers for such "imports".
* @param root the root containing the imports to check.
*/
@Check public void checkNonProto2Imports(Protobuf root) {
warnIfNonProto2ImportsFound(root.eResource());
}
private void warnIfNonProto2ImportsFound(Resource resource) {
Protobuf root = resources.rootOf(resource);
if (!protobufs.isProto2(root)) {
return;
}
ResourceSet resourceSet = resource.getResourceSet();
boolean hasNonProto2 = false;
List<Pair<Import, Resource>> resourcesToCheck = newArrayList();
Set<URI> checked = newHashSet();
checked.add(resource.getURI());
for (Import anImport : protobufs.importsIn(root)) {
Resource imported = importedResource(resourceSet, anImport);
checked.add(imported.getURI());
if (!protobufs.isProto2(resources.rootOf(imported))) {
hasNonProto2 = true;
warnNonProto2ImportFoundIn(anImport);
continue;
}
resourcesToCheck.add(pair(anImport, imported));
}
if (hasNonProto2) {
return;
}
for (Pair<Import, Resource> p : resourcesToCheck) {
if (hasNonProto2(p, checked, resourceSet)) {
warnNonProto2ImportFoundIn(p.getFirst());
break;
}
}
}
private boolean hasNonProto2(Pair<Import, Resource> toCheck, Set<URI> alreadyChecked, ResourceSet resourceSet) {
Protobuf root = resources.rootOf(toCheck.getSecond());
if (!protobufs.isProto2(root)) {
return false;
}
List<Pair<Import, Resource>> resourcesToCheck = newArrayList();
for (Import anImport : protobufs.importsIn(root)) {
Resource imported = importedResource(resourceSet, anImport);
if (alreadyChecked.contains(imported.getURI())) {
continue;
}
if (!protobufs.isProto2(resources.rootOf(imported))) {
return true;
}
resourcesToCheck.add(pair(toCheck.getFirst(), imported));
}
for (Pair<Import, Resource> p : resourcesToCheck) {
if (hasNonProto2(p, alreadyChecked, resourceSet)) {
return true;
}
}
return false;
}
private Resource importedResource(ResourceSet resourceSet, Import anImport) {
URI resolvedUri = imports.resolvedUriOf(anImport);
if (resolvedUri != null) {
return resourceSets.findResource(resourceSet, resolvedUri);
}
return null;
}
private void warnNonProto2ImportFoundIn(Import anImport) {
acceptWarning(importingNonProto2, anImport, IMPORT__IMPORT_URI, INSIGNIFICANT_INDEX, null);
}
/**
* Verifies that the URI of the given {@code Import} has been resolved. If the URI has not been resolved, this
* validator will create an error marker for the given {@code Import}.
* @param anImport the given {@code Import}.
*/
@Check public void checkUriIsResolved(Import anImport) {
if (imports.isResolved(anImport)) {
return;
}
uriResolver.apply(anImport);
if (!imports.isResolved(anImport)) {
error(format(importNotFound, anImport.getImportURI()), IMPORT__IMPORT_URI);
}
}
}