Browse Source

cmProp: refactoring: transform alias in class

To handle safely the values used by CMake variables and properties,
introduce the class cmProp as a replacement from the simple pointer
to std::string instance.
Marc Chevrier 4 years ago
parent
commit
e5cd39ca80
40 changed files with 482 additions and 224 deletions
  1. 1 0
      Source/CMakeLists.txt
  2. 4 4
      Source/CTest/cmCTestStartCommand.cxx
  3. 2 2
      Source/CTest/cmCTestSubmitCommand.cxx
  4. 3 3
      Source/QtDialog/QCMake.cxx
  5. 1 0
      Source/cmCMakePolicyCommand.cxx
  6. 3 3
      Source/cmCacheManager.cxx
  7. 1 1
      Source/cmCacheManager.h
  8. 1 1
      Source/cmCommandArgumentParserHelper.cxx
  9. 4 4
      Source/cmConditionEvaluator.cxx
  10. 4 6
      Source/cmCoreTryCompile.cxx
  11. 3 3
      Source/cmDefinitions.cxx
  12. 2 2
      Source/cmDefinitions.h
  13. 1 0
      Source/cmExportBuildFileGenerator.cxx
  14. 1 0
      Source/cmExportInstallFileGenerator.cxx
  15. 1 2
      Source/cmFileAPICodemodel.cxx
  16. 2 2
      Source/cmFileCommand.cxx
  17. 2 2
      Source/cmFindBase.cxx
  18. 1 0
      Source/cmForEachCommand.cxx
  19. 13 14
      Source/cmGeneratorTarget.cxx
  20. 2 2
      Source/cmGlobalGenerator.cxx
  21. 1 2
      Source/cmGlobalGhsMultiGenerator.cxx
  22. 1 0
      Source/cmIncludeGuardCommand.cxx
  23. 3 8
      Source/cmMakefile.cxx
  24. 1 0
      Source/cmMarkAsAdvancedCommand.cxx
  25. 2 2
      Source/cmOptionCommand.cxx
  26. 1 0
      Source/cmPolicies.cxx
  27. 113 0
      Source/cmProperty.cxx
  28. 205 5
      Source/cmProperty.h
  29. 1 1
      Source/cmPropertyMap.cxx
  30. 7 7
      Source/cmSourceFile.cxx
  31. 9 9
      Source/cmState.cxx
  32. 15 15
      Source/cmStateDirectory.cxx
  33. 1 2
      Source/cmStateSnapshot.cxx
  34. 2 1
      Source/cmStateSnapshot.h
  35. 0 70
      Source/cmStringAlgorithms.cxx
  36. 41 23
      Source/cmStringAlgorithms.h
  37. 22 21
      Source/cmTarget.cxx
  38. 3 3
      Source/cmTargetPropertyComputer.h
  39. 1 4
      Source/cmVisualStudio10TargetGenerator.cxx
  40. 1 0
      bootstrap

+ 1 - 0
Source/CMakeLists.txt

@@ -381,6 +381,7 @@ set(SRCS
   cmProcessOutput.h
   cmProcessTools.cxx
   cmProcessTools.h
+  cmProperty.cxx
   cmProperty.h
   cmPropertyDefinition.cxx
   cmPropertyDefinition.h

+ 4 - 4
Source/CTest/cmCTestStartCommand.cxx

@@ -30,8 +30,8 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
 
   size_t cnt = 0;
   const char* smodel = nullptr;
-  const std::string* src_dir = nullptr;
-  const std::string* bld_dir = nullptr;
+  cmProp src_dir;
+  cmProp bld_dir;
 
   while (cnt < args.size()) {
     if (args[cnt] == "GROUP" || args[cnt] == "TRACK") {
@@ -55,10 +55,10 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
       smodel = args[cnt].c_str();
       cnt++;
     } else if (!src_dir) {
-      src_dir = &args[cnt];
+      src_dir = cmProp(args[cnt]);
       cnt++;
     } else if (!bld_dir) {
-      bld_dir = &args[cnt];
+      bld_dir = cmProp(args[cnt]);
       cnt++;
     } else {
       this->SetError("Too many arguments");

+ 2 - 2
Source/CTest/cmCTestSubmitCommand.cxx

@@ -36,8 +36,8 @@ std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone()
 
 cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
 {
-  const std::string* submitURL = !this->SubmitURL.empty()
-    ? &this->SubmitURL
+  cmProp submitURL = !this->SubmitURL.empty()
+    ? cmProp(this->SubmitURL)
     : this->Makefile->GetDefinition("CTEST_SUBMIT_URL");
 
   if (submitURL) {

+ 3 - 3
Source/QtDialog/QCMake.cxx

@@ -128,11 +128,11 @@ void QCMake::setBinaryDirectory(const QString& _dir)
     }
     cmProp gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
     if (gen) {
-      const std::string* extraGen =
+      cmProp extraGen =
         state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
       std::string curGen =
-        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
-          *gen, extraGen ? *extraGen : "");
+        cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*gen,
+                                                                    *extraGen);
       this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
     }
 

+ 1 - 0
Source/cmCMakePolicyCommand.cxx

@@ -6,6 +6,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"

+ 3 - 3
Source/cmCacheManager.cxx

@@ -500,7 +500,7 @@ cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
 {
   if (const auto* entry = this->GetCacheEntry(key)) {
     if (entry->Initialized) {
-      return &entry->GetValue();
+      return cmProp(entry->GetValue());
     }
   }
   return nullptr;
@@ -568,10 +568,10 @@ std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const
 cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
 {
   if (prop == "TYPE") {
-    return &cmState::CacheEntryTypeToString(this->Type);
+    return cmProp(cmState::CacheEntryTypeToString(this->Type));
   }
   if (prop == "VALUE") {
-    return &this->Value;
+    return cmProp(this->Value);
   }
   return this->Properties.GetPropertyValue(prop);
 }

+ 1 - 1
Source/cmCacheManager.h

@@ -75,7 +75,7 @@ public:
   cmProp GetCacheEntryValue(const std::string& key) const
   {
     if (const auto* entry = this->GetCacheEntry(key)) {
-      return &entry->GetValue();
+      return cmProp(entry->GetValue());
     }
     return nullptr;
   }

+ 1 - 1
Source/cmCommandArgumentParserHelper.cxx

@@ -113,7 +113,7 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var)
   if (this->EscapeQuotes && value) {
     return this->AddString(cmEscapeQuotes(*value));
   }
-  return this->AddString(cmToCStrSafe(value));
+  return this->AddString(value);
 }
 
 const char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var)

