mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
internal: document source_to_def and it's connection to Kotlin&Roslyn
This commit is contained in:
parent
ff92afb4c1
commit
bf9ce9e65c
@ -1,4 +1,73 @@
|
|||||||
//! Maps *syntax* of various definitions to their semantic ids.
|
//! Maps *syntax* of various definitions to their semantic ids.
|
||||||
|
//!
|
||||||
|
//! This is a very interesting module, and, in some sense, can be considered a
|
||||||
|
//! heart of the IDE parts of rust-analyzer.
|
||||||
|
//!
|
||||||
|
//! This module solves the following problem:
|
||||||
|
//!
|
||||||
|
//! Given a piece of syntax, find the corresponding semantic definition (def).
|
||||||
|
//!
|
||||||
|
//! This problem is a part of more-or-less every IDE feature implemented. Every
|
||||||
|
//! IDE functionality (like goto to definition), conceptually starts with a
|
||||||
|
//! specific cursor position in a file. Starting with this text offset, we first
|
||||||
|
//! figure out what syntactic construct are we at: is this a pattern, an
|
||||||
|
//! expression, an item definition.
|
||||||
|
//!
|
||||||
|
//! Knowing only the syntax gives us relatively little info. For example,
|
||||||
|
//! looking at the syntax of the function we can realise that it is a part of an
|
||||||
|
//! `impl` block, but we won't be able to tell what trait function the current
|
||||||
|
//! function overrides, and whether it does that correctly. For that, we need to
|
||||||
|
//! go from [`ast::Fn`] to [`crate::Function], and that's exactly what this
|
||||||
|
//! module does.
|
||||||
|
//!
|
||||||
|
//! As syntax trees are values and don't know their place of origin/identity,
|
||||||
|
//! this module also requires [`InFile`] wrappers to understand which specific
|
||||||
|
//! real or macro-expanded file the tree comes from.
|
||||||
|
//!
|
||||||
|
//! The actual algorithm to resolve syntax to def is curious in two aspects:
|
||||||
|
//!
|
||||||
|
//! * It is recursive
|
||||||
|
//! * It uses the inverse algorithm (what is the syntax for this def?)
|
||||||
|
//!
|
||||||
|
//! Specifically, the algorithm goes like this:
|
||||||
|
//!
|
||||||
|
//! 1. Find the syntactic container for the syntax. For example, field's
|
||||||
|
//! container is the struct, and structs container is a module.
|
||||||
|
//! 2. Recursively get the def corresponding to container.
|
||||||
|
//! 3. Ask the container def for all child defs. These child defs contain
|
||||||
|
//! the answer and answer's siblings.
|
||||||
|
//! 4. For each child def, ask for it's source.
|
||||||
|
//! 5. The child def whose source is the syntax node we've started with
|
||||||
|
//! is the answer.
|
||||||
|
//!
|
||||||
|
//! It's interesting that both Roslyn and Kotlin contain very similar code
|
||||||
|
//! shape.
|
||||||
|
//!
|
||||||
|
//! Let's take a look at Roslyn:
|
||||||
|
//!
|
||||||
|
//! <https://github.com/dotnet/roslyn/blob/36a0c338d6621cc5fe34b79d414074a95a6a489c/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs#L1403-L1429>
|
||||||
|
//! <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1403>
|
||||||
|
//!
|
||||||
|
//! The `GetDeclaredType` takes `Syntax` as input, and returns `Symbol` as
|
||||||
|
//! output. First, it retrieves a `Symbol` for parent `Syntax`:
|
||||||
|
//!
|
||||||
|
//! * https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1423
|
||||||
|
//!
|
||||||
|
//! Then, it iterates parent symbol's children, looking for one which has the
|
||||||
|
//! same text span as the original node:
|
||||||
|
//!
|
||||||
|
//! <https://sourceroslyn.io/#Microsoft.CodeAnalysis.CSharp/Compilation/SyntaxTreeSemanticModel.cs,1786>
|
||||||
|
//!
|
||||||
|
//! Now, let's look at Kotlin:
|
||||||
|
//!
|
||||||
|
//! <https://github.com/JetBrains/kotlin/blob/a288b8b00e4754a1872b164999c6d3f3b8c8994a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt#L93-L125>
|
||||||
|
//!
|
||||||
|
//! This function starts with a syntax node (`KtExpression` is syntax, like all
|
||||||
|
//! `Kt` nodes), and returns a def. It uses
|
||||||
|
//! `getNonLocalContainingOrThisDeclaration` to get syntactic container for a
|
||||||
|
//! current node. Then, `findSourceNonLocalFirDeclaration` gets `Fir` for this
|
||||||
|
//! parent. Finally, `findElementIn` function traverses `Fir` children to find
|
||||||
|
//! one with the same source we originally started with.
|
||||||
|
|
||||||
use base_db::FileId;
|
use base_db::FileId;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
Loading…
Reference in New Issue
Block a user