Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,35 @@
containing scientific notation or trailing zeros (i.e. `100` and `1e2`).
([ptdewey](https://github.com/ptdewey))

- The compiler now emits a warning when a doc comment is not attached to a
definition due to a regular comment in between. For example, in the following
code:

```gleam
/// This documentation is not attached
// This is not a doc comment
/// This is actual documentation
pub fn wibble() {
todo
}
```

Will now produce the following warning:

```txt
warning: Detached doc comment
┌─ src/main.gleam:1:4
1 │ /// This documentation is not attached
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not attached to a definition

This doc comment is followed by a regular comment so it is not attached to
any definition.
Hint: Move the comment above the doc comment
```

([Surya Rose](https://github.com/GearsDatapacks))

### Build tool

- The help text displayed by `gleam dev --help`, `gleam test --help`, and
Expand Down
13 changes: 13 additions & 0 deletions compiler-core/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ pub fn parse_module(
});
}

for detached in parser.detached_doc_comments {
warnings.emit(Warning::DetachedDocComment {
path: path.clone(),
src: src.clone(),
location: detached,
});
}

Ok(parsed)
}

Expand Down Expand Up @@ -218,6 +226,7 @@ pub struct Parser<T: Iterator<Item = LexResult>> {
tok1: Option<Spanned>,
extra: ModuleExtra,
doc_comments: VecDeque<(u32, EcoString)>,
detached_doc_comments: Vec<SrcSpan>,
}
impl<T> Parser<T>
where
Expand All @@ -232,6 +241,7 @@ where
tok1: None,
extra: ModuleExtra::new(),
doc_comments: VecDeque::new(),
detached_doc_comments: Vec::new(),
};
parser.advance();
parser.advance();
Expand Down Expand Up @@ -4061,9 +4071,12 @@ functions are declared separately from types.";
if *start >= until {
break;
}

if self.extra.has_comment_between(*start, until) {
// We ignore doc comments that come before a regular comment.
let location = SrcSpan::new(*start, start + line.len() as u32);
_ = self.doc_comments.pop_front();
self.detached_doc_comments.push(location);
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
source: compiler-core/src/type_/tests/warnings.rs
expression: "\n/// This comment is detached\n//\n\n/// This is actual documentation\npub const pi = 3.14\n"
---
----- SOURCE CODE

/// This comment is detached
//

/// This is actual documentation
pub const pi = 3.14


----- WARNING
warning: Detached doc comment
┌─ test/path:2:4
2 │ /// This comment is detached
│ ^^^^^^^^^^^^^^^^^^^^^^^^^ This is not attached to a definition

This doc comment is followed by a regular comment so it is not attached to
any definition.
Hint: Move the comment above the doc comment
13 changes: 13 additions & 0 deletions compiler-core/src/type_/tests/warnings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4612,3 +4612,16 @@ pub type Wobble
"#,
);
}

#[test]
fn detached_doc_comment() {
assert_warning!(
"
/// This comment is detached
//

/// This is actual documentation
pub const pi = 3.14
"
);
}
29 changes: 29 additions & 0 deletions compiler-core/src/warning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ pub enum Warning {
path: Utf8PathBuf,
name: EcoString,
},

DetachedDocComment {
path: Utf8PathBuf,
src: EcoString,
location: SrcSpan,
},
}

#[derive(Debug, Clone, Eq, PartialEq, Copy)]
Expand Down Expand Up @@ -424,6 +430,29 @@ To have a clause without a guard, remove this.",
}
}

Warning::DetachedDocComment {
path,
src,
location,
} => Diagnostic {
title: "Detached doc comment".into(),
text: wrap(
"This doc comment is followed by a regular \
comment so it is not attached to any definition.",
),
level: diagnostic::Level::Warning,
location: Some(Location {
path: path.to_path_buf(),
src: src.clone(),
label: diagnostic::Label {
text: Some("This is not attached to a definition".into()),
span: *location,
},
extra_labels: Vec::new(),
}),
hint: Some("Move the comment above the doc comment".into()),
},

Warning::Type { path, warning, src } => match warning {
type_::Warning::Todo {
kind,
Expand Down
Loading