+ 4 - 4
Source/cmConditionEvaluator.cxx

@@ -317,7 +317,7 @@ cmProp cmConditionEvaluator::GetVariableOrString(
   cmProp def = this->GetDefinitionIfUnquoted(argument);
 
   if (!def) {
-    def = &argument.GetValue();
+    def = cmProp(argument.GetValue());
   }
 
   return def;
@@ -403,7 +403,7 @@ bool cmConditionEvaluator::GetBooleanValueOld(
   // Old GetVariableOrNumber behavior.
   cmProp def = this->GetDefinitionIfUnquoted(arg);
   if (!def && std::atoi(arg.GetValue().c_str())) {
-    def = &arg.GetValue();
+    def = cmProp(arg.GetValue());
   }
   return !cmIsOff(def);
 }
@@ -649,13 +649,13 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
 
       std::string def_buf;
       if (!def) {
-        def = &args.current->GetValue();
+        def = cmProp(args.current->GetValue());
       } else if (cmHasLiteralPrefix(args.current->GetValue(),
                                     "CMAKE_MATCH_")) {
         // The string to match is owned by our match result variables.
         // Move it to our own buffer before clearing them.
         def_buf = *def;
-        def = &def_buf;
+        def = cmProp(def_buf);
       }
 
       this->Makefile.ClearMatches();

+ 4 - 6
Source/cmCoreTryCompile.cxx

@@ -606,7 +606,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       std::string langFlags = "CMAKE_" + li + "_FLAGS";
       cmProp flags = this->Makefile->GetDefinition(langFlags);
       fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li.c_str(),
-              cmOutputConverter::EscapeForCMake(cmToCStrSafe(flags)).c_str());
+              cmOutputConverter::EscapeForCMake(flags).c_str());
       fprintf(fout,
               "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}"
               " ${COMPILE_DEFINITIONS}\")\n",
@@ -644,9 +644,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
           std::string const langFlagsCfg =
             cmStrCat("CMAKE_", li, "_FLAGS_", cfg);
           cmProp flagsCfg = this->Makefile->GetDefinition(langFlagsCfg);
-          fprintf(
-            fout, "set(%s %s)\n", langFlagsCfg.c_str(),
-            cmOutputConverter::EscapeForCMake(cmToCStrSafe(flagsCfg)).c_str());
+          fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(),
+                  cmOutputConverter::EscapeForCMake(flagsCfg).c_str());
         }
       } break;
     }
@@ -679,8 +678,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
           cmProp exeLinkFlags =
             this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS");
           fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n",
-                  cmOutputConverter::EscapeForCMake(cmToCStrSafe(exeLinkFlags))
-                    .c_str());
+                  cmOutputConverter::EscapeForCMake(exeLinkFlags).c_str());
         }
         break;
     }

+ 3 - 3
Source/cmDefinitions.cxx

@@ -34,11 +34,11 @@ cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key,
   return begin->Map.emplace(key, def).first->second;
 }
 
-const std::string* cmDefinitions::Get(const std::string& key, StackIter begin,
-                                      StackIter end)
+cmProp cmDefinitions::Get(const std::string& key, StackIter begin,
+                          StackIter end)
 {
   Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
-  return def.Value ? def.Value.str_if_stable() : nullptr;
+  return def.Value ? cmProp(def.Value.str_if_stable()) : nullptr;
 }
 
 void cmDefinitions::Raise(const std::string& key, StackIter begin,

+ 2 - 2
Source/cmDefinitions.h

@@ -12,6 +12,7 @@
 #include <cm/string_view>
 
 #include "cmLinkedTree.h"
+#include "cmProperty.h"
 #include "cmString.hxx"
 
 /** \class cmDefinitions
@@ -28,8 +29,7 @@ class cmDefinitions
 public:
   // -- Static member functions
 
-  static const std::string* Get(const std::string& key, StackIter begin,
-                                StackIter end);
+  static cmProp Get(const std::string& key, StackIter begin, StackIter end);
 
   static void Raise(const std::string& key, StackIter begin, StackIter end);
 

+ 1 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -18,6 +18,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"

+ 1 - 0
Source/cmExportInstallFileGenerator.cxx

@@ -16,6 +16,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"

+ 1 - 2
Source/cmFileAPICodemodel.cxx

@@ -813,8 +813,7 @@ Json::Value CodemodelConfig::DumpProject(Project& p)
 Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s)
 {
   Json::Value minimumCMakeVersion;
-  if (std::string const* def =
-        s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
+  if (cmProp def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
     minimumCMakeVersion = Json::objectValue;
     minimumCMakeVersion["string"] = *def;
   }

+ 2 - 2
Source/cmFileCommand.cxx

@@ -1850,7 +1850,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args,
     } else if (*i == "TLS_CAINFO") {
       ++i;
       if (i != args.end()) {
-        cainfo = &(*i);
+        cainfo = cmProp(*i);
       } else {
         status.SetError("DOWNLOAD missing file value for TLS_CAINFO.");
         return false;
@@ -2236,7 +2236,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args,
     } else if (*i == "TLS_CAINFO") {
       ++i;
       if (i != args.end()) {
-        cainfo = &(*i);
+        cainfo = cmProp(*i);
       } else {
         status.SetError("UPLOAD missing file value for TLS_CAINFO.");
         return false;

+ 2 - 2
Source/cmFindBase.cxx

@@ -311,7 +311,7 @@ bool cmFindBase::CheckForVariableDefined()
 
     if (cached && cacheType != cmStateEnums::UNINITIALIZED) {
       this->VariableType = cacheType;
-      if (const auto* hs =
+      if (const auto& hs =
             state->GetCacheEntryProperty(this->VariableName, "HELPSTRING")) {
         this->VariableDocumentation = *hs;
       }
@@ -336,7 +336,7 @@ void cmFindBase::NormalizeFindResult()
   if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0125) ==
       cmPolicies::NEW) {
     // ensure the path returned by find_* command is absolute
-    const auto* existingValue =
+    const auto& existingValue =
       this->Makefile->GetDefinition(this->VariableName);
     std::string value;
     if (!existingValue->empty()) {

+ 1 - 0
Source/cmForEachCommand.cxx

@@ -27,6 +27,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"

+ 13 - 14
Source/cmGeneratorTarget.cxx

@@ -62,7 +62,7 @@ cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>(
   cmGeneratorTarget const* tgt, cmMessenger* /* messenger */,
   cmListFileBacktrace const& /* context */)
 {
-  return &tgt->GetSourcesProperty();
+  return cmProp(tgt->GetSourcesProperty());
 }
 
 template <>
