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": """ | 
