From: Gunnar Beutner Date: Fri, 12 Aug 2016 09:25:36 +0000 (+0200) Subject: Implement support for namespaces X-Git-Tag: v2.5.0~84 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c5a170a972fbdfee0ef7826a7c277ca9e34850cd;p=icinga2 Implement support for namespaces fixes #12408 --- diff --git a/lib/base/configwriter.cpp b/lib/base/configwriter.cpp index 33be46e27..4a7f5d6e4 100644 --- a/lib/base/configwriter.cpp +++ b/lib/base/configwriter.cpp @@ -244,6 +244,7 @@ const std::vector& ConfigWriter::GetKeywords(void) keywords.push_back("globals"); keywords.push_back("locals"); keywords.push_back("use"); + keywords.push_back("__using"); keywords.push_back("ignore_on_error"); keywords.push_back("current_filename"); keywords.push_back("current_line"); diff --git a/lib/base/function.hpp b/lib/base/function.hpp index 3d76f173e..82d8b152a 100644 --- a/lib/base/function.hpp +++ b/lib/base/function.hpp @@ -66,22 +66,22 @@ private: Callback m_Callback; }; -#define REGISTER_SCRIPTFUNCTION(name, callback) \ - namespace { namespace UNIQUE_NAME(sf) { namespace sf ## name { \ +#define REGISTER_SCRIPTFUNCTION_NS(ns, name, callback) \ + namespace { namespace UNIQUE_NAME(sf) { namespace sf ## ns ## name { \ void RegisterFunction(void) { \ - Function::Ptr sf = new icinga::Function(#name, WrapFunction(callback)); \ - ScriptGlobal::Set(#name, sf); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), false); \ + ScriptGlobal::Set(#ns "." #name, sf); \ } \ INITIALIZE_ONCE_WITH_PRIORITY(RegisterFunction, 10); \ } } } -#define REGISTER_SCRIPTFUNCTION_NS(ns, name, callback) \ +#define REGISTER_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback) \ namespace { namespace UNIQUE_NAME(sf) { namespace sf ## ns ## name { \ void RegisterFunction(void) { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), false); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("__" #name " (deprecated)", WrapFunction(callback), false, true); \ - ScriptGlobal::Set("__" #name, dsf); \ + ScriptGlobal::Set("System.__" #name, dsf); \ } \ INITIALIZE_ONCE_WITH_PRIORITY(RegisterFunction, 10); \ } } } @@ -97,22 +97,22 @@ private: INITIALIZE_ONCE_WITH_PRIORITY(RegisterFunction, 10); \ } } } -#define REGISTER_SAFE_SCRIPTFUNCTION(name, callback) \ - namespace { namespace UNIQUE_NAME(sf) { namespace sf ## name { \ +#define REGISTER_SAFE_SCRIPTFUNCTION_NS(ns, name, callback) \ + namespace { namespace UNIQUE_NAME(sf) { namespace sf ## ns ## name { \ void RegisterFunction(void) { \ - Function::Ptr sf = new icinga::Function(#name, WrapFunction(callback), true); \ - ScriptGlobal::Set(#name, sf); \ + Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), true); \ + ScriptGlobal::Set(#ns "." #name, sf); \ } \ INITIALIZE_ONCE_WITH_PRIORITY(RegisterFunction, 10); \ } } } -#define REGISTER_SAFE_SCRIPTFUNCTION_NS(ns, name, callback) \ +#define REGISTER_SAFE_SCRIPTFUNCTION_NS_PREFIX(ns, name, callback) \ namespace { namespace UNIQUE_NAME(sf) { namespace sf ## ns ## name { \ void RegisterFunction(void) { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, WrapFunction(callback), true); \ ScriptGlobal::Set(#ns "." #name, sf); \ Function::Ptr dsf = new icinga::Function("__" #name " (deprecated)", WrapFunction(callback), true, true); \ - ScriptGlobal::Set("__" #name, dsf); \ + ScriptGlobal::Set("System.__" #name, dsf); \ } \ INITIALIZE_ONCE_WITH_PRIORITY(RegisterFunction, 10); \ } } } diff --git a/lib/base/scriptframe.cpp b/lib/base/scriptframe.cpp index 3526c08d4..8c5c7b14e 100644 --- a/lib/base/scriptframe.cpp +++ b/lib/base/scriptframe.cpp @@ -30,8 +30,15 @@ ScriptFrame::ScriptFrame(void) { std::stack *frames = m_ScriptFrames.get(); - if (frames && !frames->empty()) - Sandboxed = frames->top()->Sandboxed; + if (frames && !frames->empty()) { + ScriptFrame *frame = frames->top(); + + Sandboxed = frame->Sandboxed; + Imports = frame->Imports; + } else { + Imports = new Array(); + Imports->Add(ScriptGlobal::Get("System")); + } PushFrame(this); } diff --git a/lib/base/scriptframe.hpp b/lib/base/scriptframe.hpp index edb4413a6..c0ceb3829 100644 --- a/lib/base/scriptframe.hpp +++ b/lib/base/scriptframe.hpp @@ -22,6 +22,7 @@ #include "config/i2-config.hpp" #include "base/dictionary.hpp" +#include "base/array.hpp" #include #include @@ -31,6 +32,7 @@ namespace icinga struct I2_BASE_API ScriptFrame { Dictionary::Ptr Locals; + Array::Ptr Imports; Value Self; bool Sandboxed; int Depth; diff --git a/lib/base/scriptutils.cpp b/lib/base/scriptutils.cpp index 36f73d270..d27f6e59a 100644 --- a/lib/base/scriptutils.cpp +++ b/lib/base/scriptutils.cpp @@ -37,35 +37,35 @@ using namespace icinga; -REGISTER_SAFE_SCRIPTFUNCTION(regex, &ScriptUtils::Regex); -REGISTER_SAFE_SCRIPTFUNCTION(match, &Utility::Match); -REGISTER_SAFE_SCRIPTFUNCTION(cidr_match, &Utility::CidrMatch); -REGISTER_SAFE_SCRIPTFUNCTION(len, &ScriptUtils::Len); -REGISTER_SAFE_SCRIPTFUNCTION(union, &ScriptUtils::Union); -REGISTER_SAFE_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection); -REGISTER_SCRIPTFUNCTION(log, &ScriptUtils::Log); -REGISTER_SCRIPTFUNCTION(range, &ScriptUtils::Range); -REGISTER_SCRIPTFUNCTION(exit, &Application::Exit); -REGISTER_SAFE_SCRIPTFUNCTION(typeof, &ScriptUtils::TypeOf); -REGISTER_SAFE_SCRIPTFUNCTION(keys, &ScriptUtils::Keys); -REGISTER_SAFE_SCRIPTFUNCTION(random, &Utility::Random); -REGISTER_SAFE_SCRIPTFUNCTION(get_object, &ScriptUtils::GetObject); -REGISTER_SAFE_SCRIPTFUNCTION(get_objects, &ScriptUtils::GetObjects); -REGISTER_SCRIPTFUNCTION(assert, &ScriptUtils::Assert); -REGISTER_SAFE_SCRIPTFUNCTION(string, &ScriptUtils::CastString); -REGISTER_SAFE_SCRIPTFUNCTION(number, &ScriptUtils::CastNumber); -REGISTER_SAFE_SCRIPTFUNCTION(bool, &ScriptUtils::CastBool); -REGISTER_SAFE_SCRIPTFUNCTION(get_time, &Utility::GetTime); -REGISTER_SAFE_SCRIPTFUNCTION(basename, &Utility::BaseName); -REGISTER_SAFE_SCRIPTFUNCTION(dirname, &Utility::DirName); -REGISTER_SAFE_SCRIPTFUNCTION(msi_get_component_path, &ScriptUtils::MsiGetComponentPathShim); -REGISTER_SAFE_SCRIPTFUNCTION(track_parents, &ScriptUtils::TrackParents); -REGISTER_SAFE_SCRIPTFUNCTION(escape_shell_cmd, &Utility::EscapeShellCmd); -REGISTER_SAFE_SCRIPTFUNCTION(escape_shell_arg, &Utility::EscapeShellArg); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, regex, &ScriptUtils::Regex); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, match, &Utility::Match); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, cidr_match, &Utility::CidrMatch); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, len, &ScriptUtils::Len); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, union, &ScriptUtils::Union); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, intersection, &ScriptUtils::Intersection); +REGISTER_SCRIPTFUNCTION_NS(System, log, &ScriptUtils::Log); +REGISTER_SCRIPTFUNCTION_NS(System, range, &ScriptUtils::Range); +REGISTER_SCRIPTFUNCTION_NS(System, exit, &Application::Exit); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, typeof, &ScriptUtils::TypeOf); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, keys, &ScriptUtils::Keys); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, random, &Utility::Random); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_object, &ScriptUtils::GetObject); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_objects, &ScriptUtils::GetObjects); +REGISTER_SCRIPTFUNCTION_NS(System, assert, &ScriptUtils::Assert); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, string, &ScriptUtils::CastString); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, number, &ScriptUtils::CastNumber); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, bool, &ScriptUtils::CastBool); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, get_time, &Utility::GetTime); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, basename, &Utility::BaseName); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, dirname, &Utility::DirName); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, msi_get_component_path, &ScriptUtils::MsiGetComponentPathShim); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, track_parents, &ScriptUtils::TrackParents); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_shell_cmd, &Utility::EscapeShellCmd); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_shell_arg, &Utility::EscapeShellArg); #ifdef _WIN32 -REGISTER_SAFE_SCRIPTFUNCTION(escape_create_process_arg, &Utility::EscapeCreateProcessArg); +REGISTER_SAFE_SCRIPTFUNCTION_NS(System, escape_create_process_arg, &Utility::EscapeCreateProcessArg); #endif /* _WIN32 */ -REGISTER_SCRIPTFUNCTION(ptr, &ScriptUtils::Ptr); +REGISTER_SCRIPTFUNCTION_NS(System, ptr, &ScriptUtils::Ptr); String ScriptUtils::CastString(const Value& value) { diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index b52d8ebf5..8cac9f157 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -180,6 +180,7 @@ this return T_THIS; globals return T_GLOBALS; locals return T_LOCALS; use return T_USE; +__using return T_USING; apply return T_APPLY; to return T_TO; where return T_WHERE; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index baf9b241f..e778bf1b2 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -150,6 +150,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %token T_CURRENT_LINE "current_line (T_CURRENT_LINE)" %token T_DEBUGGER "debugger (T_DEBUGGER)" %token T_USE "use (T_USE)" +%token T_USING "__using (T_USING)" %token T_OBJECT "object (T_OBJECT)" %token T_TEMPLATE "template (T_TEMPLATE)" %token T_INCLUDE "include (T_INCLUDE)" @@ -596,6 +597,10 @@ lterm: T_LIBRARY rterm { $$ = new BreakpointExpression(@$); } + | T_USING rterm + { + $$ = new UsingExpression($2, @$); + } | apply | object | T_FOR '(' identifier T_FOLLOWS identifier T_IN rterm ')' diff --git a/lib/config/configfragment.hpp b/lib/config/configfragment.hpp index a528bd404..ad3efba22 100644 --- a/lib/config/configfragment.hpp +++ b/lib/config/configfragment.hpp @@ -23,6 +23,8 @@ #include "config/configcompiler.hpp" #include "base/initialize.hpp" #include "base/debug.hpp" +#include "base/exception.hpp" +#include "base/application.hpp" #define REGISTER_CONFIG_FRAGMENT(id, name, fragment) \ namespace { \ @@ -30,8 +32,13 @@ { \ icinga::Expression *expression = icinga::ConfigCompiler::CompileText(name, fragment); \ VERIFY(expression); \ - icinga::ScriptFrame frame; \ - expression->Evaluate(frame); \ + try { \ + icinga::ScriptFrame frame; \ + expression->Evaluate(frame); \ + } catch (const std::exception& ex) { \ + std::cerr << icinga::DiagnosticInformation(ex) << std::endl; \ + icinga::Application::Exit(1); \ + } \ delete expression; \ } \ \ diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index fa1b9714d..5266464cc 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -46,7 +46,7 @@ ConfigItem::TypeMap ConfigItem::m_Items; ConfigItem::ItemList ConfigItem::m_UnnamedItems; ConfigItem::IgnoredItemList ConfigItem::m_IgnoredItems; -REGISTER_SCRIPTFUNCTION_NS(Internal, run_with_activation_context, &ConfigItem::RunWithActivationContext); +REGISTER_SCRIPTFUNCTION_NS_PREFIX(Internal, run_with_activation_context, &ConfigItem::RunWithActivationContext); /** * Constructor for the ConfigItem class. diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 2e52425fd..11ffc9c08 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -124,6 +124,8 @@ ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *d return value; else if (frame.Self.IsObject() && frame.Locals != static_cast(frame.Self) && static_cast(frame.Self)->HasOwnField(m_Variable)) return VMOps::GetField(frame.Self, m_Variable, frame.Sandboxed, m_DebugInfo); + else if (VMOps::FindVarImport(frame, m_Variable, &value, m_DebugInfo)) + return value; else return ScriptGlobal::Get(m_Variable); } @@ -142,6 +144,8 @@ bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value if (dhint && *dhint) *dhint = new DebugHint((*dhint)->GetChild(m_Variable)); + } else if (VMOps::FindVarImportRef(frame, m_Variable, parent, m_DebugInfo)) { + return true; } else if (ScriptGlobal::Exists(m_Variable)) { *parent = ScriptGlobal::GetGlobals(); @@ -891,3 +895,25 @@ ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint return Empty; } +ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +{ + if (frame.Sandboxed) + BOOST_THROW_EXCEPTION(ScriptError("Using directives are not allowed in sandbox mode.", m_DebugInfo)); + + ExpressionResult importres = m_Name->Evaluate(frame); + CHECK_RESULT(importres); + Value import = importres.GetValue(); + + if (!import.IsObject()) + BOOST_THROW_EXCEPTION(ScriptError("The parameter does not resolve to an object", m_DebugInfo)); + + if (!frame.Imports) + frame.Imports = new Array(); + else + frame.Imports = static_pointer_cast(frame.Imports->Clone()); + + frame.Imports->Add(import); + + return Empty; +} + diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 226b1b90a..7eb598621 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -953,6 +953,25 @@ protected: virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; +class I2_CONFIG_API UsingExpression : public DebuggableExpression +{ +public: + UsingExpression(Expression *name, const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo), m_Name(name) + { } + + ~UsingExpression(void) + { + delete m_Name; + } + +protected: + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; + +private: + Expression *m_Name; +}; + } #endif /* EXPRESSION_H */ diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index a23687217..40d56170d 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -44,15 +44,33 @@ namespace icinga class VMOps { public: - static inline Value Variable(ScriptFrame& frame, const String& name, const DebugInfo& debugInfo = DebugInfo()) + static inline bool FindVarImportRef(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo()) { - Value value; - if (frame.Locals && frame.Locals->Get(name, &value)) - return value; - else if (frame.Self.IsObject() && frame.Locals != static_cast(frame.Self) && static_cast(frame.Self)->HasOwnField(name)) - return GetField(frame.Self, name, frame.Sandboxed, debugInfo); - else - return ScriptGlobal::Get(name); + if (!frame.Imports) + return false; + + ObjectLock olock(frame.Imports); + BOOST_FOREACH(const Value& import, frame.Imports) { + Object::Ptr obj = import; + if (obj->HasOwnField(name)) { + *result = import; + return true; + } + } + + return false; + } + + static inline bool FindVarImport(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo()) + { + Value parent; + + if (FindVarImportRef(frame, name, &parent, debugInfo)) { + *result = GetField(parent, name, frame.Sandboxed, debugInfo); + return true; + } + + return false; } static inline Value ConstructorCall(const Type::Ptr& type, const std::vector& args, const DebugInfo& debugInfo = DebugInfo()) diff --git a/lib/icinga/objectutils.cpp b/lib/icinga/objectutils.cpp index aafe72f31..7d88e6eea 100644 --- a/lib/icinga/objectutils.cpp +++ b/lib/icinga/objectutils.cpp @@ -29,16 +29,16 @@ using namespace icinga; -REGISTER_SCRIPTFUNCTION(get_host, &Host::GetByName); -REGISTER_SCRIPTFUNCTION(get_service, &ObjectUtils::GetService); -REGISTER_SCRIPTFUNCTION(get_user, &User::GetByName); -REGISTER_SCRIPTFUNCTION(get_check_command, &CheckCommand::GetByName); -REGISTER_SCRIPTFUNCTION(get_event_command, &EventCommand::GetByName); -REGISTER_SCRIPTFUNCTION(get_notification_command, &NotificationCommand::GetByName); -REGISTER_SCRIPTFUNCTION(get_host_group, &HostGroup::GetByName); -REGISTER_SCRIPTFUNCTION(get_service_group, &ServiceGroup::GetByName); -REGISTER_SCRIPTFUNCTION(get_user_group, &UserGroup::GetByName); -REGISTER_SCRIPTFUNCTION(get_time_period, &TimePeriod::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_host, &Host::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_service, &ObjectUtils::GetService); +REGISTER_SCRIPTFUNCTION_NS(System, get_user, &User::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_check_command, &CheckCommand::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_event_command, &EventCommand::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_notification_command, &NotificationCommand::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_host_group, &HostGroup::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_service_group, &ServiceGroup::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_user_group, &UserGroup::GetByName); +REGISTER_SCRIPTFUNCTION_NS(System, get_time_period, &TimePeriod::GetByName); Service::Ptr ObjectUtils::GetService(const String& host, const String& name) { diff --git a/lib/icinga/perfdatavalue.cpp b/lib/icinga/perfdatavalue.cpp index 3983e8046..5c361415f 100644 --- a/lib/icinga/perfdatavalue.cpp +++ b/lib/icinga/perfdatavalue.cpp @@ -30,7 +30,7 @@ using namespace icinga; REGISTER_TYPE(PerfdataValue); -REGISTER_SCRIPTFUNCTION(parse_performance_data, PerfdataValue::Parse); +REGISTER_SCRIPTFUNCTION_NS(System, parse_performance_data, PerfdataValue::Parse); PerfdataValue::PerfdataValue(void) { } diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp index 7e8c65677..3fb41edfc 100644 --- a/lib/remote/consolehandler.cpp +++ b/lib/remote/consolehandler.cpp @@ -215,6 +215,45 @@ static void AddSuggestion(std::vector& matches, const String& word, cons matches.push_back(suggestion); } +static void AddSuggestions(std::vector& matches, const String& word, const String& pword, const Value& value) +{ + String prefix; + + if (!pword.IsEmpty()) + prefix = pword + "."; + + if (value.IsObjectType()) { + Dictionary::Ptr dict = value; + + ObjectLock olock(dict); + BOOST_FOREACH(const Dictionary::Pair& kv, dict) { + AddSuggestion(matches, word, prefix + kv.first); + } + } + + Type::Ptr type = value.GetReflectionType(); + + for (int i = 0; i < type->GetFieldCount(); i++) { + Field field = type->GetFieldInfo(i); + + AddSuggestion(matches, word, prefix + field.Name); + } + + while (type) { + Object::Ptr prototype = type->GetPrototype(); + Dictionary::Ptr dict = dynamic_pointer_cast(prototype); + + if (dict) { + ObjectLock olock(dict); + BOOST_FOREACH(const Dictionary::Pair& kv, dict) { + AddSuggestion(matches, word, prefix + kv.first); + } + } + + type = type->GetBaseType(); + } +} + std::vector ConsoleHandler::GetAutocompletionSuggestions(const String& word, ScriptFrame& frame) { std::vector matches; @@ -237,6 +276,13 @@ std::vector ConsoleHandler::GetAutocompletionSuggestions(const String& w } } + if (frame.Imports) { + ObjectLock olock(frame.Imports); + BOOST_FOREACH(const Value& import, frame.Imports) { + AddSuggestions(matches, word, "", import); + } + } + String::SizeType cperiod = word.RFind("."); if (cperiod != String::NPos) { @@ -250,36 +296,8 @@ std::vector ConsoleHandler::GetAutocompletionSuggestions(const String& w if (expr) value = expr->Evaluate(frame); - if (value.IsObjectType()) { - Dictionary::Ptr dict = value; - - ObjectLock olock(dict); - BOOST_FOREACH(const Dictionary::Pair& kv, dict) { - AddSuggestion(matches, word, pword + "." + kv.first); - } - } + AddSuggestions(matches, word, pword, value); - Type::Ptr type = value.GetReflectionType(); - - for (int i = 0; i < type->GetFieldCount(); i++) { - Field field = type->GetFieldInfo(i); - - AddSuggestion(matches, word, pword + "." + field.Name); - } - - while (type) { - Object::Ptr prototype = type->GetPrototype(); - Dictionary::Ptr dict = dynamic_pointer_cast(prototype); - - if (dict) { - ObjectLock olock(dict); - BOOST_FOREACH(const Dictionary::Pair& kv, dict) { - AddSuggestion(matches, word, pword + "." + kv.first); - } - } - - type = type->GetBaseType(); - } } catch (...) { /* Ignore the exception */ } }