linthis 0.0.2__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {linthis-0.0.2 → linthis-0.0.3}/Cargo.lock +29 -27
- {linthis-0.0.2 → linthis-0.0.3}/Cargo.toml +1 -1
- {linthis-0.0.2 → linthis-0.0.3}/PKG-INFO +1 -1
- linthis-0.0.3/defaults/.clang-tidy +87 -0
- linthis-0.0.3/defaults/config.toml +88 -0
- {linthis-0.0.2 → linthis-0.0.3}/pyproject.toml +1 -1
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/cpp.rs +177 -9
- linthis-0.0.3/src/fixers/cpplint.rs +579 -0
- linthis-0.0.3/src/fixers/mod.rs +15 -0
- linthis-0.0.3/src/formatters/cpp.rs +316 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/lib.rs +10 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/utils/mod.rs +3 -1
- {linthis-0.0.2 → linthis-0.0.3}/src/utils/output.rs +14 -2
- {linthis-0.0.2 → linthis-0.0.3}/src/utils/types.rs +12 -0
- linthis-0.0.2/defaults/config.toml +0 -63
- linthis-0.0.2/src/formatters/cpp.rs +0 -105
- {linthis-0.0.2 → linthis-0.0.3}/.github/workflows/release.yml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/.gitignore +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/CHANGELOG.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/README.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/dev.sh +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/docs/config-cli-design.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/docs/init-hooks-design.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/docs/plan-ruff-integration.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/docs/tasks.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/benchmark.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/go.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/java.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/mod.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/python.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/rust.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/traits.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/checkers/typescript.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/config/cli.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/config/mod.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/go.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/java.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/mod.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/python.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/rust.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/traits.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/formatters/typescript.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/main.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/cache.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/config_manager.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/fetcher.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/loader.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/manifest.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/mod.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/plugin/registry.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/presets/mod.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/utils/language.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/src/utils/walker.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/test-plugin-check/README.md +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/test-plugin-check/linthis-plugin.toml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/test-plugin/linthis-plugin.toml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/test-plugin/python/ruff.toml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/test-plugin/rust/clippy.toml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/test-plugin/rust/rustfmt.toml +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/us1/good.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/fixtures/us1/unformatted.rs +0 -0
- {linthis-0.0.2 → linthis-0.0.3}/tests/integration/mod.rs +0 -0
|
@@ -2,15 +2,6 @@
|
|
|
2
2
|
# It is not intended for manual editing.
|
|
3
3
|
version = 4
|
|
4
4
|
|
|
5
|
-
[[package]]
|
|
6
|
-
name = "aho-corasick"
|
|
7
|
-
version = "0.7.20"
|
|
8
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
-
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
|
10
|
-
dependencies = [
|
|
11
|
-
"memchr",
|
|
12
|
-
]
|
|
13
|
-
|
|
14
5
|
[[package]]
|
|
15
6
|
name = "aho-corasick"
|
|
16
7
|
version = "1.1.4"
|
|
@@ -115,9 +106,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
|
|
115
106
|
|
|
116
107
|
[[package]]
|
|
117
108
|
name = "bstr"
|
|
118
|
-
version = "1.
|
|
109
|
+
version = "1.12.1"
|
|
119
110
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
120
|
-
checksum = "
|
|
111
|
+
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
|
121
112
|
dependencies = [
|
|
122
113
|
"memchr",
|
|
123
114
|
"serde",
|
|
@@ -326,12 +317,6 @@ version = "0.1.5"
|
|
|
326
317
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
327
318
|
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
|
|
328
319
|
|
|
329
|
-
[[package]]
|
|
330
|
-
name = "fnv"
|
|
331
|
-
version = "1.0.7"
|
|
332
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
333
|
-
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
334
|
-
|
|
335
320
|
[[package]]
|
|
336
321
|
name = "fs2"
|
|
337
322
|
version = "0.4.3"
|
|
@@ -367,15 +352,15 @@ dependencies = [
|
|
|
367
352
|
|
|
368
353
|
[[package]]
|
|
369
354
|
name = "globset"
|
|
370
|
-
version = "0.4.
|
|
355
|
+
version = "0.4.14"
|
|
371
356
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
372
|
-
checksum = "
|
|
357
|
+
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
|
373
358
|
dependencies = [
|
|
374
|
-
"aho-corasick
|
|
359
|
+
"aho-corasick",
|
|
375
360
|
"bstr",
|
|
376
|
-
"fnv",
|
|
377
361
|
"log",
|
|
378
|
-
"regex",
|
|
362
|
+
"regex-automata",
|
|
363
|
+
"regex-syntax 0.8.8",
|
|
379
364
|
]
|
|
380
365
|
|
|
381
366
|
[[package]]
|
|
@@ -512,7 +497,7 @@ dependencies = [
|
|
|
512
497
|
|
|
513
498
|
[[package]]
|
|
514
499
|
name = "linthis"
|
|
515
|
-
version = "0.0.
|
|
500
|
+
version = "0.0.3"
|
|
516
501
|
dependencies = [
|
|
517
502
|
"anyhow",
|
|
518
503
|
"chrono",
|
|
@@ -544,9 +529,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
|
|
544
529
|
|
|
545
530
|
[[package]]
|
|
546
531
|
name = "log"
|
|
547
|
-
version = "0.4.
|
|
532
|
+
version = "0.4.29"
|
|
548
533
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
549
|
-
checksum = "
|
|
534
|
+
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|
550
535
|
|
|
551
536
|
[[package]]
|
|
552
537
|
name = "memchr"
|
|
@@ -648,9 +633,20 @@ version = "1.8.4"
|
|
|
648
633
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
649
634
|
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
|
650
635
|
dependencies = [
|
|
651
|
-
"aho-corasick
|
|
636
|
+
"aho-corasick",
|
|
652
637
|
"memchr",
|
|
653
|
-
"regex-syntax",
|
|
638
|
+
"regex-syntax 0.7.5",
|
|
639
|
+
]
|
|
640
|
+
|
|
641
|
+
[[package]]
|
|
642
|
+
name = "regex-automata"
|
|
643
|
+
version = "0.4.13"
|
|
644
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
645
|
+
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
|
646
|
+
dependencies = [
|
|
647
|
+
"aho-corasick",
|
|
648
|
+
"memchr",
|
|
649
|
+
"regex-syntax 0.8.8",
|
|
654
650
|
]
|
|
655
651
|
|
|
656
652
|
[[package]]
|
|
@@ -659,6 +655,12 @@ version = "0.7.5"
|
|
|
659
655
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
660
656
|
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
|
661
657
|
|
|
658
|
+
[[package]]
|
|
659
|
+
name = "regex-syntax"
|
|
660
|
+
version = "0.8.8"
|
|
661
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
662
|
+
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
|
663
|
+
|
|
662
664
|
[[package]]
|
|
663
665
|
name = "rustix"
|
|
664
666
|
version = "1.1.2"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# clang-tidy configuration for linthis
|
|
2
|
+
# Reference: https://clang.llvm.org/extra/clang-tidy/
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
# 启用的检查规则
|
|
6
|
+
Checks: >
|
|
7
|
+
-*,
|
|
8
|
+
bugprone-*,
|
|
9
|
+
clang-analyzer-*,
|
|
10
|
+
cppcoreguidelines-*,
|
|
11
|
+
google-*,
|
|
12
|
+
misc-*,
|
|
13
|
+
modernize-*,
|
|
14
|
+
performance-*,
|
|
15
|
+
readability-*,
|
|
16
|
+
-modernize-use-trailing-return-type,
|
|
17
|
+
-readability-magic-numbers,
|
|
18
|
+
-cppcoreguidelines-avoid-magic-numbers,
|
|
19
|
+
-google-readability-todo,
|
|
20
|
+
-readability-identifier-length,
|
|
21
|
+
-cppcoreguidelines-pro-bounds-array-to-pointer-decay
|
|
22
|
+
|
|
23
|
+
# 将警告视为错误的规则 (可选)
|
|
24
|
+
WarningsAsErrors: ''
|
|
25
|
+
|
|
26
|
+
# 头文件过滤正则表达式
|
|
27
|
+
HeaderFilterRegex: '.*'
|
|
28
|
+
|
|
29
|
+
# 分析系统头文件
|
|
30
|
+
AnalyzeTemporaryDtors: false
|
|
31
|
+
|
|
32
|
+
# 格式化风格 (用于自动修复)
|
|
33
|
+
FormatStyle: 'google'
|
|
34
|
+
|
|
35
|
+
# 检查选项
|
|
36
|
+
CheckOptions:
|
|
37
|
+
# readability-identifier-naming: 命名规范
|
|
38
|
+
- key: readability-identifier-naming.ClassCase
|
|
39
|
+
value: CamelCase
|
|
40
|
+
- key: readability-identifier-naming.StructCase
|
|
41
|
+
value: CamelCase
|
|
42
|
+
- key: readability-identifier-naming.EnumCase
|
|
43
|
+
value: CamelCase
|
|
44
|
+
- key: readability-identifier-naming.FunctionCase
|
|
45
|
+
value: CamelCase
|
|
46
|
+
- key: readability-identifier-naming.MethodCase
|
|
47
|
+
value: CamelCase
|
|
48
|
+
- key: readability-identifier-naming.VariableCase
|
|
49
|
+
value: lower_case
|
|
50
|
+
- key: readability-identifier-naming.ParameterCase
|
|
51
|
+
value: lower_case
|
|
52
|
+
- key: readability-identifier-naming.MemberCase
|
|
53
|
+
value: lower_case
|
|
54
|
+
- key: readability-identifier-naming.MemberSuffix
|
|
55
|
+
value: '_'
|
|
56
|
+
- key: readability-identifier-naming.ConstantCase
|
|
57
|
+
value: CamelCase
|
|
58
|
+
- key: readability-identifier-naming.ConstantPrefix
|
|
59
|
+
value: 'k'
|
|
60
|
+
- key: readability-identifier-naming.GlobalConstantCase
|
|
61
|
+
value: CamelCase
|
|
62
|
+
- key: readability-identifier-naming.GlobalConstantPrefix
|
|
63
|
+
value: 'k'
|
|
64
|
+
- key: readability-identifier-naming.MacroDefinitionCase
|
|
65
|
+
value: UPPER_CASE
|
|
66
|
+
- key: readability-identifier-naming.NamespaceCase
|
|
67
|
+
value: lower_case
|
|
68
|
+
|
|
69
|
+
# modernize 相关选项
|
|
70
|
+
- key: modernize-use-nullptr.NullMacros
|
|
71
|
+
value: 'NULL'
|
|
72
|
+
- key: modernize-loop-convert.MinConfidence
|
|
73
|
+
value: reasonable
|
|
74
|
+
- key: modernize-pass-by-value.IncludeStyle
|
|
75
|
+
value: google
|
|
76
|
+
|
|
77
|
+
# performance 相关选项
|
|
78
|
+
- key: performance-move-const-arg.CheckTriviallyCopyableMove
|
|
79
|
+
value: true
|
|
80
|
+
|
|
81
|
+
# misc 相关选项
|
|
82
|
+
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
|
83
|
+
value: true
|
|
84
|
+
|
|
85
|
+
# cppcoreguidelines 相关选项
|
|
86
|
+
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
|
|
87
|
+
value: true
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Linthis Default Configuration
|
|
2
|
+
# This file contains built-in defaults that are applied when no user/project config exists.
|
|
3
|
+
|
|
4
|
+
# Maximum cyclomatic complexity threshold
|
|
5
|
+
max_complexity = 20
|
|
6
|
+
|
|
7
|
+
# Default exclusion patterns
|
|
8
|
+
exclude = [
|
|
9
|
+
".git/**",
|
|
10
|
+
".hg/**",
|
|
11
|
+
".svn/**",
|
|
12
|
+
"node_modules/**",
|
|
13
|
+
"target/**",
|
|
14
|
+
"vendor/**",
|
|
15
|
+
"build/**",
|
|
16
|
+
"dist/**",
|
|
17
|
+
"__pycache__/**",
|
|
18
|
+
"*.pyc",
|
|
19
|
+
"*.pyo",
|
|
20
|
+
".venv/**",
|
|
21
|
+
"venv/**",
|
|
22
|
+
".idea/**",
|
|
23
|
+
".vscode/**",
|
|
24
|
+
"*.min.js",
|
|
25
|
+
"*.min.css",
|
|
26
|
+
"**/Pods/**",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# Output settings
|
|
30
|
+
[output]
|
|
31
|
+
format = "human" # human, json, github-actions
|
|
32
|
+
color = "auto" # auto, always, never
|
|
33
|
+
|
|
34
|
+
# Parallel processing
|
|
35
|
+
[parallel]
|
|
36
|
+
enabled = true
|
|
37
|
+
jobs = 0 # 0 = auto-detect CPU count
|
|
38
|
+
|
|
39
|
+
# Python settings (uses ruff for both linting and formatting)
|
|
40
|
+
[python]
|
|
41
|
+
# Ruff is used for both linting and formatting (10-100x faster than flake8+black)
|
|
42
|
+
linter = "ruff"
|
|
43
|
+
formatter = "ruff"
|
|
44
|
+
line_length = 120
|
|
45
|
+
target_version = "py38"
|
|
46
|
+
|
|
47
|
+
# Rust settings
|
|
48
|
+
[rust]
|
|
49
|
+
linter = "clippy"
|
|
50
|
+
formatter = "rustfmt"
|
|
51
|
+
|
|
52
|
+
# TypeScript/JavaScript settings
|
|
53
|
+
[typescript]
|
|
54
|
+
linter = "eslint"
|
|
55
|
+
formatter = "prettier"
|
|
56
|
+
|
|
57
|
+
# Go settings
|
|
58
|
+
[go]
|
|
59
|
+
linter = "go vet"
|
|
60
|
+
formatter = "gofmt"
|
|
61
|
+
|
|
62
|
+
# C/C++ settings
|
|
63
|
+
[cpp]
|
|
64
|
+
# Linter: "clang-tidy" (preferred, more powerful) or "cpplint" (fallback)
|
|
65
|
+
linter = "clang-tidy"
|
|
66
|
+
# Formatter: clang-format for code style, clang-tidy --fix for lint fixes
|
|
67
|
+
formatter = "clang-format"
|
|
68
|
+
# Style for clang-format (google, llvm, chromium, mozilla, webkit)
|
|
69
|
+
style = "google"
|
|
70
|
+
# Enable clang-tidy --fix during format phase (fixes C-style casts, nullptr, etc.)
|
|
71
|
+
clang_tidy_fix = true
|
|
72
|
+
# Enable cpplint fixer during format phase (fixes header guards, TODOs, etc.)
|
|
73
|
+
cpplint_fix = true
|
|
74
|
+
# Directory containing compile_commands.json (optional, auto-detected if not set)
|
|
75
|
+
# Auto-detection searches up to 6 levels: cmake*/, build*/, out*/, *_build/, *-build/
|
|
76
|
+
# and platform dirs: android/, ios/, arm*/, x86*/, debug/, release/, static/, shared/
|
|
77
|
+
# compile_commands_dir = "cmake_build/debug/Android/static/arm64-v8a"
|
|
78
|
+
|
|
79
|
+
# Cpplint fixer settings
|
|
80
|
+
[cpp.cpplint_fix]
|
|
81
|
+
# Header guard mode: "fix_name" (default) or "pragma_once"
|
|
82
|
+
header_guard_mode = "fix_name"
|
|
83
|
+
# Username for TODO comments (default: git user.name or $USER)
|
|
84
|
+
# todo_username = "your_username"
|
|
85
|
+
# Copyright template (optional, with {year} placeholder)
|
|
86
|
+
# copyright_template = "// Copyright {year} Your Company. All rights reserved."
|
|
87
|
+
# Header guard prefix (optional)
|
|
88
|
+
# header_guard_prefix = "MYPROJECT_"
|
|
@@ -13,15 +13,165 @@
|
|
|
13
13
|
use crate::checkers::Checker;
|
|
14
14
|
use crate::utils::types::{LintIssue, Severity};
|
|
15
15
|
use crate::{Language, Result};
|
|
16
|
-
use std::path::Path;
|
|
16
|
+
use std::path::{Path, PathBuf};
|
|
17
17
|
use std::process::Command;
|
|
18
18
|
|
|
19
19
|
/// C/C++ checker using clang-tidy (preferred) or cpplint.
|
|
20
|
-
pub struct CppChecker
|
|
20
|
+
pub struct CppChecker {
|
|
21
|
+
/// Custom .clang-tidy config path
|
|
22
|
+
config_path: Option<PathBuf>,
|
|
23
|
+
/// Custom compile_commands.json directory path
|
|
24
|
+
compile_commands_dir: Option<PathBuf>,
|
|
25
|
+
}
|
|
21
26
|
|
|
22
27
|
impl CppChecker {
|
|
23
28
|
pub fn new() -> Self {
|
|
24
|
-
Self
|
|
29
|
+
Self {
|
|
30
|
+
config_path: None,
|
|
31
|
+
compile_commands_dir: None,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Set custom .clang-tidy config path
|
|
36
|
+
pub fn with_config(mut self, path: PathBuf) -> Self {
|
|
37
|
+
self.config_path = Some(path);
|
|
38
|
+
self
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Set custom compile_commands.json directory path
|
|
42
|
+
/// This is the directory containing compile_commands.json, not the file itself
|
|
43
|
+
pub fn with_compile_commands_dir(mut self, path: PathBuf) -> Self {
|
|
44
|
+
self.compile_commands_dir = Some(path);
|
|
45
|
+
self
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Find .clang-tidy config file by walking up from file path
|
|
49
|
+
fn find_clang_tidy_config(start_path: &Path) -> Option<PathBuf> {
|
|
50
|
+
let mut current = if start_path.is_file() {
|
|
51
|
+
start_path.parent()?.to_path_buf()
|
|
52
|
+
} else {
|
|
53
|
+
start_path.to_path_buf()
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
loop {
|
|
57
|
+
let config_path = current.join(".clang-tidy");
|
|
58
|
+
if config_path.exists() {
|
|
59
|
+
return Some(config_path);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Also check for _clang-tidy (alternative name)
|
|
63
|
+
let alt_config = current.join("_clang-tidy");
|
|
64
|
+
if alt_config.exists() {
|
|
65
|
+
return Some(alt_config);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if !current.pop() {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
None
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Find compile_commands.json for better analysis
|
|
76
|
+
/// Searches in common build directories recursively (up to max_depth levels)
|
|
77
|
+
fn find_compile_commands(start_path: &Path) -> Option<PathBuf> {
|
|
78
|
+
let mut current = if start_path.is_file() {
|
|
79
|
+
start_path.parent()?.to_path_buf()
|
|
80
|
+
} else {
|
|
81
|
+
start_path.to_path_buf()
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
loop {
|
|
85
|
+
// 1. Check in current directory directly
|
|
86
|
+
let direct = current.join("compile_commands.json");
|
|
87
|
+
if direct.exists() {
|
|
88
|
+
return Some(current.clone());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 2. Check common fixed build directory names (1 level)
|
|
92
|
+
for build_dir in &[
|
|
93
|
+
"build",
|
|
94
|
+
"Build",
|
|
95
|
+
"out",
|
|
96
|
+
"output",
|
|
97
|
+
"cmake-build-debug",
|
|
98
|
+
"cmake-build-release",
|
|
99
|
+
"cmake-build-relwithdebinfo",
|
|
100
|
+
"cmake-build-minsizerel",
|
|
101
|
+
".build",
|
|
102
|
+
"_build",
|
|
103
|
+
] {
|
|
104
|
+
let compile_db = current.join(build_dir).join("compile_commands.json");
|
|
105
|
+
if compile_db.exists() {
|
|
106
|
+
return Some(current.join(build_dir));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 3. Recursively search in directories matching build patterns (up to 6 levels deep)
|
|
111
|
+
if let Some(found) = Self::find_compile_commands_recursive(¤t, 0, 6) {
|
|
112
|
+
return Some(found);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if !current.pop() {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
None
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// Recursively search for compile_commands.json in build-like directories
|
|
123
|
+
fn find_compile_commands_recursive(dir: &Path, depth: usize, max_depth: usize) -> Option<PathBuf> {
|
|
124
|
+
if depth >= max_depth {
|
|
125
|
+
return None;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let entries = std::fs::read_dir(dir).ok()?;
|
|
129
|
+
|
|
130
|
+
for entry in entries.flatten() {
|
|
131
|
+
let path = entry.path();
|
|
132
|
+
if !path.is_dir() {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let name = path.file_name().and_then(|n| n.to_str())?;
|
|
137
|
+
let name_lower = name.to_lowercase();
|
|
138
|
+
|
|
139
|
+
// Only recurse into build-related directories
|
|
140
|
+
let is_build_dir = name_lower.starts_with("cmake")
|
|
141
|
+
|| name_lower.starts_with("build")
|
|
142
|
+
|| name_lower.starts_with("out")
|
|
143
|
+
|| name_lower.ends_with("-build")
|
|
144
|
+
|| name_lower.ends_with("_build")
|
|
145
|
+
// Also allow platform/arch subdirectories inside build dirs
|
|
146
|
+
|| (depth > 0
|
|
147
|
+
&& (name_lower.contains("android")
|
|
148
|
+
|| name_lower.contains("ios")
|
|
149
|
+
|| name_lower.contains("linux")
|
|
150
|
+
|| name_lower.contains("windows")
|
|
151
|
+
|| name_lower.contains("macos")
|
|
152
|
+
|| name_lower.contains("darwin")
|
|
153
|
+
|| name_lower.contains("arm")
|
|
154
|
+
|| name_lower.contains("x86")
|
|
155
|
+
|| name_lower.contains("x64")
|
|
156
|
+
|| name_lower.contains("static")
|
|
157
|
+
|| name_lower.contains("shared")
|
|
158
|
+
|| name_lower.contains("debug")
|
|
159
|
+
|| name_lower.contains("release")));
|
|
160
|
+
|
|
161
|
+
if is_build_dir {
|
|
162
|
+
// Check if compile_commands.json exists here
|
|
163
|
+
let compile_db = path.join("compile_commands.json");
|
|
164
|
+
if compile_db.exists() {
|
|
165
|
+
return Some(path);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Recurse deeper
|
|
169
|
+
if let Some(found) = Self::find_compile_commands_recursive(&path, depth + 1, max_depth) {
|
|
170
|
+
return Some(found);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
None
|
|
25
175
|
}
|
|
26
176
|
|
|
27
177
|
/// Check if clang-tidy is available
|
|
@@ -42,11 +192,29 @@ impl CppChecker {
|
|
|
42
192
|
.unwrap_or(false)
|
|
43
193
|
}
|
|
44
194
|
|
|
45
|
-
/// Run clang-tidy on a file
|
|
46
|
-
fn run_clang_tidy(path: &Path) -> Result<Vec<LintIssue>> {
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
195
|
+
/// Run clang-tidy on a file (check only, no fix)
|
|
196
|
+
fn run_clang_tidy(&self, path: &Path) -> Result<Vec<LintIssue>> {
|
|
197
|
+
let mut cmd = Command::new("clang-tidy");
|
|
198
|
+
cmd.arg(path);
|
|
199
|
+
|
|
200
|
+
// Add config file if specified or found
|
|
201
|
+
if let Some(ref config) = self.config_path {
|
|
202
|
+
cmd.arg(format!("--config-file={}", config.display()));
|
|
203
|
+
} else if let Some(config) = Self::find_clang_tidy_config(path) {
|
|
204
|
+
cmd.arg(format!("--config-file={}", config.display()));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Add compile_commands.json path: user-specified > auto-detected
|
|
208
|
+
if let Some(ref build_path) = self.compile_commands_dir {
|
|
209
|
+
cmd.arg(format!("-p={}", build_path.display()));
|
|
210
|
+
} else if let Some(build_path) = Self::find_compile_commands(path) {
|
|
211
|
+
cmd.arg(format!("-p={}", build_path.display()));
|
|
212
|
+
} else {
|
|
213
|
+
// Use -- to separate clang-tidy args from compiler args
|
|
214
|
+
cmd.arg("--");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
let output = cmd
|
|
50
218
|
.output()
|
|
51
219
|
.map_err(|e| crate::LintisError::Checker(format!("Failed to run clang-tidy: {}", e)))?;
|
|
52
220
|
|
|
@@ -234,7 +402,7 @@ impl Checker for CppChecker {
|
|
|
234
402
|
fn check(&self, path: &Path) -> Result<Vec<LintIssue>> {
|
|
235
403
|
// Prefer clang-tidy if available, fall back to cpplint
|
|
236
404
|
if Self::has_clang_tidy() {
|
|
237
|
-
|
|
405
|
+
self.run_clang_tidy(path)
|
|
238
406
|
} else if Self::has_cpplint() {
|
|
239
407
|
Self::run_cpplint(path)
|
|
240
408
|
} else {
|