Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / PoolQuery.cc
index 17b7615..5fe838e 100644 (file)
@@ -179,13 +179,6 @@ namespace zypp
      * match, it's also suitable for sub-structure (flexarray) inspection
      * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
      *
-     * (bsc#1035729) If SolvAttr::name searches for an explicit \c kind:name,
-     * this \c kind is stored in \ref kindPredicate and will overwrite any
-     * 'global' kind restriction applied via \ref PoolQuery::addKind. This
-     * task can't be passed off to a predicate, as \ref PoolQueryMatcher::isAMatch
-     * must accept only explicit-kind-checking predicate matches, in case the
-     * 'global' kind restriction woudl otherwise discard the match.
-     *
      * \note: \see \ref addPredicate for further constraints.
      */
     struct AttrMatchData
@@ -198,10 +191,6 @@ namespace zypp
       AttrMatchData()
       {}
 
-      AttrMatchData( sat::SolvAttr attr_r )
-        : attr( attr_r )
-      {}
-
       AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r )
         : attr( attr_r )
         , strMatcher( strMatcher_r )
@@ -220,8 +209,8 @@ namespace zypp
        * string representation instead. If you add new predicated, check the
        * deserialization code in \ref deserialize.
        */
-      template<class _Predicate>
-      void addPredicate( const _Predicate & predicate_r )
+      template<class TPredicate>
+      void addPredicate( const TPredicate & predicate_r )
       {
         predicate    = predicate_r;
         predicateStr = predicate_r.serialize();
@@ -312,18 +301,15 @@ namespace zypp
      }
 
       sat::SolvAttr    attr;
-      StrMatcher       strMatcher;
+      StrMatcher strMatcher;
       Predicate        predicate;
       std::string      predicateStr;
-      ResKind          kindPredicate = ResKind::nokind;        // holds the 'kind' part if SolvAttr:name looks for an explicit 'kind:name'
     };
 
     /** \relates AttrMatchData */
     inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
     {
       str << obj.attr << ": " << obj.strMatcher;
-      if ( obj.kindPredicate )
-        str << " +(" << obj.kindPredicate << ")";
       if ( obj.predicate )
         str << " +(" << obj.predicateStr << ")";
       return str;
@@ -371,6 +357,7 @@ namespace zypp
     Impl()
       : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
       , _match_word(false)
+      , _require_all(false)
       , _status_flags(ALL)
     {}
 
@@ -393,6 +380,7 @@ namespace zypp
     /** Sat solver search flags */
     Match _flags;
     bool _match_word;
+    bool _require_all;
 
     /** Sat solver status flags */
     StatusFilter _status_flags;
@@ -411,23 +399,6 @@ namespace zypp
 
   public:
 
-    bool operator<( const PoolQuery::Impl & rhs ) const
-    {
-#define OUTS(A) if ( A != rhs.A ) return A < rhs.A;
-      OUTS( _strings );
-      OUTS( _attrs );
-      OUTS( _uncompiledPredicated );
-      OUTS( _flags.get() );
-      OUTS( _match_word );
-      OUTS( _status_flags );
-      OUTS( _edition );
-      OUTS( _op.inSwitch() );
-      OUTS( _repos );
-      OUTS( _kinds );
-#undef OUTS
-      return false;
-    }
-
     bool operator==( const PoolQuery::Impl & rhs ) const
     {
       if ( _flags == rhs._flags
@@ -446,6 +417,7 @@ namespace zypp
              && _attrs == rhs._attrs
              && _uncompiledPredicated == rhs._uncompiledPredicated
              && _match_word == rhs._match_word
+             && _require_all == rhs._require_all
              && _status_flags == rhs._status_flags
              && _edition == rhs._edition
              && _op == rhs._op
@@ -469,10 +441,8 @@ namespace zypp
     mutable AttrMatchList _attrMatchList;
 
   private:
-    /** Join patterns in \a container_r according to \a flags_r into a single \ref StrMatcher.
-     * The \ref StrMatcher returned will be a REGEX if more than one pattern was passed.
-     */
-    StrMatcher joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const;
+    /** Pass flags from \ref compile, as they may have been changed. */
+    string createRegex( const StrContainer & container, const Match & flags ) const;
 
   private:
     friend Impl * rwcowClone<Impl>( const Impl * rhs );
@@ -509,8 +479,13 @@ namespace zypp
   {
     _attrMatchList.clear();
 
-    if ( _flags.mode() == Match::OTHER ) // this will never succeed...
-      ZYPP_THROW( MatchUnknownModeException( _flags ) );
+    Match cflags( _flags );
+    if ( cflags.mode() == Match::OTHER ) // this will never succeed...
+      ZYPP_THROW( MatchUnknownModeException( cflags ) );
+
+    /** Compiled search strings. */
+    string rcstrings;
+
 
     // 'different'         - will have to iterate through all and match by ourselves (slow)
     // 'same'              - will pass the compiled string to dataiterator_init
@@ -535,8 +510,11 @@ namespace zypp
       StrContainer joined;
       invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
       invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
-
-      _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, joinedStrMatcher( joined, _flags ) ) );
+      rcstrings = createRegex(joined, cflags);
+      if (joined.size() > 1) // switch to regex for multiple strings
+        cflags.setModeRegex();
+      _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
+                                StrMatcher( rcstrings, cflags ) ) );
     }
 
     // // MULTIPLE ATTRIBUTES
