1 // Copyright (c) Facebook, Inc. and its affiliates.
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
7 pub use ast_scope_item::*;
9 use hhbc_by_ref_hhas_coeffects::HhasCoeffects;
12 ast_defs::{FunKind, Id},
16 #[derive(Clone, Default, Debug)]
17 pub struct Scope<'a> {
18 pub items: Vec<ScopeItem<'a>>,
22 pub fn toplevel() -> Self {
23 Scope { items: vec![] }
26 pub fn push_item(&mut self, s: ScopeItem<'a>) {
30 pub fn iter(&self) -> impl ExactSizeIterator<Item = &ScopeItem<'a>> {
31 self.items.iter().rev()
34 pub fn iter_subscopes(&self) -> impl Iterator<Item = &[ScopeItem<'a>]> {
35 (0..self.items.len()).rev().map(move |i| &self.items[..i])
38 pub fn get_subscope_class<'b>(sub_scope: &'b [ScopeItem<'b>]) -> Option<&'b Class> {
39 for scope_item in sub_scope.iter().rev() {
40 if let ScopeItem::Class(cd) = scope_item {
47 pub fn get_class(&self) -> Option<&Class> {
48 Self::get_subscope_class(&self.items[..])
51 pub fn get_span(&self) -> Pos {
52 for scope_item in self.iter() {
54 ScopeItem::Class(cd) => {
55 return cd.get_span().clone();
57 ScopeItem::Function(fd) => {
58 return fd.get_span().clone();
60 ScopeItem::Method(md) => {
61 return md.get_span().clone();
69 pub fn get_tparams(&self) -> Vec<&ast::Tparam> {
70 let mut tparams = vec![];
71 let extend_shallowly = &mut |tps| {
76 for scope_item in self.iter() {
78 ScopeItem::Class(cd) => {
79 extend_shallowly(cd.get_tparams());
81 ScopeItem::Function(fd) => {
82 extend_shallowly(fd.get_tparams());
84 ScopeItem::Method(md) => {
85 extend_shallowly(md.get_tparams());
93 pub fn get_fun_tparams(&self) -> &[ast::Tparam] {
94 for scope_item in self.iter() {
96 ScopeItem::Class(_) => {
99 ScopeItem::Function(fd) => {
100 return fd.get_tparams();
102 ScopeItem::Method(md) => {
103 return md.get_tparams();
111 pub fn get_class_tparams(&self) -> &[ast::Tparam] {
112 for scope_item in self.iter() {
113 if let ScopeItem::Class(cd) = scope_item {
114 return cd.get_tparams();
120 pub fn has_this(&self) -> bool {
121 if self.items.is_empty() {
122 /* Assume top level has this */
125 for scope_item in self.iter() {
127 ScopeItem::Class(_) | ScopeItem::Function(_) => {
130 ScopeItem::Method(_) => {
139 pub fn is_in_async(&self) -> bool {
140 for scope_item in self.iter() {
142 ScopeItem::Class(_) => {
145 ScopeItem::Method(m) => {
146 let fun_kind = m.get_fun_kind();
147 return fun_kind == FunKind::FAsync || fun_kind == FunKind::FAsyncGenerator;
149 ScopeItem::Function(f) => {
150 let fun_kind = f.get_fun_kind();
151 return fun_kind == FunKind::FAsync || fun_kind == FunKind::FAsyncGenerator;
159 pub fn is_toplevel(&self) -> bool {
160 self.items.is_empty()
163 pub fn is_in_static_method(&self) -> bool {
164 for scope_item in self.iter() {
166 ScopeItem::Method(md) => {
167 return md.is_static();
169 ScopeItem::LongLambda(_) => {}
170 ScopeItem::Lambda(_) => {}
177 pub fn is_in_lambda(&self) -> bool {
178 self.items.last().map_or(false, &ScopeItem::is_in_lambda)
181 pub fn coeffects_of_scope(&self) -> HhasCoeffects {
182 for scope_item in self.iter() {
184 ScopeItem::Class(_) => {
185 return HhasCoeffects::default();
187 ScopeItem::Method(m) => {
188 return HhasCoeffects::from_ast(
192 self.get_class_tparams(),
195 ScopeItem::Function(f) => {
196 return HhasCoeffects::from_ast(
203 ScopeItem::Lambda(Lambda { coeffects, .. })
204 | ScopeItem::LongLambda(LongLambda { coeffects, .. })
205 if !coeffects.get_static_coeffects().is_empty() =>
207 return coeffects.clone();
212 HhasCoeffects::default()
215 pub fn has_function_attribute(&self, attr_name: impl AsRef<str>) -> bool {
216 let has = |ua: &[ast::UserAttribute]| ua.iter().any(|a| a.name.1 == attr_name.as_ref());
217 for scope_item in self.iter() {
219 ScopeItem::Method(m) => {
220 return has(m.get_user_attributes());
222 ScopeItem::Function(f) => {
223 return has(f.get_user_attributes());
231 pub fn is_static(&self) -> bool {
232 for x in self.iter() {
234 ScopeItem::Function(_) => return true,
235 ScopeItem::Method(md) => return md.is_static(),
236 ScopeItem::Lambda(_) | ScopeItem::LongLambda(_) => continue,
243 // get captured variables when in closure scope
244 pub fn get_captured_vars(&self) -> Vec<String> {
245 // closure scope: lambda -> method -> class
246 match &self.items[..] {
247 [.., ScopeItem::Class(ast_cls), _, _] => ast_cls
251 let Id(_, id) = &var.id;
254 .collect::<Vec<_>>(),
255 _ => panic!("closure scope should be lambda -> method -> class"),
260 pub fn is_in_debugger_eval_fun(&self) -> bool {
261 for x in self.iter() {
263 ScopeItem::LongLambda(_) | ScopeItem::Lambda(_) => continue,
264 ScopeItem::Function(f) => return f.get_name().1 == "include",