refactor(ast): change Comment struct (#5783)

This commit is contained in:
Boshen 2024-09-15 09:22:58 +00:00
parent 512be65fa7
commit 6dd6f7ca26
16 changed files with 68 additions and 71 deletions

View file

@ -8,19 +8,34 @@ use std::{
use oxc_span::Span;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CommentKind {
Line,
Block,
}
/// Single or multiline comment
#[derive(Debug, Clone, Copy)]
pub struct Comment {
pub kind: CommentKind,
/// The span of the comment text (without leading/trailing delimiters).
pub span: Span,
pub kind: CommentKind,
}
impl Comment {
#[inline]
pub fn new(start: u32, end: u32, kind: CommentKind) -> Self {
let span = Span::new(start, end);
Self { kind, span }
Self { span, kind }
}
pub fn is_line(self) -> bool {
self.kind == CommentKind::Line
}
pub fn is_block(self) -> bool {
self.kind == CommentKind::Block
}
pub fn real_span(&self) -> Span {
@ -29,36 +44,18 @@ impl Comment {
pub fn real_span_end(&self) -> u32 {
match self.kind {
CommentKind::SingleLine => self.span.end,
CommentKind::Line => self.span.end,
// length of `*/`
CommentKind::MultiLine => self.span.end + 2,
CommentKind::Block => self.span.end + 2,
}
}
pub fn real_span_start(&self) -> u32 {
match self.kind {
CommentKind::SingleLine | CommentKind::MultiLine => self.span.start - 2,
}
self.span.start - 2
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CommentKind {
SingleLine,
MultiLine,
}
impl CommentKind {
#[inline]
pub fn is_single_line(self) -> bool {
self == Self::SingleLine
}
#[inline]
pub fn is_multi_line(self) -> bool {
self == Self::MultiLine
}
}
impl CommentKind {}
/// Sorted set of unique trivia comments, in ascending order by starting position.
pub type SortedComments = Box<[Comment]>;
@ -192,11 +189,11 @@ mod test {
#[test]
fn test_comments_range() {
let comments: SortedComments = vec![
Comment { span: Span::new(0, 4), kind: CommentKind::SingleLine },
Comment { span: Span::new(5, 9), kind: CommentKind::SingleLine },
Comment { span: Span::new(10, 13), kind: CommentKind::SingleLine },
Comment { span: Span::new(14, 17), kind: CommentKind::SingleLine },
Comment { span: Span::new(18, 23), kind: CommentKind::SingleLine },
Comment::new(0, 4, CommentKind::Line),
Comment::new(5, 9, CommentKind::Line),
Comment::new(10, 13, CommentKind::Line),
Comment::new(14, 17, CommentKind::Line),
Comment::new(18, 23, CommentKind::Line),
]
.into_boxed_slice();
let full_len = comments.len();

View file

@ -106,7 +106,7 @@ impl<'a> Codegen<'a> {
}
self.update_last_consumed_comment_end(real_span_end);
match comment.kind() {
CommentKind::SingleLine => {
CommentKind::Line => {
self.print_str("//");
self.print_range_of_source_code(
comment_span.start as usize..comment_span.end as usize,
@ -114,7 +114,7 @@ impl<'a> Codegen<'a> {
self.print_soft_newline();
self.print_indent();
}
CommentKind::MultiLine => {
CommentKind::Block => {
self.print_str("/*");
self.print_range_of_source_code(
comment_span.start as usize..comment_span.end as usize,

View file

@ -642,14 +642,14 @@ impl GraphicalReportHandler {
max_gutter,
line,
labels,
LabelRenderMode::MultiLineFirst,
LabelRenderMode::BlockFirst,
)?;
self.render_multi_line_end_single(
f,
first,
label.style,
LabelRenderMode::MultiLineFirst,
LabelRenderMode::BlockFirst,
)?;
for label_line in rest {
// no line number!
@ -660,13 +660,13 @@ impl GraphicalReportHandler {
max_gutter,
line,
labels,
LabelRenderMode::MultiLineRest,
LabelRenderMode::BlockRest,
)?;
self.render_multi_line_end_single(
f,
label_line,
label.style,
LabelRenderMode::MultiLineRest,
LabelRenderMode::BlockRest,
)?;
}
}
@ -764,7 +764,7 @@ impl GraphicalReportHandler {
let applicable = highlights.iter().filter(|hl| line.span_applies_gutter(hl));
for (i, hl) in applicable.enumerate() {
if !line.span_line_only(hl) && line.span_ends(hl) {
if render_mode == LabelRenderMode::MultiLineRest {
if render_mode == LabelRenderMode::BlockRest {
// this is to make multiline labels work. We want to make the right amount
// of horizontal space for them, but not actually draw the lines
let horizontal_space = max_gutter.saturating_sub(i) + 2;
@ -792,7 +792,7 @@ impl GraphicalReportHandler {
num_repeat
// if we are rendering a multiline label, then leave a bit of space for the
// rcross character
- if render_mode == LabelRenderMode::MultiLineFirst {
- if render_mode == LabelRenderMode::BlockFirst {
1
} else {
0
@ -1039,9 +1039,9 @@ impl GraphicalReportHandler {
hl,
label_line,
if first {
LabelRenderMode::MultiLineFirst
LabelRenderMode::BlockFirst
} else {
LabelRenderMode::MultiLineRest
LabelRenderMode::BlockRest
},
)?;
first = false;
@ -1090,10 +1090,10 @@ impl GraphicalReportHandler {
LabelRenderMode::SingleLine => {
format!("{}{} {}", chars.lbot, chars.hbar.to_string().repeat(2), label,)
}
LabelRenderMode::MultiLineFirst => {
LabelRenderMode::BlockFirst => {
format!("{}{}{} {}", chars.lbot, chars.hbar, chars.rcross, label,)
}
LabelRenderMode::MultiLineRest => {
LabelRenderMode::BlockRest => {
format!(" {} {}", chars.vbar, label,)
}
};
@ -1115,10 +1115,10 @@ impl GraphicalReportHandler {
LabelRenderMode::SingleLine => {
writeln!(f, "{} {}", self.theme.characters.hbar.style(style), label)?;
}
LabelRenderMode::MultiLineFirst => {
LabelRenderMode::BlockFirst => {
writeln!(f, "{} {}", self.theme.characters.rcross.style(style), label)?;
}
LabelRenderMode::MultiLineRest => {
LabelRenderMode::BlockRest => {
writeln!(f, "{} {}", self.theme.characters.vbar.style(style), label)?;
}
}
@ -1206,9 +1206,9 @@ enum LabelRenderMode {
/// we're rendering a single line label (or not rendering in any special way)
SingleLine,
/// we're rendering a multiline label
MultiLineFirst,
BlockFirst,
/// we're rendering the rest of a multiline label
MultiLineRest,
BlockRest,
}
#[derive(Debug)]

View file

@ -83,7 +83,7 @@ impl Rule for MaxLines {
let comment_lines = if self.skip_comments {
let mut comment_lines: usize = 0;
for comment in ctx.semantic().trivias().comments() {
if comment.kind.is_single_line() {
if comment.is_line() {
let comment_line = ctx.source_text()[..comment.span.start as usize]
.lines()
.next_back()

View file

@ -155,10 +155,10 @@ impl Rule for BanTsComment {
let comments = ctx.semantic().trivias().comments();
for comm in comments {
let raw = ctx.source_range(comm.span);
if let Some(captures) = find_ts_comment_directive(raw, comm.kind.is_single_line()) {
if let Some(captures) = find_ts_comment_directive(raw, comm.is_line()) {
// safe to unwrap, if capture success, it can always capture one of the four directives
let (directive, description) = (captures.0, captures.1);
if CommentKind::MultiLine == comm.kind
if CommentKind::Block == comm.kind
&& (directive == "check" || directive == "nocheck")
{
continue;

View file

@ -44,7 +44,7 @@ impl Rule for BanTslintComment {
source_text_len,
comment.span.start,
comment.span.end,
comment.kind.is_multi_line(),
comment.is_block(),
);
ctx.diagnostic_with_fix(

View file

@ -173,12 +173,12 @@ fn check_member(member: &TSSignature, node: &AstNode<'_>, ctx: &LintContext<'_>)
[span.start as usize..span.end as usize];
match comment_interface.kind {
CommentKind::SingleLine => {
CommentKind::Line => {
let single_line_comment: String =
format!("//{comment}\n");
comments_vec.push(single_line_comment);
}
CommentKind::MultiLine => {
CommentKind::Block => {
let multi_line_comment: String =
format!("/*{comment}*/\n");
comments_vec.push(multi_line_comment);

View file

@ -1,5 +1,5 @@
use cow_utils::CowUtils;
use oxc_ast::CommentKind;
use oxc_ast::Comment;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
@ -50,11 +50,11 @@ impl Rule for PreferTsExpectError {
for comment in comments {
let raw = comment.span.source_text(ctx.semantic().source_text());
if !is_valid_ts_ignore_present(comment.kind, raw) {
if !is_valid_ts_ignore_present(*comment, raw) {
continue;
}
if comment.kind.is_single_line() {
if comment.is_line() {
let comment_span = Span::new(comment.span.start - 2, comment.span.end);
ctx.diagnostic_with_fix(prefer_ts_expect_error_diagnostic(comment_span), |fixer| {
fixer.replace(
@ -79,18 +79,18 @@ impl Rule for PreferTsExpectError {
}
}
fn get_last_comment_line(comment: CommentKind, raw: &str) -> String {
if comment.is_single_line() {
fn get_last_comment_line(comment: Comment, raw: &str) -> String {
if comment.is_line() {
return String::from(raw);
}
return String::from(raw.lines().last().unwrap_or(raw));
}
fn is_valid_ts_ignore_present(comment: CommentKind, raw: &str) -> bool {
fn is_valid_ts_ignore_present(comment: Comment, raw: &str) -> bool {
let line = get_last_comment_line(comment, raw);
if comment.is_single_line() {
if comment.is_line() {
test_single_line_comment(&line)
} else {
test_multi_line_comment(&line)

View file

@ -70,7 +70,7 @@ impl Rule for NoEmptyFile {
fn has_triple_slash_directive(ctx: &LintContext<'_>) -> bool {
for comment in ctx.semantic().trivias().comments() {
if !comment.kind.is_single_line() {
if !comment.is_line() {
continue;
}
let text = comment.span.source_text(ctx.source_text());

View file

@ -299,7 +299,7 @@ pub fn get_leading_tree_shaking_comment<'a>(span: Span, ctx: &LintContext<'a>) -
ctx.source_text()[..comment.span.end as usize].lines().next_back().unwrap_or("");
let nothing_before_comment = previous_line
.trim()
.strip_prefix(if comment.kind == CommentKind::SingleLine { "//" } else { "/*" })
.strip_prefix(if comment.kind == CommentKind::Line { "//" } else { "/*" })
.is_some_and(|s| s.trim().is_empty());
if !nothing_before_comment {
return None;

View file

@ -17,12 +17,12 @@ impl TriviaBuilder {
pub fn add_single_line_comment(&mut self, start: u32, end: u32) {
// skip leading `//`
self.add_comment(Comment::new(start + 2, end, CommentKind::SingleLine));
self.add_comment(Comment::new(start + 2, end, CommentKind::Line));
}
pub fn add_multi_line_comment(&mut self, start: u32, end: u32) {
// skip leading `/*` and trailing `*/`
self.add_comment(Comment::new(start + 2, end - 2, CommentKind::MultiLine));
self.add_comment(Comment::new(start + 2, end - 2, CommentKind::Block));
}
fn add_comment(&mut self, comment: Comment) {

View file

@ -510,11 +510,11 @@ mod test {
let allocator = Allocator::default();
let source_type = SourceType::default().with_typescript(true);
let sources = [
("// line comment", CommentKind::SingleLine),
("/* line comment */", CommentKind::MultiLine),
("// line comment", CommentKind::Line),
("/* line comment */", CommentKind::Block),
(
"type Foo = ( /* Require properties which are not generated automatically. */ 'bar')",
CommentKind::MultiLine,
CommentKind::Block,
),
];
for (source, kind) in sources {

View file

@ -18,7 +18,7 @@ impl Comment {
Self {
start: span.start,
end: span.end,
is_block: comment.kind.is_multi_line(),
is_block: comment.is_block(),
has_line_suffix: false,
}
}

View file

@ -147,7 +147,7 @@ impl<'a> JSDocBuilder<'a> {
}
fn parse_if_jsdoc_comment(&self, comment: &Comment) -> Option<JSDoc<'a>> {
if !comment.kind.is_multi_line() {
if !comment.is_block() {
return None;
}

View file

@ -420,8 +420,8 @@ impl Oxc {
.comments()
.map(|comment| Comment {
r#type: match comment.kind {
CommentKind::SingleLine => CommentType::Line,
CommentKind::MultiLine => CommentType::Block,
CommentKind::Line => CommentType::Line,
CommentKind::Block => CommentType::Block,
},
value: comment.span.source_text(source_text).to_string(),
start: comment.span.start,

View file

@ -109,8 +109,8 @@ fn parse_with_return<'a>(source_text: &'a str, options: &ParserOptions) -> Parse
.comments()
.map(|comment| Comment {
r#type: match comment.kind {
CommentKind::SingleLine => "Line",
CommentKind::MultiLine => "Block",
CommentKind::Line => "Line",
CommentKind::Block => "Block",
},
value: comment.span.source_text(source_text).to_string(),
start: comment.span.start,