Index: lldb/include/lldb/Interpreter/OptionValue.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValue.h +++ lldb/include/lldb/Interpreter/OptionValue.h @@ -87,7 +87,8 @@ virtual void Clear() = 0; - virtual lldb::OptionValueSP DeepCopy() const = 0; + virtual lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const; virtual void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request); @@ -306,6 +307,8 @@ m_parent_wp = parent_sp; } + lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); } + void SetValueChangedCallback(std::function callback) { assert(!m_callback); m_callback = std::move(callback); @@ -317,6 +320,10 @@ } protected: + // Must be overriden by a derived class for correct downcasting the result of + // DeepCopy to it. + virtual lldb::OptionValueSP Clone() const = 0; + lldb::OptionValueWP m_parent_wp; std::function m_callback; bool m_value_was_set; // This can be used to see if a value has been set Index: lldb/include/lldb/Interpreter/OptionValueArch.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueArch.h +++ lldb/include/lldb/Interpreter/OptionValueArch.h @@ -49,8 +49,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, lldb_private::CompletionRequest &request) override; @@ -71,6 +69,8 @@ void SetDefaultValue(const ArchSpec &value) { m_default_value = value; } protected: + lldb::OptionValueSP Clone() const override; + ArchSpec m_current_value; ArchSpec m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValueArgs.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueArgs.h +++ lldb/include/lldb/Interpreter/OptionValueArgs.h @@ -19,11 +19,14 @@ : OptionValueArray( OptionValue::ConvertTypeToMask(OptionValue::eTypeString)) {} - ~OptionValueArgs() override {} + ~OptionValueArgs() override = default; - size_t GetArgs(Args &args); + size_t GetArgs(Args &args) const; Type GetType() const override { return eTypeArgs; } + +protected: + lldb::OptionValueSP Clone() const override; }; } // namespace lldb_private Index: lldb/include/lldb/Interpreter/OptionValueArray.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueArray.h +++ lldb/include/lldb/Interpreter/OptionValueArray.h @@ -38,7 +38,8 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; bool IsAggregateValue() const override { return true; } @@ -112,6 +113,8 @@ Status SetArgs(const Args &args, VarSetOperationType op); protected: + lldb::OptionValueSP Clone() const override; + typedef std::vector collection; uint32_t m_type_mask; Index: lldb/include/lldb/Interpreter/OptionValueBoolean.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueBoolean.h +++ lldb/include/lldb/Interpreter/OptionValueBoolean.h @@ -72,9 +72,9 @@ void SetDefaultValue(bool value) { m_default_value = value; } - lldb::OptionValueSP DeepCopy() const override; - protected: + lldb::OptionValueSP Clone() const override; + bool m_current_value; bool m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValueChar.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueChar.h +++ lldb/include/lldb/Interpreter/OptionValueChar.h @@ -55,9 +55,9 @@ void SetDefaultValue(char value) { m_default_value = value; } - lldb::OptionValueSP DeepCopy() const override; - protected: + lldb::OptionValueSP Clone() const override; + char m_current_value; char m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValueDictionary.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueDictionary.h +++ lldb/include/lldb/Interpreter/OptionValueDictionary.h @@ -40,7 +40,8 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; bool IsAggregateValue() const override { return true; } @@ -72,6 +73,8 @@ Status SetArgs(const Args &args, VarSetOperationType op); protected: + lldb::OptionValueSP Clone() const override; + typedef std::map collection; uint32_t m_type_mask; collection m_values; Index: lldb/include/lldb/Interpreter/OptionValueEnumeration.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueEnumeration.h +++ lldb/include/lldb/Interpreter/OptionValueEnumeration.h @@ -49,8 +49,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; @@ -72,6 +70,8 @@ protected: void SetEnumerations(const OptionEnumValues &enumerators); + lldb::OptionValueSP Clone() const override; + enum_type m_current_value; enum_type m_default_value; EnumerationMap m_enumerations; Index: lldb/include/lldb/Interpreter/OptionValueFileColonLine.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueFileColonLine.h +++ lldb/include/lldb/Interpreter/OptionValueFileColonLine.h @@ -38,8 +38,6 @@ m_column_number = LLDB_INVALID_COLUMN_NUMBER; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; @@ -50,6 +48,8 @@ void SetCompletionMask(uint32_t mask) { m_completion_mask = mask; } protected: + lldb::OptionValueSP Clone() const override; + FileSpec m_file_spec; uint32_t m_line_number; uint32_t m_column_number; Index: lldb/include/lldb/Interpreter/OptionValueFileSpec.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueFileSpec.h +++ lldb/include/lldb/Interpreter/OptionValueFileSpec.h @@ -45,8 +45,6 @@ m_data_mod_time = llvm::sys::TimePoint<>(); } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; @@ -72,6 +70,8 @@ void SetCompletionMask(uint32_t mask) { m_completion_mask = mask; } protected: + lldb::OptionValueSP Clone() const override; + FileSpec m_current_value; FileSpec m_default_value; lldb::DataBufferSP m_data_sp; Index: lldb/include/lldb/Interpreter/OptionValueFileSpecList.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueFileSpecList.h +++ lldb/include/lldb/Interpreter/OptionValueFileSpecList.h @@ -18,12 +18,12 @@ class OptionValueFileSpecList : public OptionValue { public: - OptionValueFileSpecList() : OptionValue(), m_current_value() {} + OptionValueFileSpecList() = default; - OptionValueFileSpecList(const FileSpecList ¤t_value) - : OptionValue(), m_current_value(current_value) {} + OptionValueFileSpecList(const OptionValueFileSpecList &other) + : OptionValue(other), m_current_value(other.GetCurrentValue()) {} - ~OptionValueFileSpecList() override {} + ~OptionValueFileSpecList() override = default; // Virtual subclass pure virtual overrides @@ -42,8 +42,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - bool IsAggregateValue() const override { return true; } // Subclass specific functions @@ -64,6 +62,8 @@ } protected: + lldb::OptionValueSP Clone() const override; + mutable std::recursive_mutex m_mutex; FileSpecList m_current_value; }; Index: lldb/include/lldb/Interpreter/OptionValueFormat.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueFormat.h +++ lldb/include/lldb/Interpreter/OptionValueFormat.h @@ -40,8 +40,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions lldb::Format GetCurrentValue() const { return m_current_value; } @@ -53,6 +51,8 @@ void SetDefaultValue(lldb::Format value) { m_default_value = value; } protected: + lldb::OptionValueSP Clone() const override; + lldb::Format m_current_value; lldb::Format m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValueFormatEntity.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueFormatEntity.h +++ lldb/include/lldb/Interpreter/OptionValueFormatEntity.h @@ -33,8 +33,6 @@ void Clear() override; - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; @@ -53,6 +51,8 @@ const FormatEntity::Entry &GetDefaultValue() const { return m_default_entry; } protected: + lldb::OptionValueSP Clone() const override; + std::string m_current_format; std::string m_default_format; FormatEntity::Entry m_current_entry; Index: lldb/include/lldb/Interpreter/OptionValueLanguage.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueLanguage.h +++ lldb/include/lldb/Interpreter/OptionValueLanguage.h @@ -43,8 +43,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions lldb::LanguageType GetCurrentValue() const { return m_current_value; } @@ -56,6 +54,8 @@ void SetDefaultValue(lldb::LanguageType value) { m_default_value = value; } protected: + lldb::OptionValueSP Clone() const override; + lldb::LanguageType m_current_value; lldb::LanguageType m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValuePathMappings.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValuePathMappings.h +++ lldb/include/lldb/Interpreter/OptionValuePathMappings.h @@ -37,8 +37,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - bool IsAggregateValue() const override { return true; } // Subclass specific functions @@ -48,6 +46,8 @@ const PathMappingList &GetCurrentValue() const { return m_path_mappings; } protected: + lldb::OptionValueSP Clone() const override; + PathMappingList m_path_mappings; bool m_notify_changes; }; Index: lldb/include/lldb/Interpreter/OptionValueProperties.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueProperties.h +++ lldb/include/lldb/Interpreter/OptionValueProperties.h @@ -18,25 +18,27 @@ #include "lldb/Utility/ConstString.h" namespace lldb_private { +class Properties; class OptionValueProperties : public OptionValue, public std::enable_shared_from_this { public: - OptionValueProperties() - : OptionValue(), m_name(), m_properties(), m_name_to_index() {} + OptionValueProperties() = default; OptionValueProperties(ConstString name); - OptionValueProperties(const OptionValueProperties &global_properties); - ~OptionValueProperties() override = default; Type GetType() const override { return eTypeProperties; } void Clear() override; - lldb::OptionValueSP DeepCopy() const override; + static lldb::OptionValuePropertiesSP + CreateLocalCopy(const Properties &global_properties); + + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; Status SetValueFromString(llvm::StringRef value, @@ -204,6 +206,8 @@ return ((idx < m_properties.size()) ? &m_properties[idx] : nullptr); } + lldb::OptionValueSP Clone() const override; + typedef UniqueCStringMap NameToIndex; ConstString m_name; Index: lldb/include/lldb/Interpreter/OptionValueRegex.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueRegex.h +++ lldb/include/lldb/Interpreter/OptionValueRegex.h @@ -38,8 +38,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const RegularExpression *GetCurrentValue() const { return (m_regex.IsValid() ? &m_regex : nullptr); @@ -55,6 +53,8 @@ bool IsValid() const { return m_regex.IsValid(); } protected: + lldb::OptionValueSP Clone() const override; + RegularExpression m_regex; std::string m_default_regex_str; }; Index: lldb/include/lldb/Interpreter/OptionValueSInt64.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueSInt64.h +++ lldb/include/lldb/Interpreter/OptionValueSInt64.h @@ -52,8 +52,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const int64_t &operator=(int64_t value) { @@ -90,6 +88,8 @@ int64_t GetMaximumValue() const { return m_max_value; } protected: + lldb::OptionValueSP Clone() const override; + int64_t m_current_value; int64_t m_default_value; int64_t m_min_value; Index: lldb/include/lldb/Interpreter/OptionValueString.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueString.h +++ lldb/include/lldb/Interpreter/OptionValueString.h @@ -87,8 +87,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions Flags &GetOptions() { return m_options; } @@ -123,6 +121,8 @@ bool IsDefaultValueEmpty() const { return m_default_value.empty(); } protected: + lldb::OptionValueSP Clone() const override; + std::string m_current_value; std::string m_default_value; Flags m_options; Index: lldb/include/lldb/Interpreter/OptionValueUInt64.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueUInt64.h +++ lldb/include/lldb/Interpreter/OptionValueUInt64.h @@ -49,8 +49,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const uint64_t &operator=(uint64_t value) { @@ -69,6 +67,8 @@ void SetDefaultValue(uint64_t value) { m_default_value = value; } protected: + lldb::OptionValueSP Clone() const override; + uint64_t m_current_value; uint64_t m_default_value; }; Index: lldb/include/lldb/Interpreter/OptionValueUUID.h =================================================================== --- lldb/include/lldb/Interpreter/OptionValueUUID.h +++ lldb/include/lldb/Interpreter/OptionValueUUID.h @@ -38,8 +38,6 @@ m_value_was_set = false; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions UUID &GetCurrentValue() { return m_uuid; } @@ -52,6 +50,8 @@ CompletionRequest &request) override; protected: + lldb::OptionValueSP Clone() const override; + UUID m_uuid; }; Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -211,7 +211,7 @@ void SetDisplayRecognizedArguments(bool b); - const ProcessLaunchInfo &GetProcessLaunchInfo(); + const ProcessLaunchInfo &GetProcessLaunchInfo() const; void SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info); Index: lldb/source/Interpreter/OptionValue.cpp =================================================================== --- lldb/source/Interpreter/OptionValue.cpp +++ lldb/source/Interpreter/OptionValue.cpp @@ -568,6 +568,12 @@ return dumped_something; } +OptionValueSP OptionValue::DeepCopy(const OptionValueSP &new_parent) const { + auto &&clone = Clone(); + clone->SetParent(new_parent); + return clone; +} + void OptionValue::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) {} Index: lldb/source/Interpreter/OptionValueArch.cpp =================================================================== --- lldb/source/Interpreter/OptionValueArch.cpp +++ lldb/source/Interpreter/OptionValueArch.cpp @@ -64,8 +64,8 @@ return error; } -lldb::OptionValueSP OptionValueArch::DeepCopy() const { - return OptionValueSP(new OptionValueArch(*this)); +OptionValueSP OptionValueArch::Clone() const { + return std::make_shared(*this); } void OptionValueArch::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueArgs.cpp =================================================================== --- lldb/source/Interpreter/OptionValueArgs.cpp +++ lldb/source/Interpreter/OptionValueArgs.cpp @@ -13,9 +13,9 @@ using namespace lldb; using namespace lldb_private; -size_t OptionValueArgs::GetArgs(Args &args) { +size_t OptionValueArgs::GetArgs(Args &args) const { args.Clear(); - for (auto value : m_values) { + for (const auto &value : m_values) { llvm::StringRef string_value = value->GetStringValue(); if (!string_value.empty()) args.AppendArgument(string_value); @@ -23,3 +23,7 @@ return args.GetArgumentCount(); } + +OptionValueSP OptionValueArgs::Clone() const { + return std::make_shared(*this); +} Index: lldb/source/Interpreter/OptionValueArray.cpp =================================================================== --- lldb/source/Interpreter/OptionValueArray.cpp +++ lldb/source/Interpreter/OptionValueArray.cpp @@ -303,15 +303,20 @@ return error; } -lldb::OptionValueSP OptionValueArray::DeepCopy() const { - OptionValueArray *copied_array = - new OptionValueArray(m_type_mask, m_raw_value_dump); - lldb::OptionValueSP copied_value_sp(copied_array); - *static_cast(copied_array) = *this; - copied_array->m_callback = m_callback; - const uint32_t size = m_values.size(); - for (uint32_t i = 0; i < size; ++i) { - copied_array->AppendValue(m_values[i]->DeepCopy()); - } - return copied_value_sp; +OptionValueSP OptionValueArray::Clone() const { + return std::make_shared(*this); +} + +OptionValueSP +OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsArray cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *array_value_ptr = static_cast(copy_sp.get()); + lldbassert(array_value_ptr); + + for (auto &value : array_value_ptr->m_values) + value = value->DeepCopy(copy_sp); + + return copy_sp; } Index: lldb/source/Interpreter/OptionValueBoolean.cpp =================================================================== --- lldb/source/Interpreter/OptionValueBoolean.cpp +++ lldb/source/Interpreter/OptionValueBoolean.cpp @@ -67,8 +67,8 @@ return error; } -lldb::OptionValueSP OptionValueBoolean::DeepCopy() const { - return OptionValueSP(new OptionValueBoolean(*this)); +OptionValueSP OptionValueBoolean::Clone() const { + return std::make_shared(*this); } void OptionValueBoolean::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueChar.cpp =================================================================== --- lldb/source/Interpreter/OptionValueChar.cpp +++ lldb/source/Interpreter/OptionValueChar.cpp @@ -58,6 +58,6 @@ return error; } -lldb::OptionValueSP OptionValueChar::DeepCopy() const { - return OptionValueSP(new OptionValueChar(*this)); +OptionValueSP OptionValueChar::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueDictionary.cpp =================================================================== --- lldb/source/Interpreter/OptionValueDictionary.cpp +++ lldb/source/Interpreter/OptionValueDictionary.cpp @@ -311,15 +311,20 @@ return false; } -lldb::OptionValueSP OptionValueDictionary::DeepCopy() const { - OptionValueDictionary *copied_dict = - new OptionValueDictionary(m_type_mask, m_raw_value_dump); - lldb::OptionValueSP copied_value_sp(copied_dict); - collection::const_iterator pos, end = m_values.end(); - for (pos = m_values.begin(); pos != end; ++pos) { - StreamString strm; - strm.Printf("%s=", pos->first.GetCString()); - copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true); - } - return copied_value_sp; +OptionValueSP OptionValueDictionary::Clone() const { + return std::make_shared(*this); +} + +OptionValueSP +OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *dict_value_ptr = static_cast(copy_sp.get()); + lldbassert(dict_value_ptr); + + for (auto &value : dict_value_ptr->m_values) + value.second = value.second->DeepCopy(copy_sp); + + return copy_sp; } Index: lldb/source/Interpreter/OptionValueEnumeration.cpp =================================================================== --- lldb/source/Interpreter/OptionValueEnumeration.cpp +++ lldb/source/Interpreter/OptionValueEnumeration.cpp @@ -98,8 +98,8 @@ m_enumerations.Sort(); } -lldb::OptionValueSP OptionValueEnumeration::DeepCopy() const { - return OptionValueSP(new OptionValueEnumeration(*this)); +OptionValueSP OptionValueEnumeration::Clone() const { + return std::make_shared(*this); } void OptionValueEnumeration::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueFileColonLine.cpp =================================================================== --- lldb/source/Interpreter/OptionValueFileColonLine.cpp +++ lldb/source/Interpreter/OptionValueFileColonLine.cpp @@ -134,8 +134,8 @@ return error; } -lldb::OptionValueSP OptionValueFileColonLine::DeepCopy() const { - return OptionValueSP(new OptionValueFileColonLine(*this)); +OptionValueSP OptionValueFileColonLine::Clone() const { + return std::make_shared(*this); } void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueFileSpec.cpp =================================================================== --- lldb/source/Interpreter/OptionValueFileSpec.cpp +++ lldb/source/Interpreter/OptionValueFileSpec.cpp @@ -88,8 +88,8 @@ return error; } -lldb::OptionValueSP OptionValueFileSpec::DeepCopy() const { - return OptionValueSP(new OptionValueFileSpec(*this)); +OptionValueSP OptionValueFileSpec::Clone() const { + return std::make_shared(*this); } void OptionValueFileSpec::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueFileSpecList.cpp =================================================================== --- lldb/source/Interpreter/OptionValueFileSpecList.cpp +++ lldb/source/Interpreter/OptionValueFileSpecList.cpp @@ -164,7 +164,7 @@ return error; } -lldb::OptionValueSP OptionValueFileSpecList::DeepCopy() const { +OptionValueSP OptionValueFileSpecList::Clone() const { std::lock_guard lock(m_mutex); - return OptionValueSP(new OptionValueFileSpecList(m_current_value)); + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueFormat.cpp =================================================================== --- lldb/source/Interpreter/OptionValueFormat.cpp +++ lldb/source/Interpreter/OptionValueFormat.cpp @@ -57,6 +57,6 @@ return error; } -lldb::OptionValueSP OptionValueFormat::DeepCopy() const { - return OptionValueSP(new OptionValueFormat(*this)); +OptionValueSP OptionValueFormat::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueFormatEntity.cpp =================================================================== --- lldb/source/Interpreter/OptionValueFormatEntity.cpp +++ lldb/source/Interpreter/OptionValueFormatEntity.cpp @@ -111,8 +111,8 @@ return error; } -lldb::OptionValueSP OptionValueFormatEntity::DeepCopy() const { - return OptionValueSP(new OptionValueFormatEntity(*this)); +OptionValueSP OptionValueFormatEntity::Clone() const { + return std::make_shared(*this); } void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Interpreter/OptionValueLanguage.cpp =================================================================== --- lldb/source/Interpreter/OptionValueLanguage.cpp +++ lldb/source/Interpreter/OptionValueLanguage.cpp @@ -70,6 +70,6 @@ return error; } -lldb::OptionValueSP OptionValueLanguage::DeepCopy() const { - return OptionValueSP(new OptionValueLanguage(*this)); +OptionValueSP OptionValueLanguage::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValuePathMappings.cpp =================================================================== --- lldb/source/Interpreter/OptionValuePathMappings.cpp +++ lldb/source/Interpreter/OptionValuePathMappings.cpp @@ -197,6 +197,6 @@ return error; } -lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const { - return OptionValueSP(new OptionValuePathMappings(*this)); +OptionValueSP OptionValuePathMappings::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueProperties.cpp =================================================================== --- lldb/source/Interpreter/OptionValueProperties.cpp +++ lldb/source/Interpreter/OptionValueProperties.cpp @@ -23,27 +23,6 @@ OptionValueProperties::OptionValueProperties(ConstString name) : OptionValue(), m_name(name), m_properties(), m_name_to_index() {} -OptionValueProperties::OptionValueProperties( - const OptionValueProperties &global_properties) - : OptionValue(global_properties), - std::enable_shared_from_this(), - m_name(global_properties.m_name), - m_properties(global_properties.m_properties), - m_name_to_index(global_properties.m_name_to_index) { - // We now have an exact copy of "global_properties". We need to now find all - // non-global settings and copy the property values so that all non-global - // settings get new OptionValue instances created for them. - const size_t num_properties = m_properties.size(); - for (size_t i = 0; i < num_properties; ++i) { - // Duplicate any values that are not global when constructing properties - // from a global copy - if (!m_properties[i].IsGlobal()) { - lldb::OptionValueSP new_value_sp(m_properties[i].GetValue()->DeepCopy()); - m_properties[i].SetOptionValue(new_value_sp); - } - } -} - size_t OptionValueProperties::GetNumProperties() const { return m_properties.size(); } @@ -250,38 +229,50 @@ bool OptionValueProperties::GetPropertyAtIndexAsArgs( const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const { const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); - if (property) { - OptionValue *value = property->GetValue().get(); - if (value) { - const OptionValueArray *array = value->GetAsArray(); - if (array) - return array->GetArgs(args); - else { - const OptionValueDictionary *dict = value->GetAsDictionary(); - if (dict) - return dict->GetArgs(args); - } - } - } + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + const OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) + return arguments->GetArgs(args); + + const OptionValueArray *array = value->GetAsArray(); + if (array) + return array->GetArgs(args); + + const OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->GetArgs(args); + return false; } bool OptionValueProperties::SetPropertyAtIndexFromArgs( const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) { const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); - if (property) { - OptionValue *value = property->GetValue().get(); - if (value) { - OptionValueArray *array = value->GetAsArray(); - if (array) - return array->SetArgs(args, eVarSetOperationAssign).Success(); - else { - OptionValueDictionary *dict = value->GetAsDictionary(); - if (dict) - return dict->SetArgs(args, eVarSetOperationAssign).Success(); - } - } - } + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) + return arguments->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueArray *array = value->GetAsArray(); + if (array) + return array->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->SetArgs(args, eVarSetOperationAssign).Success(); + return false; } @@ -552,8 +543,36 @@ return error; } -lldb::OptionValueSP OptionValueProperties::DeepCopy() const { - llvm_unreachable("this shouldn't happen"); +OptionValuePropertiesSP +OptionValueProperties::CreateLocalCopy(const Properties &global_properties) { + auto global_props_sp = global_properties.GetValueProperties(); + lldbassert(global_props_sp); + + auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent()); + return std::static_pointer_cast(copy_sp); +} + +OptionValueSP OptionValueProperties::Clone() const { + return std::make_shared(*this); +} + +OptionValueSP +OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *props_value_ptr = static_cast(copy_sp.get()); + lldbassert(props_value_ptr); + + for (auto &property : props_value_ptr->m_properties) { + // Duplicate any values that are not global when constructing properties + // from a global copy. + if (!property.IsGlobal()) { + auto value_sp = property.GetValue()->DeepCopy(copy_sp); + property.SetOptionValue(value_sp); + } + } + return copy_sp; } const Property *OptionValueProperties::GetPropertyAtPath( Index: lldb/source/Interpreter/OptionValueRegex.cpp =================================================================== --- lldb/source/Interpreter/OptionValueRegex.cpp +++ lldb/source/Interpreter/OptionValueRegex.cpp @@ -60,6 +60,6 @@ return error; } -lldb::OptionValueSP OptionValueRegex::DeepCopy() const { - return OptionValueSP(new OptionValueRegex(m_regex.GetText().str().c_str())); +OptionValueSP OptionValueRegex::Clone() const { + return std::make_shared(m_regex.GetText().str().c_str()); } Index: lldb/source/Interpreter/OptionValueSInt64.cpp =================================================================== --- lldb/source/Interpreter/OptionValueSInt64.cpp +++ lldb/source/Interpreter/OptionValueSInt64.cpp @@ -71,6 +71,6 @@ return error; } -lldb::OptionValueSP OptionValueSInt64::DeepCopy() const { - return OptionValueSP(new OptionValueSInt64(*this)); +OptionValueSP OptionValueSInt64::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueString.cpp =================================================================== --- lldb/source/Interpreter/OptionValueString.cpp +++ lldb/source/Interpreter/OptionValueString.cpp @@ -117,8 +117,8 @@ return error; } -lldb::OptionValueSP OptionValueString::DeepCopy() const { - return OptionValueSP(new OptionValueString(*this)); +OptionValueSP OptionValueString::Clone() const { + return std::make_shared(*this); } Status OptionValueString::SetCurrentValue(llvm::StringRef value) { Index: lldb/source/Interpreter/OptionValueUInt64.cpp =================================================================== --- lldb/source/Interpreter/OptionValueUInt64.cpp +++ lldb/source/Interpreter/OptionValueUInt64.cpp @@ -69,6 +69,6 @@ return error; } -lldb::OptionValueSP OptionValueUInt64::DeepCopy() const { - return OptionValueSP(new OptionValueUInt64(*this)); +OptionValueSP OptionValueUInt64::Clone() const { + return std::make_shared(*this); } Index: lldb/source/Interpreter/OptionValueUUID.cpp =================================================================== --- lldb/source/Interpreter/OptionValueUUID.cpp +++ lldb/source/Interpreter/OptionValueUUID.cpp @@ -58,8 +58,8 @@ return error; } -lldb::OptionValueSP OptionValueUUID::DeepCopy() const { - return OptionValueSP(new OptionValueUUID(*this)); +OptionValueSP OptionValueUUID::Clone() const { + return std::make_shared(*this); } void OptionValueUUID::AutoComplete(CommandInterpreter &interpreter, Index: lldb/source/Target/Process.cpp =================================================================== --- lldb/source/Target/Process.cpp +++ lldb/source/Target/Process.cpp @@ -88,12 +88,6 @@ ProcessOptionValueProperties(ConstString name) : OptionValueProperties(name) {} - // This constructor is used when creating ProcessOptionValueProperties when - // it is part of a new lldb_private::Process instance. It will copy all - // current global property values as needed - ProcessOptionValueProperties(ProcessProperties *global_properties) - : OptionValueProperties(*global_properties->GetValueProperties()) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override { @@ -112,6 +106,11 @@ } return ProtectedGetPropertyAtIndex(idx); } + +private: + lldb::OptionValueSP Clone() const override { + return std::make_shared(*this); + } }; #define LLDB_PROPERTIES_process @@ -136,6 +135,11 @@ ProcessExperimentalOptionValueProperties() : OptionValueProperties( ConstString(Properties::GetExperimentalSettingsName())) {} + +private: + lldb::OptionValueSP Clone() const override { + return std::make_shared(*this); + } }; ProcessExperimentalProperties::ProcessExperimentalProperties() @@ -157,8 +161,8 @@ ConstString("thread"), ConstString("Settings specific to threads."), true, Thread::GetGlobalProperties()->GetValueProperties()); } else { - m_collection_sp = std::make_shared( - Process::GetGlobalProperties().get()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Process::GetGlobalProperties()); m_collection_sp->SetValueChangedCallback( ePropertyPythonOSPluginPath, [this] { m_process->LoadOperatingSystemPlugin(true); }); Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -3619,12 +3619,6 @@ public: TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {} - // This constructor is used when creating TargetOptionValueProperties when it - // is part of a new lldb_private::Target instance. It will copy all current - // global property values as needed - TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp) - : OptionValueProperties(*target_properties_sp->GetValueProperties()) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override { @@ -3643,6 +3637,11 @@ } return ProtectedGetPropertyAtIndex(idx); } + +private: + lldb::OptionValueSP Clone() const override { + return std::make_shared(*this); + } }; // TargetProperties @@ -3659,6 +3658,11 @@ TargetExperimentalOptionValueProperties() : OptionValueProperties( ConstString(Properties::GetExperimentalSettingsName())) {} + +private: + lldb::OptionValueSP Clone() const override { + return std::make_shared(*this); + } }; TargetExperimentalProperties::TargetExperimentalProperties() @@ -3671,8 +3675,8 @@ TargetProperties::TargetProperties(Target *target) : Properties(), m_launch_info(), m_target(target) { if (target) { - m_collection_sp = std::make_shared( - Target::GetGlobalProperties()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -4200,8 +4204,7 @@ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() { - m_launch_info.SetArg0(GetArg0()); // FIXME: Arg0 callback doesn't work +const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() const { return m_launch_info; } Index: lldb/source/Target/Thread.cpp =================================================================== --- lldb/source/Target/Thread.cpp +++ lldb/source/Target/Thread.cpp @@ -76,12 +76,6 @@ ThreadOptionValueProperties(ConstString name) : OptionValueProperties(name) {} - // This constructor is used when creating ThreadOptionValueProperties when it - // is part of a new lldb_private::Thread instance. It will copy all current - // global property values as needed - ThreadOptionValueProperties(ThreadProperties *global_properties) - : OptionValueProperties(*global_properties->GetValueProperties()) {} - const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override { @@ -100,6 +94,11 @@ } return ProtectedGetPropertyAtIndex(idx); } + +private: + lldb::OptionValueSP Clone() const override { + return std::make_shared(*this); + } }; ThreadProperties::ThreadProperties(bool is_global) : Properties() { @@ -108,8 +107,8 @@ std::make_shared(ConstString("thread")); m_collection_sp->Initialize(g_thread_properties); } else - m_collection_sp = std::make_shared( - Thread::GetGlobalProperties().get()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Thread::GetGlobalProperties()); } ThreadProperties::~ThreadProperties() = default; Index: lldb/test/API/commands/settings/TestSettings.py =================================================================== --- lldb/test/API/commands/settings/TestSettings.py +++ lldb/test/API/commands/settings/TestSettings.py @@ -238,6 +238,11 @@ self.assertTrue(found_env_var, "MY_ENV_VAR was not set in LunchInfo object") + self.assertEqual(launch_info.GetNumArguments(), 3) + self.assertEqual(launch_info.GetArgumentAtIndex(0), "A") + self.assertEqual(launch_info.GetArgumentAtIndex(1), "B") + self.assertEqual(launch_info.GetArgumentAtIndex(2), "C") + self.expect( 'target show-launch-environment', substrs=["MY_ENV_VAR=YES"]) Index: lldb/unittests/Interpreter/CMakeLists.txt =================================================================== --- lldb/unittests/Interpreter/CMakeLists.txt +++ lldb/unittests/Interpreter/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(InterpreterTests TestCompletion.cpp TestOptionArgParser.cpp + TestOptionValue.cpp TestOptionValueFileColonLine.cpp LINK_LIBS Index: lldb/unittests/Interpreter/TestOptionValue.cpp =================================================================== --- /dev/null +++ lldb/unittests/Interpreter/TestOptionValue.cpp @@ -0,0 +1,173 @@ +//===-- TestOptionValue.cpp -------- -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/OptionValues.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +class Callback { +public: + virtual void Invoke() const {} + void operator()() const { Invoke(); } +}; + +class MockCallback : public Callback { +public: + MOCK_CONST_METHOD0(Invoke, void()); +}; + +// Test a single-value class. +TEST(OptionValueString, DeepCopy) { + OptionValueString str; + str.SetValueFromString("ab"); + + MockCallback callback; + str.SetValueChangedCallback([&callback] { callback(); }); + EXPECT_CALL(callback, Invoke()); + + auto copy_sp = str.DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent().get(), nullptr); + ASSERT_TRUE(copy_sp->OptionWasSet()); + ASSERT_EQ(copy_sp->GetStringValue(), "ab"); + + // Trigger the callback. + copy_sp->SetValueFromString("c", eVarSetOperationAppend); + ASSERT_EQ(copy_sp->GetStringValue(), "abc"); +} + +// Test an aggregate class. +TEST(OptionValueArgs, DeepCopy) { + OptionValueArgs args; + args.SetValueFromString("A B"); + + MockCallback callback; + args.SetValueChangedCallback([&callback] { callback(); }); + EXPECT_CALL(callback, Invoke()); + + auto copy_sp = args.DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent(), nullptr); + ASSERT_TRUE(copy_sp->OptionWasSet()); + + auto *args_copy_ptr = copy_sp->GetAsArgs(); + ASSERT_EQ(args_copy_ptr->GetSize(), 2U); + ASSERT_EQ((*args_copy_ptr)[0]->GetParent(), copy_sp); + ASSERT_EQ((*args_copy_ptr)[0]->GetStringValue(), "A"); + ASSERT_EQ((*args_copy_ptr)[1]->GetParent(), copy_sp); + ASSERT_EQ((*args_copy_ptr)[1]->GetStringValue(), "B"); + + // Trigger the callback. + copy_sp->SetValueFromString("C", eVarSetOperationAppend); + ASSERT_TRUE(args_copy_ptr); + ASSERT_EQ(args_copy_ptr->GetSize(), 3U); + ASSERT_EQ((*args_copy_ptr)[2]->GetStringValue(), "C"); +} + +class TestProperties : public OptionValueProperties { +public: + static std::shared_ptr CreateGlobal() { + auto props_sp = std::make_shared(); + const bool is_global = false; + + auto dict_sp = std::make_shared(1 << eTypeUInt64); + props_sp->AppendProperty(ConstString("dict"), ConstString(), is_global, + dict_sp); + + auto file_list_sp = std::make_shared(); + props_sp->AppendProperty(ConstString("file-list"), ConstString(), is_global, + file_list_sp); + return props_sp; + } + + void SetDictionaryChangedCallback(const MockCallback &callback) { + SetValueChangedCallback(m_dict_index, [&callback] { callback(); }); + } + + void SetFileListChangedCallback(const MockCallback &callback) { + SetValueChangedCallback(m_file_list_index, [&callback] { callback(); }); + } + + OptionValueDictionary *GetDictionary() { + return GetPropertyAtIndexAsOptionValueDictionary(nullptr, m_dict_index); + } + + OptionValueFileSpecList *GetFileList() { + return GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, true, + m_file_list_index); + } + +private: + lldb::OptionValueSP Clone() const { + return std::make_shared(*this); + } + + uint32_t m_dict_index = 0; + uint32_t m_file_list_index = 1; +}; + +// Test a user-defined propery class. +TEST(TestProperties, DeepCopy) { + auto props_sp = TestProperties::CreateGlobal(); + props_sp->GetDictionary()->SetValueFromString("A=1 B=2"); + props_sp->GetFileList()->SetValueFromString("path/to/file"); + + MockCallback callback; + props_sp->SetDictionaryChangedCallback(callback); + props_sp->SetFileListChangedCallback(callback); + EXPECT_CALL(callback, Invoke()).Times(2); + + auto copy_sp = props_sp->DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent(), nullptr); + + // This cast is safe only if the class overrides Clone(). + auto *props_copy_ptr = static_cast(copy_sp.get()); + ASSERT_TRUE(props_copy_ptr); + + // Test the first child. + auto dict_copy_ptr = props_copy_ptr->GetDictionary(); + ASSERT_TRUE(dict_copy_ptr); + ASSERT_EQ(dict_copy_ptr->GetParent(), copy_sp); + ASSERT_TRUE(dict_copy_ptr->OptionWasSet()); + ASSERT_EQ(dict_copy_ptr->GetNumValues(), 2U); + + auto value_ptr = dict_copy_ptr->GetValueForKey(ConstString("A")); + ASSERT_TRUE(value_ptr); + ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr); + ASSERT_EQ(value_ptr->GetUInt64Value(), 1U); + + value_ptr = dict_copy_ptr->GetValueForKey(ConstString("B")); + ASSERT_TRUE(value_ptr); + ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr); + ASSERT_EQ(value_ptr->GetUInt64Value(), 2U); + + // Test the second child. + auto file_list_copy_ptr = props_copy_ptr->GetFileList(); + ASSERT_TRUE(file_list_copy_ptr); + ASSERT_EQ(file_list_copy_ptr->GetParent(), copy_sp); + ASSERT_TRUE(file_list_copy_ptr->OptionWasSet()); + + auto file_list_copy = file_list_copy_ptr->GetCurrentValue(); + ASSERT_EQ(file_list_copy.GetSize(), 1U); + ASSERT_EQ(file_list_copy.GetFileSpecAtIndex(0), FileSpec("path/to/file")); + + // Trigger the callback first time. + dict_copy_ptr->SetValueFromString("C=3", eVarSetOperationAppend); + + // Trigger the callback second time. + file_list_copy_ptr->SetValueFromString("0 another/path", eVarSetOperationReplace); +}