@@ -396,13 +396,7 @@ cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const
 std::string const& cmGeneratorTarget::GetSafeProperty(
   std::string const& prop) const
 {
-  cmProp ret = this->GetProperty(prop);
-  if (ret) {
-    return *ret;
-  }
-
-  static std::string const s_empty;
-  return s_empty;
+  return this->GetProperty(prop);
 }
 
 const char* cmGeneratorTarget::GetOutputTargetType(
@@ -564,7 +558,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
     // framework postfix.
     frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config);
     if (!frameworkPostfix.empty()) {
-      postfix = &frameworkPostfix;
+      postfix = cmProp(frameworkPostfix);
     }
   }
   return postfix ? *postfix : std::string();
@@ -966,7 +960,7 @@ cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
     this->GetLanguageStandardProperty(lang, config);
 
   if (languageStandard) {
-    return &(languageStandard->Value);
+    return cmProp(languageStandard->Value);
   }
 
   return nullptr;
@@ -5121,13 +5115,13 @@ void cmGeneratorTarget::GetFullNameInternal(
   if (this->IsFrameworkOnApple()) {
     fw_prefix =
       cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/');
-    targetPrefix = &fw_prefix;
+    targetPrefix = cmProp(fw_prefix);
     targetSuffix = nullptr;
   }
 
   if (this->IsCFBundleOnApple()) {
     fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/');
-    targetPrefix = &fw_prefix;
+    targetPrefix = cmProp(fw_prefix);
     targetSuffix = nullptr;
   }
 
@@ -5143,7 +5137,7 @@ void cmGeneratorTarget::GetFullNameInternal(
   // EXECUTABLE_SUFFIX attribute.
   if (this->IsFrameworkOnApple() &&
       this->GetGlobalGenerator()->GetName() == "Xcode") {
-    targetSuffix = &configPostfix;
+    targetSuffix = cmProp(configPostfix);
   } else {
     outBase += configPostfix;
   }
@@ -5674,6 +5668,11 @@ std::string valueAsString<std::string>(std::string value)
   return value;
 }
 template <>
+std::string valueAsString<cmProp>(cmProp value)
+{
+  return value ? value : std::string("(unset)");
+}
+template <>
 std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
 {
   return "(unset)";
@@ -5749,7 +5748,7 @@ std::string getTypedProperty<std::string>(
   cmProp value = tgt->GetProperty(prop);
 
   if (genexInterpreter == nullptr) {
-    return valueAsString(cmToCStr(value));
+    return valueAsString(value);
   }
 
   return genexInterpreter->Evaluate(value ? *value : "", prop);

+ 2 - 2
Source/cmGlobalGenerator.cxx

@@ -242,7 +242,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang,
   std::vector<std::string> cnameArgVec;
   if (cname && !cname->empty()) {
     cmExpandList(*cname, cnameArgVec);
-    cname = &cnameArgVec.front();
+    cname = cmProp(cnameArgVec.front());
   }
 
   std::string changeVars;
@@ -2749,7 +2749,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
         singleLine.push_back(cfgArg);
         cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
       } else {
-        cfgArg += cmToCStr(mf->GetDefinition("CMAKE_CFG_INTDIR"));
+        cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR");
       }
       singleLine.push_back(cfgArg);
     }

+ 1 - 2
Source/cmGlobalGhsMultiGenerator.cxx

@@ -186,8 +186,7 @@ void cmGlobalGhsMultiGenerator::EnableLanguage(
 
   mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
 
-  const char* tgtPlatform =
-    cmToCStrSafe(mf->GetDefinition("GHS_TARGET_PLATFORM"));
+  const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM")->c_str();
   if (!tgtPlatform) {
     cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
                            "specified; defaulting to \"integrity\"");

+ 1 - 0
Source/cmIncludeGuardCommand.cxx

@@ -4,6 +4,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmProperty.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"

+ 3 - 8
Source/cmMakefile.cxx

@@ -2579,12 +2579,7 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const
 
 const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
 {
-  static std::string const empty;
-  cmProp def = this->GetDefinition(name);
-  if (!def) {
-    return empty;
-  }
-  return *def;
+  return this->GetDefinition(name);
 }
 
 bool cmMakefile::GetDefExpandList(const std::string& name,
@@ -2967,7 +2962,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew(
               break;
             case ENVIRONMENT:
               if (cmSystemTools::GetEnv(lookup, svalue)) {
-                value = &svalue;
+                value = cmProp(svalue);
               }
               break;
             case CACHE:
@@ -4012,7 +4007,7 @@ cmProp cmMakefile::GetProperty(const std::string& prop) const
                      return pair.first;
                    });
     output = cmJoin(keys, ";");
-    return &output;
+    return cmProp(output);
   }
 
   return this->StateSnapshot.GetDirectory().GetProperty(prop);

+ 1 - 0
Source/cmMarkAsAdvancedCommand.cxx

@@ -6,6 +6,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"

+ 2 - 2
Source/cmOptionCommand.cxx

@@ -29,7 +29,7 @@ bool cmOptionCommand(std::vector<std::string> const& args,
   {
     auto policyStatus =
       status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0077);
-    const auto* existsBeforeSet =
+    const auto& existsBeforeSet =
       status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
     switch (policyStatus) {
       case cmPolicies::WARN:
@@ -77,7 +77,7 @@ bool cmOptionCommand(std::vector<std::string> const& args,
   }
 
   if (checkAndWarn) {
-    const auto* existsAfterSet =
+    const auto& existsAfterSet =
       status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]);
     if (!existsAfterSet) {
       status.GetMakefile().IssueMessage(

+ 1 - 0
Source/cmPolicies.cxx

@@ -10,6 +10,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStateTypes.h"

+ 113 - 0
Source/cmProperty.cxx

@@ -0,0 +1,113 @@
+
+#include "cmProperty.h"
+
+#include <string>
+
+#include <cmext/string_view>
+
+#include "cmStringAlgorithms.h"
+
+std::string cmProp::Empty;
+
+bool cmProp::IsOn(cm::string_view value) noexcept
+{
+  switch (value.size()) {
+    case 1:
+      return value[0] == '1' || value[0] == 'Y' || value[0] == 'y';
+    case 2:
+      return                                    //
+        (value[0] == 'O' || value[0] == 'o') && //
+        (value[1] == 'N' || value[1] == 'n');
+    case 3:
+      return                                    //
+        (value[0] == 'Y' || value[0] == 'y') && //
+        (value[1] == 'E' || value[1] == 'e') && //
+        (value[2] == 'S' || value[2] == 's');
+    case 4:
+      return                                    //
+        (value[0] == 'T' || value[0] == 't') && //
+        (value[1] == 'R' || value[1] == 'r') && //
+        (value[2] == 'U' || value[2] == 'u') && //
+        (value[3] == 'E' || value[3] == 'e');
+    default:
+      break;
+  }
+
+  return false;
+}
+
+bool cmProp::IsOff(cm::string_view value) noexcept
+{
+  switch (value.size()) {
+    case 0:
+      return true;
+    case 1:
+      return value[0] == '0' || value[0] == 'N' || value[0] == 'n';
+    case 2:
+      return                                    //
+        (value[0] == 'N' || value[0] == 'n') && //
+        (value[1] == 'O' || value[1] == 'o');
+    case 3:
+      return                                    //
+        (value[0] == 'O' || value[0] == 'o') && //
+        (value[1] == 'F' || value[1] == 'f') && //
+        (value[2] == 'F' || value[2] == 'f');
+    case 5:
+      return                                    //
+        (value[0] == 'F' || value[0] == 'f') && //
+        (value[1] == 'A' || value[1] == 'a') && //
+        (value[2] == 'L' || value[2] == 'l') && //
+        (value[3] == 'S' || value[3] == 's') && //
+        (value[4] == 'E' || value[4] == 'e');
+    case 6:
+      return                                    //
+        (value[0] == 'I' || value[0] == 'i') && //
+        (value[1] == 'G' || value[1] == 'g') && //
+        (value[2] == 'N' || value[2] == 'n') && //
+        (value[3] == 'O' || value[3] == 'o') && //
+        (value[4] == 'R' || value[4] == 'r') && //
+        (value[5] == 'E' || value[5] == 'e');
+    default:
+      break;
+  }
+
+  return IsNOTFOUND(value);
+}
+bool cmProp::IsNOTFOUND(cm::string_view value) noexcept
+{
+  return (value == "NOTFOUND"_s) || cmHasSuffix(value, "-NOTFOUND"_s);
+}
+
+int cmProp::Compare(cmProp value) const noexcept
+{
+  if (this->Value == nullptr && !value) {
+    return 0;
+  }
+  if (this->Value == nullptr) {
+    return -1;
+  }
+  if (!value) {
+    return 1;
+  }
+  return this->Value->compare(*value);
+}
+
+int cmProp::Compare(cm::string_view value) const noexcept
+{
+  if (this->Value == nullptr && value.data() == nullptr) {
+    return 0;
+  }
+  if (this->Value == nullptr) {
+    return -1;
+  }
+  if (value.data() == nullptr) {
+    return 1;
+  }
+  return cm::string_view(*this->Value).compare(value);
+}
+
+std::ostream& operator<<(std::ostream& o, cmProp v)
+{
+  o << *v;
+  return o;
+}

+ 205 - 5
Source/cmProperty.h

@@ -4,8 +4,12 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
+#include <iosfwd>
 #include <string>
 
+#include <cm/string_view>
+
 class cmProperty
 {
 public:
@@ -23,14 +27,210 @@ public:
   };
 };
 
-using cmProp = const std::string*;
+class cmProp
+{
+public:
+  cmProp() noexcept = default;
+  cmProp(std::nullptr_t) noexcept {}
+  explicit cmProp(const std::string* value) noexcept
+    : Value(value)
+  {
+  }
+  explicit cmProp(const std::string& value) noexcept
+    : Value(&value)
+  {
+  }
+  cmProp(const cmProp& other) noexcept = default;
 
-inline const char* cmToCStr(cmProp p)
+  cmProp& operator=(const cmProp& other) noexcept = default;
+  cmProp& operator=(std::nullptr_t) noexcept
+  {
+    this->Value = nullptr;
+    return *this;
+  }
+
+  const std::string* Get() const noexcept { return this->Value; }
+  const char* GetCStr() const noexcept
+  {
+    return this->Value == nullptr ? nullptr : this->Value->c_str();
+  }
+
+  const std::string* operator->() const noexcept
+  {
+    return this->Value == nullptr ? &cmProp::Empty : this->Value;
+  }
+  const std::string& operator*() const noexcept
+  {
+    return this->Value == nullptr ? cmProp::Empty : *this->Value;
+  }
+
+  explicit operator bool() const noexcept { return this->Value != nullptr; }
+  operator const std::string&() const noexcept { return this->operator*(); }
+  operator cm::string_view() const noexcept { return this->operator*(); }
+
+  /**
+   * Does the value indicate a true or ON value?
+   */
+  bool IsOn() const noexcept
+  {
+    return this->Value != nullptr &&
+      cmProp::IsOn(cm::string_view(*this->Value));
+  }
+  /**
+   * Does the value indicate a false or off value ? Note that this is
+   * not the same as !IsOn(...) because there are a number of
+   * ambiguous values such as "/usr/local/bin" a path will result in
+   * IsOn and IsOff both returning false. Note that the special path
+   * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+   */
+  bool IsOff() const noexcept
+  {
+    return this->Value == nullptr ||
+      cmProp::IsOff(cm::string_view(*this->Value));
+  }
+  /** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
+  bool IsNOTFOUND() const noexcept
+  {
+    return this->Value != nullptr &&
+      cmProp::IsNOTFOUND(cm::string_view(*this->Value));
+  }
+  bool IsEmpty() const noexcept
+  {
+    return this->Value == nullptr || this->Value->empty();
+  }
+
+  bool IsSet() const noexcept
+  {
+    return !this->IsEmpty() && !this->IsNOTFOUND();
+  }
+
+  /**
+   * Does a string indicate a true or ON value?
+   */
+  static bool IsOn(const char* value) noexcept
+  {
+    return value != nullptr && IsOn(cm::string_view(value));
+  }
+  static bool IsOn(cm::string_view) noexcept;
+
+  /**
+   * Compare method has same semantic as std::optional::compare
+   */
+  int Compare(cmProp value) const noexcept;
+  int Compare(cm::string_view value) const noexcept;
+
+  /**
+   * Does a string indicate a false or off value ? Note that this is
+   * not the same as !IsOn(...) because there are a number of
+   * ambiguous values such as "/usr/local/bin" a path will result in
+   * IsOn and IsOff both returning false. Note that the special path
+   * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
+   */
+  static bool IsOff(const char* value) noexcept
+  {
+    return value == nullptr || IsOff(cm::string_view(value));
+  }
+  static bool IsOff(cm::string_view) noexcept;
+
+  /** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
+  static bool IsNOTFOUND(const char* value) noexcept
+  {
+    return value == nullptr || IsNOTFOUND(cm::string_view(value));
+  }
+  static bool IsNOTFOUND(cm::string_view) noexcept;
+
+  static bool IsEmpty(const char* value) noexcept
+  {
+    return value == nullptr || *value == '\0';
+  }
+  static bool IsEmpty(cm::string_view value) noexcept { return value.empty(); }
+
+private:
+  static std::string Empty;
+  const std::string* Value = nullptr;
+};
+
+std::ostream& operator<<(std::ostream& o, cmProp v);
+
+inline bool operator==(cmProp l, cmProp r) noexcept
+{
+  return l.Compare(r) == 0;
+}
+inline bool operator!=(cmProp l, cmProp r) noexcept
 {
-  return p ? p->c_str() : nullptr;
+  return l.Compare(r) != 0;
+}
+inline bool operator<(cmProp l, cmProp r) noexcept
+{
+  return l.Compare(r) < 0;
+}
+inline bool operator<=(cmProp l, cmProp r) noexcept
+{
+  return l.Compare(r) <= 0;
+}
+inline bool operator>(cmProp l, cmProp r) noexcept
+{
+  return l.Compare(r) > 0;
+}
+inline bool operator>=(cmProp l, cmProp r) noexcept
+{
+  return l.Compare(r) >= 0;
 }
 
-inline const char* cmToCStrSafe(cmProp p)
+inline bool operator==(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) == 0;
+}
+inline bool operator!=(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) != 0;
+}
+inline bool operator<(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) < 0;
+}
+inline bool operator<=(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) <= 0;
+}
+inline bool operator>(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) > 0;
+}
+inline bool operator>=(cmProp l, cm::string_view r) noexcept
+{
+  return l.Compare(r) >= 0;
+}
+
+inline bool operator==(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) == 0;
+}
+inline bool operator!=(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) != 0;
+}
+inline bool operator<(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) < 0;
+}
+inline bool operator<=(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) <= 0;
+}
+inline bool operator>(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) > 0;
+}
+inline bool operator>=(cmProp l, std::nullptr_t) noexcept
+{
+  return l.Compare(cmProp{}) >= 0;
+}
+
+/**
+ * Temporary wrapper
+ */
+inline const char* cmToCStr(cmProp p)
 {
-  return p ? p->c_str() : "";
+  return p.GetCStr();
 }

+ 1 - 1
Source/cmPropertyMap.cxx

@@ -46,7 +46,7 @@ cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const
 {
   auto it = this->Map_.find(name);
   if (it != this->Map_.end()) {
-    return &it->second;
+    return cmProp(it->second);
   }
   return nullptr;
 }

+ 7 - 7
Source/cmSourceFile.cxx

@@ -342,7 +342,7 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
   // if it is requested by the user.
   if (prop == propLANGUAGE) {
     // The pointer is valid until `this->Language` is modified.
-    return &this->GetOrDetermineLanguage();
+    return cmProp(this->GetOrDetermineLanguage());
   }
 
   // Special handling for GENERATED property.
@@ -355,9 +355,9 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
           (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)
             ? CheckScope::GlobalAndLocal
             : CheckScope::Global)) {
-      return &propTRUE;
+      return cmProp(propTRUE);
     }
-    return &propFALSE;
+    return cmProp(propFALSE);
   }
 
   // Perform the normal property lookup.
@@ -371,7 +371,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
     if (this->FullPath.empty()) {
       return nullptr;
     }
-    return &this->FullPath;
+    return cmProp(this->FullPath);
   }
 
   // Check for the properties with backtraces.
