123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336openBaseopenPpxlibletannotated_ignores=reffalse;;letcheck_comments=reffalse;;letcompat_32=reffalseleterrorf~locfmt=Location.raise_errorf~loc(Caml.(^^)"Jane Street style: "fmt);;moduleIgnored_reason=structtypet=Argument_to_ignore|Underscore_patternletfail~loc_t=errorf~loc"Ignored expression must come with a type annotation"endmoduleInvalid_deprecated=structtypet=|Not_a_string|Missing_date|Invalid_monthletfail~loc=function|Not_a_string->errorf~loc"Invalid [@@deprecated payload], must be a string"|Missing_date->errorf~loc"deprecated message must start with the date in this format: \
[since YYYY-MM]"|Invalid_month->errorf~loc"invalid month in deprecation date"endmoduleInvalid_constant=structtypet=string*stringletfail~loc((s,typ):t)=Location.raise_errorf~loc"Integer literal %s exceeds the range of representable \
integers of type %s on 32bit architectures"stypendtypeerror=|Invalid_deprecatedofInvalid_deprecated.t|Missing_type_annotationofIgnored_reason.t|Invalid_constantofInvalid_constant.t|Docstring_on_openletfail~loc=function|Invalid_deprecatede->Invalid_deprecated.faile~loc|Missing_type_annotatione->Ignored_reason.faile~loc|Invalid_constante->Invalid_constant.faile~loc|Docstring_on_open->errorf~loc"A documentation comment is attached to this [open] which will be dropped by odoc.";;letcheck_deprecated_string~f~locs=matchCaml.Scanf.sscanfs"[since %u-%u]"(funym->(y,m))with|exception_->f~loc(Invalid_deprecatedMissing_date)|(_year,month)->ifmonth=0||month>12thenf~loc(Invalid_deprecatedInvalid_month);;letnot_really_a_binding~ext_name:s=List.mem["test";"test_unit";"test_module";"bench";"bench_fun";"bench_module";"expect";"expect_test";]s~equal:String.equal;;letignored_expr_must_be_annotatedignored_reason(expr:Parsetree.expression)~f=matchexpr.pexp_descwith(* explicitely annotated -> good *)|Pexp_constraint_|Pexp_coerce_(* no need to warn people trying to silence other warnings *)|Pexp_construct_|Pexp_ident_|Pexp_fun_|Pexp_function_->()|_->f~loc:expr.pexp_loc(Missing_type_annotationignored_reason);;letconstant_with_loc=letmax_int_31=Int32.(-)(Int32.shift_left1l30)1linletmin_int_31=Int32.neg(Int32.shift_left1l30)infun~locc->if!compat_32thenmatchcwith|Pconst_integer(s,Some'n')->begintryignore(Int32.of_strings)with_->fail~loc(Invalid_constant(s,"nativeint"))end|Pconst_integer(s,None)->begintryleti=Int32.of_stringsinifInt32.(i<min_int_31||i>max_int_31)thenfailwith"out of bound"with_->fail~loc(Invalid_constant(s,"int"))end|_->()letis_deprecated=function|"ocaml.deprecated"|"deprecated"->true|_->falseletcheck_deprecatedattr=ifis_deprecated(fstattr).txtthenerrorf~loc:(loc_of_attributeattr)"Invalid deprecated attribute, it will be ignored by the compiler"letiter_style_errors~f=object(self)inheritAst_traverse.iterassupermethod!attribute(name,payload)=letloc=loc_of_attribute(name,payload)inif!Dated_deprecation.enabled&&is_deprecatedname.txtthenmatchAst_pattern.(parse(single_expr_payload(estring__')))locpayload(funs->s)with|exception_->f~loc(Invalid_deprecatedNot_a_string)|{Location.loc;txt=s}->check_deprecated_string~f~locsmethod!open_descriptionod=if!check_commentsthen(lethas_doc_comments=List.existsod.popen_attributes~f:(fun(attr_name,_)->matchattr_name.txtwith|"ocaml.doc"|"doc"->true|_->false)inifhas_doc_commentsthenf~loc:od.popen_locDocstring_on_open);super#open_descriptionodmethod!value_bindingvb=if!annotated_ignoresthen(letloc=vb.Parsetree.pvb_locinmatchAst_pattern.(parseppat_any)locvb.Parsetree.pvb_pat()with|exception_->()|()->ignored_expr_must_be_annotatedUnderscore_pattern~fvb.Parsetree.pvb_expr);super#value_bindingvbmethod!extension(ext_name,payloadasext)=ifnot!annotated_ignoresthensuper#extensionextelseifnot(not_really_a_binding~ext_name:ext_name.Location.txt)thenself#payloadpayloadelse(* We want to allow "let % test _ = ..." (and similar extensions which don't
actually bind) without warning. *)matchpayloadwith|PStrstr->letcheck_str_itemi=letloc=i.Parsetree.pstr_locinAst_pattern.(parse(pstr_value____))loci(fun_rec_flagvbs->List.iter~f:super#value_bindingvbs)inList.iter~f:check_str_itemstr|_->super#payloadpayloadmethod!expressione=if!annotated_ignoresthen(matchewith|[%exprignore[%e?ignored]]->ignored_expr_must_be_annotatedArgument_to_ignore~fignored|_->());beginmatchewith|{pexp_desc=Pexp_constantc;pexp_loc;_}->constant_with_loc~loc:pexp_locc|_->()end;super#expressionemethod!patterne=beginmatchewith|{ppat_desc=Ppat_constantc;ppat_loc;_}->constant_with_loc~loc:ppat_locc|_->()end;super#patternemethod!core_typet=List.itert.ptyp_attributes~f:check_deprecated;super#core_typetendletcheck=iter_style_errors~f:failmoduleComments_checking=structleterrorf~locfmt=Location.raise_errorf~loc(Caml.(^^)"Documentation error: "fmt)(* Assumption in the following functions: [s <> ""] *)letis_cr_comments=lets=String.stripsin(String.is_prefixs~prefix:"CR")||(String.is_prefixs~prefix:"XX")||(String.is_prefixs~prefix:"XCR")||(String.is_prefixs~prefix:"JS-only")letis_cinapss=Char.equals.[0]'$'letis_doc_comments=Char.equals.[0]'*'letis_ignored_comments=Char.equals.[0]'_'letcan_appear_in_mlis=is_doc_comments||is_ignored_comments||is_cr_comments||is_cinapssletsyntax_check_doc_comment~loccomment=matchOctavius.parse(Lexing.from_stringcomment)with|Ok_->()|Error{Octavius.Errors.error;location}->letoctavius_msg=Octavius.Errors.messageerrorinletoctavius_loc=let{Octavius.Errors.start;finish}=locationinletloc_start=loc.Location.loc_startinletopenLexinginletloc_start=letpos_bol=ifstart.line=1thenloc_start.pos_bolelse0in{loc_startwithpos_bol;pos_lnum=loc_start.pos_lnum+start.line-1;pos_cnum=ifstart.line=1thenloc_start.pos_cnum+start.columnelsestart.column}inletloc_end=letpos_bol=iffinish.line=1thenloc_start.pos_bolelse0in{loc_startwithpos_bol;pos_lnum=loc_start.pos_lnum+finish.line-1;pos_cnum=iffinish.line=1thenloc_start.pos_cnum+finish.columnelsefinish.column}in{locwithLocation.loc_start;loc_end}inerrorf~loc:octavius_loc"%s\nYou can look at \
http://caml.inria.fr/pub/docs/manual-ocaml/ocamldoc.html#sec318\n\
for a description of the recognized syntax."octavius_msgletis_intf_dot_mlfname=String.is_suffix(Caml.Filename.chop_extensionfname)~suffix:"_intf"letcheck_all?(intf=false)()=List.iter~f:(fun(comment,loc)->letintf=intf||is_intf_dot_mlloc.Location.loc_start.Lexing.pos_fnameinif(String.(<>)comment"")then((* Ensures that all comments present in the file are either ocamldoc comments
or (*_ *) comments. *)ifintf&¬(can_appear_in_mlicomment)thenbeginerrorf~loc"That kind of comment shouldn't be present in interfaces.\n\
Either turn it to a documentation comment or use the special (*_ *) form."end;ifis_doc_commentcommentthensyntax_check_doc_comment~loccomment))(Lexer.comments())endlet()=Driver.add_arg"-annotated-ignores"(Setannotated_ignores)~doc:" If set, forces all ignored expressions (either under ignore or \
inside a \"let _ = ...\") to have a type annotation.";;let()=Driver.add_arg"-compat-32"(Setcompat_32)~doc:" If set, checks that all constants are representable on 32bit architectures.";;(* Enable warning 50 by default, one can opt-out with [-dont-check-doc-comments-attachment] *)let()=(* A bit hackish: as we're running ppx_driver with -pp the parsing is done
by ppx_driver and not ocaml itself, so giving "-w @50" to ocaml (as we
did up to now) had no incidence.
We want to enable the warning here. For some reason one can't just enable
a warning programatically, one has to call [parse_options]... *)Ocaml_common.Warnings.parse_optionsfalse"+50"let()=letdisable_w50()=Ocaml_common.Warnings.parse_optionsfalse"-50"inDriver.add_arg"-dont-check-doc-comments-attachment"(Unitdisable_w50)~doc:" ignore warning 50 on the file.";;let()=letenable_checks()=check_comments:=trueinDriver.add_arg"-check-doc-comments"(Unitenable_checks)~doc:" If set, ensures that all comments in .mli files are either \
documentation or (*_ *) comments. Also check the syntax of doc comments.";;let()=letenable()=Dated_deprecation.enabled:=trueinletdisable()=Dated_deprecation.enabled:=falseinDriver.add_arg"-dated-deprecation"(Unitenable)~doc:{| If set, ensures that all `[@@deprecated]` attributes must contain \
the date of deprecation, using the format `"[since MM-YYYY] ..."`.|};Driver.add_arg"-no-dated-deprecation"(Unitdisable)~doc:" inverse of -dated-deprecation."let()=Driver.register_transformation"js_style"~intf:(funsg->check#signaturesg;if!check_commentsthenComments_checking.check_all~intf:true();sg)~impl:(funst->check#structurest;if!check_commentsthenComments_checking.check_all();st);;