================
@@ -0,0 +1,147 @@
+.. title:: clang-tidy - performance-redundant-lookup
+
+performance-redundant-lookup
+============================
+
+This check warns about potential redundant container lookup operations within
+a function.
+
+Examples
+--------
+
+.. code-block:: c++
+
+    if (map.count(key) && map[key] < threshold) {
+      // do stuff
+    }
+
+In this example, we would check if the key is present in the map,
+and then do a second lookup to actually load the value.
+We could refactor the code into this, to use a single lookup:
+
+.. code-block:: c++
+
+    if (auto it = map.find(key); it != map.end() && it->second < threshold) {
+      // do stuff
+    }
+
+In this example, we do three lookups while calculating, caching and then
+using the result of some expensive computation:
+
+.. code-block:: c++
+
+    if (!cache.contains(key)) {
+        cache[key] = computeExpensiveValue();
+    }
+    use(cache[key]);
+
+We could refactor this code using ``try_emplace`` to fill up the cache entry
+if wasn't present, and just use it if we already computed the value.
+This way we would only have a single unavoidable lookup:
+
+.. code-block:: c++
+
+    auto [cacheSlot, inserted] cache.try_emplace(key);
+    if (inserted) {
+        cacheSlot->second = computeExpensiveValue();
+    }
+    use(cacheSlot->second);
+
+
+What is a "lookup"?
+-------------------
+
+All container operations that walk the internal structure of the container
+should be considered as "lookups".
+This means that checking if an element is present or inserting an element
+is also considered as a "lookup".
+
+For example, ``contains``, ``count`` but even the ``operator[]``
+should be considered as "lookups".
+
+Technically ``insert``, ``emplace`` or ``try_emplace`` are also lookups,
+even if due to limitations, they are not recognized as such.
+
+Lookups inside macros are ignored, thus not considered as "lookups".
+For example:
+
+.. code-block:: c++
+
+    assert(map.count(key) == 0); // Not considered as a "lookup".
+
+Options
+-------
+
+.. option:: ContainerNameRegex
+
+   The regular expression matching the type of the container objects.
+   This is matched in a case insensitive manner.
+   Default is ``set|map``.
+
+.. option:: LookupMethodNames
+
+   Member function names to consider as **lookup** operation.
+   These methods must have exactly 1 argument.
+   Default is ``at;contains;count;find_as;find``.
+
+Limitations
+-----------
+
+ - The "redundant lookups" may span across a large chunk of code.
+   Such reports can be considered as false-positives because it's hard to judge
+   if the container is definitely not mutated between the lookups.
+   It would be hard to split the lookup groups in a stable and meaningful way,
+   and a threshold for proximity would be just an arbitrary limit.
+
+ - The "redundant lookups" may span across different control-flow constructs,
+   making it impossible to refactor.
+   It may be that the code was deliberately structured like it was, thus the
+   report is considered a false-positive.
+   Use your best judgement to see if anything needs to be fixed or not.
+   For example:
+
+   .. code-block:: c++
+
+    if (coin())
+        map[key] = foo();
+    else
+        map[key] = bar();
+
+   Could be refactored into:
+
+   .. code-block:: c++
+
+    map[key] = coin() ? foo() : bar();
+
+   However, the following code could be considered intentional:
+
+   .. code-block:: c++
+
+    // Handle the likely case.
+    if (auto it = map.find(key); it != map.end()) {
+        return process(*it);
+    }
+
+    // Commit the dirty items, and check again.
+    for (const auto &item : dirtyList) {
+        commit(item, map); // Updates the "map".
+    }
+
+    // Do a final check.
+    if (auto it = map.find(key); it != map.end()) {
+        return process(*it);
+    }
+
+ - The key argument of a lookup may have sideffects. Sideffects are ignored 
when identifying lookups.
+   This can introduce some false-positives. For example:
+
+   .. code-block:: c++
+
+    m.contains(rng(++n));
+    m.contains(rng(++n)); // FP: This is considered a redundant lookup.
+
+ - Lookup member functions must have exactly 1 argument to match.
+   There are technically lookup functions, such as ``insert`` or 
``try_emplace``,
+   but it would be hard to identify the "key" part of the argument,
+   while leaving the implementation open for user-configuration via the
+   ``LookupMethodNames`` option.
----------------
EugeneZelenko wrote:

```suggestion
   `LookupMethodNames` option.
```

https://github.com/llvm/llvm-project/pull/125420
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to