In case we have an enumeration defined directly in a leaf of the same
name as its containing generated type (list, container, etc.), we can
end up violating JLS section 8.1 class naming requirements.
Detect this condition and munge the type name by appending a '$' to
prevent this conflict.
Change-Id: Ia68cac2a96ac0a95fa38a83cb1cdc1c09540533b
JIRA: MDSAL-321
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName,
final GeneratedTypeBuilder typeBuilder, final ModuleContext context) {
if (enumTypeDef != null && typeBuilder != null && enumTypeDef.getQName().getLocalName() != null) {
private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName,
final GeneratedTypeBuilder typeBuilder, final ModuleContext context) {
if (enumTypeDef != null && typeBuilder != null && enumTypeDef.getQName().getLocalName() != null) {
- final String enumerationName = BindingMapping.getClassName(enumName);
- final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+ final EnumBuilder enumBuilder = typeBuilder.addEnumeration(BindingMapping.getClassName(enumName));
typeProvider.addEnumDescription(enumBuilder, enumTypeDef);
enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
context.addInnerTypedefType(enumTypeDef.getPath(), enumBuilder);
typeProvider.addEnumDescription(enumBuilder, enumTypeDef);
enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
context.addInnerTypedefType(enumTypeDef.getPath(), enumBuilder);
"Local Name in EnumTypeDefinition QName cannot be NULL!");
Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
"Local Name in EnumTypeDefinition QName cannot be NULL!");
Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
- final String enumerationName = BindingMapping.getClassName(enumName);
-
- final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+ final EnumBuilder enumBuilder = typeBuilder.addEnumeration(BindingMapping.getClassName(enumName));
addEnumDescription(enumBuilder, enumTypeDef);
enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
addEnumDescription(enumBuilder, enumTypeDef);
enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
- public EnumBuilder addEnumeration(final String name) {
+ public EnumBuilder addEnumeration(String name) {
Preconditions.checkArgument(name != null, "Name of enumeration cannot be null!");
Preconditions.checkArgument(name != null, "Name of enumeration cannot be null!");
- final EnumBuilder builder = newEnumerationBuilder(getIdentifier().createEnclosed(name));
+ // This enumeration may be generated from a leaf, which may end up colliding with its enclosing type
+ // hierarchy. Check it and assign another name if that should be the case.
+ final boolean canCreate = getIdentifier().canCreateEnclosed(name);
+ if (!canCreate) {
+ // Append a single '$' -- it cannot come from the user, hence it marks our namespace.
+ name = name + '$';
+ }
+
+ final EnumBuilder builder = newEnumerationBuilder(getIdentifier().createEnclosed(name));
Preconditions.checkArgument(!this.enumDefinitions.contains(builder),
Preconditions.checkArgument(!this.enumDefinitions.contains(builder),
- "This generated type already contains equal enumeration.");
+ "Generated type %s already contains an enumeration for %s", this, builder);
this.enumDefinitions = LazyCollections.lazyAdd(this.enumDefinitions, builder);
return builder;
}
this.enumDefinitions = LazyCollections.lazyAdd(this.enumDefinitions, builder);
return builder;
}
CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
}
CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
}
+ @Test
+ public void innerEnumerationNameCollisionTest() throws Exception {
+ final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal321");
+ final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal321");
+ generateTestSources("/compilation/mdsal321", sourcesOutputDir);
+ CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
+ CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
+ }
+
private void generateTestSources(final String resourceDirPath, final File sourcesOutputDir)
throws IOException, URISyntaxException {
final List<File> sourceFiles = CompilationTestUtils.getSourceFiles(resourceDirPath);
private void generateTestSources(final String resourceDirPath, final File sourcesOutputDir)
throws IOException, URISyntaxException {
final List<File> sourceFiles = CompilationTestUtils.getSourceFiles(resourceDirPath);
--- /dev/null
+module odl-mdsal {
+ namespace "urn:odl:mdsal321";
+ prefix odl;
+
+ container foo {
+ leaf foo {
+ type enumeration {
+ enum "foo";
+ }
+ description "Enumeration defined in a leaf. This triggers a nested
+ class with a name derived from leaf name to be created
+ in a class from container name. Both names are 'foo'.
+ Measures have to be taken to rename the class, so it
+ does not clash with its enclosing class.";
+ }
+ }
+}