aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts/linters/contiguous_use_block.rb
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/linters/contiguous_use_block.rb')
-rw-r--r--scripts/linters/contiguous_use_block.rb80
1 files changed, 80 insertions, 0 deletions
diff --git a/scripts/linters/contiguous_use_block.rb b/scripts/linters/contiguous_use_block.rb
new file mode 100644
index 0000000..bce9e32
--- /dev/null
+++ b/scripts/linters/contiguous_use_block.rb
@@ -0,0 +1,80 @@
+def contiguous_use_block(root_dir)
+ pattern = root_dir.join('crates', '**', '*.rs').to_s
+ errors = Dir.glob(pattern).sort.flat_map do |path|
+ relative = Pathname.new(path).relative_path_from(root_dir).to_s
+ find_split_use_block(path, relative)
+ end
+
+ return true if errors.empty?
+
+ puts 'Found blank lines splitting the leading `use` block into sections.'
+ puts 'All `use` statements at the top of the file must be contiguous (no blank lines between them):'
+ errors.each do |err|
+ puts " #{err}"
+ end
+ false
+end
+
+USE_START_RE = /\A(?:pub(?:\([^)]*\))?\s+)?use\b/
+
+def find_split_use_block(path, relative)
+ lines = File.readlines(path)
+ errors = []
+
+ i = skip_preamble(lines)
+ return [] if i.nil?
+
+ loop do
+ i = consume_use_statement(lines, i)
+ break if i >= lines.length
+
+ blanks = []
+ j = i
+ while j < lines.length
+ stripped = lines[j].strip
+ if stripped.empty?
+ blanks << j
+ j += 1
+ elsif stripped.start_with?('//') || stripped.start_with?('#[')
+ j += 1
+ else
+ break
+ end
+ end
+
+ if j < lines.length && lines[j].strip =~ USE_START_RE
+ blanks.each do |bi|
+ errors << "#{relative}:#{bi + 1}: blank line splits the leading `use` block"
+ end
+ i = j
+ else
+ break
+ end
+ end
+
+ errors
+end
+
+def skip_preamble(lines)
+ lines.each_with_index do |raw, idx|
+ stripped = raw.strip
+ return idx if stripped =~ USE_START_RE
+ next if stripped.empty? || stripped.start_with?('//') || stripped.start_with?('#![') || stripped.start_with?('#[')
+
+ return nil
+ end
+ nil
+end
+
+def consume_use_statement(lines, start_idx)
+ brace_depth = 0
+ i = start_idx
+ while i < lines.length
+ line = lines[i]
+ brace_depth += line.count('{') - line.count('}')
+ done = brace_depth <= 0 && line.rstrip.end_with?(';')
+ i += 1
+ return i if done
+ end
+ i
+end