Skip to content

Commit 9e284df

Browse files
Wilfredfacebook-github-bot
authored andcommitted
Define a __Docs attribute on classes
Summary: Define a `<<__Docs("http://example.com/my_project")>>` attribute that allows users to mark the docs homepage for their classes. This makes docs URLs visible to the toolchain, which will enable them to be inherited and shown in the IDE (see later diffs in this stack). This diff introduces the `__Docs` attribute, adds the field to the AAST and updates the lowerer to set this field. Ignore hhvm-and-hack-ubuntu which is failing on trunk too. Reviewed By: hgoldstein Differential Revision: D37003893 fbshipit-source-id: 131c4174f4d11a36c4f82206a92ad0b9f232d560
1 parent 16c94fb commit 9e284df

File tree

123 files changed

+575
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

123 files changed

+575
-344
lines changed

hphp/hack/src/annotated_ast/aast.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ and ('ex, 'en) class_ = {
834834
c_namespace: nsenv;
835835
c_user_attributes: ('ex, 'en) user_attribute list;
836836
c_file_attributes: ('ex, 'en) file_attribute list;
837+
c_docs_url: string option;
837838
c_enum: enum_ option;
838839
c_doc_comment: doc_comment option;
839840
c_emit_id: emit_id option;

hphp/hack/src/hackc/compile/closure_convert.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,7 @@ fn make_closure(
643643
internal: false,
644644
// TODO: closures should have the visibility of the module they are defined in
645645
module: None,
646+
docs_url: None,
646647
};
647648

648649
// TODO(hrust): can we reconstruct fd here from the scratch?

hphp/hack/src/naming/naming.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,7 @@ let rec class_ ctx c =
965965
N.c_emit_id = c.Aast.c_emit_id;
966966
N.c_internal = c.Aast.c_internal;
967967
N.c_module = c.Aast.c_module;
968+
N.c_docs_url = c.Aast.c_docs_url;
968969
}
969970

970971
and user_attributes env attrl =

hphp/hack/src/naming/naming_special_names.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ module UserAttributes = struct
263263

264264
let uaDeprecated = "__Deprecated"
265265

266+
let uaDocs = "__Docs"
267+
266268
let uaEntryPoint = "__EntryPoint"
267269

