Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match compilers dummy loc #540

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ details.
- Support class type declarations in derivers with the new, optional arguments
`{str,sig}_class_type_decl` in `Deriving.add` (#538, @patricoferris)

- Change `Location.none` to match the compiler's `Location.none` as of OCaml
4.08. Also provide `Location.is_none` which checks if a location is none for
all versions of the compiler we support. This has been used to fix a bug in
`loc_of_attribute` (#540, @ncik-roberts, @patricoferris)

0.33.0 (2024-07-22)
-------------------

Expand Down
4 changes: 2 additions & 2 deletions src/common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ let loc_of_attribute { attr_name; attr_payload; attr_loc = _ } =
from older asts. *)
(* "ocaml.doc" attributes are generated with [Location.none], which is not helpful for
error messages. *)
if Poly.( = ) attr_name.loc Location.none then
if Location.is_none attr_name.loc then
loc_of_name_and_payload attr_name attr_payload
else
{
Expand All @@ -157,7 +157,7 @@ let loc_of_attribute { attr_name; attr_payload; attr_loc = _ } =
}

let loc_of_extension (name, payload) =
if Poly.( = ) name.loc Location.none then loc_of_name_and_payload name payload
if Location.is_none name.loc then loc_of_name_and_payload name payload
else
{ name.loc with loc_end = (loc_of_name_and_payload name payload).loc_end }

Expand Down
11 changes: 10 additions & 1 deletion src/location.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type t = location = {
}

let in_file name =
let loc = { pos_fname = name; pos_lnum = 1; pos_bol = 0; pos_cnum = -1 } in
let loc = { pos_fname = name; pos_lnum = 0; pos_bol = 0; pos_cnum = -1 } in
{ loc_start = loc; loc_end = loc; loc_ghost = true }

let set_filename loc fn =
Expand All @@ -18,6 +18,15 @@ let set_filename loc fn =

let none = in_file "_none_"

(* Can be removed once ppxlib only supports 4.08.0+ *)
let none_4_07_and_less =
let loc =
{ pos_fname = "_none_"; pos_lnum = 1; pos_bol = 0; pos_cnum = -1 }
in
{ loc_start = loc; loc_end = loc; loc_ghost = true }

let is_none v = Poly.( = ) v none || Poly.( = ) v none_4_07_and_less

let init lexbuf fname =
let open Lexing in
lexbuf.lex_curr_p <-
Expand Down
6 changes: 6 additions & 0 deletions src/location.mli
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ val set_filename : t -> string -> t
val none : t
(** An arbitrary value of type [t]; describes an empty ghost range. *)

val is_none : t -> bool
(** Checks whether a given location is equal to [none].
Note that this function returns [true] for none locations from all supported
compiler versions. *)

val init : Lexing.lexbuf -> string -> unit
(** Set the file name and line number of the [lexbuf] to be the start of the
named file. *)
Expand Down
7 changes: 7 additions & 0 deletions test/location/attributes/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(executable
(name pp)
(libraries ppxlib))

(cram
(applies_to print_attr_loc)
(deps pp.exe))
18 changes: 18 additions & 0 deletions test/location/attributes/pp.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
open Ppxlib

let pp_attr str =
let iter =
object
inherit Ast_traverse.iter as super

method! attribute v =
let loc = loc_of_attribute v in
Format.printf "%a %s" Location.print loc v.attr_name.txt;
super#attribute v
end
in
iter#structure str;
str

let () = Driver.register_transformation ~impl:pp_attr "print-attributes"
let () = Ppxlib.Driver.standalone ()
15 changes: 15 additions & 0 deletions test/location/attributes/print_attr_loc.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
The compiler inserts documentation comments with their location set to
`Location.none`. The value for `Location.none` has changed in the compiler (at
4.08.0). We provide a function, `loc_of_attribute` to handle deriving better location
errors for attributes with a none location.

$ cat > test.ml << EOF
> let v = 1
> (** A documentation comment! *)
> EOF

We run an identity driver that prints the locations of attributes.

$ ./pp.exe --impl test.ml -o ignore.ml
File "test.ml", line 2, characters 0-31: ocaml.doc

Loading
Loading