{"id":15048013,"url":"https://github.com/p-ranav/fccf","last_synced_at":"2025-05-16T05:07:41.647Z","repository":{"id":38021842,"uuid":"485145664","full_name":"p-ranav/fccf","owner":"p-ranav","description":"fccf: A command-line tool that quickly searches through C/C++ source code in a directory based on a search string and prints relevant code snippets that match the query.","archived":false,"fork":false,"pushed_at":"2024-10-23T23:56:31.000Z","size":481,"stargazers_count":372,"open_issues_count":6,"forks_count":20,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-08T15:11:50.712Z","etag":null,"topics":["abstract-syntax-tree","c-language","c-programming","clang","code-search-engine","command-line-tool","cpp","cpp11","cpp17","fast","find","libclang","needle","search","simd","sse2"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/p-ranav.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-24T21:35:02.000Z","updated_at":"2025-03-23T09:26:17.000Z","dependencies_parsed_at":"2024-05-02T00:53:28.433Z","dependency_job_id":"2e25ed78-fcd3-405b-aef2-10cd5578b6d6","html_url":"https://github.com/p-ranav/fccf","commit_stats":{"total_commits":146,"total_committers":6,"mean_commits":"24.333333333333332","dds":0.09589041095890416,"last_synced_commit":"03d373fc65e2d7ceeac441ba4bbddfdc25618dff"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Ffccf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Ffccf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Ffccf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Ffccf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p-ranav","download_url":"https://codeload.github.com/p-ranav/fccf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254471060,"owners_count":22076585,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract-syntax-tree","c-language","c-programming","clang","code-search-engine","command-line-tool","cpp","cpp11","cpp17","fast","find","libclang","needle","search","simd","sse2"],"created_at":"2024-09-24T21:06:56.499Z","updated_at":"2025-05-16T05:07:36.639Z","avatar_url":"https://github.com/p-ranav.png","language":"C++","readme":"# fccf: Fast C/C++ Code Finder\n\n`fccf` is a command-line tool that quickly searches through C/C++ source code in a directory based on a search string and prints relevant code snippets that match the query.\n\n## Highlights\n\n* Quickly identifies source files that contain a search string.\n* For each candidate source file, builds an abstract syntax tree (AST).\n* Visits the nodes in the AST, looking for function declarations, classes, enums, variables etc., that match the user's request.\n* Pretty-prints the identified snippet of source code to the terminal.\n* MIT License\n\n## Searching the Linux kernel source tree\n\nThe following video shows `fccf` searching and finding snippets of code in [torvalds/linux](https://github.com/torvalds/linux/).\n\nhttps://user-images.githubusercontent.com/8450091/165400381-9ba49a62-97fb-4f4a-890a-0dc9b20dfe75.mp4\n\n## Searching the `fccf` source tree (Modern C++)\n\nThe following video shows `fccf` searching the `fccf` C++ source code. \n\nNote that search results here include:\n1. Class declaration\n2. Functions and function templates\n3. Variable declarations, including lambda functions\n\nhttps://user-images.githubusercontent.com/8450091/165402206-65d9ed43-b9dd-4528-92bd-0b4ce76b6468.mp4\n\n## Search for any of `--flag` that matches\n  \nProvide an empty query to match any `--flag`, e.g., any enum declaration.\n  \n\u003cimg width=\"697\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165854416-bc3e0cd1-042b-4f8c-b653-dd43ecae1e3a.png\"\u003e\n\n... or any class constructor\n\n\u003cimg width=\"694\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165858122-ecfaf103-8e84-418f-8aaa-8f0fc1d087ea.png\"\u003e\n\n## Searching a `for` statement \n\nUse `--for-statement` to search `for` statements. `fccf` will try to find `for` statements (including C++ ranged `for`) that contain the query string.\n\n\u003cimg width=\"694\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165875203-0c30623f-b935-4dcd-b929-1053e0348d12.png\"\u003e\n\n## Searching expressions\n\nUse the `--include-expressions` option to find expressions that match the query.\n\nThe following example shows `fccf` find calls to `isdigit()`.\n\n\u003cimg width=\"700\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165769520-8c640847-280e-4d7d-8c6a-ce2cc108cdaf.png\"\u003e\n\nThe following example shows `fccf` finding references to the `clang_options` variable.\n\n\u003cimg width=\"575\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165769421-6d6141ff-0f00-45f6-9396-92a56abbd308.png\"\u003e\n\n## Searching for `using` declarations\n\nUse the `--using-declaration` option to find `using` declarations, `using` directives, and type alias declarations.\n\n\u003cimg width=\"750\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165815095-cce0d7c1-3568-4a1b-b5f1-427e163fa81b.png\"\u003e\n\n## Searching for `namespace` aliases\n\nUse the `--namespace-alias` option to find `namespace` aliases.\n\n\u003cimg width=\"400\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165815204-bfe3f900-82cd-4411-acc5-0f1b63ec926e.png\"\u003e\n\n## Searching for `throw` expressions\n\nUse `--throw-expression` with a query to search for specific `throw` expressions that contain the query string.\n\n\u003cimg width=\"740\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165873571-652d43d1-03be-4569-8329-2e481795f330.png\"\u003e\n\nAs presented earlier, an empty query here will attempt to match any `throw` expression in the code base:\n\n\u003cimg width=\"800\" alt=\"image\" src=\"https://user-images.githubusercontent.com/8450091/165873839-70730714-a7bc-46d8-8ea7-6be5438e374b.png\"\u003e\n\n## Build Instructions\n\nBuild `fccf` using CMake. For more details, see [BUILDING.md](https://github.com/p-ranav/fccf/blob/master/BUILDING.md).\n\nNOTE: `fccf` requires `libclang` and `LLVM` installed.\n\n```bash\n# Install libclang and LLVM\n# sudo apt install libclang-dev llvm\n\ngit clone https://github.com/p-ranav/fccf\ncd fccf\n\n# Build\ncmake -S . -B build -D CMAKE_BUILD_TYPE=Release\ncmake --build build\n\n# Install\nsudo cmake --install build\n```\n\n## `fccf` Usage\n\n```console\nfoo@bar:~$ fccf --help\nUsage: fccf [--help] [--version] [--help] [--exact-match] [--json] [--filter VAR] [-j VAR] [--enum] [--struct] [--union] [--member-function] [--function] [--function-template] [-F] [--class] [--class-template] [--class-constructor] [--class-destructor] [-C] [--for-statement] [--namespace-alias] [--parameter-declaration] [--typedef] [--using-declaration] [--variable-declaration] [--verbose] [--include-expressions] [--static-cast] [--dynamic-cast] [--reinterpret-cast] [--const-cast] [-c] [--throw-expression] [--ignore-single-line-results] [--include-dir VAR]... [--language VAR] [--std VAR] [--no-color] query [path]...\n\nPositional arguments:\n  query                                \n  path                                 [nargs: 0 or more] \n\nOptional arguments:\n  -h, --help                           shows help message and exits \n  -v, --version                        prints version information and exits \n  -h, --help                           Shows help message and exits \n  -E, --exact-match                    Only consider exact matches \n  --json                               Print results in JSON format \n  -f, --filter                         Only evaluate files that match filter pattern [nargs=0..1] [default: \"*.*\"]\n  -j                                   Number of threads [nargs=0..1] [default: 5]\n  --enum                               Search for enum declaration \n  --struct                             Search for struct declaration \n  --union                              Search for union declaration \n  --member-function                    Search for class member function declaration \n  --function                           Search for function declaration \n  --function-template                  Search for function template declaration \n  -F                                   Search for any function or function template or class member function \n  --class                              Search for class declaration \n  --class-template                     Search for class template declaration \n  --class-constructor                  Search for class constructor declaration \n  --class-destructor                   Search for class destructor declaration \n  -C                                   Search for any class or class template or struct \n  --for-statement                      Search for `for` statement \n  --namespace-alias                    Search for namespace alias \n  --parameter-declaration              Search for function or method parameter \n  --typedef                            Search for typedef declaration \n  --using-declaration                  Search for using declarations, using directives, and type alias declarations \n  --variable-declaration               Search for variable declaration \n  --verbose                            Request verbose output \n  --ie, --include-expressions          Search for expressions that refer to some value or member, e.g., function, variable, or enumerator. \n  --static-cast                        Search for static_cast \n  --dynamic-cast                       Search for dynamic_cast \n  --reinterpret-cast                   Search for reinterpret_cast \n  --const-cast                         Search for const_cast \n  -c                                   Search for any static_cast, dynamic_cast, reinterpret_cast, orconst_cast expression \n  --throw-expression                   Search for throw expression \n  --isl, --ignore-single-line-results  Ignore forward declarations, member function declarations, etc. \n  -I, --include-dir                    Additional include directories [nargs=0..1] [default: {}] [may be repeated]\n  -l, --language                       Language option used by clang [nargs=0..1] [default: \"c++\"]\n  --std                                C++ standard to be used by clang [nargs=0..1] [default: \"c++17\"]\n  --nc, --no-color                     Stops fccf from coloring the output \n```\n\n## How it works\n\n1. `fccf` does a recursive directory search for a needle in a haystack - like `grep` or `ripgrep` - It uses an `SSE2` `strstr` SIMD algorithm (modified Rabin-Karp SIMD search; see [here](http://0x80.pl/articles/simd-strfind.html)) if possible to quickly find, in multiple threads, a subset of the source files in the directory that contain a needle.\n2. For each candidate source file, it uses `libclang` to parse the translation unit (build an abstract syntax tree).\n3. Then it visits each child node in the AST, looking for specific node types, e.g., `CXCursor_FunctionDecl` for function declarations.\n4. Once the relevant nodes are identified, if the node's \"spelling\" (`libclang` name for the node) matches the search query, then the source range of the AST node is identified - source range is the start and end index of the snippet of code in the buffer\n5. Then, it pretty-prints this snippet of code. I have a simple lexer that tokenizes this code and prints colored output.\n\n### Note on `include_directories`\n\nFor all this to work, fccf first identifies candidate directories that contain header files, e.g., paths that end with `include/`. It then adds these paths to the clang options (before parsing the translation unit) as `-Ifoo -Ibar/baz` etc. Additionally, for each translation unit, the parent and grandparent paths are also added to the include directories for that unit in order to increase the likelihood of successful parsing.\n\nAdditional include directories can also be provided to `fccf` using the `-I` or `--include-dir` option. Using verbose output (`--verbose`), errors in the libclang parsing can be identified and fixes can be attempted (e.g., adding the right include directories so that `libclang` is happy).\n\nTo run `fccf` on the `fccf` source code without any libclang errors, I had to explicitly provide the include path from LLVM-12 like so:\n\n```console\nfoo@bar:~$ fccf --verbose 'lexer' . --include-dir /usr/lib/llvm-12/include/\nChecking ./source/lexer.cpp\nChecking ./source/lexer.hpp\nChecking ./source/searcher.cpp\n\n// ./source/lexer.hpp (Line: 14 to 40)\nclass lexer\n{\n  std::string_view m_input;\n  fmt::memory_buffer* m_out;\n  std::size_t m_index {0};\n  bool m_is_stdout {true};\n\n  char previous() const;\n  char current() const;\n  char next() const;\n  void move_forward(std::size_t n = 1);\n  bool is_line_comment();\n  bool is_block_comment();\n  bool is_start_of_identifier();\n  bool is_start_of_string();\n  bool is_start_of_number();\n  void process_line_comment();\n  void process_block_comment();\n  bool process_identifier(bool maybe_class_or_struct = false);\n  void process_string();\n  std::size_t get_number_of_characters(std::string_view str);\n\npublic:\n  void tokenize_and_pretty_print(std::string_view source,\n                                 fmt::memory_buffer* out,\n                                 bool is_stdout = true);\n}\n```\n\n## References\n\n1. [SIMD-friendly algorithms for substring searching](http://0x80.pl/articles/simd-strfind.html)\n2. [libclang: C Interface to Clang](https://clang.llvm.org/doxygen/group__CINDEX.html)\n","funding_links":[],"categories":["Miscellaneous","C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Ffccf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp-ranav%2Ffccf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Ffccf/lists"}