Report error when a global reference maps to a proto enum and a global definition.
GITHUB_BREAKING_CHANGES=if a global reference resolves to both a value in the --compileTimeGlobals file and a registered proto, this is now an error.  Remove the definition from the compileTimeGlobals file.
@@ -41,10 +41,16 @@ import com.google.template.soy.types.SoyTypeRegistry;
@RunAfter({
VeRewritePass.class, // rewrites some VE references that are parsed as globals in a different way
})
+@RunBefore({CheckGlobalsPass.class})
final class RewriteGlobalsPass implements CompilerFilePass {
private static final SoyErrorKind ENUM_MEMBERSHIP_ERROR =
SoyErrorKind.of("''{0}'' is not a member of enum ''{1}''.");
+ private static final SoyErrorKind PROTO_GLOBAL_OVERLAP_ERROR =
+ SoyErrorKind.of(
+ "''{0}'' corresponds to a proto enum and is registered as a global with the value"
+ + " ''{1}''. Remove the global definition.");
+
private final ImmutableMap<String, PrimitiveData> compileTimeGlobals;
private final ErrorReporter errorReporter;
@@ -79,13 +85,18 @@ final class RewriteGlobalsPass implements CompilerFilePass {
if (enumValue != null) {
// TODO(lukes): consider introducing a new PrimitiveNode for enums
global.resolve(enumType, new IntegerNode(enumValue, global.getSourceLocation()));
+ String fullyQualifiedName = enumType.getName() + "." + enumMemberName;
+ PrimitiveData value = compileTimeGlobals.get(fullyQualifiedName);
+ if (value != null) {
+ errorReporter.report(
+ global.getSourceLocation(), PROTO_GLOBAL_OVERLAP_ERROR, fullyQualifiedName, value);
+ }
} else {
// If we found the type definition but not the value, then that's an error
// regardless of whether we're allowing unbound globals or not.
errorReporter.report(
global.getSourceLocation(), ENUM_MEMBERSHIP_ERROR, enumMemberName, enumTypeName);
}
- // TODO(lukes): issue a warning if a registered global also matches
return;
}
}
@@ -94,13 +105,22 @@ final class RewriteGlobalsPass implements CompilerFilePass {
if (alias != null) {
global.setName(alias.identifier());
}
-
+ name = global.getName();
// if that doesn't work, see if it was registered in the globals file.
- PrimitiveData value = compileTimeGlobals.get(global.getName());
+ PrimitiveData value = compileTimeGlobals.get(name);
+
if (value != null) {
PrimitiveNode expr =
InternalValueUtils.convertPrimitiveDataToExpr(value, global.getSourceLocation());
global.resolve(expr.getType(), expr);
+ // check if the fully qualified name matches a known proto, even if it isn't imported.
+ lastDot = name.lastIndexOf('.');
+ if (lastDot > 0) {
+ SoyType type = typeRegistry.getProtoRegistry().getProtoType(name.substring(0, lastDot));
+ if (type != null) {
+ errorReporter.report(global.getSourceLocation(), PROTO_GLOBAL_OVERLAP_ERROR, name, value);
+ }
+ }
}
}
}
