• Stars
    star
    359
  • Rank 118,537 (Top 3 %)
  • Language
    C++
  • License
    MIT License
  • Created over 2 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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.

fccf: Fast C/C++ Code Finder

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.

Highlights

  • Quickly identifies source files that contain a search string.
  • For each candidate source file, builds an abstract syntax tree (AST).
  • Visits the nodes in the AST, looking for function declarations, classes, enums, variables etc., that match the user's request.
  • Pretty-prints the identified snippet of source code to the terminal.
  • MIT License

Searching the Linux kernel source tree

The following video shows fccf searching and finding snippets of code in torvalds/linux.

Searching.the.Linux.Kernel.Source.Tree.mp4

Searching the fccf source tree (Modern C++)

The following video shows fccf searching the fccf C++ source code.

Note that search results here include:

  1. Class declaration
  2. Functions and function templates
  3. Variable declarations, including lambda functions
Searching.the.fccf.Source.Tree.mp4

Search for any of --flag that matches

Provide an empty query to match any --flag, e.g., any enum declaration.

image

... or any class constructor

image

Searching a for statement

Use --for-statement to search for statements. fccf will try to find for statements (including C++ ranged for) that contain the query string.

image

Searching expressions

Use the --include-expressions option to find expressions that match the query.

The following example shows fccf find calls to isdigit().

image

The following example shows fccf finding references to the clang_options variable.

image

Searching for using declarations

Use the --using-declaration option to find using declarations, using directives, and type alias declarations.

image

Searching for namespace aliases

Use the --namespace-alias option to find namespace aliases.

image

Searching for throw expressions

Use --throw-expression with a query to search for specific throw expressions that contain the query string.

image

As presented earlier, an empty query here will attempt to match any throw expression in the code base:

image

Build Instructions

Build fccf using CMake. For more details, see BUILDING.md.

NOTE: fccf requires libclang and LLVM installed.

# Install libclang and LLVM
# sudo apt install libclang-dev llvm

git clone https://github.com/p-ranav/fccf
cd fccf

# Build
cmake -S . -B build -D CMAKE_BUILD_TYPE=Release
cmake --build build

# Install
sudo cmake --install build

fccf Usage

foo@bar:~$ fccf --help
Usage: 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]...

Positional arguments:
  query                                
  path                                 [nargs: 0 or more] 

Optional arguments:
  -h, --help                           shows help message and exits 
  -v, --version                        prints version information and exits 
  -h, --help                           Shows help message and exits 
  -E, --exact-match                    Only consider exact matches 
  --json                               Print results in JSON format 
  -f, --filter                         Only evaluate files that match filter pattern [nargs=0..1] [default: "*.*"]
  -j                                   Number of threads [nargs=0..1] [default: 5]
  --enum                               Search for enum declaration 
  --struct                             Search for struct declaration 
  --union                              Search for union declaration 
  --member-function                    Search for class member function declaration 
  --function                           Search for function declaration 
  --function-template                  Search for function template declaration 
  -F                                   Search for any function or function template or class member function 
  --class                              Search for class declaration 
  --class-template                     Search for class template declaration 
  --class-constructor                  Search for class constructor declaration 
  --class-destructor                   Search for class destructor declaration 
  -C                                   Search for any class or class template or struct 
  --for-statement                      Search for `for` statement 
  --namespace-alias                    Search for namespace alias 
  --parameter-declaration              Search for function or method parameter 
  --typedef                            Search for typedef declaration 
  --using-declaration                  Search for using declarations, using directives, and type alias declarations 
  --variable-declaration               Search for variable declaration 
  --verbose                            Request verbose output 
  --ie, --include-expressions          Search for expressions that refer to some value or member, e.g., function, variable, or enumerator. 
  --static-cast                        Search for static_cast 
  --dynamic-cast                       Search for dynamic_cast 
  --reinterpret-cast                   Search for reinterpret_cast 
  --const-cast                         Search for const_cast 
  -c                                   Search for any static_cast, dynamic_cast, reinterpret_cast, orconst_cast expression 
  --throw-expression                   Search for throw expression 
  --isl, --ignore-single-line-results  Ignore forward declarations, member function declarations, etc. 
  -I, --include-dir                    Additional include directories [nargs=0..1] [default: {}] [may be repeated]
  -l, --language                       Language option used by clang [nargs=0..1] [default: "c++"]
  --std                                C++ standard to be used by clang [nargs=0..1] [default: "c++17"]
  --nc, --no-color                     Stops fccf from coloring the output 

How it works

  1. 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) if possible to quickly find, in multiple threads, a subset of the source files in the directory that contain a needle.
  2. For each candidate source file, it uses libclang to parse the translation unit (build an abstract syntax tree).
  3. Then it visits each child node in the AST, looking for specific node types, e.g., CXCursor_FunctionDecl for function declarations.
  4. 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
  5. Then, it pretty-prints this snippet of code. I have a simple lexer that tokenizes this code and prints colored output.

Note on include_directories

For 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.

Additional 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).

To run fccf on the fccf source code without any libclang errors, I had to explicitly provide the include path from LLVM-12 like so:

foo@bar:~$ fccf --verbose 'lexer' . --include-dir /usr/lib/llvm-12/include/
Checking ./source/lexer.cpp
Checking ./source/lexer.hpp
Checking ./source/searcher.cpp

// ./source/lexer.hpp (Line: 14 to 40)
class lexer
{
  std::string_view m_input;
  fmt::memory_buffer* m_out;
  std::size_t m_index {0};
  bool m_is_stdout {true};

