11//! See `Semantics`.
22
3+ mod source_to_def;
4+
35use std:: { cell:: RefCell , fmt, iter:: successors} ;
46
57use hir_def:: {
68 resolver:: { self , HasResolver , Resolver } ,
7- DefWithBodyId , TraitId ,
9+ TraitId ,
810} ;
11+ use hir_expand:: ExpansionInfo ;
912use ra_db:: { FileId , FileRange } ;
13+ use ra_prof:: profile;
1014use ra_syntax:: {
11- algo:: skip_trivia_token, ast, match_ast, AstNode , Direction , SyntaxNode , SyntaxToken ,
12- TextRange , TextUnit ,
15+ algo:: skip_trivia_token, ast, AstNode , Direction , SyntaxNode , SyntaxToken , TextRange , TextUnit ,
1316} ;
1417use rustc_hash:: { FxHashMap , FxHashSet } ;
1518
1619use crate :: {
1720 db:: HirDatabase ,
21+ semantics:: source_to_def:: { ChildContainer , SourceToDefCache , SourceToDefCtx } ,
1822 source_analyzer:: { resolve_hir_path, ReferenceDescriptor , SourceAnalyzer } ,
19- source_binder:: { ChildContainer , SourceBinder } ,
2023 Function , HirFileId , InFile , Local , MacroDef , Module , ModuleDef , Name , Origin , Path ,
2124 PathResolution , ScopeDef , StructField , Trait , Type , TypeParam , VariantDef ,
2225} ;
23- use hir_expand:: ExpansionInfo ;
24- use ra_prof:: profile;
2526
2627/// Primary API to get semantic information, like types, from syntax trees.
2728pub struct Semantics < ' db , DB > {
2829 pub db : & ' db DB ,
29- sb : RefCell < SourceBinder > ,
30+ s2d_cache : RefCell < SourceToDefCache > ,
3031 cache : RefCell < FxHashMap < SyntaxNode , HirFileId > > ,
3132}
3233
@@ -38,8 +39,7 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
3839
3940impl < ' db , DB : HirDatabase > Semantics < ' db , DB > {
4041 pub fn new ( db : & DB ) -> Semantics < DB > {
41- let sb = RefCell :: new ( SourceBinder :: new ( ) ) ;
42- Semantics { db, sb, cache : RefCell :: default ( ) }
42+ Semantics { db, s2d_cache : Default :: default ( ) , cache : Default :: default ( ) }
4343 }
4444
4545 pub fn parse ( & self , file_id : FileId ) -> ast:: SourceFile {
@@ -136,13 +136,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
136136 // FIXME: use this instead?
137137 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
138138
139- pub fn to_def < T : ToDef + Clone > ( & self , src : & T ) -> Option < T :: Def > {
139+ pub fn to_def < T : ToDef > ( & self , src : & T ) -> Option < T :: Def > {
140+ let src = self . find_file ( src. syntax ( ) . clone ( ) ) . with_value ( src) . cloned ( ) ;
140141 T :: to_def ( self , src)
141142 }
142143
144+ fn with_ctx < F : FnOnce ( & mut SourceToDefCtx < & DB > ) -> T , T > ( & self , f : F ) -> T {
145+ let mut cache = self . s2d_cache . borrow_mut ( ) ;
146+ let mut ctx = SourceToDefCtx { db : self . db , cache : & mut * cache } ;
147+ f ( & mut ctx)
148+ }
149+
143150 pub fn to_module_def ( & self , file : FileId ) -> Option < Module > {
144- let mut sb = self . sb . borrow_mut ( ) ;
145- sb. to_module_def ( self . db , file)
151+ self . with_ctx ( |ctx| ctx. file_to_def ( file) ) . map ( Module :: from)
146152 }
147153
148154 pub fn scope ( & self , node : & SyntaxNode ) -> SemanticsScope < ' db , DB > {
@@ -176,7 +182,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
176182 fn analyze2 ( & self , src : InFile < & SyntaxNode > , offset : Option < TextUnit > ) -> SourceAnalyzer {
177183 let _p = profile ( "Semantics::analyze2" ) ;
178184
179- let container = match self . sb . borrow_mut ( ) . find_container ( self . db , src) {
185+ let container = match self . with_ctx ( |ctx| ctx . find_container ( src) ) {
180186 Some ( it) => it,
181187 None => return SourceAnalyzer :: new_for_resolver ( Resolver :: default ( ) , src) ,
182188 } ;
@@ -233,68 +239,42 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
233239 }
234240}
235241
236- pub trait ToDef : Sized + AstNode + ' static {
242+ pub trait ToDef : AstNode + Clone {
237243 type Def ;
238- fn to_def < DB : HirDatabase > ( sema : & Semantics < DB > , src : & Self ) -> Option < Self :: Def > ;
244+
245+ fn to_def < DB : HirDatabase > ( sema : & Semantics < DB > , src : InFile < Self > ) -> Option < Self :: Def > ;
239246}
240247
241248macro_rules! to_def_impls {
242- ( $( ( $def: path, $ast: path) ) ,* , ) => { $(
249+ ( $( ( $def: path, $ast: path, $meth : ident ) ) ,* , ) => { $(
243250 impl ToDef for $ast {
244251 type Def = $def;
245- fn to_def<DB : HirDatabase >( sema: & Semantics <DB >, src: & Self )
246- -> Option <Self :: Def >
247- {
248- let src = sema. find_file( src. syntax( ) . clone( ) ) . with_value( src) ;
249- sema. sb. borrow_mut( ) . to_id( sema. db, src. cloned( ) ) . map( Into :: into)
252+ fn to_def<DB : HirDatabase >( sema: & Semantics <DB >, src: InFile <Self >) -> Option <Self :: Def > {
253+ sema. with_ctx( |ctx| ctx. $meth( src) ) . map( <$def>:: from)
250254 }
251255 }
252256 ) * }
253257}
254258
255259to_def_impls ! [
256- ( crate :: Module , ast:: Module ) ,
257- ( crate :: Struct , ast:: StructDef ) ,
258- ( crate :: Enum , ast:: EnumDef ) ,
259- ( crate :: Union , ast:: UnionDef ) ,
260- ( crate :: Trait , ast:: TraitDef ) ,
261- ( crate :: ImplBlock , ast:: ImplBlock ) ,
262- ( crate :: TypeAlias , ast:: TypeAliasDef ) ,
263- ( crate :: Const , ast:: ConstDef ) ,
264- ( crate :: Static , ast:: StaticDef ) ,
265- ( crate :: Function , ast:: FnDef ) ,
266- ( crate :: StructField , ast:: RecordFieldDef ) ,
267- ( crate :: EnumVariant , ast:: EnumVariant ) ,
268- ( crate :: TypeParam , ast:: TypeParam ) ,
269- ( crate :: MacroDef , ast:: MacroCall ) , // this one is dubious, not all calls are macros
260+ ( crate :: Module , ast:: Module , module_to_def) ,
261+ ( crate :: Struct , ast:: StructDef , struct_to_def) ,
262+ ( crate :: Enum , ast:: EnumDef , enum_to_def) ,
263+ ( crate :: Union , ast:: UnionDef , union_to_def) ,
264+ ( crate :: Trait , ast:: TraitDef , trait_to_def) ,
265+ ( crate :: ImplBlock , ast:: ImplBlock , impl_to_def) ,
266+ ( crate :: TypeAlias , ast:: TypeAliasDef , type_alias_to_def) ,
267+ ( crate :: Const , ast:: ConstDef , const_to_def) ,
268+ ( crate :: Static , ast:: StaticDef , static_to_def) ,
269+ ( crate :: Function , ast:: FnDef , fn_to_def) ,
270+ ( crate :: StructField , ast:: RecordFieldDef , record_field_to_def) ,
271+ ( crate :: StructField , ast:: TupleFieldDef , tuple_field_to_def) ,
272+ ( crate :: EnumVariant , ast:: EnumVariant , enum_variant_to_def) ,
273+ ( crate :: TypeParam , ast:: TypeParam , type_param_to_def) ,
274+ ( crate :: MacroDef , ast:: MacroCall , macro_call_to_def) , // this one is dubious, not all calls are macros
275+ ( crate :: Local , ast:: BindPat , bind_pat_to_def) ,
270276] ;
271277
272- impl ToDef for ast:: BindPat {
273- type Def = Local ;
274-
275- fn to_def < DB : HirDatabase > ( sema : & Semantics < DB > , src : & Self ) -> Option < Local > {
276- let src = sema. find_file ( src. syntax ( ) . clone ( ) ) . with_value ( src) ;
277- let file_id = src. file_id ;
278- let mut sb = sema. sb . borrow_mut ( ) ;
279- let db = sema. db ;
280- let parent: DefWithBodyId = src. value . syntax ( ) . ancestors ( ) . find_map ( |it| {
281- let res = match_ast ! {
282- match it {
283- ast:: ConstDef ( value) => { sb. to_id( db, InFile { value, file_id} ) ?. into( ) } ,
284- ast:: StaticDef ( value) => { sb. to_id( db, InFile { value, file_id} ) ?. into( ) } ,
285- ast:: FnDef ( value) => { sb. to_id( db, InFile { value, file_id} ) ?. into( ) } ,
286- _ => return None ,
287- }
288- } ;
289- Some ( res)
290- } ) ?;
291- let ( _body, source_map) = db. body_with_source_map ( parent) ;
292- let src = src. cloned ( ) . map ( ast:: Pat :: from) ;
293- let pat_id = source_map. node_pat ( src. as_ref ( ) ) ?;
294- Some ( Local { parent : parent. into ( ) , pat_id } )
295- }
296- }
297-
298278fn find_root ( node : & SyntaxNode ) -> SyntaxNode {
299279 node. ancestors ( ) . last ( ) . unwrap ( )
300280}
0 commit comments