diff options
author | Nils Gladitz <nilsgladitz@gmail.com> | 2014-09-04 18:21:28 (GMT) |
---|---|---|
committer | Nils Gladitz <nilsgladitz@gmail.com> | 2014-09-11 19:23:17 (GMT) |
commit | 188a1f236e1594fc46163fbad5e062e3978c1e5a (patch) | |
tree | ee62bcd7bc77a1defe2080a17451c01a985d293a /Source | |
parent | b900c1ccaae7a500dda88240873122d0d899bf93 (diff) | |
download | CMake-188a1f236e1594fc46163fbad5e062e3978c1e5a.zip CMake-188a1f236e1594fc46163fbad5e062e3978c1e5a.tar.gz CMake-188a1f236e1594fc46163fbad5e062e3978c1e5a.tar.bz2 |
If: Introduce policy CMP0054 - don't dereference quoted variables in if()
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmBootstrapCommands2.cxx | 1 | ||||
-rw-r--r-- | Source/cmConditionEvaluator.cxx | 236 | ||||
-rw-r--r-- | Source/cmConditionEvaluator.h | 20 | ||||
-rw-r--r-- | Source/cmExpandedCommandArgument.cxx | 51 | ||||
-rw-r--r-- | Source/cmExpandedCommandArgument.h | 45 | ||||
-rw-r--r-- | Source/cmIfCommand.cxx | 10 | ||||
-rw-r--r-- | Source/cmIfCommand.h | 4 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 61 | ||||
-rw-r--r-- | Source/cmMakefile.h | 35 | ||||
-rw-r--r-- | Source/cmPolicies.cxx | 5 | ||||
-rw-r--r-- | Source/cmPolicies.h | 2 | ||||
-rw-r--r-- | Source/cmWhileCommand.cxx | 2 |
12 files changed, 379 insertions, 93 deletions
diff --git a/Source/cmBootstrapCommands2.cxx b/Source/cmBootstrapCommands2.cxx index 91c189f..5675295 100644 --- a/Source/cmBootstrapCommands2.cxx +++ b/Source/cmBootstrapCommands2.cxx @@ -15,6 +15,7 @@ // like to have CMake to build CMake. #include "cmCommands.h" #include "cmConditionEvaluator.cxx" +#include "cmExpandedCommandArgument.cxx" #include "cmGeneratorExpressionEvaluationFile.cxx" #include "cmGetCMakePropertyCommand.cxx" #include "cmGetDirectoryPropertyCommand.cxx" diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 869d3c5..aba26de 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -14,7 +14,8 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile): Makefile(makefile), - Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)) + Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)), + Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)) { } @@ -36,7 +37,7 @@ cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile): // directly. AND OR take variables or the values 0 or 1. bool cmConditionEvaluator::IsTrue( - const std::vector<std::string> &args, + const std::vector<cmExpandedCommandArgument> &args, std::string &errorString, cmake::MessageType &status) { @@ -99,22 +100,93 @@ bool cmConditionEvaluator::IsTrue( } //========================================================================= +const char* cmConditionEvaluator::GetDefinitionIfUnquoted( + cmExpandedCommandArgument const& argument) const +{ + if((this->Policy54Status != cmPolicies::WARN && + this->Policy54Status != cmPolicies::OLD) && + argument.WasQuoted()) + { + return 0; + } + + const char* def = this->Makefile.GetDefinition(argument.GetValue()); + + if(def && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN) + { + bool hasBeenReported = this->Makefile.HasCMP0054AlreadyBeenReported( + this->Makefile.GetBacktrace()[0]); + + if(!hasBeenReported) + { + cmOStringStream e; + e << (this->Makefile.GetPolicies()->GetPolicyWarning( + cmPolicies::CMP0054)) << "\n"; + e << "Quoted variables like \"" << argument.GetValue() << + "\" will no longer be dereferenced " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str()); + } + } + + return def; +} + +//========================================================================= const char* cmConditionEvaluator::GetVariableOrString( - const std::string& str) const + const cmExpandedCommandArgument& argument) const { - const char* def = this->Makefile.GetDefinition(str); + const char* def = this->GetDefinitionIfUnquoted(argument); if(!def) { - def = str.c_str(); + def = argument.c_str(); } return def; } //========================================================================= +bool cmConditionEvaluator::IsKeyword(std::string const& keyword, + cmExpandedCommandArgument& argument) const +{ + if((this->Policy54Status != cmPolicies::WARN && + this->Policy54Status != cmPolicies::OLD) && + argument.WasQuoted()) + { + return false; + } + + bool isKeyword = argument.GetValue() == keyword; + + if(isKeyword && argument.WasQuoted() && + this->Policy54Status == cmPolicies::WARN) + { + bool hasBeenReported = this->Makefile.HasCMP0054AlreadyBeenReported( + this->Makefile.GetBacktrace()[0]); + + if(!hasBeenReported) + { + cmOStringStream e; + e << (this->Makefile.GetPolicies()->GetPolicyWarning( + cmPolicies::CMP0054)) << "\n"; + e << "Quoted keywords like \"" << argument.GetValue() << + "\" will no longer be interpreted as keywords " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str()); + } + } + + return isKeyword; +} + +//========================================================================= bool cmConditionEvaluator::GetBooleanValue( - std::string& arg) const + cmExpandedCommandArgument& arg) const { // Check basic constants. if (arg == "0") @@ -149,14 +221,14 @@ bool cmConditionEvaluator::GetBooleanValue( } // Check definition. - const char* def = this->Makefile.GetDefinition(arg); + const char* def = this->GetDefinitionIfUnquoted(arg); return !cmSystemTools::IsOff(def); } //========================================================================= // Boolean value behavior from CMake 2.6.4 and below. bool cmConditionEvaluator::GetBooleanValueOld( - std::string const& arg, bool one) const + cmExpandedCommandArgument const& arg, bool one) const { if(one) { @@ -166,12 +238,15 @@ bool cmConditionEvaluator::GetBooleanValueOld( else if(arg == "1") { return true; } else - { return !cmSystemTools::IsOff(this->Makefile.GetDefinition(arg)); } + { + const char* def = this->GetDefinitionIfUnquoted(arg); + return !cmSystemTools::IsOff(def); + } } else { // Old GetVariableOrNumber behavior. - const char* def = this->Makefile.GetDefinition(arg); + const char* def = this->GetDefinitionIfUnquoted(arg); if(!def && atoi(arg.c_str())) { def = arg.c_str(); @@ -183,7 +258,7 @@ bool cmConditionEvaluator::GetBooleanValueOld( //========================================================================= // returns the resulting boolean value bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( - std::string &newArg, + cmExpandedCommandArgument &newArg, std::string &errorString, cmake::MessageType &status, bool oneArg) const @@ -208,7 +283,7 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( case cmPolicies::WARN: { cmPolicies* policies = this->Makefile.GetPolicies(); - errorString = "An argument named \"" + newArg + errorString = "An argument named \"" + newArg.GetValue() + "\" appears in a conditional statement. " + policies->GetPolicyWarning(cmPolicies::CMP0012); status = cmake::AUTHOR_WARNING; @@ -219,7 +294,7 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( case cmPolicies::REQUIRED_ALWAYS: { cmPolicies* policies = this->Makefile.GetPolicies(); - errorString = "An argument named \"" + newArg + errorString = "An argument named \"" + newArg.GetValue() + "\" appears in a conditional statement. " + policies->GetRequiredPolicyError(cmPolicies::CMP0012); status = cmake::FATAL_ERROR; @@ -257,11 +332,11 @@ void cmConditionEvaluator::HandlePredicate(bool value, int &reducible, { if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP1); argP1 = arg; @@ -279,11 +354,11 @@ void cmConditionEvaluator::HandleBinaryOp(bool value, int &reducible, { if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP2); newArgs.erase(argP1); @@ -302,23 +377,23 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, do { reducible = 0; - std::list<std::string>::iterator arg = newArgs.begin(); + cmArgumentList::iterator arg = newArgs.begin(); while (arg != newArgs.end()) { - if (*arg == "(") + if (IsKeyword("(", *arg)) { // search for the closing paren for this opening one - std::list<std::string>::iterator argClose; + cmArgumentList::iterator argClose; argClose = arg; argClose++; unsigned int depth = 1; while (argClose != newArgs.end() && depth) { - if (*argClose == "(") + if (this->IsKeyword("(", *argClose)) { depth++; } - if (*argClose == ")") + if (this->IsKeyword(")", *argClose)) { depth--; } @@ -331,10 +406,10 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, return false; } // store the reduced args in this vector - std::vector<std::string> newArgs2; + std::vector<cmExpandedCommandArgument> newArgs2; // copy to the list structure - std::list<std::string>::iterator argP1 = arg; + cmArgumentList::iterator argP1 = arg; argP1++; for(; argP1 != argClose; argP1++) { @@ -347,11 +422,11 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs, this->IsTrue(newArgs2, errorString, status); if(value) { - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } argP1 = arg; argP1++; @@ -374,77 +449,78 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList &newArgs, do { reducible = 0; - std::list<std::string>::iterator arg = newArgs.begin(); - std::list<std::string>::iterator argP1; - std::list<std::string>::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); // does a file exist - if (*arg == "EXISTS" && argP1 != newArgs.end()) + if (this->IsKeyword("EXISTS", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileExists((argP1)->c_str()), + cmSystemTools::FileExists(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a directory with this name exist - if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_DIRECTORY", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsDirectory((argP1)->c_str()), + cmSystemTools::FileIsDirectory(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a symlink with this name exist - if (*arg == "IS_SYMLINK" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_SYMLINK", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsSymlink((argP1)->c_str()), + cmSystemTools::FileIsSymlink(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // is the given path an absolute path ? - if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end()) + if (this->IsKeyword("IS_ABSOLUTE", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - cmSystemTools::FileIsFullPath((argP1)->c_str()), + cmSystemTools::FileIsFullPath(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a command exist - if (*arg == "COMMAND" && argP1 != newArgs.end()) + if (this->IsKeyword("COMMAND", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - this->Makefile.CommandExists((argP1)->c_str()), + this->Makefile.CommandExists(argP1->c_str()), reducible, arg, newArgs, argP1, argP2); } // does a policy exist - if (*arg == "POLICY" && argP1 != newArgs.end()) + if (this->IsKeyword("POLICY", *arg) && argP1 != newArgs.end()) { cmPolicies::PolicyID pid; this->HandlePredicate( - this->Makefile.GetPolicies()->GetPolicyID((argP1)->c_str(), pid), - reducible, arg, newArgs, argP1, argP2); + this->Makefile.GetPolicies()->GetPolicyID( + argP1->c_str(), pid), + reducible, arg, newArgs, argP1, argP2); } // does a target exist - if (*arg == "TARGET" && argP1 != newArgs.end()) + if (this->IsKeyword("TARGET", *arg) && argP1 != newArgs.end()) { this->HandlePredicate( - this->Makefile.FindTargetToUse(*argP1)?true:false, + this->Makefile.FindTargetToUse(argP1->GetValue())?true:false, reducible, arg, newArgs, argP1, argP2); } // is a variable defined - if (*arg == "DEFINED" && argP1 != newArgs.end()) + if (this->IsKeyword("DEFINED", *arg) && argP1 != newArgs.end()) { - size_t argP1len = argP1->size(); + size_t argP1len = argP1->GetValue().size(); bool bdef = false; - if(argP1len > 4 && argP1->substr(0, 4) == "ENV{" && - argP1->operator[](argP1len-1) == '}') + if(argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" && + argP1->GetValue().operator[](argP1len-1) == '}') { - std::string env = argP1->substr(4, argP1len-5); + std::string env = argP1->GetValue().substr(4, argP1len-5); bdef = cmSystemTools::GetEnv(env.c_str())?true:false; } else { - bdef = this->Makefile.IsDefinitionSet(*(argP1)); + bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); } this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2); } @@ -467,18 +543,18 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, do { reducible = 0; - std::list<std::string>::iterator arg = newArgs.begin(); - std::list<std::string>::iterator argP1; - std::list<std::string>::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); if (argP1 != newArgs.end() && argP2 != newArgs.end() && - *(argP1) == "MATCHES") + IsKeyword("MATCHES", *argP1)) { def = this->GetVariableOrString(*arg); - const char* rex = (argP2)->c_str(); + const char* rex = argP2->c_str(); this->Makefile.ClearMatches(); cmsys::RegularExpression regEntry; if ( !regEntry.compile(rex) ) @@ -492,11 +568,11 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, if (regEntry.find(def)) { this->Makefile.StoreMatches(regEntry); - *arg = "1"; + *arg = cmExpandedCommandArgument("1", true); } else { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); } newArgs.erase(argP2); newArgs.erase(argP1); @@ -505,9 +581,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, reducible = 1; } - if (argP1 != newArgs.end() && *arg == "MATCHES") + if (argP1 != newArgs.end() && this->IsKeyword("MATCHES", *arg)) { - *arg = "0"; + *arg = cmExpandedCommandArgument("0", true); newArgs.erase(argP1); argP1 = arg; this->IncrementArguments(newArgs,argP1,argP2); @@ -515,8 +591,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "LESS" || *(argP1) == "GREATER" || - *(argP1) == "EQUAL")) + (this->IsKeyword("LESS", *argP1) || + this->IsKeyword("GREATER", *argP1) || + this->IsKeyword("EQUAL", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -540,14 +617,14 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, { result = (lhs == rhs); } - HandleBinaryOp(result, + this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "STRLESS" || - *(argP1) == "STREQUAL" || - *(argP1) == "STRGREATER")) + (this->IsKeyword("STRLESS", *argP1) || + this->IsKeyword("STREQUAL", *argP1) || + this->IsKeyword("STRGREATER", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -570,8 +647,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, } if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (*(argP1) == "VERSION_LESS" || *(argP1) == "VERSION_GREATER" || - *(argP1) == "VERSION_EQUAL")) + (this->IsKeyword("VERSION_LESS", *argP1) || + this->IsKeyword("VERSION_GREATER", *argP1) || + this->IsKeyword("VERSION_EQUAL", *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); @@ -591,11 +669,11 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, // is file A newer than file B if (argP1 != newArgs.end() && argP2 != newArgs.end() && - *(argP1) == "IS_NEWER_THAN") + this->IsKeyword("IS_NEWER_THAN", *argP1)) { int fileIsNewer=0; - bool success=cmSystemTools::FileTimeCompare(arg->c_str(), - (argP2)->c_str(), + bool success=cmSystemTools::FileTimeCompare(arg->GetValue(), + (argP2)->GetValue(), &fileIsNewer); this->HandleBinaryOp( (success==false || fileIsNewer==1 || fileIsNewer==0), @@ -619,14 +697,14 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList &newArgs, do { reducible = 0; - std::list<std::string>::iterator arg = newArgs.begin(); - std::list<std::string>::iterator argP1; - std::list<std::string>::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; IncrementArguments(newArgs,argP1,argP2); - if (argP1 != newArgs.end() && *arg == "NOT") + if (argP1 != newArgs.end() && IsKeyword("NOT", *arg)) { bool rhs = this->GetBooleanValueWithAutoDereference(*argP1, errorString, @@ -652,14 +730,14 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList &newArgs, do { reducible = 0; - std::list<std::string>::iterator arg = newArgs.begin(); - std::list<std::string>::iterator argP1; - std::list<std::string>::iterator argP2; + cmArgumentList::iterator arg = newArgs.begin(); + cmArgumentList::iterator argP1; + cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; IncrementArguments(newArgs,argP1,argP2); - if (argP1 != newArgs.end() && *(argP1) == "AND" && + if (argP1 != newArgs.end() && IsKeyword("AND", *argP1) && argP2 != newArgs.end()) { lhs = this->GetBooleanValueWithAutoDereference(*arg, @@ -672,7 +750,7 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList &newArgs, reducible, arg, newArgs, argP1, argP2); } - if (argP1 != newArgs.end() && *(argP1) == "OR" && + if (argP1 != newArgs.end() && this->IsKeyword("OR", *argP1) && argP2 != newArgs.end()) { lhs = this->GetBooleanValueWithAutoDereference(*arg, diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index 9076988..01624f9 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -13,36 +13,41 @@ #define cmConditionEvaluator_h #include "cmCommand.h" +#include "cmExpandedCommandArgument.h" class cmConditionEvaluator { public: - typedef std::list<std::string> cmArgumentList; + typedef std::list<cmExpandedCommandArgument> cmArgumentList; cmConditionEvaluator(cmMakefile& makefile); // this is a shared function for both If and Else to determine if the // arguments were valid, and if so, was the response true. If there is // an error, the errorString will be set. - bool IsTrue(const std::vector<std::string> &args, + bool IsTrue(const std::vector<cmExpandedCommandArgument> &args, std::string &errorString, cmake::MessageType &status); private: + // Filter the given variable definition based on policy CMP0054. + const char* GetDefinitionIfUnquoted( + const cmExpandedCommandArgument& argument) const; + const char* GetVariableOrString( - const std::string& argument) const; + const cmExpandedCommandArgument& argument) const; bool IsKeyword(std::string const& keyword, - std::string& argument) const; + cmExpandedCommandArgument& argument) const; bool GetBooleanValue( - std::string& arg) const; + cmExpandedCommandArgument& arg) const; bool GetBooleanValueOld( - std::string const& arg, bool one) const; + cmExpandedCommandArgument const& arg, bool one) const; bool GetBooleanValueWithAutoDereference( - std::string &newArg, + cmExpandedCommandArgument &newArg, std::string &errorString, cmake::MessageType &status, bool oneArg = false) const; @@ -85,6 +90,7 @@ private: cmMakefile& Makefile; cmPolicies::PolicyStatus Policy12Status; + cmPolicies::PolicyStatus Policy54Status; }; #endif diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx new file mode 100644 index 0000000..4477cf5 --- /dev/null +++ b/Source/cmExpandedCommandArgument.cxx @@ -0,0 +1,51 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmExpandedCommandArgument.h" + +cmExpandedCommandArgument::cmExpandedCommandArgument(): + Quoted(false) +{ + +} + +cmExpandedCommandArgument::cmExpandedCommandArgument( + std::string const& value, bool quoted): + Value(value), Quoted(quoted) +{ + +} + +std::string const& cmExpandedCommandArgument::GetValue() const +{ + return this->Value; +} + +bool cmExpandedCommandArgument::WasQuoted() const +{ + return this->Quoted; +} + +bool cmExpandedCommandArgument::operator== (std::string const& value) const +{ + return this->Value == value; +} + +bool cmExpandedCommandArgument::empty() const +{ + return this->Value.empty(); +} + +const char* cmExpandedCommandArgument::c_str() const +{ + return this->Value.c_str(); +} diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h new file mode 100644 index 0000000..f4e1517 --- /dev/null +++ b/Source/cmExpandedCommandArgument.h @@ -0,0 +1,45 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2014 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExpandedCommandArgument_h +#define cmExpandedCommandArgument_h + +#include "cmStandardIncludes.h" + +/** \class cmExpandedCommandArgument + * \brief Represents an expanded command argument + * + * cmCommandArgument stores a string representing an expanded + * command argument and context information. + */ + +class cmExpandedCommandArgument +{ +public: + cmExpandedCommandArgument(); + cmExpandedCommandArgument(std::string const& value, bool quoted); + + std::string const& GetValue() const; + + bool WasQuoted() const; + + bool operator== (std::string const& value) const; + + bool empty() const; + + const char* c_str() const; + +private: + std::string Value; + bool Quoted; +}; + +#endif diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 25ee25a..f728c15 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -20,15 +20,15 @@ static std::string cmIfCommandError( - cmMakefile* mf, std::vector<std::string> const& args) + cmMakefile* mf, std::vector<cmExpandedCommandArgument> const& args) { cmLocalGenerator* lg = mf->GetLocalGenerator(); std::string err = "given arguments:\n "; - for(std::vector<std::string>::const_iterator i = args.begin(); + for(std::vector<cmExpandedCommandArgument>::const_iterator i = args.begin(); i != args.end(); ++i) { err += " "; - err += lg->EscapeForCMake(*i); + err += lg->EscapeForCMake(i->GetValue()); } err += "\n"; return err; @@ -105,7 +105,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, std::string errorString; - std::vector<std::string> expandedArguments; + std::vector<cmExpandedCommandArgument> expandedArguments; mf.ExpandArguments(this->Functions[c].Arguments, expandedArguments); @@ -189,7 +189,7 @@ bool cmIfCommand { std::string errorString; - std::vector<std::string> expandedArguments; + std::vector<cmExpandedCommandArgument> expandedArguments; this->Makefile->ExpandArguments(args, expandedArguments); cmake::MessageType status; diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index ea2a68f..689efce 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -70,6 +70,10 @@ public: */ virtual bool IsScriptable() const { return true; } + // Filter the given variable definition based on policy CMP0054. + static const char* GetDefinitionIfUnquoted( + const cmMakefile* mf, cmExpandedCommandArgument const& argument); + cmTypeMacro(cmIfCommand, cmCommand); }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 04b2d27..3017d15 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3292,6 +3292,7 @@ void cmMakefile::PopFunctionBlockerBarrier(bool reportError) this->FunctionBlockerBarriers.pop_back(); } +//---------------------------------------------------------------------------- bool cmMakefile::ExpandArguments( std::vector<cmListFileArgument> const& inArgs, std::vector<std::string>& outArgs) const @@ -3328,6 +3329,47 @@ bool cmMakefile::ExpandArguments( } //---------------------------------------------------------------------------- +bool cmMakefile::ExpandArguments( + std::vector<cmListFileArgument> const& inArgs, + std::vector<cmExpandedCommandArgument>& outArgs) const +{ + std::vector<cmListFileArgument>::const_iterator i; + std::string value; + outArgs.reserve(inArgs.size()); + for(i = inArgs.begin(); i != inArgs.end(); ++i) + { + // No expansion in a bracket argument. + if(i->Delim == cmListFileArgument::Bracket) + { + outArgs.push_back(cmExpandedCommandArgument(i->Value, true)); + continue; + } + // Expand the variables in the argument. + value = i->Value; + this->ExpandVariablesInString(value, false, false, false, + i->FilePath, i->Line, + false, false); + + // If the argument is quoted, it should be one argument. + // Otherwise, it may be a list of arguments. + if(i->Delim == cmListFileArgument::Quoted) + { + outArgs.push_back(cmExpandedCommandArgument(value, true)); + } + else + { + std::vector<std::string> stringArgs; + cmSystemTools::ExpandListArgument(value, stringArgs); + for(size_t j = 0; j < stringArgs.size(); ++j) + { + outArgs.push_back(cmExpandedCommandArgument(stringArgs[j], false)); + } + } + } + return !cmSystemTools::GetFatalErrorOccured(); +} + +//---------------------------------------------------------------------------- void cmMakefile::AddFunctionBlocker(cmFunctionBlocker* fb) { if(!this->CallStack.empty()) @@ -4938,12 +4980,14 @@ void cmMakefile::PopPolicyBarrier(bool reportError) this->PolicyBarriers.pop_back(); } +//---------------------------------------------------------------------------- bool cmMakefile::SetPolicyVersion(const char *version) { return this->GetCMakeInstance()->GetPolicies()-> ApplyPolicyVersion(this,version); } +//---------------------------------------------------------------------------- cmPolicies *cmMakefile::GetPolicies() const { if (!this->GetCMakeInstance()) @@ -4954,6 +4998,23 @@ cmPolicies *cmMakefile::GetPolicies() const } //---------------------------------------------------------------------------- +bool cmMakefile::HasCMP0054AlreadyBeenReported( + cmListFileContext context) const +{ + cmCMP0054Id id(context); + + bool alreadyReported = + this->CMP0054ReportedIds.find(id) != this->CMP0054ReportedIds.end(); + + if(!alreadyReported) + { + this->CMP0054ReportedIds.insert(id); + } + + return alreadyReported; +} + +//---------------------------------------------------------------------------- void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) { /* Record the setting of every policy. */ diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index d728a62..164290a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -21,6 +21,7 @@ #include "cmTarget.h" #include "cmNewLineStyle.h" #include "cmGeneratorTarget.h" +#include "cmExpandedCommandArgument.h" #include "cmake.h" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -375,7 +376,35 @@ public: /** * Get the Policies Instance */ - cmPolicies *GetPolicies() const; + cmPolicies *GetPolicies() const; + + struct cmCMP0054Id + { + cmCMP0054Id(cmListFileContext const& context): + Context(context) + { + + } + + bool operator< (cmCMP0054Id const& id) const + { + if(this->Context.FilePath != id.Context.FilePath) + return this->Context.FilePath < id.Context.FilePath; + + return this->Context.Line < id.Context.Line; + } + + cmListFileContext Context; + }; + + mutable std::set<cmCMP0054Id> CMP0054ReportedIds; + + /** + * Determine if the given context, name pair has already been reported + * in context of CMP0054. + */ + bool HasCMP0054AlreadyBeenReported( + cmListFileContext context) const; /** * Add an auxiliary directory to the build. @@ -770,6 +799,10 @@ public: */ bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs, std::vector<std::string>& outArgs) const; + + bool ExpandArguments(std::vector<cmListFileArgument> const& inArgs, + std::vector<cmExpandedCommandArgument>& outArgs) const; + /** * Get the instance */ diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 693945d..a420f59 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -359,6 +359,11 @@ cmPolicies::cmPolicies() CMP0053, "CMP0053", "Simplify variable reference and escape sequence evaluation.", 3,1,0, cmPolicies::WARN); + + this->DefinePolicy( + CMP0054, "CMP0054", + "Only interpret if() arguments as variables or keywords when unquoted.", + 3,1,0, cmPolicies::WARN); } cmPolicies::~cmPolicies() diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 5d69d14..7c73da8 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -109,6 +109,8 @@ public: /// INTERFACE_INCLUDE_DIRECTORIES CMP0053, ///< Simplify variable reference and escape sequence evaluation + CMP0054, ///< Only interpret if() arguments as variables + /// or keywords when unquoted. /** \brief Always the last entry. * diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 5565b8a..851c4cb 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -34,7 +34,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf, std::string errorString; - std::vector<std::string> expandedArguments; + std::vector<cmExpandedCommandArgument> expandedArguments; mf.ExpandArguments(this->Args, expandedArguments); cmake::MessageType messageType; |