Skip to content

Commit

Permalink
feat: assoc method completion (#578)
Browse files Browse the repository at this point in the history
This PR refactors how we analyze the context of completions and adds
completion of associated methods.

There is some unused code in this PR which I need for adding more
completions (like methods and use statements). I didnt add them to this
PR yet to make sure it doesnt grow to big.
  • Loading branch information
baszalmstra authored Jan 11, 2025
1 parent 3d70e0e commit 058072c
Show file tree
Hide file tree
Showing 30 changed files with 680 additions and 379 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ concurrency:
jobs:
check:
name: Check
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -53,7 +53,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest", "macOS-latest"]
os: ["ubuntu-22.04", "windows-latest", "macOS-latest"]
include:
- RUSTFLAGS: "-Dwarnings"
CARGO_INCREMENTAL: 1
Expand All @@ -74,7 +74,7 @@ jobs:
submodules: true

- name: Install packages
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install libasound2-dev libudev-dev
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest", "macOS-latest"]
os: ["ubuntu-22.04", "windows-latest", "macOS-latest"]
include:
- RUSTFLAGS: "-Dwarnings"
CARGO_INCREMENTAL: 1
Expand Down Expand Up @@ -167,7 +167,7 @@ jobs:

test-mdbook:
name: Test mdbook
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: check
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -220,7 +220,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest", "windows-latest", "macOS-latest"]
os: ["ubuntu-22.04", "windows-latest", "macOS-latest"]
include:
- RUSTFLAGS: "-Dwarnings"
- os: "windows-latest"
Expand Down Expand Up @@ -288,7 +288,7 @@ jobs:

style:
name: Check Style
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: check
steps:
- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/mun_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use crate::{
ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, ExprScopes, Literal, LogicOp, Ordering, Pat,
PatId, RecordLitField, Statement, UnaryOp,
},
ids::ItemLoc,
ids::{AssocItemId, ItemLoc},
in_file::InFile,
name::Name,
name_resolution::PerNs,
Expand Down Expand Up @@ -62,7 +62,7 @@ mod utils;

mod has_module;
mod item_scope;
mod method_resolution;
pub mod method_resolution;
#[cfg(test)]
mod mock;
mod package_defs;
Expand Down
20 changes: 20 additions & 0 deletions crates/mun_hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ use crate::{
HirDatabase, InFile, ModuleDef, Name, PatId, PerNs, Resolver, Ty, Visibility,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PathResolution {
/// An item
Def(ModuleDef),
/// A local binding (only value namespace)
Local(Local),
SelfType(Impl),
}

/// The primary API to get semantic information, like types, from syntax trees.
/// Exposes the database it was created with through the `db` field.
pub struct Semantics<'db> {
Expand Down Expand Up @@ -147,6 +156,11 @@ impl<'db> Semantics<'db> {
});
InFile::new(file_id, node)
}

/// Resolves the specified `ast::Path`
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.analyze(path.syntax()).resolve_path(self.db, path)
}
}

/// Returns the root node of the specified node.
Expand Down Expand Up @@ -201,6 +215,12 @@ pub struct Impl {
pub(crate) id: ImplId,
}

impl From<ImplId> for Impl {
fn from(id: ImplId) -> Self {
Impl { id }
}
}

impl Impl {
pub fn self_ty(self, db: &dyn HirDatabase) -> Ty {
db.type_for_impl_self(self.id)
Expand Down
50 changes: 48 additions & 2 deletions crates/mun_hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use mun_syntax::{ast, AstNode, SyntaxNode, TextRange, TextSize};
use crate::{
expr::{scope::LocalScopeId, BodySourceMap},
ids::DefWithBodyId,
resolver_for_scope, Body, ExprId, ExprScopes, HirDatabase, InFile, InferenceResult, Resolver,
Ty,
resolver_for_scope,
semantics::PathResolution,
Body, ExprId, ExprScopes, HirDatabase, InFile, InferenceResult, Path, Resolver, Struct, Ty,
TypeAlias, TypeNs,
};

/// A `SourceAnalyzer` is a wrapper which exposes the HIR API in terms of the
Expand Down Expand Up @@ -79,6 +81,22 @@ impl SourceAnalyzer {
let sm = self.body_source_map.as_ref()?;
sm.node_expr(expr)
}

pub(crate) fn resolve_path(
&self,
db: &dyn HirDatabase,
path: &ast::Path,
) -> Option<PathResolution> {
let hir_path = Path::from_ast(path.clone())?;

// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
// are trying to resolve foo::bar.
if path.parent_path().is_some() {
return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
}

None
}
}

/// Returns the id of the scope that is active at the location of `node`.
Expand Down Expand Up @@ -173,3 +191,31 @@ fn adjust(
})
.map(|(_ptr, scope)| *scope)
}