  char previous() const;
  char current() const;
  char next() const;
  void move_forward(std::size_t n = 1);
  bool is_line_comment();
  bool is_block_comment();
  bool is_start_of_identifier();
  bool is_start_of_string();
  bool is_start_of_number();
  void process_line_comment();
  void process_block_comment();
  bool process_identifier(bool maybe_class_or_struct = false);
  void process_string();
  std::size_t get_number_of_characters(std::string_view str);

public:
  void tokenize_and_pretty_print(std::string_view source,
                                 fmt::memory_buffer* out,
                                 bool is_stdout = true);
}

References

  1. SIMD-friendly algorithms for substring searching
  2. libclang: C Interface to Clang

More Repositories

1

awesome-hpp

A curated list of awesome header-only C++ libraries
3,468
star
2

indicators

Activity Indicators for Modern C++
C++
3,004
star
3

argparse

Argument Parser for Modern C++
C++
2,655
star
4

tabulate

Table Maker for Modern C++
C++
1,926
star
5

pprint

Pretty Printer for Modern C++
C++
911
star
6

csv2

Fast CSV parser and writer for Modern C++
C++
552
star
7

alpaca

Serialization library written in C++17 - Pack C++ structs into a compact byte-array without any macros or boilerplate code
C++
474
star
8

structopt

Parse command line arguments by defining a struct
C++
455
star
9

glob

Glob for C++17
C++
246
star
10

csv

[DEPRECATED] See https://github.com/p-ranav/csv2
C++
234
star
11

criterion

Microbenchmarking for Modern C++
C++
211
star
12

binary_log

Fast binary logger for C++
C++
207
star
13

hypergrep

Recursively search directories for a regex pattern
C++
201
star
14

saveddit

Bulk Downloader for Reddit
Python
169
star
15

PhotoLab

AI-Powered Photo Editor (Python, PyQt6, PyTorch)
Python
161
star
16

box

box is a text-based visual programming language inspired by Unreal Engine Blueprint function graphs.
Python
120
star
17

cppgit2

Git for Modern C++ (A libgit2 Wrapper Library)
C++
116
star
18

psched

Priority-based Task Scheduling for Modern C++
C++
84
star
19

repr

repr for Modern C++: Return printable string representation of a value
C++
83
star
20

fswatch

File/Directory Watcher for Modern C++
C++
79
star
21

envy

envy: Deserialize environment variables into type-safe structs
C++
66
star
22

pipeline

Pipelines for Modern C++
C++
57
star
23

iris

Lightweight Component Model and Messaging Framework based on ร˜MQ
C++
53
star
24

merged_depth

Monocular Depth Estimation - Weighted-average prediction from multiple pre-trained depth estimation models
Python
47
star
25

unicode_display_width

Displayed width of UTF-8 strings in Modern C++
C++
44
star
26

task_system

Task System presented in "Better Code: Concurrency - Sean Parent"
C++
39
star
27

cgol

Conway's Game of Life in the Terminal
C++
35
star
28

small_vector

"Small Vector" optimization for Modern C++: store up to a small number of items on the stack
C++
33
star
29

jsonlint

Lightweight command-line tool for validating JSON
C++
33
star
30

result

Result<T, E> for Modern C++
C++
32
star
31

container_traits

Container Traits for Modern C++
C++
28
star
32

lexer

Hackable Lexer with UTF-8 support
C++
21
star
33

lc

Fast multi-threaded line counter in Modern C++ (2-10x faster than `wc -l` for large files)
C++
18
star
34

oystr

oystr recursively searches directories for a substring.
C++
10
star
35

walnut.v1

The Walnut programming language
C++
8
star
36

line-detector

OpenCV-based Hough Transform Line Detection
C++
8
star
37

ttt

Terminal Typing Test
C++
7
star
38

OpenGL-Engine

OpenGL 3D Rendering Engine
C++
7
star
39

wxPython-text-editor

wxPython Text Editor
Python
6
star
40

Vulkan-Earth

Vulkan-based 3D Rendering of Earth
HTML
6
star
41

strcpp.old

String Manipulation API for C++
C++
6
star
42

DiverseDepth

The code and data of DiverseDepth
Python
6
star
43

ImageViewer-Qt6

Minimalist image viewer in Qt6
C++
6
star
44

any_of_trait

Type traits for any_of and any_but
C++
5
star
45

zcm

A Lightweight Component Model using ZeroMQ
C++
4
star
46

StaticAnalysis

GitHub action for C++ static analysis
Python
4
star
47

video_device_discovery

Find all video devices connected to Linux-based embedded platform
C++
3
star
48

krpci

C++ client to kRPC for communication with Kerbal Space Program (KSP)
C++
2
star
49

activity-plotter

Linux Scheduler Thread Activity Plotter
Python
2
star
50

python-zcm

ZeroMQ-based Component Model in Python
Python
2
star
51

emacs_config

Emacs configuration
Emacs Lisp
1
star
52

plexil-analysis

Timing Analysis for the Plan Interchange Language (Plexil)
Python
1
star
53

object-tracker

OpenCV-based Real-time Object Tracking
C++
1
star
54

json.old

JSON Manipulation Library for C++
C++
1
star
55

phd-dissertation

TeX
1
star
56

OpenGL-Engine-II

OpenGL 3D Rendering Engine II - Alternate Architecture
C++
1
star
57

arangit

Python program that can scan a .git folder and reconstruct a git version control property graph in ArangoDB
Python
1
star
58

ros-installer

Script to install ROS Indigo from source
Python
1
star