@@ -544,21 +522,16 @@ namespace zypp
     {
       // check whether there are any per-attribute strings
       bool attrvals_empty = true;
-      for_( ai, _attrs.begin(), _attrs.end() )
-      {
-        if ( ai->second.empty() )
-         continue;
-       for_( it, ai->second.begin(), ai->second.end() )
-       {
-         if ( !it->empty() )
-         {
-           attrvals_empty = false;
-           break;
-         }
-       }
-        if ( ! attrvals_empty )
-         break;
-      }
+      for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
+        if (!ai->second.empty())
+          for(StrContainer::const_iterator it = ai->second.begin();
+              it != ai->second.end(); it++)
+            if (!it->empty())
+            {
+              attrvals_empty = false;
+              goto attremptycheckend;
+            }
+attremptycheckend:
 
       // chceck whether the per-attribute strings are all the same
       bool attrvals_thesame = true;
@@ -589,15 +562,18 @@ namespace zypp
         if (attrvals_empty)
         {
           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
+          rcstrings = createRegex(joined, cflags);
         }
         else
         {
           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
           invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
+          rcstrings = createRegex(joined, cflags);
         }
-
+        if (joined.size() > 1) // switch to regex for multiple strings
+          cflags.setModeRegex();
         // May use the same StrMatcher for all
-        StrMatcher matcher( joinedStrMatcher( joined, _flags ) );
+        StrMatcher matcher( rcstrings, cflags );
         for_( ai, _attrs.begin(), _attrs.end() )
         {
           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
@@ -615,8 +591,11 @@ namespace zypp
           StrContainer joined;
           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
-
-          _attrMatchList.push_back( AttrMatchData( ai->first, joinedStrMatcher( joined, _flags ) ) );
+          string s = createRegex(joined, cflags);
+          if (joined.size() > 1) // switch to regex for multiple strings
+            cflags.setModeRegex();
+          _attrMatchList.push_back( AttrMatchData( ai->first,
+                                    StrMatcher( s, cflags ) ) );
         }
       }
     }
@@ -636,10 +615,14 @@ namespace zypp
           if ( ! mstr.empty() )
             joined.insert( mstr );
 
-         // copy and exchange the StrMatcher
-         AttrMatchData nattr( *it );
-         nattr.strMatcher = joinedStrMatcher( joined, _flags );
-          _attrMatchList.push_back( std::move(nattr) );
+          cflags = _flags;
+          rcstrings = createRegex( joined, cflags );
+          if ( joined.size() > 1 ) // switch to regex for multiple strings
+            cflags.setModeRegex();
+
+          _attrMatchList.push_back( AttrMatchData( it->attr,
+                                    StrMatcher( rcstrings, cflags ),
+                                                      it->predicate, it->predicateStr ) );
         }
         else
         {
@@ -652,7 +635,12 @@ namespace zypp
     // If no attributes defined at all, then add 'query all'
     if ( _attrMatchList.empty() )
     {
-      _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, joinedStrMatcher( _strings, _flags ) ) );
+      cflags = _flags;
+      rcstrings = createRegex( _strings, cflags );
+      if ( _strings.size() > 1 ) // switch to regex for multiple strings
+        cflags.setModeRegex();
+      _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
+                                StrMatcher( rcstrings, cflags ) ) );
     }
 
     // Finally check here, whether all involved regex compile.
