mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 05:26:58 +08:00
string(GENEX_STRIP): Fix regression on nested generator expressions
Since commit 13c7bb5b0c
(cmGeneratorExpression: Update strip function to
collect parsed expressions, 2025-04-08), the logic to strip generator
expressions from a string made incorrect assumptions about the contents of
generator expressions, leading certain cases to be stripped incorrectly.
Clean up the logic and fix broken behavior, and add test coverage with
`string(GENEX_STRIP)`.
Fixes: #27133
This commit is contained in:
@@ -164,33 +164,36 @@ static std::string extractAllGeneratorExpressions(
|
|||||||
std::string result;
|
std::string result;
|
||||||
std::string::size_type pos = 0;
|
std::string::size_type pos = 0;
|
||||||
std::string::size_type lastPos = pos;
|
std::string::size_type lastPos = pos;
|
||||||
// stack of { Generator Expression Name, Start Position of Value }
|
std::stack<char const*> starts; // indices of "$<"
|
||||||
std::stack<std::pair<std::string, std::string::size_type>> genexps;
|
std::stack<char const*> colons; // indices of ":"
|
||||||
while ((pos = input.find("$<", lastPos)) != std::string::npos) {
|
while ((pos = input.find("$<", lastPos)) != std::string::npos) {
|
||||||
result += input.substr(lastPos, pos - lastPos);
|
result += input.substr(lastPos, pos - lastPos);
|
||||||
|
starts.push(input.c_str() + pos);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
char const* c = input.c_str() + pos;
|
char const* c = input.c_str() + pos;
|
||||||
char const* cName = c;
|
|
||||||
char const* const cStart = c;
|
char const* const cStart = c;
|
||||||
for (; *c; ++c) {
|
for (; *c; ++c) {
|
||||||
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
|
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
|
||||||
|
starts.push(c);
|
||||||
++c;
|
++c;
|
||||||
cName = c + 1;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c[0] == ':' && cName) {
|
if (c[0] == ':') {
|
||||||
genexps.push({ input.substr(pos + (cName - cStart), c - cName),
|
if (colons.size() < starts.size()) {
|
||||||
pos + (c + 1 - cStart) });
|
colons.push(c);
|
||||||
cName = nullptr;
|
}
|
||||||
} else if (c[0] == '>') {
|
} else if (c[0] == '>') {
|
||||||
if (!cName && !genexps.empty()) {
|
if (collected && !starts.empty() && !colons.empty()) {
|
||||||
if (collected) {
|
(*collected)[std::string(starts.top() + 2, colons.top())].push_back(
|
||||||
(*collected)[genexps.top().first].push_back(input.substr(
|
std::string(colons.top() + 1, c));
|
||||||
genexps.top().second, pos + c - cStart - genexps.top().second));
|
|
||||||
}
|
}
|
||||||
genexps.pop();
|
if (!starts.empty()) {
|
||||||
|
starts.pop();
|
||||||
}
|
}
|
||||||
if (genexps.empty()) {
|
if (!colons.empty()) {
|
||||||
|
colons.pop();
|
||||||
|
}
|
||||||
|
if (starts.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +205,7 @@ static std::string extractAllGeneratorExpressions(
|
|||||||
pos += traversed;
|
pos += traversed;
|
||||||
lastPos = pos;
|
lastPos = pos;
|
||||||
}
|
}
|
||||||
if (genexps.empty()) {
|
if (starts.empty()) {
|
||||||
result += input.substr(lastPos);
|
result += input.substr(lastPos);
|
||||||
}
|
}
|
||||||
return cmGeneratorExpression::StripEmptyListElements(result);
|
return cmGeneratorExpression::StripEmptyListElements(result);
|
||||||
|
37
Tests/RunCMake/string/GenexpStrip.cmake
Normal file
37
Tests/RunCMake/string/GenexpStrip.cmake
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
function(test_strip input expected)
|
||||||
|
string(GENEX_STRIP "${input}" strip)
|
||||||
|
if (NOT strip STREQUAL expected)
|
||||||
|
message(FATAL_ERROR "message(GENEXP_STRIP \"${input}\")
|
||||||
|
evaluated to \"${strip}\"
|
||||||
|
expected \"${expected}\"")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
test_strip( # Simple case
|
||||||
|
"$<BOOL:1>"
|
||||||
|
""
|
||||||
|
)
|
||||||
|
test_strip( # LHS contains generator expression
|
||||||
|
"$<$<CONFIG:Release>:NDEBUG>;DEBUG"
|
||||||
|
"DEBUG"
|
||||||
|
)
|
||||||
|
test_strip( # RHS contains generator expression
|
||||||
|
"$<AND:1,$<BOOL:TRUE>>"
|
||||||
|
""
|
||||||
|
)
|
||||||
|
test_strip( # Empty and unfinished expressions
|
||||||
|
"$<>$<$<>"
|
||||||
|
"$<$<>"
|
||||||
|
)
|
||||||
|
test_strip( # Multiple independent expressions
|
||||||
|
"$<IF:TRUE,TRUE,FALSE> / $<IF:TRUE,TRUE,FALSE>"
|
||||||
|
" / "
|
||||||
|
)
|
||||||
|
test_strip( # Multiple : in one expression
|
||||||
|
"$<1:2:3>"
|
||||||
|
""
|
||||||
|
)
|
||||||
|
test_strip( # Multiple case
|
||||||
|
"1$<AND:1,0>2$<IF:$<$<BOOL:1>:$<CONFIG:RELEASE>>,TRUE,FALSE>3"
|
||||||
|
"123"
|
||||||
|
)
|
@@ -56,3 +56,5 @@ run_cmake(RepeatNegativeCount)
|
|||||||
run_cmake(Hex)
|
run_cmake(Hex)
|
||||||
run_cmake(HexTooManyArgs)
|
run_cmake(HexTooManyArgs)
|
||||||
run_cmake(HexNotEnoughArgs)
|
run_cmake(HexNotEnoughArgs)
|
||||||
|
|
||||||
|
run_cmake(GenexpStrip)
|
||||||
|
Reference in New Issue
Block a user