From c76500949d3fcf5ff83ac6e7f1d565f5d786c5f0 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 23 Jul 2019 23:00:28 +0200 Subject: cm*FunctionBlocker: Move to source file --- Source/cmForEachCommand.cxx | 19 +++++++++++++++++++ Source/cmForEachCommand.h | 20 -------------------- Source/cmFunctionCommand.cxx | 14 ++++++++++++++ Source/cmFunctionCommand.h | 15 --------------- Source/cmIfCommand.cxx | 17 +++++++++++++++++ Source/cmIfCommand.h | 20 +------------------- Source/cmMacroCommand.cxx | 14 ++++++++++++++ Source/cmMacroCommand.h | 15 --------------- Source/cmWhileCommand.cxx | 19 +++++++++++++++++++ Source/cmWhileCommand.h | 22 +--------------------- 10 files changed, 85 insertions(+), 90 deletions(-) diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 06dce2c..b04f14c 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -10,11 +10,30 @@ #include "cm_memory.hxx" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" #include "cmSystemTools.h" +class cmForEachFunctionBlocker : public cmFunctionBlocker +{ +public: + cmForEachFunctionBlocker(cmMakefile* mf); + ~cmForEachFunctionBlocker() override; + bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, + cmExecutionStatus&) override; + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + + std::vector Args; + std::vector Functions; + +private: + cmMakefile* Makefile; + int Depth; +}; + cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf) : Makefile(mf) , Depth(0) diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h index cd112b8..135abf0 100644 --- a/Source/cmForEachCommand.h +++ b/Source/cmForEachCommand.h @@ -11,28 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmForEachFunctionBlocker : public cmFunctionBlocker -{ -public: - cmForEachFunctionBlocker(cmMakefile* mf); - ~cmForEachFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector Args; - std::vector Functions; - -private: - cmMakefile* Makefile; - int Depth; -}; /// Starts foreach() ... endforeach() block class cmForEachCommand : public cmCommand diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 2809cf7..f8230f1 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -7,6 +7,8 @@ #include "cmAlgorithms.h" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmRange.h" @@ -102,6 +104,18 @@ bool cmFunctionHelperCommand::operator()( return true; } +class cmFunctionFunctionBlocker : public cmFunctionBlocker +{ +public: + bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, + cmExecutionStatus&) override; + bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + + std::vector Args; + std::vector Functions; + int Depth = 0; +}; + bool cmFunctionFunctionBlocker::IsFunctionBlocked( const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) { diff --git a/Source/cmFunctionCommand.h b/Source/cmFunctionCommand.h index 449a180..b334525 100644 --- a/Source/cmFunctionCommand.h +++ b/Source/cmFunctionCommand.h @@ -11,23 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmFunctionFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; - - std::vector Args; - std::vector Functions; - int Depth = 0; -}; /// Starts function() ... endfunction() block class cmFunctionCommand : public cmCommand diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 385022c..20fe2f8 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -7,6 +7,8 @@ #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOutputConverter.h" @@ -28,6 +30,21 @@ static std::string cmIfCommandError( return err; } +class cmIfFunctionBlocker : public cmFunctionBlocker +{ +public: + bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, + cmExecutionStatus&) override; + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + + std::vector Args; + std::vector Functions; + bool IsBlocking; + bool HasRun = false; + bool ElseSeen = false; + unsigned int ScopeDepth = 0; +}; + //========================================================================= bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index 775e609..820ffa4 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -7,26 +7,8 @@ #include -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" - class cmExecutionStatus; -class cmMakefile; - -class cmIfFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector Args; - std::vector Functions; - bool IsBlocking; - bool HasRun = false; - bool ElseSeen = false; - unsigned int ScopeDepth = 0; -}; +struct cmListFileArgument; /// Starts an if block bool cmIfCommand(std::vector const& args, diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 1f2b5b2..a123f22 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -10,6 +10,8 @@ #include "cmAlgorithms.h" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmRange.h" @@ -136,6 +138,18 @@ bool cmMacroHelperCommand::operator()( return true; } +class cmMacroFunctionBlocker : public cmFunctionBlocker +{ +public: + bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, + cmExecutionStatus&) override; + bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + + std::vector Args; + std::vector Functions; + int Depth = 0; +}; + bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) diff --git a/Source/cmMacroCommand.h b/Source/cmMacroCommand.h index 3ebd959..0d7083a 100644 --- a/Source/cmMacroCommand.h +++ b/Source/cmMacroCommand.h @@ -11,23 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmMacroFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; - - std::vector Args; - std::vector Functions; - int Depth = 0; -}; /// Starts macro() ... endmacro() block class cmMacroCommand : public cmCommand diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 37d1c74..914860c 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -7,6 +7,8 @@ #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSystemTools.h" @@ -14,6 +16,23 @@ #include #include +class cmWhileFunctionBlocker : public cmFunctionBlocker +{ +public: + cmWhileFunctionBlocker(cmMakefile* mf); + ~cmWhileFunctionBlocker() override; + bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, + cmExecutionStatus&) override; + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + + std::vector Args; + std::vector Functions; + +private: + cmMakefile* Makefile; + int Depth; +}; + cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf) : Makefile(mf) , Depth(0) diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h index 2257799..beca652 100644 --- a/Source/cmWhileCommand.h +++ b/Source/cmWhileCommand.h @@ -7,28 +7,8 @@ #include -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" - class cmExecutionStatus; -class cmMakefile; - -class cmWhileFunctionBlocker : public cmFunctionBlocker -{ -public: - cmWhileFunctionBlocker(cmMakefile* mf); - ~cmWhileFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector Args; - std::vector Functions; - -private: - cmMakefile* Makefile; - int Depth; -}; +struct cmListFileArgument; /// \brief Starts a while loop bool cmWhileCommand(std::vector const& args, -- cgit v0.12 From b51fba6298012c3b697c461486ce06c9e5c97c16 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Sat, 27 Jul 2019 00:21:01 +0200 Subject: cmMakefile: Add OnExecuteCommand callback In cmCTestScriptHandler, port away from cmFunctionBlocker and update the elapsed time with the new callback instead. --- Source/CTest/cmCTestScriptHandler.cxx | 33 ++------------------------------- Source/cmMakefile.cxx | 9 +++++++++ Source/cmMakefile.h | 6 ++++++ 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 7a5b8d1..f8d9f1b 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -24,7 +24,6 @@ #include "cmCTestUploadCommand.h" #include "cmCommand.h" #include "cmDuration.h" -#include "cmFunctionBlocker.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -49,32 +48,8 @@ # include #endif -class cmExecutionStatus; -struct cmListFileFunction; - #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" -// used to keep elapsed time up to date -class cmCTestScriptFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus& /*status*/) override; - // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf); - // virtual void ScopeEnded(cmMakefile &mf); - - cmCTestScriptHandler* CTestScriptHandler; -}; - -// simply update the time and don't block anything -bool cmCTestScriptFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& /*lff*/, cmMakefile& /*mf*/, - cmExecutionStatus& /*status*/) -{ - this->CTestScriptHandler->UpdateElapsedTime(); - return false; -} - cmCTestScriptHandler::cmCTestScriptHandler() { this->Backup = false; @@ -373,12 +348,8 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0"); #endif - // always add a function blocker to update the elapsed time - { - auto fb = cm::make_unique(); - fb->CTestScriptHandler = this; - this->Makefile->AddFunctionBlocker(std::move(fb)); - } + // set a callback function to update the elapsed time + this->Makefile->OnExecuteCommand([this] { this->UpdateElapsedTime(); }); /* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and CMakeSystemSpecificInformation, so diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8188ffa..f297fdf 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -353,6 +353,11 @@ private: cmMakefile* Makefile; }; +void cmMakefile::OnExecuteCommand(std::function callback) +{ + this->ExecuteCommandCallback = std::move(callback); +} + bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, cmExecutionStatus& status) { @@ -364,6 +369,10 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, return result; } + if (this->ExecuteCommandCallback) { + this->ExecuteCommandCallback(); + } + // Place this call on the call stack. cmMakefileCall stack_manager(this, lff, status); static_cast(stack_manager); diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index dc196ac..941e335 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -628,6 +628,11 @@ public: void PrintCommandTrace(const cmListFileFunction& lff) const; /** + * Set a callback that is invoked whenever ExecuteCommand is called. + */ + void OnExecuteCommand(std::function callback); + + /** * Execute a single CMake command. Returns true if the command * succeeded or false if it failed. */ @@ -964,6 +969,7 @@ private: bool EnforceUniqueDir(const std::string& srcPath, const std::string& binPath) const; + std::function ExecuteCommandCallback; using FunctionBlockerPtr = std::unique_ptr; using FunctionBlockersType = std::stack>; -- cgit v0.12 From ef38ff22f71ad0ffe83db42d903d26d4a41f4114 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 23 Jul 2019 23:50:33 +0200 Subject: cm*FunctionBlocker: Extract function Replay --- Source/cmForEachCommand.cxx | 86 +++++++++-------- Source/cmFunctionCommand.cxx | 30 +++--- Source/cmIfCommand.cxx | 218 ++++++++++++++++++++++--------------------- Source/cmMacroCommand.cxx | 32 ++++--- Source/cmWhileCommand.cxx | 133 ++++++++++++++------------ 5 files changed, 272 insertions(+), 227 deletions(-) diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index b04f14c..af32040 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -25,6 +25,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -63,44 +65,7 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - // at end of for each execute recorded commands - // store the old value - std::string oldDef; - if (mf.GetDefinition(this->Args[0])) { - oldDef = mf.GetDefinition(this->Args[0]); - } - - for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { - // set the variable to the loop value - mf.AddDefinition(this->Args[0], arg); - // Invoke all the functions that were collected in the block. - cmExecutionStatus status(mf); - for (cmListFileFunction const& func : this->Functions) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetBreakInvoked()) { - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } - } - - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; + return this->Replay(this->Functions, inStatus); } // close out a nested foreach this->Depth--; @@ -129,6 +94,51 @@ bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmForEachFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // at end of for each execute recorded commands + // store the old value + std::string oldDef; + if (mf.GetDefinition(this->Args[0])) { + oldDef = mf.GetDefinition(this->Args[0]); + } + + for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { + // set the variable to the loop value + mf.AddDefinition(this->Args[0], arg); + // Invoke all the functions that were collected in the block. + cmExecutionStatus status(mf); + for (cmListFileFunction const& func : functions) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetBreakInvoked()) { + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; + } + } + } + + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; +} + bool cmForEachCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index f8230f1..51b6970 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -110,6 +110,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& status); std::vector Args; std::vector Functions; @@ -117,7 +119,7 @@ public: }; bool cmFunctionFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) + const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus& status) { // record commands until we hit the ENDFUNCTION // at the ENDFUNCTION call we shift gears and start looking for invocations @@ -126,16 +128,8 @@ bool cmFunctionFunctionBlocker::IsFunctionBlocked( } else if (lff.Name.Lower == "endfunction") { // if this is the endfunction for this function then execute if (!this->Depth) { - // create a new command and add it to cmake - cmFunctionHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the function is defined - mf.RemoveFunctionBlocker(this, lff); - return true; + auto self = mf.RemoveFunctionBlocker(this, lff); + return this->Replay(this->Functions, status); } // decrement for each nested function that ends this->Depth--; @@ -165,6 +159,20 @@ bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmFunctionFunctionBlocker::Replay( + std::vector const& functions, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + // create a new command and add it to cmake + cmFunctionHelperCommand f; + f.Args = this->Args; + f.Functions = functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; +} + bool cmFunctionCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 20fe2f8..95f8177 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -36,6 +36,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -64,110 +66,7 @@ bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - // execute the functions for the true parts of the if statement - cmExecutionStatus status(mf); - int scopeDepth = 0; - for (cmListFileFunction const& func : this->Functions) { - // keep track of scope depth - if (func.Name.Lower == "if") { - scopeDepth++; - } - if (func.Name.Lower == "endif") { - scopeDepth--; - } - // watch for our state change - if (scopeDepth == 0 && func.Name.Lower == "else") { - - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "A duplicate ELSE command was found inside an IF block.", bt); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - - this->IsBlocking = this->HasRun; - this->HasRun = true; - this->ElseSeen = true; - - // if trace is enabled, print a (trivially) evaluated "else" - // statement - if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "An ELSEIF command was found after an ELSE command.", bt); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - - if (this->HasRun) { - this->IsBlocking = true; - } else { - // if trace is enabled, print the evaluated "elseif" statement - if (mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - - std::string errorString; - - std::vector expandedArguments; - mf.ExpandArguments(func.Arguments, expandedArguments); - - MessageType messType; - - cmListFileContext conditionContext = - cmListFileContext::FromCommandContext( - func, this->GetStartingContext().FilePath); - - cmConditionEvaluator conditionEvaluator(mf, conditionContext, - mf.GetBacktrace(func)); - - bool isTrue = conditionEvaluator.IsTrue(expandedArguments, - errorString, messType); - - if (!errorString.empty()) { - std::string err = cmIfCommandError(expandedArguments); - err += errorString; - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage(messType, err, bt); - if (messType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - if (isTrue) { - this->IsBlocking = false; - this->HasRun = true; - } - } - } - - // should we execute? - else if (!this->IsBlocking) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - inStatus.SetBreakInvoked(); - return true; - } - if (status.GetContinueInvoked()) { - inStatus.SetContinueInvoked(); - return true; - } - } - } - return true; + return this->Replay(this->Functions, inStatus); } } @@ -193,6 +92,117 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmIfFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // execute the functions for the true parts of the if statement + cmExecutionStatus status(mf); + int scopeDepth = 0; + for (cmListFileFunction const& func : functions) { + // keep track of scope depth + if (func.Name.Lower == "if") { + scopeDepth++; + } + if (func.Name.Lower == "endif") { + scopeDepth--; + } + // watch for our state change + if (scopeDepth == 0 && func.Name.Lower == "else") { + + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "A duplicate ELSE command was found inside an IF block.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + + this->IsBlocking = this->HasRun; + this->HasRun = true; + this->ElseSeen = true; + + // if trace is enabled, print a (trivially) evaluated "else" + // statement + if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); + } + } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "An ELSEIF command was found after an ELSE command.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + + if (this->HasRun) { + this->IsBlocking = true; + } else { + // if trace is enabled, print the evaluated "elseif" statement + if (mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); + } + + std::string errorString; + + std::vector expandedArguments; + mf.ExpandArguments(func.Arguments, expandedArguments); + + MessageType messType; + + cmListFileContext conditionContext = + cmListFileContext::FromCommandContext( + func, this->GetStartingContext().FilePath); + + cmConditionEvaluator conditionEvaluator(mf, conditionContext, + mf.GetBacktrace(func)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messType); + + if (!errorString.empty()) { + std::string err = cmIfCommandError(expandedArguments); + err += errorString; + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage(messType, err, bt); + if (messType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + return true; + } + } + + if (isTrue) { + this->IsBlocking = false; + this->HasRun = true; + } + } + } + + // should we execute? + else if (!this->IsBlocking) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + inStatus.SetBreakInvoked(); + return true; + } + if (status.GetContinueInvoked()) { + inStatus.SetContinueInvoked(); + return true; + } + } + } + return true; +} + //========================================================================= bool cmIfCommand(std::vector const& args, cmExecutionStatus& inStatus) diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index a123f22..e82d6fa 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -144,6 +144,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& status); std::vector Args; std::vector Functions; @@ -152,7 +154,7 @@ public: bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) + cmExecutionStatus& status) { // record commands until we hit the ENDMACRO // at the ENDMACRO call we shift gears and start looking for invocations @@ -161,17 +163,8 @@ bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, } else if (lff.Name.Lower == "endmacro") { // if this is the endmacro for this macro then execute if (!this->Depth) { - mf.AppendProperty("MACROS", this->Args[0].c_str()); - // create a new command and add it to cmake - cmMacroHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the macro is defined - mf.RemoveFunctionBlocker(this, lff); - return true; + auto self = mf.RemoveFunctionBlocker(this, lff); + return this->Replay(this->Functions, status); } // decrement for each nested macro that ends this->Depth--; @@ -201,6 +194,21 @@ bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmMacroFunctionBlocker::Replay( + std::vector const& functions, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + mf.AppendProperty("MACROS", this->Args[0].c_str()); + // create a new command and add it to cmake + cmMacroHelperCommand f; + f.Args = this->Args; + f.Functions = functions; + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; +} + bool cmMacroCommand::InitialPass(std::vector const& args, cmExecutionStatus&) { diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 914860c..025d14a 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -24,6 +24,8 @@ public: bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) override; bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool Replay(std::vector const& functions, + cmExecutionStatus& inStatus); std::vector Args; std::vector Functions; @@ -62,68 +64,7 @@ bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, if (!fb) { return false; } - - std::string errorString; - - std::vector expandedArguments; - mf.ExpandArguments(this->Args, expandedArguments); - MessageType messageType; - - cmListFileContext execContext = this->GetStartingContext(); - - cmCommandContext commandContext; - commandContext.Line = execContext.Line; - commandContext.Name = execContext.Name; - - cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), - mf.GetBacktrace(commandContext)); - - bool isTrue = - conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); - - while (isTrue) { - if (!errorString.empty()) { - std::string err = "had incorrect arguments: "; - for (cmListFileArgument const& arg : this->Args) { - err += (arg.Delim ? "\"" : ""); - err += arg.Value; - err += (arg.Delim ? "\"" : ""); - err += " "; - } - err += "("; - err += errorString; - err += ")."; - mf.IssueMessage(messageType, err); - if (messageType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - // Invoke all the functions that were collected in the block. - for (cmListFileFunction const& fn : this->Functions) { - cmExecutionStatus status(mf); - mf.ExecuteCommand(fn, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } - expandedArguments.clear(); - mf.ExpandArguments(this->Args, expandedArguments); - isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, - messageType); - } - return true; + return this->Replay(this->Functions, inStatus); } // decrement for each nested while that ends this->Depth--; @@ -149,6 +90,74 @@ bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, return false; } +bool cmWhileFunctionBlocker::Replay( + std::vector const& functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + std::string errorString; + + std::vector expandedArguments; + mf.ExpandArguments(this->Args, expandedArguments); + MessageType messageType; + + cmListFileContext execContext = this->GetStartingContext(); + + cmCommandContext commandContext; + commandContext.Line = execContext.Line; + commandContext.Name = execContext.Name; + + cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), + mf.GetBacktrace(commandContext)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); + + while (isTrue) { + if (!errorString.empty()) { + std::string err = "had incorrect arguments: "; + for (cmListFileArgument const& arg : this->Args) { + err += (arg.Delim ? "\"" : ""); + err += arg.Value; + err += (arg.Delim ? "\"" : ""); + err += " "; + } + err += "("; + err += errorString; + err += ")."; + mf.IssueMessage(messageType, err); + if (messageType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + return true; + } + } + + // Invoke all the functions that were collected in the block. + for (cmListFileFunction const& fn : functions) { + cmExecutionStatus status(mf); + mf.ExecuteCommand(fn, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; + } + } + expandedArguments.clear(); + mf.ExpandArguments(this->Args, expandedArguments); + isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); + } + return true; +} + bool cmWhileCommand(std::vector const& args, cmExecutionStatus& status) { -- cgit v0.12 From af24e4ef6e216184b8c207728d6b0312ce3c1525 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 30 Jul 2019 18:15:13 +0200 Subject: cmFunctionBlocker: Move common logic to base --- Source/CMakeLists.txt | 2 ++ Source/cmForEachCommand.cxx | 43 +++++++------------------------------------ Source/cmFunctionBlocker.cxx | 24 ++++++++++++++++++++++++ Source/cmFunctionBlocker.h | 19 +++++++++++++++++-- Source/cmFunctionCommand.cxx | 35 +++++++---------------------------- Source/cmIfCommand.cxx | 43 ++++++------------------------------------- Source/cmMacroCommand.cxx | 35 ++++++----------------------------- Source/cmMakefile.cxx | 2 +- Source/cmWhileCommand.cxx | 43 +++++++------------------------------------ bootstrap | 1 + 10 files changed, 78 insertions(+), 169 deletions(-) create mode 100644 Source/cmFunctionBlocker.cxx diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 041c606..a6babe5 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -531,6 +531,8 @@ set(SRCS cmFindProgramCommand.h cmForEachCommand.cxx cmForEachCommand.h + cmFunctionBlocker.cxx + cmFunctionBlocker.h cmFunctionCommand.cxx cmFunctionCommand.h cmGetCMakePropertyCommand.cxx diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index af32040..53ae479 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -8,6 +8,8 @@ #include #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" @@ -22,23 +24,22 @@ class cmForEachFunctionBlocker : public cmFunctionBlocker public: cmForEachFunctionBlocker(cmMakefile* mf); ~cmForEachFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; + + cm::string_view StartCommandName() const override { return "foreach"_s; } + cm::string_view EndCommandName() const override { return "endforeach"_s; } + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; bool Replay(std::vector const& functions, - cmExecutionStatus& inStatus); + cmExecutionStatus& inStatus) override; std::vector Args; - std::vector Functions; private: cmMakefile* Makefile; - int Depth; }; cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf) : Makefile(mf) - , Depth(0) { this->Makefile->PushLoopBlock(); } @@ -48,36 +49,6 @@ cmForEachFunctionBlocker::~cmForEachFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) -{ - if (lff.Name.Lower == "foreach") { - // record the number of nested foreach commands - this->Depth++; - } else if (lff.Name.Lower == "endforeach") { - // if this is the endofreach for this statement - if (!this->Depth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } - - return this->Replay(this->Functions, inStatus); - } - // close out a nested foreach - this->Depth--; - } - - // record the command - this->Functions.push_back(lff); - - // always return true - return true; -} - bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) { diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx new file mode 100644 index 0000000..2999691 --- /dev/null +++ b/Source/cmFunctionBlocker.cxx @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFunctionBlocker.h" + +#include "cmExecutionStatus.h" +#include "cmMakefile.h" + +bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, + cmExecutionStatus& status) +{ + if (lff.Name.Lower == this->StartCommandName()) { + this->ScopeDepth++; + } else if (lff.Name.Lower == this->EndCommandName()) { + this->ScopeDepth--; + if (this->ScopeDepth == 0U) { + cmMakefile& mf = status.GetMakefile(); + auto self = mf.RemoveFunctionBlocker(this, lff); + return this->Replay(this->Functions, status); + } + } + + this->Functions.push_back(lff); + return true; +} diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h index cd6b05d..8fc2c1c 100644 --- a/Source/cmFunctionBlocker.h +++ b/Source/cmFunctionBlocker.h @@ -3,6 +3,12 @@ #ifndef cmFunctionBlocker_h #define cmFunctionBlocker_h +#include "cmConfigure.h" // IWYU pragma: keep + +#include + +#include "cm_string_view.hxx" + #include "cmListFileCache.h" class cmExecutionStatus; @@ -14,8 +20,8 @@ public: /** * should a function be blocked */ - virtual bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus& status) = 0; + bool IsFunctionBlocked(cmListFileFunction const& lff, + cmExecutionStatus& status); /** * should this function blocker be removed, useful when one function adds a @@ -39,7 +45,16 @@ public: } private: + virtual cm::string_view StartCommandName() const = 0; + virtual cm::string_view EndCommandName() const = 0; + + virtual bool Replay(std::vector const& functions, + cmExecutionStatus& status) = 0; + +private: cmListFileContext StartingContext; + std::vector Functions; + unsigned int ScopeDepth = 1; }; #endif diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 51b6970..6a04196 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -5,6 +5,9 @@ #include #include +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" + #include "cmAlgorithms.h" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" @@ -107,40 +110,16 @@ bool cmFunctionHelperCommand::operator()( class cmFunctionFunctionBlocker : public cmFunctionBlocker { public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; + cm::string_view StartCommandName() const override { return "function"_s; } + cm::string_view EndCommandName() const override { return "endfunction"_s; } + bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; bool Replay(std::vector const& functions, - cmExecutionStatus& status); + cmExecutionStatus& status) override; std::vector Args; - std::vector Functions; - int Depth = 0; }; -bool cmFunctionFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus& status) -{ - // record commands until we hit the ENDFUNCTION - // at the ENDFUNCTION call we shift gears and start looking for invocations - if (lff.Name.Lower == "function") { - this->Depth++; - } else if (lff.Name.Lower == "endfunction") { - // if this is the endfunction for this function then execute - if (!this->Depth) { - auto self = mf.RemoveFunctionBlocker(this, lff); - return this->Replay(this->Functions, status); - } - // decrement for each nested function that ends - this->Depth--; - } - - // if it wasn't an endfunction and we are not executing then we must be - // recording - this->Functions.push_back(lff); - return true; -} - bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) { diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 95f8177..63cdd20 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -3,6 +3,8 @@ #include "cmIfCommand.h" #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" @@ -33,51 +35,19 @@ static std::string cmIfCommandError( class cmIfFunctionBlocker : public cmFunctionBlocker { public: - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; + cm::string_view StartCommandName() const override { return "if"_s; } + cm::string_view EndCommandName() const override { return "endif"_s; } + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; bool Replay(std::vector const& functions, - cmExecutionStatus& inStatus); + cmExecutionStatus& inStatus) override; std::vector Args; - std::vector Functions; bool IsBlocking; bool HasRun = false; bool ElseSeen = false; - unsigned int ScopeDepth = 0; }; -//========================================================================= -bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) -{ - // we start by recording all the functions - if (lff.Name.Lower == "if") { - this->ScopeDepth++; - } else if (lff.Name.Lower == "endif") { - this->ScopeDepth--; - // if this is the endif for this if statement, then start executing - if (!this->ScopeDepth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } - - return this->Replay(this->Functions, inStatus); - } - } - - // record the command - this->Functions.push_back(lff); - - // always return true - return true; -} - -//========================================================================= bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, cmMakefile&) { @@ -235,7 +205,6 @@ bool cmIfCommand(std::vector const& args, { auto fb = cm::make_unique(); // if is isn't true block the commands - fb->ScopeDepth = 1; fb->IsBlocking = !isTrue; if (isTrue) { fb->HasRun = true; diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index e82d6fa..030bb66 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -7,6 +7,8 @@ #include #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmAlgorithms.h" #include "cmExecutionStatus.h" @@ -141,41 +143,16 @@ bool cmMacroHelperCommand::operator()( class cmMacroFunctionBlocker : public cmFunctionBlocker { public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; + cm::string_view StartCommandName() const override { return "macro"_s; } + cm::string_view EndCommandName() const override { return "endmacro"_s; } + bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; bool Replay(std::vector const& functions, - cmExecutionStatus& status); + cmExecutionStatus& status) override; std::vector Args; - std::vector Functions; - int Depth = 0; }; -bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& status) -{ - // record commands until we hit the ENDMACRO - // at the ENDMACRO call we shift gears and start looking for invocations - if (lff.Name.Lower == "macro") { - this->Depth++; - } else if (lff.Name.Lower == "endmacro") { - // if this is the endmacro for this macro then execute - if (!this->Depth) { - auto self = mf.RemoveFunctionBlocker(this, lff); - return this->Replay(this->Functions, status); - } - // decrement for each nested macro that ends - this->Depth--; - } - - // if it wasn't an endmacro and we are not executing then we must be - // recording - this->Functions.push_back(lff); - return true; -} - bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index f297fdf..8c11786 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3070,7 +3070,7 @@ bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - return this->FunctionBlockers.top()->IsFunctionBlocked(lff, *this, status); + return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status); } void cmMakefile::PushFunctionBlockerBarrier() diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 025d14a..bacee58 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -3,6 +3,8 @@ #include "cmWhileCommand.h" #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" @@ -21,23 +23,22 @@ class cmWhileFunctionBlocker : public cmFunctionBlocker public: cmWhileFunctionBlocker(cmMakefile* mf); ~cmWhileFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; + + cm::string_view StartCommandName() const override { return "while"_s; } + cm::string_view EndCommandName() const override { return "endwhile"_s; } + bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; bool Replay(std::vector const& functions, - cmExecutionStatus& inStatus); + cmExecutionStatus& inStatus) override; std::vector Args; - std::vector Functions; private: cmMakefile* Makefile; - int Depth; }; cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf) : Makefile(mf) - , Depth(0) { this->Makefile->PushLoopBlock(); } @@ -47,36 +48,6 @@ cmWhileFunctionBlocker::~cmWhileFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) -{ - // at end of for each execute recorded commands - if (lff.Name.Lower == "while") { - // record the number of while commands past this one - this->Depth++; - } else if (lff.Name.Lower == "endwhile") { - // if this is the endwhile for this while loop then execute - if (!this->Depth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } - return this->Replay(this->Functions, inStatus); - } - // decrement for each nested while that ends - this->Depth--; - } - - // record the command - this->Functions.push_back(lff); - - // always return true - return true; -} - bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, cmMakefile&) { diff --git a/bootstrap b/bootstrap index 7d9631c..5742d53 100755 --- a/bootstrap +++ b/bootstrap @@ -326,6 +326,7 @@ CMAKE_CXX_SOURCES="\ cmFindPathCommand \ cmFindProgramCommand \ cmForEachCommand \ + cmFunctionBlocker \ cmFunctionCommand \ cmFSPermissions \ cmGeneratedFileStream \ -- cgit v0.12 From 6491270e0d3699f5151c08ef41dce84724f9ffc1 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 30 Jul 2019 22:58:40 +0200 Subject: cmFunctionBlocker: Move check for matching args --- Source/cmForEachCommand.cxx | 22 ++++++++-------------- Source/cmFunctionBlocker.cxx | 23 ++++++++++++++++++++++- Source/cmFunctionBlocker.h | 12 +++--------- Source/cmFunctionCommand.cxx | 25 +++++++++---------------- Source/cmIfCommand.cxx | 18 ++++++------------ Source/cmMacroCommand.cxx | 25 +++++++++---------------- Source/cmMakefile.cxx | 20 +------------------- Source/cmMakefile.h | 3 +-- Source/cmWhileCommand.cxx | 17 ++++++----------- 9 files changed, 65 insertions(+), 100 deletions(-) diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 53ae479..10ce459 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -28,7 +28,9 @@ public: cm::string_view StartCommandName() const override { return "foreach"_s; } cm::string_view EndCommandName() const override { return "endforeach"_s; } - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const override; + bool Replay(std::vector const& functions, cmExecutionStatus& inStatus) override; @@ -49,20 +51,12 @@ cmForEachFunctionBlocker::~cmForEachFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) +bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "endforeach") { - std::vector expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments); - // if the endforeach has arguments then make sure - // they match the begin foreach arguments - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } - return false; + std::vector expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; } bool cmForEachFunctionBlocker::Replay( diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx index 2999691..437d4b5 100644 --- a/Source/cmFunctionBlocker.cxx +++ b/Source/cmFunctionBlocker.cxx @@ -2,8 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmFunctionBlocker.h" +#include +#include + #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmMessageType.h" bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, cmExecutionStatus& status) @@ -14,7 +18,24 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, this->ScopeDepth--; if (this->ScopeDepth == 0U) { cmMakefile& mf = status.GetMakefile(); - auto self = mf.RemoveFunctionBlocker(this, lff); + auto self = mf.RemoveFunctionBlocker(); + assert(self.get() == this); + + if (!this->ArgumentsMatch(lff, mf)) { + cmListFileContext const& lfc = this->GetStartingContext(); + cmListFileContext closingContext = + cmListFileContext::FromCommandContext(lff, lfc.FilePath); + std::ostringstream e; + /* clang-format off */ + e << "A logical block opening on the line\n" + << " " << lfc << "\n" + << "closes on the line\n" + << " " << closingContext << "\n" + << "with mis-matching arguments."; + /* clang-format on */ + mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); + } + return this->Replay(this->Functions, status); } } diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h index 8fc2c1c..8b05993 100644 --- a/Source/cmFunctionBlocker.h +++ b/Source/cmFunctionBlocker.h @@ -23,15 +23,6 @@ public: bool IsFunctionBlocked(cmListFileFunction const& lff, cmExecutionStatus& status); - /** - * should this function blocker be removed, useful when one function adds a - * blocker and another must remove it - */ - virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile&) - { - return false; - } - virtual ~cmFunctionBlocker() = default; /** Set/Get the context in which this blocker is created. */ @@ -48,6 +39,9 @@ private: virtual cm::string_view StartCommandName() const = 0; virtual cm::string_view EndCommandName() const = 0; + virtual bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const = 0; + virtual bool Replay(std::vector const& functions, cmExecutionStatus& status) = 0; diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 6a04196..dd0a5d0 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -113,29 +113,22 @@ public: cm::string_view StartCommandName() const override { return "function"_s; } cm::string_view EndCommandName() const override { return "endfunction"_s; } - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool ArgumentsMatch(cmListFileFunction const&, + cmMakefile& mf) const override; + bool Replay(std::vector const& functions, cmExecutionStatus& status) override; std::vector Args; }; -bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) +bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "endfunction") { - std::vector expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); - // if the endfunction has arguments then make sure - // they match the ones in the opening function command - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } - - return false; + std::vector expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments, + this->GetStartingContext().FilePath.c_str()); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; } bool cmFunctionFunctionBlocker::Replay( diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 63cdd20..418a74b 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -38,7 +38,9 @@ public: cm::string_view StartCommandName() const override { return "if"_s; } cm::string_view EndCommandName() const override { return "endif"_s; } - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const override; + bool Replay(std::vector const& functions, cmExecutionStatus& inStatus) override; @@ -48,18 +50,10 @@ public: bool ElseSeen = false; }; -bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile&) +bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const { - if (lff.Name.Lower == "endif") { - // if the endif has arguments, then make sure - // they match the arguments of the matching if - if (lff.Arguments.empty() || lff.Arguments == this->Args) { - return true; - } - } - - return false; + return lff.Arguments.empty() || lff.Arguments == this->Args; } bool cmIfFunctionBlocker::Replay( diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 030bb66..eb328cc 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -146,29 +146,22 @@ public: cm::string_view StartCommandName() const override { return "macro"_s; } cm::string_view EndCommandName() const override { return "endmacro"_s; } - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; + bool ArgumentsMatch(cmListFileFunction const&, + cmMakefile& mf) const override; + bool Replay(std::vector const& functions, cmExecutionStatus& status) override; std::vector Args; }; -bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) +bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "endmacro") { - std::vector expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); - // if the endmacro has arguments make sure they - // match the arguments of the macro - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } - - return false; + std::vector expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments, + this->GetStartingContext().FilePath.c_str()); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; } bool cmMacroFunctionBlocker::Replay( diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8c11786..015453a 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3220,30 +3220,12 @@ void cmMakefile::AddFunctionBlocker(std::unique_ptr fb) this->FunctionBlockers.push(std::move(fb)); } -std::unique_ptr cmMakefile::RemoveFunctionBlocker( - cmFunctionBlocker* fb, const cmListFileFunction& lff) +std::unique_ptr cmMakefile::RemoveFunctionBlocker() { assert(!this->FunctionBlockers.empty()); - assert(this->FunctionBlockers.top().get() == fb); assert(this->FunctionBlockerBarriers.empty() || this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back()); - // Warn if the arguments do not match, but always remove. - if (!fb->ShouldRemove(lff, *this)) { - cmListFileContext const& lfc = fb->GetStartingContext(); - cmListFileContext closingContext = - cmListFileContext::FromCommandContext(lff, lfc.FilePath); - std::ostringstream e; - /* clang-format off */ - e << "A logical block opening on the line\n" - << " " << lfc << "\n" - << "closes on the line\n" - << " " << closingContext << "\n" - << "with mis-matching arguments."; - /* clang-format on */ - this->IssueMessage(MessageType::AUTHOR_WARNING, e.str()); - } - auto b = std::move(this->FunctionBlockers.top()); this->FunctionBlockers.pop(); return b; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 941e335..4d61c05 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -107,8 +107,7 @@ public: * Remove the function blocker whose scope ends with the given command. * This returns ownership of the function blocker object. */ - std::unique_ptr RemoveFunctionBlocker( - cmFunctionBlocker* fb, const cmListFileFunction& lff); + std::unique_ptr RemoveFunctionBlocker(); /** * Try running cmake and building a file. This is used for dynalically diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index bacee58..1e442e5 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -27,7 +27,9 @@ public: cm::string_view StartCommandName() const override { return "while"_s; } cm::string_view EndCommandName() const override { return "endwhile"_s; } - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const override; + bool Replay(std::vector const& functions, cmExecutionStatus& inStatus) override; @@ -48,17 +50,10 @@ cmWhileFunctionBlocker::~cmWhileFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile&) +bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const { - if (lff.Name.Lower == "endwhile") { - // if the endwhile has arguments, then make sure - // they match the arguments of the matching while - if (lff.Arguments.empty() || lff.Arguments == this->Args) { - return true; - } - } - return false; + return lff.Arguments.empty() || lff.Arguments == this->Args; } bool cmWhileFunctionBlocker::Replay( -- cgit v0.12 From 41364824ad84a40c9906b7b5de492e45a74c8945 Mon Sep 17 00:00:00 2001 From: Regina Pfeifer Date: Tue, 30 Jul 2019 23:54:12 +0200 Subject: cmFunctionBlocker: Recycle functions --- Source/cmForEachCommand.cxx | 5 ++--- Source/cmFunctionBlocker.cxx | 3 ++- Source/cmFunctionBlocker.h | 2 +- Source/cmFunctionCommand.cxx | 6 +++--- Source/cmIfCommand.cxx | 7 +++---- Source/cmMacroCommand.cxx | 8 ++++---- Source/cmWhileCommand.cxx | 7 +++---- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 10ce459..1d961be 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -31,7 +31,7 @@ public: bool ArgumentsMatch(cmListFileFunction const& lff, cmMakefile& mf) const override; - bool Replay(std::vector const& functions, + bool Replay(std::vector functions, cmExecutionStatus& inStatus) override; std::vector Args; @@ -60,8 +60,7 @@ bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, } bool cmForEachFunctionBlocker::Replay( - std::vector const& functions, - cmExecutionStatus& inStatus) + std::vector functions, cmExecutionStatus& inStatus) { cmMakefile& mf = inStatus.GetMakefile(); // at end of for each execute recorded commands diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx index 437d4b5..5778a71 100644 --- a/Source/cmFunctionBlocker.cxx +++ b/Source/cmFunctionBlocker.cxx @@ -4,6 +4,7 @@ #include #include +#include #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -36,7 +37,7 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); } - return this->Replay(this->Functions, status); + return this->Replay(std::move(this->Functions), status); } } diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h index 8b05993..87bdccd 100644 --- a/Source/cmFunctionBlocker.h +++ b/Source/cmFunctionBlocker.h @@ -42,7 +42,7 @@ private: virtual bool ArgumentsMatch(cmListFileFunction const& lff, cmMakefile& mf) const = 0; - virtual bool Replay(std::vector const& functions, + virtual bool Replay(std::vector functions, cmExecutionStatus& status) = 0; private: diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index dd0a5d0..610f516 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -116,7 +116,7 @@ public: bool ArgumentsMatch(cmListFileFunction const&, cmMakefile& mf) const override; - bool Replay(std::vector const& functions, + bool Replay(std::vector functions, cmExecutionStatus& status) override; std::vector Args; @@ -132,13 +132,13 @@ bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, } bool cmFunctionFunctionBlocker::Replay( - std::vector const& functions, cmExecutionStatus& status) + std::vector functions, cmExecutionStatus& status) { cmMakefile& mf = status.GetMakefile(); // create a new command and add it to cmake cmFunctionHelperCommand f; f.Args = this->Args; - f.Functions = functions; + f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; mf.RecordPolicies(f.Policies); mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 418a74b..c5cfd8c 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -41,7 +41,7 @@ public: bool ArgumentsMatch(cmListFileFunction const& lff, cmMakefile&) const override; - bool Replay(std::vector const& functions, + bool Replay(std::vector functions, cmExecutionStatus& inStatus) override; std::vector Args; @@ -56,9 +56,8 @@ bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, return lff.Arguments.empty() || lff.Arguments == this->Args; } -bool cmIfFunctionBlocker::Replay( - std::vector const& functions, - cmExecutionStatus& inStatus) +bool cmIfFunctionBlocker::Replay(std::vector functions, + cmExecutionStatus& inStatus) { cmMakefile& mf = inStatus.GetMakefile(); // execute the functions for the true parts of the if statement diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index eb328cc..8689c8f 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -149,7 +149,7 @@ public: bool ArgumentsMatch(cmListFileFunction const&, cmMakefile& mf) const override; - bool Replay(std::vector const& functions, + bool Replay(std::vector functions, cmExecutionStatus& status) override; std::vector Args; @@ -164,15 +164,15 @@ bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; } -bool cmMacroFunctionBlocker::Replay( - std::vector const& functions, cmExecutionStatus& status) +bool cmMacroFunctionBlocker::Replay(std::vector functions, + cmExecutionStatus& status) { cmMakefile& mf = status.GetMakefile(); mf.AppendProperty("MACROS", this->Args[0].c_str()); // create a new command and add it to cmake cmMacroHelperCommand f; f.Args = this->Args; - f.Functions = functions; + f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; mf.RecordPolicies(f.Policies); mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 1e442e5..a396852 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -30,7 +30,7 @@ public: bool ArgumentsMatch(cmListFileFunction const& lff, cmMakefile& mf) const override; - bool Replay(std::vector const& functions, + bool Replay(std::vector functions, cmExecutionStatus& inStatus) override; std::vector Args; @@ -56,9 +56,8 @@ bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, return lff.Arguments.empty() || lff.Arguments == this->Args; } -bool cmWhileFunctionBlocker::Replay( - std::vector const& functions, - cmExecutionStatus& inStatus) +bool cmWhileFunctionBlocker::Replay(std::vector functions, + cmExecutionStatus& inStatus) { cmMakefile& mf = inStatus.GetMakefile(); std::string errorString; -- cgit v0.12