@@ -663,62 +651,102 @@ namespace zypp
     //DBG << asString() << endl;
   }
 
-  ///////////////////////////////////////////////////////////////////
-  namespace
+
+  /**
+   * Converts '*' and '?' wildcards within str into their regex equivalents.
+   */
+  static string wildcards2regex(const string & str)
   {
-    /** Escape \a str_r for use in a regex.
-     * \a flags_r determines whether the input string is interpreted
-     * as regex, glob or plain string.
-     */
-    std::string rxEscape( std::string str_r, const Match & flags_r )
+    string regexed = str;
+
+    string r_all(".*"); // regex equivalent of '*'
+    string r_one(".");  // regex equivalent of '?'
+    string::size_type pos;
+
+    // replace all "*" in input with ".*"
+    for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
+      regexed = regexed.replace(pos, 1, r_all);
+
+    // replace all "?" in input with "."
+    for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
+      regexed = regexed.replace(pos, 1, r_one);
+
+    return regexed;
+  }
+
+  string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
+  {
+//! macro for word boundary tags for regexes
+#define WB (_match_word ? string("\\b") : string())
+    string rstr;
+
+    if (container.empty())
+      return rstr;
+
+    if (container.size() == 1)
     {
-      if ( str_r.empty() || flags_r.isModeRegex() )
-       return str_r;
+      return WB + *container.begin() + WB;
+    }
+
+    // multiple strings
+
+    bool use_wildcards = flags.isModeGlob();
+    StrContainer::const_iterator it = container.begin();
+    string tmp;
 
-      if ( flags_r.isModeGlob() )
-       return str::rxEscapeGlob( std::move(str_r) );
+    if (use_wildcards)
+      tmp = wildcards2regex(*it);
+    else
+      tmp = *it;
 
-      return str::rxEscapeStr( std::move(str_r) );
+    if (_require_all)
+    {
+      if ( ! flags.isModeString() ) // not match exact
+        tmp += ".*" + WB + tmp;
+      rstr = "(?=" + tmp + ")";
+    }
+    else
+    {
+      if ( flags.isModeString() || flags.isModeGlob() )
+        rstr = "^";
+      rstr += WB + "(" + tmp;
     }
-  } // namespace
-  ///////////////////////////////////////////////////////////////////
 
-  StrMatcher PoolQuery::Impl::joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const
-  {
-    if ( container_r.empty() )
-      return StrMatcher( std::string(), flags_r );
-
-    if ( container_r.size() == 1 && !_match_word )     // use RX to match words
-      return StrMatcher( *container_r.begin(), flags_r );
-
-    // Convert to a regex.
-    // Note: Modes STRING and GLOB match whole strings (anchored ^ $)
-    //       SUBSTRING and REGEX match substrings      (match_word anchores SUBSTRING \b)
-    Match retflags( flags_r );
-    retflags.setModeRegex();
-    str::Str ret;
-
-    if ( flags_r.isModeString() || flags_r.isModeGlob() )
-      ret << "^";
-    else if ( _match_word )
-      ret << "\\b";
-
-    // (..|..|..)
-    char sep = '(';
-    for ( const::std::string & s : container_r )
+    ++it;
+
+    for (; it != container.end(); ++it)
     {
-      ret << sep << rxEscape( s, flags_r );
-      if ( sep == '(' )
-       sep = '|';
+      if (use_wildcards)
+        tmp = wildcards2regex(*it);
+      else
+        tmp = *it;
+
+      if (_require_all)
+      {
+        if ( ! flags.isModeString() ) // not match exact
+          tmp += ".*" + WB + tmp;
+        rstr += "(?=" + tmp + ")";
+      }
+      else
+      {
+        rstr += "|" + tmp;
+      }
     }
-    ret << ')';
 
-    if ( flags_r.isModeString() || flags_r.isModeGlob() )
-      ret << "$";
-    else if ( _match_word )
-      ret << "\\b";
+    if (_require_all)
+    {
+      if ( ! flags.isModeString() ) // not match exact
+        rstr += WB + ".*";
+    }
+    else
+    {
+      rstr += ")" + WB;
+      if ( flags.isModeString() || flags.isModeGlob() )
+        rstr += "$";
+    }
 
-    return StrMatcher( ret, retflags );
+    return rstr;
+#undef WB
   }
 
   string PoolQuery::Impl::asString() const