@@ -382,7 +382,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->IncludeDirectories, ";");
-    return &output;
+    return cmProp(output);
   }
 
   if (prop == propCOMPILE_OPTIONS) {
@@ -392,7 +392,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->CompileOptions, ";");
-    return &output;
+    return cmProp(output);
   }
 
   if (prop == propCOMPILE_DEFINITIONS) {
@@ -402,7 +402,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const
 
     static std::string output;
     output = cmJoin(this->CompileDefinitions, ";");
-    return &output;
+    return cmProp(output);
   }
 
   cmProp retVal = this->Properties.GetPropertyValue(prop);

+ 9 - 9
Source/cmState.cxx

@@ -603,47 +603,47 @@ cmProp cmState::GetGlobalProperty(const std::string& prop)
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_C90_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_C99_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_C11_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
   if (prop == "CMAKE_CUDA_KNOWN_FEATURES") {
     static const std::string s_out(
       &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]);
-    return &s_out;
+    return cmProp(s_out);
   }
 
 #undef STRING_LIST_ELEMENT

+ 15 - 15
Source/cmStateDirectory.cxx

@@ -450,17 +450,17 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
   if (prop == "PARENT_DIRECTORY") {
     cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent();
     if (parent.IsValid()) {
-      return &parent.GetDirectory().GetCurrentSource();
+      return cmProp(parent.GetDirectory().GetCurrentSource());
     }
-    return &output;
+    return cmProp(output);
   }
   if (prop == kBINARY_DIR) {
     output = this->GetCurrentBinary();
-    return &output;
+    return cmProp(output);
   }
   if (prop == kSOURCE_DIR) {
     output = this->GetCurrentSource();
-    return &output;
+    return cmProp(output);
   }
   if (prop == kSUBDIRECTORIES) {
     std::vector<std::string> child_dirs;
@@ -471,15 +471,15 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
       child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
     }
     output = cmJoin(child_dirs, ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == kBUILDSYSTEM_TARGETS) {
     output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "IMPORTED_TARGETS"_s) {
     output = cmJoin(this->DirectoryState->ImportedTargetNames, ";");
-    return &output;
+    return cmProp(output);
   }
 
   if (prop == "LISTFILE_STACK") {
@@ -491,38 +491,38 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const
     }
     std::reverse(listFiles.begin(), listFiles.end());
     output = cmJoin(listFiles, ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "CACHE_VARIABLES") {
     output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
     cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
     output = cmJoin(res, ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "INCLUDE_DIRECTORIES") {
     output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "COMPILE_OPTIONS") {
     output = cmJoin(this->GetCompileOptionsEntries(), ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "COMPILE_DEFINITIONS") {
     output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "LINK_OPTIONS") {
     output = cmJoin(this->GetLinkOptionsEntries(), ";");
-    return &output;
+    return cmProp(output);
   }
   if (prop == "LINK_DIRECTORIES") {
     output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
-    return &output;
+    return cmProp(output);
   }
 
   cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop);

+ 1 - 2
Source/cmStateSnapshot.cxx

@@ -201,8 +201,7 @@ bool cmStateSnapshot::HasDefinedPolicyCMP0011()
   return !this->Position->Policies->IsEmpty();
 }
 
