Skip to content

Commit ffcaa60

Browse files
committed
Add basic bazelrc-lsp lint command
1 parent 99328b2 commit ffcaa60

File tree

2 files changed

+158
-102
lines changed

2 files changed

+158
-102
lines changed

src/diagnostic.rs

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use ropey::Rope;
66
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, DiagnosticTag};
77

88
use crate::{
9-
bazel_flags::{BazelFlags, FlagLookupType},
9+
bazel_flags::{combine_key_value_flags, BazelFlags, FlagLookupType},
1010
file_utils::resolve_bazelrc_path,
1111
lsp_utils::range_to_lsp,
12-
parser::Line,
12+
parser::{parse_from_str, Line, ParserResult},
1313
};
1414

1515
pub fn diagnostics_from_parser<'a>(
@@ -246,24 +246,36 @@ pub fn diagnostics_from_rcconfig(
246246
diagnostics
247247
}
248248

249-
#[cfg(test)]
250-
fn diagnose_string(str: &str) -> Vec<String> {
251-
use crate::bazel_flags::combine_key_value_flags;
252-
use crate::bazel_flags::load_packaged_bazel_flags;
253-
use crate::parser::parse_from_str;
254-
use crate::parser::ParserResult;
255-
249+
pub fn diagnostics_from_string(
250+
str: &str,
251+
bazel_flags: &BazelFlags,
252+
file_path: Option<&Path>,
253+
) -> Vec<Diagnostic> {
256254
let rope = Rope::from_str(str);
257255
let ParserResult {
258256
tokens: _,
259257
mut lines,
260258
errors,
261259
} = parse_from_str(str);
262-
assert!(errors.is_empty());
260+
combine_key_value_flags(&mut lines, bazel_flags);
261+
262+
let mut diagnostics: Vec<Diagnostic> = Vec::<Diagnostic>::new();
263+
diagnostics.extend(diagnostics_from_parser(&rope, &errors));
264+
diagnostics.extend(diagnostics_from_rcconfig(
265+
&rope,
266+
&lines,
267+
bazel_flags,
268+
file_path,
269+
));
270+
diagnostics
271+
}
272+
273+
#[cfg(test)]
274+
fn test_diagnose_string(str: &str) -> Vec<String> {
275+
use crate::bazel_flags::load_packaged_bazel_flags;
263276

264277
let bazel_flags = load_packaged_bazel_flags("8.0.0");
265-
combine_key_value_flags(&mut lines, &bazel_flags);
266-
return diagnostics_from_rcconfig(&rope, &lines, &bazel_flags, None)
278+
return diagnostics_from_string(str, &bazel_flags, None)
267279
.iter_mut()
268280
.map(|d| std::mem::take(&mut d.message))
269281
.collect::<Vec<_>>();
@@ -273,22 +285,22 @@ fn diagnose_string(str: &str) -> Vec<String> {
273285
fn test_diagnose_commands() {
274286
// Nothing wrong with this `build` command
275287
assert_eq!(
276-
diagnose_string("build --remote_upload_local_results=false"),
288+
test_diagnose_string("build --remote_upload_local_results=false"),
277289
Vec::<&str>::new()
278290
);
279291
// The command should be named `build`, not `built`
280292
assert_eq!(
281-
diagnose_string("built --remote_upload_local_results=false"),
293+
test_diagnose_string("built --remote_upload_local_results=false"),
282294
vec!["Unknown command \"built\""]
283295
);
284296
// Completely missing command
285297
assert_eq!(
286-
diagnose_string("--remote_upload_local_results=false"),
298+
test_diagnose_string("--remote_upload_local_results=false"),
287299
vec!["Missing command"]
288300
);
289301
// Completely missing command
290302
assert_eq!(
291-
diagnose_string(":opt --remote_upload_local_results=false"),
303+
test_diagnose_string(":opt --remote_upload_local_results=false"),
292304
vec!["Missing command"]
293305
);
294306
}
@@ -297,58 +309,58 @@ fn test_diagnose_commands() {
297309
fn test_diagnose_config_names() {
298310
// Diagnose empty config names
299311
assert_eq!(
300-
diagnose_string("build: --disk_cache="),
312+
test_diagnose_string("build: --disk_cache="),
301313
vec!["Empty configuration names are pointless"]
302314
);
303315

304316
// Diagnose config names on commands which don't support configs
305317
assert_eq!(
306-
diagnose_string("startup:opt --digest_function=blake3"),
318+
test_diagnose_string("startup:opt --digest_function=blake3"),
307319
vec!["Configuration names not supported on \"startup\" commands"]
308320
);
309321
assert_eq!(
310-
diagnose_string("import:opt \"x.bazelrc\""),
322+
test_diagnose_string("import:opt \"x.bazelrc\""),
311323
vec!["Configuration names not supported on \"import\" commands"]
312324
);
313325
assert_eq!(
314-
diagnose_string("try-import:opt \"x.bazelrc\""),
326+
test_diagnose_string("try-import:opt \"x.bazelrc\""),
315327
vec!["Configuration names not supported on \"try-import\" commands"]
316328
);
317329

318330
// Diagnose overly complicated config names
319331
let config_name_diag = "Overly complicated config name. Config names should consist only of lower-case ASCII characters.";
320332
assert_eq!(
321-
diagnose_string("common:Uncached --disk_cache="),
333+
test_diagnose_string("common:Uncached --disk_cache="),
322334
vec![config_name_diag]
323335
);
324336
assert_eq!(
325-
diagnose_string("common:-opt --disk_cache="),
337+
test_diagnose_string("common:-opt --disk_cache="),
326338
vec![config_name_diag]
327339
);
328340
assert_eq!(
329-
diagnose_string("common:opt- --disk_cache="),
341+
test_diagnose_string("common:opt- --disk_cache="),
330342
vec![config_name_diag]
331343
);
332344
assert_eq!(
333-
diagnose_string("common:2opt --disk_cache="),
345+
test_diagnose_string("common:2opt --disk_cache="),
334346
vec![config_name_diag]
335347
);
336348
assert_eq!(
337-
diagnose_string("common:opt2 --disk_cache="),
349+
test_diagnose_string("common:opt2 --disk_cache="),
338350
Vec::<String>::new()
339351
);
340352
assert_eq!(
341-
diagnose_string("common:opt-2 --disk_cache="),
353+
test_diagnose_string("common:opt-2 --disk_cache="),
342354
Vec::<String>::new()
343355
);
344356
assert_eq!(
345-
diagnose_string("common:opt--2 --disk_cache="),
357+
test_diagnose_string("common:opt--2 --disk_cache="),
346358
vec![config_name_diag]
347359
);
348360
// The Bazel documentation recommends to prefix all user-specific settings with an `_`.
349361
// As such, config names prefixed that way shouldn't be diagnosed as errors.
350362
assert_eq!(
351-
diagnose_string("common:_personal --disk_cache="),
363+
test_diagnose_string("common:_personal --disk_cache="),
352364
Vec::<String>::new()
353365
);
354366
}
@@ -357,33 +369,33 @@ fn test_diagnose_config_names() {
357369
fn test_diagnose_flags() {
358370
// Diagnose unknown flags
359371
assert_eq!(
360-
diagnose_string("build --unknown_flag"),
372+
test_diagnose_string("build --unknown_flag"),
361373
vec!["Unknown flag \"--unknown_flag\""]
362374
);
363375
// Diagnose flags which are applied for the wrong command
364376
assert_eq!(
365-
diagnose_string("startup --disk_cache="),
377+
test_diagnose_string("startup --disk_cache="),
366378
vec!["The flag \"--disk_cache\" is not supported for \"startup\". It is supported for [\"analyze-profile\", \"aquery\", \"build\", \"canonicalize-flags\", \"clean\", \"config\", \"coverage\", \"cquery\", \"dump\", \"fetch\", \"help\", \"info\", \"license\", \"mobile-install\", \"mod\", \"print_action\", \"query\", \"run\", \"shutdown\", \"sync\", \"test\", \"vendor\", \"version\"] commands, though."]
367379
);
368380
// Diagnose deprecated flags
369381
assert_eq!(
370-
diagnose_string("common --legacy_whole_archive"),
382+
test_diagnose_string("common --legacy_whole_archive"),
371383
vec!["The flag \"--legacy_whole_archive\" is deprecated."]
372384
);
373385
// Diagnose no_op flags
374386
assert_eq!(
375-
diagnose_string("common --incompatible_override_toolchain_transition"),
387+
test_diagnose_string("common --incompatible_override_toolchain_transition"),
376388
vec!["The flag \"--incompatible_override_toolchain_transition\" is a no-op."]
377389
);
378390
// Diagnose abbreviated flag names
379391
assert_eq!(
380-
diagnose_string("build -k"),
392+
test_diagnose_string("build -k"),
381393
vec!["Use the full name \"keep_going\" instead of its abbreviation."]
382394
);
383395

384396
// Don't diagnose custom flags
385397
assert_eq!(
386-
diagnose_string(
398+
test_diagnose_string(
387399
"build --//my/package:setting=foobar
388400
build --no//my/package:bool_flag
389401
build --@dependency:my/package:bool_flag
@@ -399,28 +411,31 @@ fn test_diagnose_combined_flags() {
399411
// following `--std=c++20`. `--std=c++20` should not raise
400412
// an error about an unrecognized Bazel flag.
401413
assert_eq!(
402-
diagnose_string("build --copt --std=c++20"),
414+
test_diagnose_string("build --copt --std=c++20"),
403415
Vec::<&str>::new()
404416
);
405417
// On the other hand, `--keep_going` only takes an optional value.
406418
// Hence, the `true` is interpreted as a separate flag, which then triggers
407419
// an error.
408420
assert_eq!(
409-
diagnose_string("build --keep_going --foobar"),
421+
test_diagnose_string("build --keep_going --foobar"),
410422
vec!["Unknown flag \"--foobar\""]
411423
);
412424
}
413425

414426
#[test]
415427
fn test_diagnose_import() {
416-
assert_eq!(diagnose_string("import"), vec!["Missing file path"]);
417-
assert_eq!(diagnose_string("try-import"), vec!["Missing file path"]);
428+
assert_eq!(test_diagnose_string("import"), vec!["Missing file path"]);
429+
assert_eq!(
430+
test_diagnose_string("try-import"),
431+
vec!["Missing file path"]
432+
);
418433
assert_eq!(
419-
diagnose_string("import --a"),
434+
test_diagnose_string("import --a"),
420435
vec!["`import` expects a file name, not a flag name"]
421436
);
422437
assert_eq!(
423-
diagnose_string("import a b"),
438+
test_diagnose_string("import a b"),
424439
vec!["`import` expects a single file name, but received multiple arguments"]
425440
);
426441
}

0 commit comments

Comments
 (0)