diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index a7dfe77fc1..7ec87852da 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -3855,6 +3855,13 @@ bool ExpressionParser::isTokenAnIndentifier(const std::string & str) return (status == 0 && (token == IDENTIFIER || token == CELLADDRESS)); } +bool ExpressionParser::isTokenAConstant(const std::string & str) +{ + int token{}, status{}; + std::tie(token, status) = getTokenAndStatus(str); + return (status == 0 && token == CONSTANT); +} + bool ExpressionParser::isTokenAUnit(const std::string & str) { int token{}, status{}; diff --git a/src/App/ExpressionParser.h b/src/App/ExpressionParser.h index 305df966bf..4535e64719 100644 --- a/src/App/ExpressionParser.h +++ b/src/App/ExpressionParser.h @@ -500,6 +500,7 @@ AppExport Expression * parse(const App::DocumentObject *owner, const char *buffe AppExport UnitExpression * parseUnit(const App::DocumentObject *owner, const char *buffer); AppExport ObjectIdentifier parsePath(const App::DocumentObject *owner, const char* buffer); AppExport bool isTokenAnIndentifier(const std::string & str); +AppExport bool isTokenAConstant(const std::string & str); AppExport bool isTokenAUnit(const std::string & str); AppExport std::vector > tokenize(const std::string & str); diff --git a/src/Gui/DlgAddProperty.cpp b/src/Gui/DlgAddProperty.cpp index c1ff8f2472..1454fec98a 100644 --- a/src/Gui/DlgAddProperty.cpp +++ b/src/Gui/DlgAddProperty.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "DlgAddProperty.h" @@ -111,6 +112,13 @@ void DlgAddProperty::accept() if(ui->chkAppend->isChecked()) name = group + "_" + name; + if (App::ExpressionParser::isTokenAUnit(name) || App::ExpressionParser::isTokenAConstant(name)) { + QMessageBox::critical(getMainWindow(), + QObject::tr("Invalid name"), + QObject::tr("The property name is a reserved word.")); + return; + } + for(auto c : containers) { auto prop = c->getPropertyByName(name.c_str()); if(prop && prop->getContainer() == c) { diff --git a/src/Gui/DlgAddPropertyVarSet.cpp b/src/Gui/DlgAddPropertyVarSet.cpp index 0c64439970..5993a89f82 100644 --- a/src/Gui/DlgAddPropertyVarSet.cpp +++ b/src/Gui/DlgAddPropertyVarSet.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -351,6 +352,14 @@ void DlgAddPropertyVarSet::checkName() { throw CreatePropertyException("Invalid name"); } + if(App::ExpressionParser::isTokenAUnit(name) || App::ExpressionParser::isTokenAConstant(name)) { + QMessageBox::critical(getMainWindow(), + QObject::tr("Invalid name"), + QObject::tr("The property name is a reserved word.")); + clearEditors(!CLEAR_NAME); + throw CreatePropertyException("Invalid name"); + } + if (namePropertyToAdd.empty()) { // we are adding a new property, check whether it doesn't already exist auto prop = varSet->getPropertyByName(name.c_str()); diff --git a/src/Gui/DlgExpressionInput.cpp b/src/Gui/DlgExpressionInput.cpp index c573d68ac5..5353d5d7b6 100644 --- a/src/Gui/DlgExpressionInput.cpp +++ b/src/Gui/DlgExpressionInput.cpp @@ -437,6 +437,11 @@ static bool isNamePropOk(const QString& nameProp, App::DocumentObject* obj, return false; } + if (ExpressionParser::isTokenAUnit(name) || ExpressionParser::isTokenAConstant(name)) { + message << name << " is a reserved word"; + return false; + } + auto prop = obj->getPropertyByName(name.c_str()); if (prop && prop->getContainer() == obj) { message << name << " already exists"; diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 652185cf14..5933cdc5ae 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -137,8 +137,9 @@ bool PropertySheet::isValidAlias(const std::string& candidate) return false; } - /* Check to make sure it doesn't clash with a predefined unit */ - if (ExpressionParser::isTokenAUnit(candidate)) { + /* Check to make sure it doesn't clash with a reserved name */ + if (ExpressionParser::isTokenAUnit(candidate) + || ExpressionParser::isTokenAConstant(candidate)) { return false; } diff --git a/tests/src/App/ExpressionParser.cpp b/tests/src/App/ExpressionParser.cpp index f0eff0b626..de59657c8a 100644 --- a/tests/src/App/ExpressionParser.cpp +++ b/tests/src/App/ExpressionParser.cpp @@ -102,4 +102,19 @@ TEST_F(ExpressionParserTest, functionPARSEQUANT) } +TEST_F(ExpressionParserTest, isTokenAConstant) +{ + std::array constants {"pi", "e", "True", "False", "true", "false", "None"}; + for (const auto & constant : constants) { + EXPECT_TRUE(App::ExpressionParser::isTokenAConstant(constant)) + << "\"" << constant << "\" did not evaluate as a constant"; + } + + std::array notConstants {"PI", "E", "TRUE", "FALSE", "NONE", "none"}; + for (const auto & nonConstant : notConstants) { + EXPECT_FALSE(App::ExpressionParser::isTokenAConstant(nonConstant)) + << "\"" << nonConstant << "\" evaluated as a constant"; + } +} + // clang-format on