-std::string const* cmStateSnapshot::GetDefinition(
-  std::string const& name) const
+cmProp cmStateSnapshot::GetDefinition(std::string const& name) const
 {
   assert(this->Position->Vars.IsValid());
   return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root);

+ 2 - 1
Source/cmStateSnapshot.h

@@ -12,6 +12,7 @@
 
 #include "cmLinkedTree.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmStateTypes.h"
 
 class cmState;
@@ -23,7 +24,7 @@ public:
   cmStateSnapshot(cmState* state = nullptr);
   cmStateSnapshot(cmState* state, cmStateDetail::PositionType position);
 
-  std::string const* GetDefinition(std::string const& name) const;
+  cmProp GetDefinition(std::string const& name) const;
   bool IsInitialized(std::string const& name) const;
   void SetDefinition(std::string const& name, cm::string_view value);
   void RemoveDefinition(std::string const& name);

+ 0 - 70
Source/cmStringAlgorithms.cxx

@@ -227,76 +227,6 @@ bool cmIsInternallyOn(cm::string_view val)
     (val[3] == 'N' || val[3] == 'n');
 }
 
-bool cmIsNOTFOUND(cm::string_view val)
-{
-  return (val == "NOTFOUND") || cmHasLiteralSuffix(val, "-NOTFOUND");
-}
-
-bool cmIsOn(cm::string_view val)
-{
-  switch (val.size()) {
-    case 1:
-      return val[0] == '1' || val[0] == 'Y' || val[0] == 'y';
-    case 2:
-      return                                //
-        (val[0] == 'O' || val[0] == 'o') && //
-        (val[1] == 'N' || val[1] == 'n');
-    case 3:
-      return                                //
-        (val[0] == 'Y' || val[0] == 'y') && //
-        (val[1] == 'E' || val[1] == 'e') && //
-        (val[2] == 'S' || val[2] == 's');
-    case 4:
-      return                                //
-        (val[0] == 'T' || val[0] == 't') && //
-        (val[1] == 'R' || val[1] == 'r') && //
-        (val[2] == 'U' || val[2] == 'u') && //
-        (val[3] == 'E' || val[3] == 'e');
-    default:
-      break;
-  }
-
-  return false;
-}
-
-bool cmIsOff(cm::string_view val)
-{
-  switch (val.size()) {
-    case 0:
-      return true;
-    case 1:
-      return val[0] == '0' || val[0] == 'N' || val[0] == 'n';
-    case 2:
-      return                                //
-        (val[0] == 'N' || val[0] == 'n') && //
-        (val[1] == 'O' || val[1] == 'o');
-    case 3:
-      return                                //
-        (val[0] == 'O' || val[0] == 'o') && //
-        (val[1] == 'F' || val[1] == 'f') && //
-        (val[2] == 'F' || val[2] == 'f');
-    case 5:
-      return                                //
-        (val[0] == 'F' || val[0] == 'f') && //
-        (val[1] == 'A' || val[1] == 'a') && //
-        (val[2] == 'L' || val[2] == 'l') && //
-        (val[3] == 'S' || val[3] == 's') && //
-        (val[4] == 'E' || val[4] == 'e');
-    case 6:
-      return                                //
-        (val[0] == 'I' || val[0] == 'i') && //
-        (val[1] == 'G' || val[1] == 'g') && //
-        (val[2] == 'N' || val[2] == 'n') && //
-        (val[3] == 'O' || val[3] == 'o') && //
-        (val[4] == 'R' || val[4] == 'r') && //
-        (val[5] == 'E' || val[5] == 'e');
-    default:
-      break;
-  }
-
-  return cmIsNOTFOUND(val);
-}
-
 bool cmStrToLong(const char* str, long* value)
 {
   errno = 0;

+ 41 - 23
Source/cmStringAlgorithms.h

@@ -14,25 +14,12 @@
 
 #include <cm/string_view>
 
+#include "cmProperty.h"
 #include "cmRange.h"
 
 /** String range type.  */
 using cmStringRange = cmRange<std::vector<std::string>::const_iterator>;
 
-/** Check for non-empty string.  */
-inline bool cmNonempty(const char* str)
-{
-  return str && *str;
-}
-inline bool cmNonempty(cm::string_view str)
-{
-  return !str.empty();
-}
-inline bool cmNonempty(std::string const* str)
-{
-  return str && !str->empty();
-}
-
 /** Returns length of a literal string.  */
 template <size_t N>
 constexpr size_t cmStrLen(const char (&/*str*/)[N])
@@ -175,6 +162,10 @@ public:
   cmAlphaNum(unsigned long long int val);
   cmAlphaNum(float val);
   cmAlphaNum(double val);
+  cmAlphaNum(cmProp value)
+    : View_(*value)
+  {
+  }
 
   cm::string_view View() const { return this->View_; }
 
@@ -227,20 +218,44 @@ inline bool cmIsInternallyOn(const char* val)
   return cmIsInternallyOn(cm::string_view(val));
 }
 
