fccf
هي أداة سطر أوامر تبحث بسرعة من خلال كود مصدر C/C++ في دليل يعتمد على سلسلة بحث وتطبع مقتطفات التعليمات البرمجية ذات الصلة التي تطابق الاستعلام.
يُظهر مقطع الفيديو التالي بحث fccf
والعثور على مقتطفات من التعليمات البرمجية في torvalds/linux.
fccf
(Modern C++) يُظهر مقطع الفيديو التالي fccf
وهو يبحث في كود مصدر fccf
C++.
لاحظ أن نتائج البحث هنا تشمل:
--flag
المطابق قم بتوفير استعلام فارغ لمطابقة أي --flag
، على سبيل المثال، أي إعلان تعداد.
... أو أي منشئ فئة
for
بيان استخدم --for-statement
للبحث for
البيانات. سيحاول fccf
البحث for
العبارات (بما في ذلك C++ ranged for
) التي تحتوي على سلسلة الاستعلام.
استخدم خيار --include-expressions
للعثور على التعبيرات التي تطابق الاستعلام.
يوضح المثال التالي استدعاءات البحث fccf
إلى isdigit()
.
يوضح المثال التالي العثور على مراجع fccf
للمتغير clang_options
.
using
التصريحات استخدم خيار --using-declaration
للعثور على using
الإعلانات، using
التوجيهات، واكتب إعلانات الاسم المستعار.
namespace
استخدم خيار --namespace-alias
للعثور على الأسماء المستعارة namespace
.
throw
استخدم --throw-expression
مع استعلام للبحث عن تعبيرات throw
محددة تحتوي على سلسلة الاستعلام.
كما هو موضح سابقًا، سيحاول الاستعلام الفارغ هنا مطابقة أي تعبير throw
في قاعدة التعليمات البرمجية:
بناء fccf
باستخدام CMake. لمزيد من التفاصيل، راجع BUILDING.md.
ملاحظة: يتطلب fccf
تثبيت libclang
و 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
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
بإجراء بحث متكرر في الدليل عن إبرة في كومة قش - مثل grep
أو ripgrep
- ويستخدم خوارزمية SSE2
strstr
SIMD (بحث Rabin-Karp SIMD المعدل؛ انظر هنا) للعثور بسرعة، في سلاسل رسائل متعددة، على مجموعة فرعية من الملفات المصدر في الدليل الذي يحتوي على إبرة.libclang
لتحليل وحدة الترجمة (إنشاء شجرة بناء جملة مجردة).CXCursor_FunctionDecl
لتعريفات الوظائف.libclang
للعقدة) يتطابق مع استعلام البحث، فسيتم تحديد نطاق المصدر لعقدة AST - نطاق المصدر هو فهرس البداية والنهاية لمقتطف التعليمات البرمجية في المخزن المؤقتinclude_directories
لكي ينجح كل هذا، يقوم fccf أولاً بتحديد الدلائل المرشحة التي تحتوي على ملفات رأس، على سبيل المثال، المسارات التي تنتهي بـ include/
. ثم يضيف هذه المسارات إلى خيارات clang (قبل تحليل وحدة الترجمة) مثل -Ifoo -Ibar/baz
وما إلى ذلك. بالإضافة إلى ذلك، لكل وحدة ترجمة، تتم أيضًا إضافة المسارات الأصلية والأجداد إلى أدلة التضمين لتلك الوحدة من أجل زيادة احتمالية التحليل الناجح.
يمكن أيضًا توفير أدلة تضمين إضافية إلى fccf
باستخدام الخيار -I
أو --include-dir
. باستخدام الإخراج المطول ( --verbose
)، يمكن تحديد الأخطاء في تحليل libclang ويمكن محاولة الإصلاحات (على سبيل المثال، إضافة أدلة التضمين الصحيحة بحيث يكون libclang
سعيدًا).
لتشغيل fccf
على كود مصدر fccf
دون أي أخطاء libclang، كان علي أن أقدم مسار التضمين بشكل صريح من LLVM-12 كما يلي:
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);
}