llvm-project/clang-tools-extra
Roman Lebedev 49bffa5f8b
[clang-tidy] misc-no-recursion: a new check
Summary:
Recursion is a powerful tool, but like any tool
without care it can be dangerous. For example,
if the recursion is unbounded, you will
eventually run out of stack and crash.

You can of course track the recursion depth
but if it is hardcoded, there can always be some
other environment when that depth is too large,
so said magic number would need to be env-dependent.
But then your program's behavior is suddenly more env-dependent.

Also, recursion, while it does not outright stop optimization,
recursive calls are less great than normal calls,
for example they hinder inlining.

Recursion is banned in some coding guidelines:
* SEI CERT DCL56-CPP. Avoid cycles during initialization of static objects
* JPL 2.4 Do not use direct or indirect recursion.
* I'd say it is frowned upon in LLVM, although not banned
And is plain unsupported in some cases:
* OpenCL 1.2, 6.9 Restrictions: i. Recursion is not supported.

So there's clearly a lot of reasons why one might want to
avoid recursion, and replace it with worklist handling.
It would be great to have a enforcement for it though.

This implements such a check.
Here we detect both direct and indirect recursive calls,
although since clang-tidy (unlike clang static analyzer)
is CTU-unaware, if the recursion transcends a single standalone TU,
we will naturally not find it :/

The algorithm is pretty straight-forward:
1. Build call-graph for the entire TU.
   For that, the existing `clang::CallGraph` is re-used,
   although it had to be modified to also track the location of the call.
2. Then, the hard problem: how do we detect recursion?
   Since we have a graph, let's just do the sane thing,
   and look for Strongly Connected Function Declarations - widely known as `SCC`.
   For that LLVM provides `llvm::scc_iterator`,
   which is internally an Tarjan's DFS algorithm, and is used throught LLVM,
   so this should be as performant as possible.
3. Now that we've got SCC's, we discard those that don't contain loops.
   Note that there may be more than one loop in SCC!
4. For each loopy SCC, we call out each function, and print a single example
   call graph that shows recursion -- it didn't seem worthwhile enumerating
   every possible loop in SCC, although i suppose it could be implemented.
   * To come up with that call graph cycle example, we start at first SCC node,
     see which callee of the node is within SCC (and is thus known to be in cycle),
     and recurse into it until we hit the callee that is already in call stack.

Reviewers: JonasToth, aaron.ballman, ffrankies, Eugene.Zelenko, erichkeane, NoQ

Reviewed By: aaron.ballman

Subscribers: Charusso, Naghasan, bader, riccibruno, mgorny, Anastasia, xazax.hun, cfe-commits

Tags: #llvm, #clang

Differential Revision: https://reviews.llvm.org/D72362
2020-02-13 23:37:53 +03:00
..
clang-apply-replacements NFC: Fix trivial typos in comments 2020-01-04 10:28:41 -05:00
clang-change-namespace Make llvm::StringRef to std::string conversions explicit. 2020-01-28 23:25:25 +01:00
clang-doc Revert "[clang-doc] Improving Markdown Output" 2020-02-07 19:43:47 -08:00
clang-include-fixer Make llvm::StringRef to std::string conversions explicit. 2020-01-28 23:25:25 +01:00
clang-move [clang][Analysis] CallGraph: store the actual call `Expr*` in the CallGraphNode::CallRecord 2020-02-13 23:37:53 +03:00
clang-query Make llvm::StringRef to std::string conversions explicit. 2020-01-28 23:25:25 +01:00
clang-reorder-fields [ASTMatchers] StringRef'ify hasName 2020-01-29 10:53:08 +01:00
clang-tidy [clang-tidy] misc-no-recursion: a new check 2020-02-13 23:37:53 +03:00
clangd [clangd] Expose Code Completion score to the client 2020-02-13 15:05:18 +01:00
docs [clang-tidy] misc-no-recursion: a new check 2020-02-13 23:37:53 +03:00
modularize Make llvm::StringRef to std::string conversions explicit. 2020-01-28 23:25:25 +01:00
pp-trace NFC: Fix trivial typos in comments 2020-01-04 10:28:41 -05:00
test [clang-tidy] misc-no-recursion: a new check 2020-02-13 23:37:53 +03:00
tool-template Revert "Use InitLLVM to setup a pretty stack printer" 2019-11-25 21:06:56 -05:00
unittests Revert "[clang-doc] Improving Markdown Output" 2020-02-07 19:43:47 -08:00
.arcconfig [clang-tools-extra] Set up .arcconfig to point to new Diffusion CTE repository 2017-11-27 15:58:25 +00:00
.gitignore
CMakeLists.txt Remove clang-tidy-vs from clang-tools-extra (PR41791) 2019-08-27 18:36:08 +00:00
CODE_OWNERS.TXT [clangd] add CODE_OWNERS 2020-01-29 12:43:19 +01:00
LICENSE.TXT Fix typos throughout the license files that somehow I and my reviewers 2019-01-21 09:52:34 +00:00
README.txt

README.txt

//===----------------------------------------------------------------------===//
// Clang Tools repository
//===----------------------------------------------------------------------===//

Welcome to the repository of extra Clang Tools.  This repository holds tools
that are developed as part of the LLVM compiler infrastructure project and the
Clang frontend.  These tools are kept in a separate "extra" repository to
allow lighter weight checkouts of the core Clang codebase.

This repository is only intended to be checked out inside of a full LLVM+Clang
tree, and in the 'tools/extra' subdirectory of the Clang checkout.

All discussion regarding Clang, Clang-based tools, and code in this repository
should be held using the standard Clang mailing lists:
  http://lists.llvm.org/mailman/listinfo/cfe-dev

Code review for this tree should take place on the standard Clang patch and
commit lists:
  http://lists.llvm.org/mailman/listinfo/cfe-commits

If you find a bug in these tools, please file it in the LLVM bug tracker:
  http://llvm.org/bugs/