Summary
A qualified name whose qualification contains a non-ASCII character never resolves. Namespace#qualificationOf passes the qualification through StringEscapeUtils.escapeJava, which turns every non-ASCII character into a \uXXXX sequence, and Namespace#resolve then looks that mangled string up against the real element names.
Models written in a language other than English cannot use qualified names to refer to their own elements.
Version
- Reproduced on SysON
2026.9.2
- The code is unchanged on
main (b380dada4); line numbers below are from main
Steps to reproduce
- In any project, insert this text. The two packages differ only in whether the name is ASCII:
package Ascii {
part def Thing;
}
package Café {
part def Thing;
}
part viaAscii : Ascii::Thing;
part viaNonAscii : Café::Thing;
- Read the report of the import.
Actual
Ascii::Thing resolves. Café::Thing does not, and the import reports:
Unable to resolve name 'Café::Thing' for reference 'type'
on element '[FeatureTyping] Batmobile::viaNonAscii::<FeatureTyping>'
The FeatureTyping is left without a type.
Expected
Both resolve. Nothing in the SysML v2 textual notation restricts a name to ASCII, and the element is present in the model under exactly that name.
Where
NamespaceImpl.java on main:
// 248
public String qualificationOf(String qualifiedName) {
List<String> segments = NameHelper.parseQualifiedName(qualifiedName);
if (segments.size() < 2) {
return null;
} else {
String qualification = String.join("::", segments.subList(0, segments.size() - 1));
return NameHelper.escapeString(qualification);
}
}
// 269
public Membership resolve(String qualifiedName) {
String qualification = this.qualificationOf(qualifiedName);
String name = this.unqualifiedNameOf(qualifiedName);
Membership result = null;
if (qualification == null) {
result = this.resolveLocal(name);
} else {
Membership membership = this.resolve(qualification);
...
NameHelper#escapeString is StringEscapeUtils.escapeJava. Running it over the names above gives:
Ascii -> Ascii
Café -> Café
日本語 -> 日本語
Ascii::Sub -> Ascii::Sub
Café::Sub -> Café::Sub
So for an ASCII name escapeJava is the identity and nothing is noticed. For any other name, resolve recurses on a string that no element is called, the recursion bottoms out in resolveLocal with no match, and the whole qualified name fails.
The two halves are also not inverses of each other: unqualifiedNameOf calls NameHelper#unescapeString, which only strips surrounding single quotes, while qualificationOf calls escapeString. Whatever escapeString is there for, the qualification and the unqualified name are not treated the same way.
Scale
In a model of ours with Japanese package and element names, 1 of 126 qualified names resolved. The same model with the names transliterated to ASCII resolved 126 of 126. The one that resolved had no qualification, so it never reached qualificationOf.
This also affects accented Latin names, so it is not limited to non-Latin scripts.
Suggested direction
escapeString looks like it belongs to the textual export, where a name may need quoting, rather than to name resolution, where the string has to match an element name exactly. Removing it from qualificationOf is the obvious change, but I do not know what it was protecting against, so I would rather leave the decision to you than send a patch that quietly drops it.
If it is needed for some inputs, then resolve has to compare escaped against escaped, or unescape before comparing — at the moment one side is escaped and the other is not.
Out of scope
- The quoting of names in the textual export.
unqualifiedNameOf and unescapeString, except for the asymmetry noted above.
Summary
A qualified name whose qualification contains a non-ASCII character never resolves.
Namespace#qualificationOfpasses the qualification throughStringEscapeUtils.escapeJava, which turns every non-ASCII character into a\uXXXXsequence, andNamespace#resolvethen looks that mangled string up against the real element names.Models written in a language other than English cannot use qualified names to refer to their own elements.
Version
2026.9.2main(b380dada4); line numbers below are frommainSteps to reproduce
Actual
Ascii::Thingresolves.Café::Thingdoes not, and the import reports:The
FeatureTypingis left without a type.Expected
Both resolve. Nothing in the SysML v2 textual notation restricts a name to ASCII, and the element is present in the model under exactly that name.
Where
NamespaceImpl.javaonmain:NameHelper#escapeStringisStringEscapeUtils.escapeJava. Running it over the names above gives:So for an ASCII name
escapeJavais the identity and nothing is noticed. For any other name,resolverecurses on a string that no element is called, the recursion bottoms out inresolveLocalwith no match, and the whole qualified name fails.The two halves are also not inverses of each other:
unqualifiedNameOfcallsNameHelper#unescapeString, which only strips surrounding single quotes, whilequalificationOfcallsescapeString. WhateverescapeStringis there for, the qualification and the unqualified name are not treated the same way.Scale
In a model of ours with Japanese package and element names, 1 of 126 qualified names resolved. The same model with the names transliterated to ASCII resolved 126 of 126. The one that resolved had no qualification, so it never reached
qualificationOf.This also affects accented Latin names, so it is not limited to non-Latin scripts.
Suggested direction
escapeStringlooks like it belongs to the textual export, where a name may need quoting, rather than to name resolution, where the string has to match an element name exactly. Removing it fromqualificationOfis the obvious change, but I do not know what it was protecting against, so I would rather leave the decision to you than send a patch that quietly drops it.If it is needed for some inputs, then
resolvehas to compare escaped against escaped, or unescape before comparing — at the moment one side is escaped and the other is not.Out of scope
unqualifiedNameOfandunescapeString, except for the asymmetry noted above.