/// Resolves a path where we know it is a qualifier of another path.
fn resolve_hir_path_qualifier(
db: &dyn HirDatabase,
resolver: &Resolver,
path: &Path,
) -> Option<PathResolution> {
let (ty, _, remaining_idx) = resolver.resolve_path_as_type(db.upcast(), path)?;
let (ty, _unresolved) = match remaining_idx {
Some(remaining_idx) => {
if remaining_idx + 1 == path.segments.len() {
Some((ty, path.segments.last()))
} else {
None
}
}
None => Some((ty, None)),
}?;

let res = match ty {
TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
TypeNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
TypeNs::PrimitiveType(it) => PathResolution::Def(it.into()),
};

Some(res)
}
2 changes: 1 addition & 1 deletion crates/mun_hir/src/ty/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ pub mod diagnostics {
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) enum LowerDiagnostic {
pub enum LowerDiagnostic {
UnresolvedType { id: LocalTypeRefId },
TypeIsPrivate { id: LocalTypeRefId },
}
Expand Down
1 change: 1 addition & 0 deletions crates/mun_language_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ mun_test = { path = "../mun_test"}
insta = { workspace = true }
itertools = { workspace = true }
tempdir = { workspace = true }
text_trees = { workspace = true }
38 changes: 31 additions & 7 deletions crates/mun_language_server/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@
//! completions.
mod context;
mod dot;
// mod dot;
mod item;
mod render;
mod unqualified_path;
// mod unqualified_path;

mod dot;
mod expr;
mod name_ref;
#[cfg(test)]
mod test_utils;

use context::CompletionContext;
use context::{
CompletionAnalysis, CompletionContext, DotAccess, NameRefContext, NameRefKind,
PathCompletionContext, PathExprContext, PathKind, Qualified,
};
pub use item::{CompletionItem, CompletionItemKind, CompletionKind};
use mun_hir::semantics::ScopeDef;

use crate::{
completion::render::{render_field, render_resolution, RenderContext},
completion::render::{render_field, render_fn, render_resolution, RenderContext},
db::AnalysisDatabase,
FilePosition,
};
Expand All @@ -36,11 +42,18 @@ use crate::{
/// complete the fields of `foo` and don't want the local variables of
/// the active scope.
pub(crate) fn completions(db: &AnalysisDatabase, position: FilePosition) -> Option<Completions> {
let context = CompletionContext::new(db, position)?;
let (context, analysis) = CompletionContext::new(db, position)?;

let mut result = Completions::default();
unqualified_path::complete_unqualified_path(&mut result, &context);
dot::complete_dot(&mut result, &context);

match analysis {
CompletionAnalysis::NameRef(name_ref_ctx) => {
name_ref::complete_name_ref(&mut result, &context, &name_ref_ctx);
}
}

// unqualified_path::complete_unqualified_path(&mut result, &context);
// dot::complete_dot(&mut result, &context);
Some(result)
}

Expand Down Expand Up @@ -80,4 +93,15 @@ impl Completions {
let item = render_field(RenderContext::new(ctx), field);
self.add(item);
}

fn add_function(
&mut self,
ctx: &CompletionContext<'_>,
func: mun_hir::Function,
local_name: Option<String>,
) {
if let Some(item) = render_fn(RenderContext::new(ctx), local_name, func) {
self.add(item);
}
}
}
Loading

0 comments on commit 058072c

Please sign in to comment.