+/** Check for non-empty Property/Variable value.  */
+inline bool cmNonempty(cm::string_view val)
+{
+  return !cmProp::IsEmpty(val);
+}
+inline bool cmNonempty(const char* val)
+{
+  return !cmProp::IsEmpty(val);
+}
+inline bool cmNonempty(cmProp val)
+{
+  return !val.IsEmpty();
+}
+
 /** Return true if value is NOTFOUND or ends in -NOTFOUND.  */
-bool cmIsNOTFOUND(cm::string_view val);
+inline bool cmIsNOTFOUND(cm::string_view val)
+{
+  return cmProp::IsNOTFOUND(val);
+}
+inline bool cmIsNOTFOUND(cmProp val)
+{
+  return val.IsNOTFOUND();
+}
 
 /**
  * Does a string indicate a true or ON value? This is not the same as ifdef.
  */
-bool cmIsOn(cm::string_view val);
+inline bool cmIsOn(cm::string_view val)
+{
+  return cmProp::IsOn(val);
+}
 inline bool cmIsOn(const char* val)
 {
-  return val && cmIsOn(cm::string_view(val));
+  return cmProp::IsOn(val);
 }
-inline bool cmIsOn(std::string const* val)
+inline bool cmIsOn(cmProp val)
 {
-  return val && cmIsOn(*val);
+  return val.IsOn();
 }
 
 /**
@@ -250,14 +265,17 @@ inline bool cmIsOn(std::string const* val)
  * IsON and IsOff both returning false. Note that the special path
  * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
  */