268270
let uaMemoize = "__Memoize"
@@ -401,6 +403,12 @@ module UserAttributes = struct
401403
^ " If the sampling rate is 100, a notice is only raised every 1/100 calls. If omitted, the default sampling rate is 1 (i.e. all calls raise notices)."
402404
^ " To disable runtime notices, use a sampling rate of 0.";
403405
} );
406+
( uaDocs,
407+
{
408+
contexts = [cls];
409+
autocomplete = true;
410+
doc = "Shows the linked URL when hovering over this type.";
411+
} );
404412
( uaEntryPoint,
405413
{
406414
contexts = [fn];

hphp/hack/src/naming/naming_special_names.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ pub mod user_attributes {
240240

241241
pub const DEPRECATED: &str = "__Deprecated";
242242

243+
pub const DOCS: &str = "__Docs";
244+
243245
pub const ENTRY_POINT: &str = "__EntryPoint";
244246

245247
pub const MEMOIZE: &str = "__Memoize";
@@ -326,6 +328,7 @@ pub mod user_attributes {
326328
CONSISTENT_CONSTRUCT,
327329
CONST,
328330
DEPRECATED,
331+
DOCS,
329332
ENTRY_POINT,
330333
MEMOIZE,
331334
MEMOIZE_LSB,

hphp/hack/src/oxidized/aast_visitor/node_impl_gen.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// This source code is licensed under the MIT license found in the
44
// LICENSE file in the "hack" directory of this source tree.
55
//
6-
// @generated SignedSource<<7f946d2ac10b9b206329cbc119e54016>>
6+
// @generated SignedSource<<e1ad32b29dd247f9d61fc11411c303cb>>
77
//
88
// To regenerate this file, run:
99
// hphp/hack/src/oxidized_regen.sh
@@ -468,6 +468,7 @@ impl<P: Params> Node<P> for Class_<P::Ex, P::En> {
468468
self.namespace.accept(c, v)?;
469469
self.user_attributes.accept(c, v)?;
470470
self.file_attributes.accept(c, v)?;
471+
self.docs_url.accept(c, v)?;
471472
self.enum_.accept(c, v)?;
472473
self.doc_comment.accept(c, v)?;
473474
self.emit_id.accept(c, v)?;

hphp/hack/src/oxidized/aast_visitor/node_mut_impl_gen.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// This source code is licensed under the MIT license found in the
44
// LICENSE file in the "hack" directory of this source tree.
55
//
6-
// @generated SignedSource<<f0a0d5ca179c975cc43c092d869d512b>>
6+
// @generated SignedSource<<76a71fa7428d740c66237265628d4493>>
77
//
88
// To regenerate this file, run:
99
// hphp/hack/src/oxidized_regen.sh
@@ -468,6 +468,7 @@ impl<P: Params> NodeMut<P> for Class_<P::Ex, P::En> {
468468
self.namespace.accept(c, v)?;
469469
self.user_attributes.accept(c, v)?;
470470
self.file_attributes.accept(c, v)?;
471+
self.docs_url.accept(c, v)?;
471472
self.enum_.accept(c, v)?;
472473
self.doc_comment.accept(c, v)?;
473474
self.emit_id.accept(c, v)?;

hphp/hack/src/oxidized/gen/aast.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// This source code is licensed under the MIT license found in the
44
// LICENSE file in the "hack" directory of this source tree.
55
//
6-
// @generated SignedSource<<71e7d74c1497c94a5c83d21a60f09212>>
6+
// @generated SignedSource<<2abc1b50c5c8dbc44a30c38131a22352>>
77
//
88
// To regenerate this file, run:
99
// hphp/hack/src/oxidized_regen.sh
@@ -1338,6 +1338,7 @@ pub struct Class_<Ex, En> {
13381338
pub namespace: Nsenv,
13391339
pub user_attributes: Vec<UserAttribute<Ex, En>>,
13401340
pub file_attributes: Vec<FileAttribute<Ex, En>>,
1341+
pub docs_url: Option<String>,
13411342
pub enum_: Option<Enum_>,
13421343
pub doc_comment: Option<DocComment>,
13431344
pub emit_id: Option<EmitId>,

hphp/hack/src/oxidized_by_ref/gen/aast.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// This source code is licensed under the MIT license found in the
44
// LICENSE file in the "hack" directory of this source tree.
55
//
6-
// @generated SignedSource<<2b43d33ace096c053aa8f91b8a3f7787>>
6+
// @generated SignedSource<<e8b27d9579188e6f6d400168bcea586a>>
77
//
88
// To regenerate this file, run:
99
// hphp/hack/src/oxidized_regen.sh
@@ -1696,6 +1696,8 @@ pub struct Class_<'a, Ex, En> {
16961696
#[serde(deserialize_with = "arena_deserializer::arena", borrow)]
16971697
pub file_attributes: &'a [&'a FileAttribute<'a, Ex, En>],
16981698
#[serde(deserialize_with = "arena_deserializer::arena", borrow)]
1699+
pub docs_url: Option<&'a str>,
1700+
#[serde(deserialize_with = "arena_deserializer::arena", borrow)]
16991701
pub enum_: Option<&'a Enum_<'a>>,
17001702
#[serde(deserialize_with = "arena_deserializer::arena", borrow)]
17011703
pub doc_comment: Option<&'a DocComment<'a>>,

hphp/hack/src/parser/lowerer/lowerer.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4236,6 +4236,43 @@ fn p_user_attributes<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::User
42364236
Ok(attributes.into_iter().flatten().collect())
42374237
}
42384238

4239+
/// Extract the URL in `<<__Docs("http://example.com")>>` if the __Docs attribute
4240+
/// is present.
4241+
fn p_docs_url<'a>(attrs: &[ast::UserAttribute], env: &mut Env<'a>) -> Option<String> {
4242+
let mut url = None;
4243+
4244+
for attr in attrs {
4245+
if attr.name.1 == naming_special_names_rust::user_attributes::DOCS {
4246+
match attr.params.as_slice() {
4247+
[param] => match &param.2 {
4248+
ast::Expr_::String(s) => match String::from_utf8(s.to_vec()) {
4249+
Ok(s) => {
4250+
url = Some(s);
4251+
}
4252+
Err(_) => raise_parsing_error_pos(
4253+
&attr.name.0,
4254+
env,
4255+
"`__Docs` URLs must be valid UTF-8",
4256+
),
4257+
},
4258+
_ => raise_parsing_error_pos(
4259+
&attr.name.0,
4260+
env,
4261+
"`__Docs` URLs must be a string literal",
4262+
),
4263+
},
4264+
_ => {
4265+
// Wrong number of arguments to __Docs,
4266+
// ignore. The attribute arity checks will tell
4267+
// the user their code is wrong.
4268+
}
4269+
}
4270+
}
4271+
}
4272+
4273+
url
4274+
}
4275+
42394276
fn map_yielding<'a, F, R>(node: S<'a>, env: &mut Env<'a>, p: F) -> Result<(R, bool)>
42404277
where
42414278
F: FnOnce(S<'a>, &mut Env<'a>) -> Result<R>,
@@ -5124,6 +5161,8 @@ fn p_def<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Def>> {
51245161
let env = env.as_mut();
51255162
let mode = env.file_mode();
51265163
let user_attributes = p_user_attributes(&c.attribute, env)?;
5164+
let docs_url = p_docs_url(&user_attributes, env);
5165+
51275166
let kinds = p_kinds(&c.modifiers, env)?;
51285167
let final_ = kinds.has(modifier::FINAL);
51295168
let is_xhp = matches!(
@@ -5186,6 +5225,7 @@ fn p_def<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Def>> {
51865225
emit_id: None,
51875226
internal: kinds.has(modifier::INTERNAL),
51885227
module: None,
5228+
docs_url,
51895229
};
51905230
match &c.body.children {
51915231
ClassishBody(c1) => {
@@ -5385,6 +5425,7 @@ fn p_def<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Def>> {
53855425
emit_id: None,
53865426
internal: kinds.has(modifier::INTERNAL),
53875427
module: None,
5428+
docs_url: None,
53885429
})])
53895430
}
53905431

@@ -5459,6 +5500,7 @@ fn p_def<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Def>> {
54595500
emit_id: None,
54605501
internal: kinds.has(modifier::INTERNAL),
54615502
module: None,
5503+
docs_url: None,
54625504
};
54635505

54645506
for n in c.elements.syntax_node_to_list_skip_separator() {

0 commit comments

Comments
 (0)