Reimplemented the code that backed the "settings" in lldb. There were many issues with the previous implementation:
- no setting auto completion
- very manual and error prone way of getting/setting variables
- tons of code duplication
- useless instance names for processes, threads

Now settings can easily be defined like option values. The new settings makes use of the "OptionValue" classes so we can re-use the option value code that we use to set settings in command options. No more instances, just "does the right thing".



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@162366 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp
new file mode 100644
index 0000000..ce31c15
--- /dev/null
+++ b/source/Interpreter/OptionValueProperties.cpp
@@ -0,0 +1,719 @@
+//===-- OptionValueProperties.cpp ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Interpreter/OptionValueProperties.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Interpreter/Property.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+OptionValueProperties::OptionValueProperties (const ConstString &name) :
+    m_name (name)
+{
+}
+
+OptionValueProperties::OptionValueProperties (const OptionValueProperties &global_properties) :
+    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 contructing properties from
+        // a global copy
+        if (m_properties[i].IsGlobal() == false)
+        {
+            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();
+}
+
+
+void
+OptionValueProperties::Initialize (const PropertyDefinition *defs)
+{
+    for (size_t i=0; defs[i].name; ++i)
+    {
+        Property property(defs[i]);
+        assert(property.IsValid());
+        m_name_to_index.Append(property.GetName().GetCString(),m_properties.size());
+        property.GetValue()->SetParent(shared_from_this());
+        m_properties.push_back(property);
+    }
+    m_name_to_index.Sort();
+}
+
+void
+OptionValueProperties::AppendProperty(const ConstString &name,
+                                      const ConstString &desc,
+                                      bool is_global,
+                                      const OptionValueSP &value_sp)
+{
+    Property property(name, desc, is_global, value_sp);
+    m_name_to_index.Append(name.GetCString(),m_properties.size());
+    m_properties.push_back(property);
+    value_sp->SetParent (shared_from_this());
+    m_name_to_index.Sort();
+}
+
+
+
+//bool
+//OptionValueProperties::GetQualifiedName (Stream &strm)
+//{
+//    bool dumped_something = false;
+////    lldb::OptionValuePropertiesSP parent_sp(GetParent ());
+////    if (parent_sp)
+////    {
+////        parent_sp->GetQualifiedName (strm);
+////        strm.PutChar('.');
+////        dumped_something = true;
+////    }
+//    if (m_name)
+//    {
+//        strm << m_name;
+//        dumped_something = true;
+//    }
+//    return dumped_something;
+//}
+//
+lldb::OptionValueSP
+OptionValueProperties::GetValueForKey  (const ExecutionContext *exe_ctx,
+                                        const ConstString &key,
+                                        bool will_modify) const
+{
+    lldb::OptionValueSP value_sp;
+    size_t idx = m_name_to_index.Find (key.GetCString(), SIZE_MAX);
+    if (idx < m_properties.size())
+        value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue();
+    return value_sp;
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx,
+                                    const char *name,
+                                    bool will_modify,
+                                    Error &error) const
+{
+    lldb::OptionValueSP value_sp;
+    
+    if (name && name[0])
+    {
+        const char *sub_name = NULL;
+        ConstString key;
+        size_t key_len = ::strcspn (name, ".[{");
+        
+        if (name[key_len])
+        {
+            key.SetCStringWithLength (name, key_len);
+            sub_name = name + key_len;
+        }
+        else
+            key.SetCString (name);
+        
+        value_sp = GetValueForKey (exe_ctx, key, will_modify);
+        if (sub_name && value_sp)
+        {
+            switch (sub_name[0])
+            {
+            case '.':
+                return value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error);
+            
+            case '{':
+                // Predicate matching for predicates like
+                // "<setting-name>{<predicate>}"
+                // strings are parsed by the current OptionValueProperties subclass
+                // to mean whatever they want to. For instance a subclass of
+                // OptionValueProperties for a lldb_private::Target might implement:
+                // "target.run-args{arch==i386}"   -- only set run args if the arch is i386
+                // "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path matches
+                // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if exectable basename is "test" and arch is "x86_64"
+                if (sub_name[1])
+                {
+                    const char *predicate_start = sub_name + 1;
+                    const char *predicate_end = strchr(predicate_start, '}');
+                    if (predicate_end)
+                    {
+                        std::string predicate(predicate_start, predicate_end);
+                        if (PredicateMatches(exe_ctx, predicate.c_str()))
+                        {
+                            if (predicate_end[1])
+                            {
+                                // Still more subvalue string to evaluate
+                                return value_sp->GetSubValue (exe_ctx, predicate_end + 1, will_modify, error);
+                            }
+                            else
+                            {
+                                // We have a match!
+                                break;
+                            }
+                        }
+                    }
+                }
+                // Predicate didn't match or wasn't correctly formed
+                value_sp.reset();
+                break;
+            
+            case '[':
+                // Array or dictionary access for subvalues like:
+                // "[12]"       -- access 12th array element
+                // "['hello']"  -- dictionary access of key named hello
+                return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error);
+
+            default:
+                value_sp.reset();
+                break;
+            }
+        }
+    }
+    return value_sp;
+}
+
+Error
+OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
+                                    VarSetOperationType op,
+                                    const char *name,
+                                    const char *value)
+{
+    Error error;
+    const bool will_modify = true;
+    lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
+    if (value_sp)
+        error = value_sp->SetValueFromCString(value, op);
+    else
+    {
+        if (error.AsCString() == NULL)
+            error.SetErrorStringWithFormat("invalid value path '%s'", name);
+    }
+    return error;
+}
+
+
+ConstString
+OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex(NULL, false, idx);
+    if (property)
+        return property->GetName();
+    return ConstString();
+    
+}
+
+const char *
+OptionValueProperties::GetPropertyDescriptionAtIndex (uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex(NULL, false, idx);
+    if (property)
+        return property->GetDescription();
+    return NULL;
+}
+
+uint32_t
+OptionValueProperties::GetPropertyIndex (const ConstString &name) const
+{
+    return m_name_to_index.Find (name.GetCString(), SIZE_MAX);
+}
+
+const Property *
+OptionValueProperties::GetProperty (const ExecutionContext *exe_ctx, bool will_modify, const ConstString &name) const
+{
+    return GetPropertyAtIndex (exe_ctx, will_modify, m_name_to_index.Find (name.GetCString(), SIZE_MAX));
+}
+
+const Property *
+OptionValueProperties::GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+    return ProtectedGetPropertyAtIndex (idx);
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetPropertyValueAtIndex (const ExecutionContext *exe_ctx,
+                                                bool will_modify,
+                                                uint32_t idx) const
+{
+    const Property *setting = GetPropertyAtIndex (exe_ctx, will_modify, idx);
+    if (setting)
+        return setting->GetValue();
+    return OptionValueSP();
+}
+
+OptionValuePathMappings *
+OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+    OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
+    if (value_sp)
+        return value_sp->GetAsPathMappings();
+    return NULL;
+}
+
+OptionValueFileSpecList *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+    OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
+    if (value_sp)
+        return value_sp->GetAsFileSpecList();
+    return NULL;    
+}
+
+OptionValueArch *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueArch (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+        return property->GetValue()->GetAsArch();
+    return NULL;
+}
+
+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);
+            }
+        }
+    }
+    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();
+            }
+        }
+    }
+    return false;
+}
+
+bool
+OptionValueProperties::GetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetBooleanValue(fail_value);
+    }
+    return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+        {
+            value->SetBooleanValue(new_value);
+            return true;
+        }
+    }
+    return false;
+}
+
+OptionValueDictionary *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+        return property->GetValue()->GetAsDictionary();
+    return NULL;
+}
+
+int64_t
+OptionValueProperties::GetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetEnumerationValue(fail_value);
+    }
+    return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->SetEnumerationValue(new_value);
+    }
+    return false;
+}
+
+
+FileSpec
+OptionValueProperties::GetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetFileSpecValue();
+    }
+    return FileSpec();
+}
+
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx, const FileSpec &new_file_spec)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->SetFileSpecValue(new_file_spec);
+    }
+    return false;
+}
+
+const RegularExpression *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetRegexValue();
+    }
+    return NULL;
+}
+
+OptionValueSInt64 *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetAsSInt64();
+    }
+    return NULL;
+}
+
+int64_t
+OptionValueProperties::GetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetSInt64Value(fail_value);
+    }
+    return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->SetSInt64Value(new_value);
+    }
+    return false;
+}
+
+const char *
+OptionValueProperties::GetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *fail_value) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetStringValue(fail_value);
+    }
+    return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->SetStringValue(new_value);
+    }
+    return false;
+}
+
+uint64_t
+OptionValueProperties::GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->GetUInt64Value(fail_value);
+    }
+    return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value)
+{
+    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+    if (property)
+    {
+        OptionValue *value = property->GetValue().get();
+        if (value)
+            return value->SetUInt64Value(new_value);
+    }
+    return false;
+}
+
+bool
+OptionValueProperties::Clear ()
+{
+    const size_t num_properties = m_properties.size();
+    for (size_t i=0; i<num_properties; ++i)
+        m_properties[i].GetValue()->Clear();
+    return true;
+}
+
+
+Error
+OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+    Error error;
+    
+//    Args args(value_cstr);
+//    const size_t argc = args.GetArgumentCount();
+    switch (op)
+    {
+        case eVarSetOperationClear:
+            Clear ();
+            break;
+            
+        case eVarSetOperationReplace:
+        case eVarSetOperationAssign:
+        case eVarSetOperationRemove:
+        case eVarSetOperationInsertBefore:
+        case eVarSetOperationInsertAfter:
+        case eVarSetOperationAppend:
+        case eVarSetOperationInvalid:
+            error = OptionValue::SetValueFromCString (value, op);
+            break;
+    }
+    
+    return error;
+}
+
+void
+OptionValueProperties::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+    const size_t num_properties = m_properties.size();
+    for (size_t i=0; i<num_properties; ++i)
+    {
+        const Property *property = GetPropertyAtIndex(exe_ctx, false, i);
+        if (property)
+        {
+            OptionValue *option_value = property->GetValue().get();
+            assert (option_value);
+            const bool transparent_value = option_value->ValueIsTransparent ();
+            property->Dump (exe_ctx,
+                            strm,
+                            dump_mask);
+            if (!transparent_value)
+                strm.EOL();
+        }
+    }
+}
+
+Error
+OptionValueProperties::DumpPropertyValue (const ExecutionContext *exe_ctx,
+                                          Stream &strm,
+                                          const char *property_path,
+                                          uint32_t dump_mask)
+{
+    Error error;
+    const bool will_modify = false;
+    lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, property_path, will_modify, error));
+    if (value_sp)
+    {
+        if (!value_sp->ValueIsTransparent ())
+        {
+            if (dump_mask & eDumpOptionName)
+                strm.PutCString (property_path);
+            if (dump_mask & ~eDumpOptionName)
+                strm.PutChar (' ');
+        }
+        value_sp->DumpValue (exe_ctx, strm, dump_mask);
+    }
+    return error;
+}
+
+lldb::OptionValueSP
+OptionValueProperties::DeepCopy () const
+{
+    assert(!"this shouldn't happen");
+}
+
+const Property *
+OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx,
+                                          bool will_modify,
+                                          const char *name) const
+{
+    const Property *property = NULL;
+    if (name && name[0])
+    {
+        const char *sub_name = NULL;
+        ConstString key;
+        size_t key_len = ::strcspn (name, ".[{");
+        
+        if (name[key_len])
+        {
+            key.SetCStringWithLength (name, key_len);
+            sub_name = name + key_len;
+        }
+        else
+            key.SetCString (name);
+        
+        property = GetProperty (exe_ctx, will_modify, key);
+        if (sub_name && property)
+        {
+            if (sub_name[0] == '.')
+            {
+                OptionValueProperties *sub_properties = property->GetValue()->GetAsProperties();
+                if (sub_properties)
+                    return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, sub_name + 1);
+            }
+            property = NULL;
+        }
+    }
+    return property;
+}
+
+void
+OptionValueProperties::DumpAllDescriptions (CommandInterpreter &interpreter,
+                                            Stream &strm) const
+{
+    size_t max_name_len = 0;
+    const size_t num_properties = m_properties.size();
+    for (size_t i=0; i<num_properties; ++i)
+    {
+        const Property *property = ProtectedGetPropertyAtIndex(i);
+        if (property)
+            max_name_len = std::max<size_t>(property->GetName().GetLength(), max_name_len);
+    }
+    for (size_t i=0; i<num_properties; ++i)
+    {
+        const Property *property = ProtectedGetPropertyAtIndex(i);
+        if (property)
+            property->DumpDescription (interpreter, strm, max_name_len, false);
+    }
+}
+
+void
+OptionValueProperties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const
+{
+    const size_t num_properties = m_properties.size();
+    StreamString strm;
+    for (size_t i=0; i<num_properties; ++i)
+    {
+        const Property *property = ProtectedGetPropertyAtIndex(i);
+        if (property)
+        {
+            const OptionValueProperties *properties = property->GetValue()->GetAsProperties();
+            if (properties)
+            {
+                properties->Apropos (keyword, matching_properties);
+            }
+            else
+            {
+                bool match = false;
+                const char *name = property->GetName().GetCString();
+                if (name && ::strcasestr(name, keyword))
+                    match = true;
+                else
+                {
+                    const char *desc = property->GetDescription();
+                    if (desc && ::strcasestr(desc, keyword))
+                        match = true;
+                }
+                if (match)
+                {
+                    matching_properties.push_back (property);
+                }
+            }
+        }
+    }
+}
+
+