-bool cmIsOff(cm::string_view val);
+inline bool cmIsOff(cm::string_view val)
+{
+  return cmProp::IsOff(val);
+}
 inline bool cmIsOff(const char* val)
 {
-  return !val || cmIsOff(cm::string_view(val));
+  return cmProp::IsOff(val);
 }
-inline bool cmIsOff(std::string const* val)
+inline bool cmIsOff(cmProp val)
 {
-  return !val || cmIsOff(*val);
+  return val.IsOff();
 }
 
 /** Returns true if string @a str starts with the character @a prefix.  */

+ 22 - 21
Source/cmTarget.cxx

@@ -157,7 +157,7 @@ cmProp cmTargetPropertyComputer::GetSources<cmTarget>(
   }
   static std::string srcs;
   srcs = ss.str();
-  return &srcs;
+  return cmProp(srcs);
 }
 
 class cmTargetInternals
@@ -1749,7 +1749,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       if (propertyIter == this->impl->LanguageStandardProperties.end()) {
         return nullptr;
       }
-      return &(propertyIter->second.Value);
+      return cmProp(propertyIter->second.Value);
     }
     if (prop == propLINK_LIBRARIES) {
       if (this->impl->LinkImplementationPropertyEntries.empty()) {
@@ -1758,11 +1758,11 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     // the type property returns what type the target is
     if (prop == propTYPE) {
-      return &cmState::GetTargetTypeName(this->GetType());
+      return cmProp(cmState::GetTargetTypeName(this->GetType()));
     }
     if (prop == propINCLUDE_DIRECTORIES) {
       if (this->impl->IncludeDirectoriesEntries.empty()) {
@@ -1771,7 +1771,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->IncludeDirectoriesEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propCOMPILE_FEATURES) {
       if (this->impl->CompileFeaturesEntries.empty()) {
@@ -1780,7 +1780,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileFeaturesEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propCOMPILE_OPTIONS) {
       if (this->impl->CompileOptionsEntries.empty()) {
@@ -1789,7 +1789,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileOptionsEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propCOMPILE_DEFINITIONS) {
       if (this->impl->CompileDefinitionsEntries.empty()) {
@@ -1798,7 +1798,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->CompileDefinitionsEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propLINK_OPTIONS) {
       if (this->impl->LinkOptionsEntries.empty()) {
@@ -1807,7 +1807,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->LinkOptionsEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propLINK_DIRECTORIES) {
       if (this->impl->LinkDirectoriesEntries.empty()) {
@@ -1817,7 +1817,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
       static std::string output;
       output = cmJoin(this->impl->LinkDirectoriesEntries, ";");
 
-      return &output;
+      return cmProp(output);
     }
     if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
       if (this->impl->Utilities.empty()) {
@@ -1834,7 +1834,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
           return item.Value.first;
         });
       output = cmJoin(utilities, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propPRECOMPILE_HEADERS) {
       if (this->impl->PrecompileHeadersEntries.empty()) {
@@ -1843,26 +1843,27 @@ cmProp cmTarget::GetProperty(const std::string& prop) const
 
       static std::string output;
       output = cmJoin(this->impl->PrecompileHeadersEntries, ";");
-      return &output;
+      return cmProp(output);
     }
     if (prop == propIMPORTED) {
-      return this->IsImported() ? &propTRUE : &propFALSE;
+      return this->IsImported() ? cmProp(propTRUE) : cmProp(propFALSE);
     }
     if (prop == propIMPORTED_GLOBAL) {
-      return this->IsImportedGloballyVisible() ? &propTRUE : &propFALSE;
+      return this->IsImportedGloballyVisible() ? cmProp(propTRUE)
+                                               : cmProp(propFALSE);
     }
     if (prop == propNAME) {
-      return &this->GetName();
+      return cmProp(this->GetName());
     }
     if (prop == propBINARY_DIR) {
-      return &this->impl->Makefile->GetStateSnapshot()
-                .GetDirectory()
-                .GetCurrentBinary();
+      return cmProp(this->impl->Makefile->GetStateSnapshot()
+                      .GetDirectory()
+                      .GetCurrentBinary());
     }
     if (prop == propSOURCE_DIR) {
-      return &this->impl->Makefile->GetStateSnapshot()
-                .GetDirectory()
-                .GetCurrentSource();
+      return cmProp(this->impl->Makefile->GetStateSnapshot()
+                      .GetDirectory()
+                      .GetCurrentSource());
     }
   }
 

+ 3 - 3
Source/cmTargetPropertyComputer.h

@@ -65,7 +65,7 @@ private:
                                           context)) {
           return nullptr;
         }
-        return &ComputeLocationForBuild(tgt);
+        return cmProp(ComputeLocationForBuild(tgt));
       }
 
       // Support "LOCATION_<CONFIG>".
@@ -76,7 +76,7 @@ private:
           return nullptr;
         }
         std::string configName = prop.substr(9);
-        return &ComputeLocation(tgt, configName);
+        return cmProp(ComputeLocation(tgt, configName));
       }
 
       // Support "<CONFIG>_LOCATION".
@@ -89,7 +89,7 @@ private:
                                             context)) {
             return nullptr;
           }
-          return &ComputeLocation(tgt, configName);
+          return cmProp(ComputeLocation(tgt, configName));
         }
       }
     }

+ 1 - 4
Source/cmVisualStudio10TargetGenerator.cxx

@@ -490,10 +490,7 @@ void cmVisualStudio10TargetGenerator::Generate()
 
       e1.Element("Platform", this->Platform);
       cmProp projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL");
-      if (!projLabel) {
-        projLabel = &this->Name;
-      }
-      e1.Element("ProjectName", *projLabel);
+      e1.Element("ProjectName", projLabel ? projLabel : this->Name);
       {
         cmProp targetFramework =
           this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");

+ 1 - 0
bootstrap

@@ -426,6 +426,7 @@ CMAKE_CXX_SOURCES="\
   cmPolicies \
   cmProcessOutput \
   cmProjectCommand \
+  cmProperty \
   cmPropertyDefinition \
   cmPropertyMap \
   cmGccDepfileLexerHelper \