fccf
ist ein Befehlszeilentool, das anhand einer Suchzeichenfolge schnell den C/C++-Quellcode in einem Verzeichnis durchsucht und relevante Codeausschnitte ausgibt, die der Abfrage entsprechen.
Das folgende Video zeigt die Suche und das Finden von Codeschnipseln fccf
in Torvalds/Linux.
fccf
Quellbaums (Modern C++) Das folgende Video zeigt, wie fccf
den fccf
C++-Quellcode durchsucht.
Beachten Sie, dass die Suchergebnisse hier Folgendes umfassen:
--flag
Stellen Sie eine leere Abfrage bereit, die zu jedem --flag
passt, z. B. zu jeder Enum-Deklaration.
... oder ein beliebiger Klassenkonstruktor
for
Anweisung Verwenden Sie --for-statement
um for
Anweisungen zu suchen. fccf
wird versuchen, for
-Anweisungen (einschließlich C++ ranged for
) zu finden, die die Abfragezeichenfolge enthalten.
Verwenden Sie die Option --include-expressions
um Ausdrücke zu finden, die der Abfrage entsprechen.
Das folgende Beispiel zeigt fccf
find-Aufrufe von isdigit()
.
Das folgende Beispiel zeigt, wie fccf
Verweise auf die Variable clang_options
findet.
using
Verwenden Sie die Option --using-declaration
, um using
-Deklarationen, using
-Direktiven und Typ-Alias-Deklarationen zu finden.
namespace
Aliassen Verwenden Sie die Option --namespace-alias
um namespace
Aliase zu finden.
throw
Verwenden Sie --throw-expression
mit einer Abfrage, um nach bestimmten throw
Ausdrücken zu suchen, die die Abfragezeichenfolge enthalten.
Wie bereits erwähnt, versucht eine leere Abfrage hier, mit jedem throw
in der Codebasis übereinzustimmen:
Erstellen Sie fccf
mit CMake. Weitere Einzelheiten finden Sie unter BUILDING.md.
HINWEIS: fccf
erfordert die Installation libclang
und LLVM
.
# 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
Nutzung 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
fccf
führt eine rekursive Verzeichnissuche nach der Nadel im Heuhaufen durch – wie grep
oder ripgrep
. Es verwendet einen SSE2
strstr
-SIMD-Algorithmus (modifizierte Rabin-Karp-SIMD-Suche; siehe hier), um nach Möglichkeit in mehreren Threads schnell eine Teilmenge davon zu finden Quelldateien im Verzeichnis, die eine Nadel enthalten.libclang
verwendet, um die Übersetzungseinheit zu analysieren (einen abstrakten Syntaxbaum zu erstellen).CXCursor_FunctionDecl
für Funktionsdeklarationen.libclang
-Name für den Knoten) mit der Suchabfrage übereinstimmt, wird der Quellbereich des AST-Knotens identifiziert – der Quellbereich ist der Start- und Endindex des Codeausschnitts in der Pufferinclude_directories
Damit dies alles funktioniert, identifiziert fccf zunächst Kandidatenverzeichnisse, die Header-Dateien enthalten, z. B. Pfade, die mit include/
enden. Anschließend werden diese Pfade zu den Clang-Optionen hinzugefügt (vor dem Parsen der Übersetzungseinheit) als -Ifoo -Ibar/baz
usw. Darüber hinaus werden für jede Übersetzungseinheit die übergeordneten und übergeordneten Pfade auch zu den Include-Verzeichnissen für diese Einheit hinzugefügt, um dies zu ermöglichen Erhöhen Sie die Wahrscheinlichkeit einer erfolgreichen Analyse.
Zusätzliche Include-Verzeichnisse können fccf
auch mit der Option -I
oder --include-dir
bereitgestellt werden. Mithilfe der ausführlichen Ausgabe ( --verbose
) können Fehler beim Parsen von libclang identifiziert und Korrekturen versucht werden (z. B. Hinzufügen der richtigen Include-Verzeichnisse, damit libclang
zufrieden ist).
Um fccf
ohne libclang-Fehler auf dem fccf
Quellcode auszuführen, musste ich den Include-Pfad von LLVM-12 explizit angeben, etwa 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);
}