@@ -831,14 +859,10 @@ namespace zypp
 
   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
   {
-    // SolvAttr::name with explicit 'kind:name' will overwrite the default _kinds
-    ResKind explicitKind;
-    if ( attr == sat::SolvAttr::name ) explicitKind = ResKind::explicitBuiltin( name );
-
     switch ( op.inSwitch() )
     {
       case Rel::ANY_e: // no additional constraint on edition.
-        if ( arch.empty() && !explicitKind )   // no additional constraint on arch/kind
+        if ( arch.empty() )    // no additional constraint on arch.
        {
          addAttribute( attr, name );
          return;
@@ -854,15 +878,7 @@ namespace zypp
 
     // Match::OTHER indicates need to compile
     // (merge global search strings into name).
-    AttrMatchData attrMatchData( attr );
-    if ( !explicitKind )
-      attrMatchData.strMatcher = StrMatcher( name, Match::OTHER );
-    else
-    {
-      // ResKind::explicitBuiltin call above asserts the presence of the ':' in name
-      attrMatchData.strMatcher = StrMatcher( strchr( name.c_str(), ':')+1, Match::OTHER );
-      attrMatchData.kindPredicate = explicitKind;
-    }
+    AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
 
     if ( isDependencyAttribute( attr ) )
       attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
@@ -895,11 +911,15 @@ namespace zypp
     _pimpl->_op = op;
   }
 
-  void PoolQuery::setMatchSubstring()  { _pimpl->_flags.setModeSubstring();    _pimpl->_match_word = false; }
-  void PoolQuery::setMatchExact()      { _pimpl->_flags.setModeString();       _pimpl->_match_word = false; }
-  void PoolQuery::setMatchRegex()      { _pimpl->_flags.setModeRegex();        _pimpl->_match_word = false; }
-  void PoolQuery::setMatchGlob()       { _pimpl->_flags.setModeGlob();         _pimpl->_match_word = false; }
-  void PoolQuery::setMatchWord()       { _pimpl->_flags.setModeSubstring();    _pimpl->_match_word = true; }
+  void PoolQuery::setMatchSubstring()  { _pimpl->_flags.setModeSubstring(); }
+  void PoolQuery::setMatchExact()      { _pimpl->_flags.setModeString(); }
+  void PoolQuery::setMatchRegex()      { _pimpl->_flags.setModeRegex(); }
+  void PoolQuery::setMatchGlob()       { _pimpl->_flags.setModeGlob(); }
+  void PoolQuery::setMatchWord()
+  {
+    _pimpl->_match_word = true;
+    _pimpl->_flags.setModeRegex();
+  }
 
   Match PoolQuery::flags() const
   { return _pimpl->_flags; }
@@ -915,6 +935,10 @@ namespace zypp
   { _pimpl->_status_flags = flags; }
 
 
+  void PoolQuery::setRequireAll(bool require_all)
+  { _pimpl->_require_all = require_all; }
+
+
   const PoolQuery::StrContainer &
   PoolQuery::strings() const
   { return _pimpl->_strings; }
@@ -957,10 +981,15 @@ namespace zypp
   { _pimpl->_flags.turn( Match::FILES, value ); }
 
   bool PoolQuery::matchExact() const           { return _pimpl->_flags.isModeString(); }
-  bool PoolQuery::matchSubstring() const       { return _pimpl->_flags.isModeSubstring() && !_pimpl->_match_word; }
+  bool PoolQuery::matchSubstring() const       { return _pimpl->_flags.isModeSubstring(); }
   bool PoolQuery::matchGlob() const            { return _pimpl->_flags.isModeGlob(); }
   bool PoolQuery::matchRegex() const           { return _pimpl->_flags.isModeRegex(); }
-  bool PoolQuery::matchWord() const            { return _pimpl->_flags.isModeSubstring() && _pimpl->_match_word; }
+
+  bool PoolQuery::matchWord() const
+  { return _pimpl->_match_word; }
+
+  bool PoolQuery::requireAll() const
+  { return _pimpl->_require_all; }
 
   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
   { return _pimpl->_status_flags; }
@@ -989,9 +1018,6 @@ namespace zypp
   { invokeOnEach( begin(), end(), fnc); }
 
 
-  /*DEPRECATED LEGACY:*/void PoolQuery::setRequireAll( bool ) {}
-  /*DEPRECATED LEGACY:*/bool PoolQuery::requireAll() const    { return false; }
-
   ///////////////////////////////////////////////////////////////////
   //
   //  CLASS NAME : PoolQuery::Attr
@@ -1026,7 +1052,7 @@ namespace zypp
     static const PoolQueryAttr kindAttr;
     static const PoolQueryAttr stringAttr;
     static const PoolQueryAttr stringTypeAttr;
-    static const PoolQueryAttr requireAllAttr; // LEAGACY: attribute was defined but never implemented.
+    static const PoolQueryAttr requireAllAttr;
     static const PoolQueryAttr caseSensitiveAttr;
     static const PoolQueryAttr installStatusAttr;
     static const PoolQueryAttr editionAttr;
@@ -1039,7 +1065,7 @@ namespace zypp
   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
-  const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");    // LEAGACY: attribute was defined but never implemented.
+  const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
@@ -1163,8 +1189,18 @@ namespace zypp
       }
       else if ( attribute==PoolQueryAttr::requireAllAttr )
       {
-       // LEAGACY: attribute was defined but never implemented.
-       // Actually it should not occur outside our testcases.
+        if ( str::strToTrue(attrValue) )
+        {
+          setRequireAll(true);
+        }
+        else if ( !str::strToFalse(attrValue) )
+        {
+          setRequireAll(false);
+        }
+        else
+        {
+          WAR << "unknown boolean value " << attrValue << endl;
+        }
       }
       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
       {
@@ -1249,70 +1285,6 @@ namespace zypp
 
     } while ( true );
 
-    // OLD STYLE VERSIONED LOCKS:
-    // solvable_name: kernel
-    // version: > 1
-    //
-    // NEW STYLE VERSIONED LOCKS:
-    // complex: AttrMatchData solvable:name kernel C SolvableRange\ >\ 1\ \"\"
-    //   or
-    // solvable_name: kernel > 1
-    //
-    // Semantically equivalent as locks, but due to the different syntax
-    // the complex lock is wrongly handled by zypper.
-    //
-    // bsc#1112911: Unfortunately all styles are found in real-life locks-files.
-    // libzypp will try to make sure, when parsing the locks-file, that complex
-    // locks are rewritten into to OLD STYLE queries zypper can handle.
-    if ( !_pimpl->_attrs.count(SolvAttr::name) && _pimpl->_uncompiledPredicated.size() == 1 )
-    {
-      // No OLD STYLE lock for SolvAttr::name and exactly one complex lock...
-      const AttrMatchData & attrmatch {  *_pimpl->_uncompiledPredicated.begin() };
-      if ( attrmatch.attr == SolvAttr::name && attrmatch.strMatcher.flags().mode() == Match::OTHER )
-      {
-       // ...for SolvAttr::name and following the global search flags.
-       // A candidate for a rewrite?
-
-       std::vector<std::string> words;
-       str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) );
-       if ( words.size() < 4 || words[3].empty() )
-       {
-         // We have _NO_ arch rule in the complex predicate, so we can simplify it.
-         //
-         // NOTE: AFAIK it's not possible to create (or have created) a complex lock
-         // with arch rule with zypper means. Nevertheless, in case such a rule made it
-         // into a locks file, it's better to have a strange looking 'zypper locks' list
-         // than to lock the wrong packages.
-         // (and remember that you can't use "addAttribute( SolvAttr::arch, ... )" because
-         // attributes are `OR`ed)
-
-         // kind
-         if ( attrmatch.kindPredicate )
-         {
-           _pimpl->_kinds.clear();     // an explicit kind overwrites any global one
-           addKind( attrmatch.kindPredicate );
-         }
-
-         // name
-         addAttribute( SolvAttr::name, attrmatch.strMatcher.searchstring() );
-
-         // edition
-         std::vector<std::string> words;
-         str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) );
-         if ( ! words.empty() )
-         {
-           if ( words[0] == "EditionRange" || words[0] == "SolvableRange" )
-           {
-             setEdition( Edition(words[2]), Rel(words[1]) );
-           }
-         }
-
-         // finally remove the complex lock
-         _pimpl->_uncompiledPredicated.clear();
-       }
-      }
-    }
-
     return finded_something;
   }
 
