Skip to content

Commit ab06732

Browse files
committed
Add a directive for cargo lint extraction
1 parent 3c77e5d commit ab06732

9 files changed

Lines changed: 121 additions & 5 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# gazelle:rust_mode generate_from_cargo
2+
# gazelle:rust_extract_cargo_lints true
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
load("@rules_rust//cargo:defs.bzl", "extract_cargo_lints")
2+
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
3+
4+
# gazelle:rust_mode generate_from_cargo
5+
# gazelle:rust_extract_cargo_lints true
6+
7+
extract_cargo_lints(
8+
name = "workspace_lints",
9+
manifest = "Cargo.toml",
10+
workspace = "//:Cargo.toml",
11+
)
12+
13+
rust_library(
14+
name = "extract_lints_test_lib",
15+
srcs = ["src/lib.rs"],
16+
compile_data = ["Cargo.toml"],
17+
crate_name = "extract_lints_test",
18+
edition = "2021",
19+
lint_config = ":workspace_lints",
20+
visibility = ["//visibility:public"],
21+
)
22+
23+
rust_binary(
24+
name = "extract_lints_test",
25+
srcs = ["src/main.rs"],
26+
compile_data = ["Cargo.toml"],
27+
edition = "2021",
28+
lint_config = ":workspace_lints",
29+
visibility = ["//visibility:public"],
30+
)
31+
32+
rust_test(
33+
name = "extract_lints_test_lib_test",
34+
compile_data = ["Cargo.toml"],
35+
crate = ":extract_lints_test_lib",
36+
edition = "2021",
37+
lint_config = ":workspace_lints",
38+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[package]
2+
name = "extract_lints_test"
3+
version = "0.1.0"
4+
edition = "2021"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
Tests that the rust_extract_cargo_lints directive generates extract_cargo_lints targets and adds lint_config attributes.

generation_tests/cargo/extract_cargo_lints/WORKSPACE

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub fn add(a: i32, b: i32) -> i32 {
2+
a + b
3+
}
4+
5+
#[cfg(test)]
6+
mod tests {
7+
use super::*;
8+
9+
#[test]
10+
fn test_add() {
11+
assert_eq!(add(1, 2), 3);
12+
}
13+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("Hello, world!");
3+
}

rust_language/generate.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,30 @@ func (l *rustLang) generateRulesFromCargo(args language.GenerateArgs) language.G
401401
// Determine if there are binaries (which would have main.rs files)
402402
hasMainRs := len(response.Binaries) > 0
403403

404+
// Check if we're generating any Rust targets that use lint_config
405+
// Note: cargo_build_script does not use lint_config, so we exclude it
406+
hasAnyRustTargets := response.Library != nil ||
407+
len(response.Binaries) > 0 ||
408+
len(response.Tests) > 0 ||
409+
len(response.Benches) > 0 ||
410+
len(response.Examples) > 0
411+
412+
// Generate extract_cargo_lints target only if we're generating Rust targets that use it
413+
if cfg.ExtractCargoLints && hasAnyRustTargets {
414+
lintsRule := rule.NewRule("extract_cargo_lints", "workspace_lints")
415+
lintsRule.SetAttr("manifest", "Cargo.toml")
416+
lintsRule.SetAttr("workspace", "//:Cargo.toml")
417+
result.Gen = append(result.Gen, lintsRule)
418+
result.Imports = append(result.Imports, RuleData{
419+
rule: lintsRule,
420+
responses: []*pb.RustImportsResponse{},
421+
testedCrate: nil,
422+
buildScript: nil,
423+
parentCrateName: parentCrateName,
424+
aliases: dependencyAliases,
425+
})
426+
}
427+
404428
if response.Library != nil {
405429
// if there is a main.rs next to lib.rs, they will both have the same crate
406430
// name; need to give the library a different name
@@ -472,6 +496,10 @@ func (l *rustLang) generateRulesFromCargo(args language.GenerateArgs) language.G
472496
testRule.SetAttr("edition", parentCrateEdition)
473497
}
474498

499+
if cfg.ExtractCargoLints {
500+
testRule.SetAttr("lint_config", ":workspace_lints")
501+
}
502+
475503
result.Gen = append(result.Gen, testRule)
476504
result.Imports = append(result.Imports, RuleData{
477505
rule: testRule,
@@ -581,6 +609,10 @@ func (l *rustLang) generateCargoRule(c *config.Config, args *language.GenerateAr
581609
newRule.SetAttr("crate_features", enabledFeatures)
582610
}
583611

612+
if cfg.ExtractCargoLints {
613+
newRule.SetAttr("lint_config", ":workspace_lints")
614+
}
615+
584616
var buildScript *label.Label = nil
585617
if hasBuildScript && (kind == "rust_library" || kind == "rust_binary") {
586618
build_script_label, err := label.Parse(":build_script")

rust_language/lang.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ var (
6565
// Ignore a specific import when resolving dependencies.
6666
// usage: # gazelle:rust_ignore_import <import name>
6767
ignoreImportDirective string = "rust_ignore_import"
68+
69+
// Extract cargo lints from Cargo.toml files.
70+
// When enabled in generate_from_cargo mode, creates extract_cargo_lints targets
71+
// and adds lint_config attributes to all generated targets.
72+
extractCargoLintsDirective string = "rust_extract_cargo_lints"
6873
)
6974

7075
type rustConfig struct {
@@ -78,6 +83,7 @@ type rustConfig struct {
7883
DefaultEdition string
7984
SrcsGlob bool
8085
IgnoredImports map[string]bool
86+
ExtractCargoLints bool
8187
}
8288

8389
func (cfg *rustConfig) Clone() *rustConfig {
@@ -121,9 +127,10 @@ func (*rustLang) Name() string { return langName }
121127
var (
122128
commonDefs []string = []string{"rust_library", "rust_binary", "rust_test",
123129
"rust_proc_macro", "rust_shared_library", "rust_static_library"}
124-
protoDefs []string = []string{"rust_proto_library", "rust_grpc_library"}
125-
prostDefs []string = []string{"rust_prost_library"}
126-
cargoDefs []string = []string{"cargo_build_script"}
130+
protoDefs []string = []string{"rust_proto_library", "rust_grpc_library"}
131+
prostDefs []string = []string{"rust_prost_library"}
132+
cargoDefs []string = []string{"cargo_build_script"}
133+
cargoLintsDefs []string = []string{"extract_cargo_lints"}
127134
)
128135

129136
var resolvableDefs = append(
@@ -164,6 +171,13 @@ func (*rustLang) Kinds() map[string]rule.KindInfo {
164171
}
165172
}
166173

174+
for _, cargoLintsDef := range cargoLintsDefs {
175+
kinds[cargoLintsDef] = rule.KindInfo{
176+
MergeableAttrs: map[string]bool{},
177+
ResolveAttrs: map[string]bool{},
178+
}
179+
}
180+
167181
return kinds
168182
}
169183

@@ -183,7 +197,7 @@ func (*rustLang) Loads() []rule.LoadInfo {
183197
},
184198
{
185199
Name: "@rules_rust//cargo:defs.bzl",
186-
Symbols: cargoDefs,
200+
Symbols: append(cargoDefs, cargoLintsDefs...),
187201
},
188202
}
189203
}
@@ -201,7 +215,7 @@ func (*rustLang) KnownDirectives() []string {
201215
return []string{modeDirective, lockfileDirective, cargoLockfileDirective,
202216
cratesPrefixDirective, procMacroOverrideDirective, allowUnusedCrateDirective,
203217
rustFeatureDirective, defaultFeaturesDirective, defaultEditionDirective,
204-
srcsGlobDirective, ignoreImportDirective}
218+
srcsGlobDirective, ignoreImportDirective, extractCargoLintsDirective}
205219
}
206220

207221
func (l *rustLang) GetConfig(c *config.Config) *rustConfig {
@@ -238,6 +252,7 @@ func (l *rustLang) Configure(c *config.Config, rel string, from *rule.File) {
238252
DefaultEdition: "",
239253
SrcsGlob: false,
240254
IgnoredImports: make(map[string]bool),
255+
ExtractCargoLints: false,
241256
}
242257
} else {
243258
// NOTE(will): important to clone so that we don't leak state across directories
@@ -306,6 +321,13 @@ func (l *rustLang) Configure(c *config.Config, rel string, from *rule.File) {
306321
cfg.SrcsGlob = value
307322
} else if directive.Key == ignoreImportDirective {
308323
cfg.IgnoredImports[directive.Value] = true
324+
} else if directive.Key == extractCargoLintsDirective {
325+
value, err := strconv.ParseBool(directive.Value)
326+
if err != nil {
327+
l.Log(c, logFatal, "bad %s, should be gazelle:%s <true|false>",
328+
directive.Key, directive.Key)
329+
}
330+
cfg.ExtractCargoLints = value
309331
}
310332
}
311333
}

0 commit comments

Comments
 (0)