Pass through DeclParserOptions created from NativeEnv
[hiphop-php.git] / hphp / hack / src / hackc / decl_provider / self_provider.rs
blob9b5806246e6a32980d5ec1f85d61c8904d35413a
1 // Copyright (c) Meta Platforms, Inc. and affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use std::sync::Arc;
8 use direct_decl_parser::parse_decls_without_reference_text;
9 use direct_decl_parser::Decls;
10 use oxidized::decl_parser_options::DeclParserOptions;
11 use oxidized_by_ref::shallow_decl_defs::ConstDecl;
12 use oxidized_by_ref::shallow_decl_defs::FunDecl;
13 use oxidized_by_ref::shallow_decl_defs::ModuleDecl;
14 use parser_core_types::source_text::SourceText;
16 use crate::DeclProvider;
17 use crate::Result;
18 use crate::TypeDecl;
20 /// A decl provider that also provides decls found in the given file.
21 ///
22 /// Checks the current file first for decls. If not found,
23 /// checks the provided decl provider for the decls next.
24 ///
25 /// Useful when the file under compilation is not indexed by the HHVM autoloader
26 /// or similar circumstances.
27 pub struct SelfProvider<'d> {
28     fallback_decl_provider: Option<Arc<dyn DeclProvider<'d> + 'd>>,
29     decls: Decls<'d>,
32 impl<'d> SelfProvider<'d> {
33     pub fn new(
34         fallback_decl_provider: Option<Arc<dyn DeclProvider<'d> + 'd>>,
35         decl_opts: DeclParserOptions,
36         source_text: SourceText<'_>,
37         arena: &'d bumpalo::Bump,
38     ) -> Self {
39         let parsed_file = parse_decls_without_reference_text(
40             &decl_opts,
41             source_text.file_path().clone(),
42             source_text.text(),
43             arena,
44         );
45         SelfProvider {
46             fallback_decl_provider,
47             decls: parsed_file.decls,
48         }
49     }
51     /// Currently, because decls are not on by default everywhere
52     /// only create a new SelfProvider when given a fallback provider,
53     /// which indicates that we want to compile with decls.
54     /// When decls are turned on everywhere by default and it is no longer optional
55     /// this can simply return a nonoption decl provider
56     pub fn wrap_existing_provider(
57         fallback_decl_provider: Option<Arc<dyn DeclProvider<'d> + 'd>>,
58         decl_opts: DeclParserOptions,
59         source_text: SourceText<'_>,
60         arena: &'d bumpalo::Bump,
61     ) -> Option<Arc<dyn DeclProvider<'d> + 'd>> {
62         if fallback_decl_provider.is_none() {
63             None
64         } else {
65             Some(Arc::new(SelfProvider::new(
66                 fallback_decl_provider,
67                 decl_opts,
68                 source_text,
69                 arena,
70             )) as Arc<dyn DeclProvider<'d> + 'd>)
71         }
72     }
74     fn result_or_else<T>(
75         &self,
76         decl: Result<T>,
77         get_fallback_decl: impl Fn(&Arc<dyn DeclProvider<'d> + 'd>) -> Result<T>,
78     ) -> Result<T> {
79         decl.or_else(|_| {
80             self.fallback_decl_provider
81                 .as_ref()
82                 .map_or(Err(crate::Error::NotFound), get_fallback_decl)
83         })
84     }
87 impl<'d> DeclProvider<'d> for SelfProvider<'d> {
88     fn type_decl(&self, symbol: &str, depth: u64) -> Result<TypeDecl<'d>> {
89         self.result_or_else(crate::find_type_decl(&self.decls, symbol), |provider| {
90             provider.type_decl(symbol, depth)
91         })
92     }
94     fn func_decl(&self, symbol: &str) -> Result<&'d FunDecl<'d>> {
95         self.result_or_else(crate::find_func_decl(&self.decls, symbol), |provider| {
96             provider.func_decl(symbol)
97         })
98     }
100     fn const_decl(&self, symbol: &str) -> Result<&'d ConstDecl<'d>> {
101         self.result_or_else(crate::find_const_decl(&self.decls, symbol), |provider| {
102             provider.const_decl(symbol)
103         })
104     }
106     fn module_decl(&self, symbol: &str) -> Result<&'d ModuleDecl<'d>> {
107         self.result_or_else(crate::find_module_decl(&self.decls, symbol), |provider| {
108             provider.module_decl(symbol)
109         })
110     }
113 impl<'d> std::fmt::Debug for SelfProvider<'d> {
114     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115         if let Some(p) = &self.fallback_decl_provider {
116             write!(f, "SelfProvider({:?})", p)
117         } else {
118             write!(f, "SelfProvider")
119         }
120     }