Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion core/foundation/src/TClassEdit.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1303,9 +1303,16 @@ string TClassEdit::CleanType(const char *typeDesc, int mode, const char **tail)
const char* c;

for(c=typeDesc;*c;c++) {
if (c[0]==' ') {
if (std::isspace(c[0])) {
if (kbl) continue;
if (!isalnum(c[ 1]) && c[ 1] !='_') continue;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!isalnum(c[ 1]) && c[ 1] !='_') continue;
if (c + 1 == nullptr || (!isalnum(c[ 1]) && c[ 1] !='_')) continue;

should this be maybe guarded?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming here that c is not nullptr, because typesDesc is expected to be a non-nullptr input. Then, also the c + 1 expression can also never be nullptr. About accessing the elements: reading c[1] is safe because the loop condition *c guarantees c[0] != '\0', so c[1] is at most the null terminator.

if (c[0] != ' ') {
// Significant whitespace other than ' ' (e.g. \n in a multi-line
// class name from a selection XML) is replaced by a plain space.
result += ' ';
kbl = 1;
continue;
}
}
if (kbl && (mode>=2 || parensStack.empty())) { //remove "const' etc...
int done = 0;
Expand Down
17 changes: 17 additions & 0 deletions core/foundation/test/testClassEdit.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,20 @@ TEST(TClassEdit, SplitType)
auto si = (TStreamerInfo*) c->GetStreamerInfo();
si->ls("noaddr");
}

TEST(TClassEdit, MultiLineName)
{
// A class name in a selection XML can span multiple lines. Whitespace
// other than ' ' used to empty out the template arguments it preceded,
// e.g. "Foo<,vector<float>,>" (https://github.com/root-project/root/issues/22359).
const char *name = "Foo<\n std::vector<int>, std::vector<float>,\n\tunsigned int,\n Bar ::Ref<std::vector<int>>>";
TClassEdit::TSplitType split(name, (TClassEdit::EModType)(TClassEdit::kLong64 | TClassEdit::kDropStd));
std::string out;
split.ShortType(out, TClassEdit::kLong64 | TClassEdit::kDropStd);
EXPECT_STREQ("Foo<vector<int>,vector<float>,unsigned int,Bar::Ref<vector<int> > >", out.c_str());

// Whitespace that separates two identifiers is significant and must be
// kept as a single plain space.
EXPECT_STREQ("unsigned int", TClassEdit::CleanType("unsigned\nint").c_str());
EXPECT_STREQ("Foo<int>", TClassEdit::CleanType("\n Foo<\n int\n>").c_str());
}
Loading