diff options
-rw-r--r-- | find-modules/Qt5Ruleset.py | 7 | ||||
-rwxr-xr-x | find-modules/rules_engine.py | 76 | ||||
-rw-r--r-- | find-modules/sip_generator.py | 19 | ||||
-rw-r--r-- | tests/GenerateSipBindings/cpplib.cpp | 7 | ||||
-rw-r--r-- | tests/GenerateSipBindings/cpplib.h | 16 | ||||
-rw-r--r-- | tests/GenerateSipBindings/rules_SipTest.py | 7 |
6 files changed, 126 insertions, 6 deletions
diff --git a/find-modules/Qt5Ruleset.py b/find-modules/Qt5Ruleset.py index 8ce6f8da..9392ae18 100644 --- a/find-modules/Qt5Ruleset.py +++ b/find-modules/Qt5Ruleset.py @@ -104,6 +104,9 @@ def variable_rules(): [".*", "d", ".*Private.*", rules_engine.variable_discard], ] +def typedef_rules(): + return [] + class RuleSet(rules_engine.RuleSet): """ SIP file generator rules. This is a set of (short, non-public) functions @@ -113,6 +116,7 @@ class RuleSet(rules_engine.RuleSet): self._container_db = rules_engine.ContainerRuleDb(container_rules) self._fn_db = rules_engine.FunctionRuleDb(function_rules) self._param_db = rules_engine.ParameterRuleDb(parameter_rules) + self._typedef_db = rules_engine.TypedefRuleDb(typedef_rules) self._var_db = rules_engine.VariableRuleDb(variable_rules) self._methodcode = rules_engine.MethodCodeDb({}) self._modulecode = rules_engine.ModuleCodeDb({}) @@ -126,6 +130,9 @@ class RuleSet(rules_engine.RuleSet): def parameter_rules(self): return self._param_db + def typedef_rules(self): + return self._typedef_db + def variable_rules(self): return self._var_db diff --git a/find-modules/rules_engine.py b/find-modules/rules_engine.py index 3bd6ccfc..64ce1d97 100755 --- a/find-modules/rules_engine.py +++ b/find-modules/rules_engine.py @@ -386,6 +386,68 @@ class ParameterRuleDb(AbstractCompiledRuleDb): return None +class TypedefRuleDb(AbstractCompiledRuleDb): + """ + THE RULES FOR TYPEDEFS. + + These are used to customise the behaviour of the SIP generator by allowing + the declaration for any typedef to be customised, for example to add SIP + compiler annotations. + + Each entry in the raw rule database must be a list with members as follows: + + 0. A regular expression which matches the fully-qualified name of the + "container" enclosing the typedef. + + 1. A regular expression which matches the typedef name. + + 2. A function. + + In use, the database is walked in order from the first entry. If the regular + expressions are matched, the function is called, and no further entries are + walked. The function is called with the following contract: + + def typedef_xxx(container, typedef, sip, matcher): + ''' + Return a modified declaration for the given function. + + :param container: The clang.cindex.Cursor for the container. + :param typedef: The clang.cindex.Cursor for the typedef. + :param sip: A dict with the following keys: + + name The name of the typedef. + annotations Any SIP annotations. + + :param matcher: The re.Match object. This contains named + groups corresponding to the key names above + EXCEPT annotations. + + :return: An updated set of sip.xxx values. Setting sip.name to the + empty string will cause the container to be suppressed. + ''' + + :return: The compiled form of the rules. + """ + def __init__(self, db): + super(TypedefRuleDb, self).__init__(db, ["container", "typedef"]) + + def apply(self, container, typedef, sip): + """ + Walk over the rules database for typedefs, applying the first matching transformation. + + :param container: The clang.cindex.Cursor for the container. + :param typedef: The clang.cindex.Cursor for the typedef. + :param sip: The SIP dict. + """ + parents = _parents(typedef) + matcher, rule = self._match(parents, sip["name"]) + if matcher: + before = deepcopy(sip) + rule.fn(container, typedef, sip, matcher) + return rule.trace_result(parents, typedef, before, sip) + return None + + class VariableRuleDb(AbstractCompiledRuleDb): """ THE RULES FOR VARIABLES. @@ -727,6 +789,15 @@ class RuleSet(object): raise NotImplemented(_("Missing subclass implementation")) @abstractmethod + def typedef_rules(self): + """ + Return a compiled list of rules for typedefs. + + :return: A TypedefRuleDb instance + """ + raise NotImplemented(_("Missing subclass implementation")) + + @abstractmethod def variable_rules(self): """ Return a compiled list of rules for variables. @@ -761,7 +832,7 @@ class RuleSet(object): else: logger.warn(_("Rule {} was not used".format(rule))) - for db in [self.container_rules(), self.function_rules(), self.parameter_rules(), + for db in [self.container_rules(), self.function_rules(), self.parameter_rules(), self.typedef_rules(), self.variable_rules(), self.methodcode_rules(), self.modulecode_rules()]: db.dump_usage(dumper) @@ -808,6 +879,9 @@ def function_discard_impl(container, function, sip, matcher): if function.extent.start.column == 1: sip["name"] = "" +def typedef_discard(container, typedef, sip, matcher): + sip["name"] = "" + def rules(project_rules): """ Constructor. diff --git a/find-modules/sip_generator.py b/find-modules/sip_generator.py index e5e807ed..a8c164b5 100644 --- a/find-modules/sip_generator.py +++ b/find-modules/sip_generator.py @@ -228,7 +228,7 @@ class SipGenerator(object): elif member.kind == CursorKind.CXX_ACCESS_SPEC_DECL: decl = self._get_access_specifier(member, level + 1) elif member.kind == CursorKind.TYPEDEF_DECL: - decl = self._typedef_get(member, level + 1) + decl = self._typedef_get(container, member, level + 1) elif member.kind == CursorKind.CXX_BASE_SPECIFIER: # # Strip off the leading "class". Except for TypeKind.UNEXPOSED... @@ -627,7 +627,7 @@ class SipGenerator(object): return _get_param_value(text, parameterType) return "" - def _typedef_get(self, typedef, level): + def _typedef_get(self, container, typedef, level): """ Generate the translation for a typedef. @@ -637,10 +637,19 @@ class SipGenerator(object): :return: A string. """ - pad = " " * (level * 4) + sip = { + "name": typedef.displayname, + "annotations": set(), + } + + self.rules.typedef_rules().apply(container, typedef, sip) - decl = pad + "typedef {} {}".format(typedef.underlying_typedef_type.spelling, typedef.displayname) - decl += ";\n" + pad = " " * (level * 4) + if sip["name"]: + decl = pad + "typedef {} {}".format(typedef.underlying_typedef_type.spelling, typedef.displayname) + decl += ";\n" + else: + decl = pad + "// Discarded {}\n".format(SipGenerator.describe(typedef)) return decl def _var_get(self, container, variable, level): diff --git a/tests/GenerateSipBindings/cpplib.cpp b/tests/GenerateSipBindings/cpplib.cpp index 7eb15939..f996c998 100644 --- a/tests/GenerateSipBindings/cpplib.cpp +++ b/tests/GenerateSipBindings/cpplib.cpp @@ -161,3 +161,10 @@ int anotherCustomMethod(QList<int> const& nums) { return 0; } + +void TypedefUser::setTagPattern(const QString &tagName, + SomeNS::TagFormatter formatter, + int leadingNewlines) +{ + +} diff --git a/tests/GenerateSipBindings/cpplib.h b/tests/GenerateSipBindings/cpplib.h index b69480ee..34167ad3 100644 --- a/tests/GenerateSipBindings/cpplib.h +++ b/tests/GenerateSipBindings/cpplib.h @@ -128,8 +128,24 @@ qreal useEnum(MyFlags flags = EnumValueOne); int customMethod(QList<int> const& nums); +typedef QString(*TagFormatter)(const QStringList &languages, + const QString &tagName, + const QHash<QString, QString> &attributes, + const QString &text, + const QStringList &tagPath, + SomeNS::MyFlagType format); + } +class TypedefUser +{ +public: + + void setTagPattern(const QString &tagName, + SomeNS::TagFormatter formatter = NULL, + int leadingNewlines = 0); +}; + int anotherCustomMethod(QList<int> const& nums); enum __attribute__((visibility("default"))) EnumWithAttributes { diff --git a/tests/GenerateSipBindings/rules_SipTest.py b/tests/GenerateSipBindings/rules_SipTest.py index 1331da41..73c5451b 100644 --- a/tests/GenerateSipBindings/rules_SipTest.py +++ b/tests/GenerateSipBindings/rules_SipTest.py @@ -9,6 +9,12 @@ def local_function_rules(): return [ ["MyObject", "fwdDecl", ".*", ".*", ".*", rules_engine.function_discard], ["MyObject", "fwdDeclRef", ".*", ".*", ".*", rules_engine.function_discard], + ["TypedefUser", "setTagPattern", ".*", ".*", ".*", rules_engine.function_discard], + ] + +def local_typedef_rules(): + return [ + [".*", "TagFormatter", rules_engine.typedef_discard], ] def methodGenerator(function, sip, entry): @@ -23,6 +29,7 @@ class RuleSet(Qt5Ruleset.RuleSet): def __init__(self): Qt5Ruleset.RuleSet.__init__(self) self._fn_db = rules_engine.FunctionRuleDb(lambda: local_function_rules() + Qt5Ruleset.function_rules()) + self._typedef_db = rules_engine.TypedefRuleDb(lambda: local_typedef_rules() + Qt5Ruleset.typedef_rules()) self._modulecode = rules_engine.ModuleCodeDb({ "cpplib.h": { "code": """ |