mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	Resolve offset_of!() in IDE
				
					
				
			This commit is contained in:
		
							parent
							
								
									db6db2aacc
								
							
						
					
					
						commit
						8d824c7828
					
				
					 5 changed files with 169 additions and 3 deletions
				
			
		|  | @ -1622,6 +1622,13 @@ impl<'db> SemanticsImpl<'db> { | |||
|         self.analyze(name.syntax())?.resolve_use_type_arg(name) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resolve_offset_of_field( | ||||
|         &self, | ||||
|         name_ref: &ast::NameRef, | ||||
|     ) -> Option<(Either<Variant, Field>, GenericSubstitution)> { | ||||
|         self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resolve_mod_path( | ||||
|         &self, | ||||
|         scope: &SyntaxNode, | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ use crate::{ | |||
| }; | ||||
| use either::Either; | ||||
| use hir_def::{ | ||||
|     AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, | ||||
|     AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, | ||||
|     ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId, | ||||
|     expr_store::{ | ||||
|         Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, | ||||
|  | @ -34,8 +34,8 @@ use hir_expand::{ | |||
|     name::{AsName, Name}, | ||||
| }; | ||||
| use hir_ty::{ | ||||
|     Adjustment, InferenceResult, Interner, Substitution, TraitEnvironment, Ty, TyExt, TyKind, | ||||
|     TyLoweringContext, | ||||
|     Adjustment, AliasTy, InferenceResult, Interner, ProjectionTy, Substitution, TraitEnvironment, | ||||
|     Ty, TyExt, TyKind, TyLoweringContext, | ||||
|     diagnostics::{ | ||||
|         InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, | ||||
|         unsafe_operations, | ||||
|  | @ -47,6 +47,7 @@ use hir_ty::{ | |||
| use intern::sym; | ||||
| use itertools::Itertools; | ||||
| use smallvec::SmallVec; | ||||
| use stdx::never; | ||||
| use syntax::{ | ||||
|     SyntaxKind, SyntaxNode, TextRange, TextSize, | ||||
|     ast::{self, AstNode, RangeItem, RangeOp}, | ||||
|  | @ -791,6 +792,78 @@ impl SourceAnalyzer { | |||
|             .map(crate::TypeParam::from) | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn resolve_offset_of_field( | ||||
|         &self, | ||||
|         db: &dyn HirDatabase, | ||||
|         name_ref: &ast::NameRef, | ||||
|     ) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> { | ||||
|         let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?; | ||||
|         let container = offset_of_expr.ty()?; | ||||
|         let container = self.type_of_type(db, &container)?; | ||||
| 
 | ||||
|         let trait_env = container.env; | ||||
|         let mut container = Either::Right(container.ty); | ||||
|         for field_name in offset_of_expr.fields() { | ||||
|             if let Some( | ||||
|                 TyKind::Alias(AliasTy::Projection(ProjectionTy { associated_ty_id, substitution })) | ||||
|                 | TyKind::AssociatedType(associated_ty_id, substitution), | ||||
|             ) = container.as_ref().right().map(|it| it.kind(Interner)) | ||||
|             { | ||||
|                 let projection = ProjectionTy { | ||||
|                     associated_ty_id: *associated_ty_id, | ||||
|                     substitution: substitution.clone(), | ||||
|                 }; | ||||
|                 container = Either::Right(db.normalize_projection(projection, trait_env.clone())); | ||||
|             } | ||||
|             let handle_variants = |variant, subst: &Substitution, container: &mut _| { | ||||
|                 let fields = db.variant_fields(variant); | ||||
|                 let field = fields.field(&field_name.as_name())?; | ||||
|                 let field_types = db.field_types(variant); | ||||
|                 *container = Either::Right(field_types[field].clone().substitute(Interner, subst)); | ||||
|                 let generic_def = match variant { | ||||
|                     VariantId::EnumVariantId(it) => it.loc(db).parent.into(), | ||||
|                     VariantId::StructId(it) => it.into(), | ||||
|                     VariantId::UnionId(it) => it.into(), | ||||
|                 }; | ||||
|                 Some(( | ||||
|                     Either::Right(Field { parent: variant.into(), id: field }), | ||||
|                     generic_def, | ||||
|                     subst.clone(), | ||||
|                 )) | ||||
|             }; | ||||
|             let temp_ty = TyKind::Error.intern(Interner); | ||||
|             let (field_def, generic_def, subst) = | ||||
|                 match std::mem::replace(&mut container, Either::Right(temp_ty.clone())) { | ||||
|                     Either::Left((variant_id, subst)) => { | ||||
|                         handle_variants(VariantId::from(variant_id), &subst, &mut container)? | ||||
|                     } | ||||
|                     Either::Right(container_ty) => match container_ty.kind(Interner) { | ||||
|                         TyKind::Adt(adt_id, subst) => match adt_id.0 { | ||||
|                             AdtId::StructId(id) => { | ||||
|                                 handle_variants(id.into(), subst, &mut container)? | ||||
|                             } | ||||
|                             AdtId::UnionId(id) => { | ||||
|                                 handle_variants(id.into(), subst, &mut container)? | ||||
|                             } | ||||
|                             AdtId::EnumId(id) => { | ||||
|                                 let variants = db.enum_variants(id); | ||||
|                                 let variant = variants.variant(&field_name.as_name())?; | ||||
|                                 container = Either::Left((variant, subst.clone())); | ||||
|                                 (Either::Left(Variant { id: variant }), id.into(), subst.clone()) | ||||
|                             } | ||||
|                         }, | ||||
|                         _ => return None, | ||||
|                     }, | ||||
|                 }; | ||||
| 
 | ||||
|             if field_name.syntax().text_range() == name_ref.syntax().text_range() { | ||||
|                 return Some((field_def, GenericSubstitution::new(generic_def, subst, trait_env))); | ||||
|             } | ||||
|         } | ||||
|         never!("the `NameRef` is a child of the `OffsetOfExpr`, we should've visited it"); | ||||
|         None | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn resolve_path( | ||||
|         &self, | ||||
|         db: &dyn HirDatabase, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Chayim Refael Friedman
						Chayim Refael Friedman