メモリ上のソースの分析
big-code-analysis never requires source to live on disk. The recommended entry point analyze takes a Source carrying the language, source bytes, and an optional caller-supplied display name. No filesystem path is involved unless the C/C++ preprocessor lookup needs one (Source::preproc_path).
これは次の用途に有用です:
- 生成コードを書き出す前にスコアリングする。
- Scoring pre-processed or bundled source, such as the output of a template expansion.
- すでにバッファをメモリ上に保持している言語サーバーやエディタプラグインから分析ツールを駆動する。
- Running stdin pipelines and unit tests that should not touch the filesystem.
バッファからの読み取り
#![allow(unused)]
fn main() {
use big_code_analysis::{analyze, MetricsOptions, Source, LANG};
fn analyze_buffer(source: &[u8]) -> Option<u64> {
// `Source::name` はトップレベルの `FuncSpace` に埋め込まれる
// 表示識別子です。下流の消費者(ログ、JSON 出力)にとって
// 意味のあるものを選んでください。付ける価値のあるものが
// なければ `None` を渡します。
let space = analyze(
Source::new(LANG::Python, source).with_name(Some("<stdin>".to_owned())),
MetricsOptions::default(),
)
.ok()?;
Some(space.metrics.cognitive.cognitive_sum())
}
}
Source::new borrows the source bytes; the caller keeps ownership. If your downstream pipeline needs to highlight findings on the same bytes, you can keep using the original buffer after analyze returns.
標準入力からの読み取り
use std::io::{self, Read};
use big_code_analysis::{analyze, MetricsOptions, Source, LANG};
fn main() -> io::Result<()> {
let mut source = Vec::new();
io::stdin().read_to_end(&mut source)?;
let space = match analyze(
Source::new(LANG::Javascript, &source)
.with_name(Some("<stdin>".to_owned())),
MetricsOptions::default(),
) {
Ok(space) => space,
Err(err) => {
eprintln!("parse failed: {err}");
std::process::exit(1);
}
};
println!("{}", space.metrics.cyclomatic.cyclomatic_sum());
Ok(())
}
内容から言語を選択する
If you do not know the language up front, combine guess_language with analyze. guess_language checks the path extension, an Emacs mode declaration, and the shebang, in that order:
#![allow(unused)]
fn main() {
use std::path::PathBuf;
use big_code_analysis::{analyze, guess_language, MetricsOptions, Source};
fn analyze_unknown(path: PathBuf, source: Vec<u8>) -> Option<()> {
let (lang, _name) = guess_language(&source, &path);
let lang = lang?;
// `.ok()?` は `MetricsError` を `None` に畳み込み、このヘルパーの
// `Option` の戻り値の形を保ちます。バリアントを保持するより
// 詳細なマッピングは `error-handling.md` を参照してください。
let _space = analyze(
Source::new(lang, &source)
.with_name(path.to_str().map(str::to_owned)),
MetricsOptions::default(),
)
.ok()?;
Some(())
}
}
guess_language returns (None, _) when the extension, the mode line, and the shebang all fail to name a language. Treat that as “skip” rather than as a hard error.
注意点
- Name identity matters. Top-level
FuncSpace::nameis whatever string you put inSource::name. Two analyses sharing the same name look identical to a downstream consumer that keys on it. Use distinct labels for distinct buffers. Source::nameisOption<String>. PassingNoneleaves the top-levelFuncSpace::nameasNone, which suits ad-hoc snippets with no meaningful identity. Downstream consumers that require a stable identifier should check forNoneexplicitly.- ファイルシステムへのフォールバックはありません。 CLI と異なり、ライブラリは隣接ファイルを読んだり、
#includeを辿ったり、.gitignoreを解釈したりしません。分析したいバイト列を正確に与えてください。
一度のパースを複数のパスで再利用する
analyze is the one-shot entry point: bytes in, FuncSpace out. When you need more than metrics from a single parse (operators and operands, an AST dump, a function-span list), parse once with Ast::parse and call the per-pass methods on the returned handle (metrics, ops, dump, functions, and so on). See Parse once, run metrics many times.