@@ -1372,6 +1344,19 @@ namespace zypp
       }
     }
 
+    if( requireAll() != q.requireAll() )
+    {
+      str << "require_all: ";
+      if (requireAll())
+      {
+        str << "on" << delim;
+      }
+      else
+      {
+        str << "off" << delim;
+      }
+    }
+
     if( statusFilterFlags() != q.statusFilterFlags() )
     {
       switch( statusFilterFlags() )
@@ -1424,9 +1409,6 @@ namespace zypp
   bool PoolQuery::operator==( const PoolQuery & rhs ) const
   { return *_pimpl == *rhs._pimpl; }
 
-  bool PoolQuery::operator<( const PoolQuery & rhs ) const
-  { return *_pimpl < *rhs._pimpl; }
-
   ///////////////////////////////////////////////////////////////////
   namespace detail
   { /////////////////////////////////////////////////////////////////
@@ -1632,18 +1614,19 @@ namespace zypp
          }
          /////////////////////////////////////////////////////////////////////
          sat::Solvable inSolvable( base_r.inSolvable() );
+         // Kind restriction:
+         if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
+         {
+            base_r.nextSkipSolvable();
+            return false;
+         }
+
          // Edition restriction:
          if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
          {
            base_r.nextSkipSolvable();
            return false;
          }
-
-         // Kind restriction:
-         // Delay the decision to nextSkipSolvable and return false, as there may be
-         // some explicit kind:name predicate which overrules the global kinds.
-         bool globalKindOk =( _kinds.empty() || inSolvable.isKind( _kinds.begin(), _kinds.end() ) );
-
          /////////////////////////////////////////////////////////////////////
          // string and predicate matching:
 
@@ -1651,38 +1634,17 @@ namespace zypp
           {
             // String matching was done by the base iterator.
             // Now check any predicate:
-           const AttrMatchData & matchData( _attrMatchList.front() );
-
-           if ( matchData.kindPredicate )
-           {
-             if ( matchData.kindPredicate != inSolvable.kind() )
-             {
-               base_r.nextSkipSolvable();      // this matchData will never match in this solvable
-               return false;
-             }
-           }
-           else if ( !globalKindOk )
-             return false;                     // only matching kindPredicate could overwrite this
-
-            if ( !matchData.predicate || matchData.predicate( base_r ) )
+            const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
+            if ( ! predicate || predicate( base_r ) )
               return true;
 
-            return false; // no skip as there may be more occurrences in this solvable of this attr.
+            return false; // no skip as there may be more occurrences od this attr.
           }
 
           // Here: search all attributes ;(
           for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
           {
             const AttrMatchData & matchData( *mi );
-
-           if ( matchData.kindPredicate )
-           {
-             if ( matchData.kindPredicate != inSolvable.kind() )
-               continue;                       // this matchData does not apply
-           }
-           else if ( !globalKindOk )
-             continue;                         // only matching kindPredicate could overwrite this
-
             sat::LookupAttr q( matchData.attr, inSolvable );
             if ( matchData.strMatcher ) // an empty searchstring matches always
               q.setStrMatcher( matchData.strMatcher );