Skip to content

Commit

Permalink
Hacky implementation of find implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
andyyu2004 committed Apr 25, 2022
1 parent 84c6215 commit c1d6f11
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 13 deletions.
12 changes: 10 additions & 2 deletions src/gqls-ide/src/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,16 @@ use vfs::FileId;
use crate::{Analysis, Location};

impl Analysis {
pub fn implementations(&self, file: FileId, at: Point) -> Vec<Location> {
todo!()
pub fn goto_implementation(&self, file: FileId, at: Point) -> Vec<Location> {
let name = match self.name_at(file, at) {
Some(name) => name,
None => return vec![],
};
self.implementations(file, name)
.into_iter()
.map(|res| self.item(res))
.map(|item| Location::new(file, item.name.range.into()))
.collect()
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/gqls-ide/src/implementation/tests.rs
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
use std::collections::HashSet;

use gqls_fixture::{fixture, Fixture};

use crate::{Ide, Location};

fn test(fixture: Fixture) {
let mut ide = Ide::default();
ide.setup_fixture(&fixture);
let analysis = ide.analysis();
let expected_locations = fixture
.all_ranges()
.map(|(file, range)| Location::new(file, range.into()))
.collect::<HashSet<_>>();

for (file, at) in fixture.all_points() {
let locations = analysis.goto_implementation(file, at).into_iter().collect::<HashSet<_>>();
assert_eq!(expected_locations, locations);
}
}

#[test]
fn test_find_implementations() {
let fixture = fixture!(
"foo" => "
interface Iface {
#^^^^^
i: Int
}
type Foo implements Iface {
#...
i: Int
}
extend type Foo implements Iface {
#...
k: Int
}"
);
test(fixture);
}
25 changes: 21 additions & 4 deletions src/gqls-ir/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::sync::Arc;
use std::vec;

use gqls_base_db::SourceDatabase;
use gqls_parse::{NodeExt, NodeKind, Point, RangeExt};
Expand All @@ -10,19 +11,35 @@ use crate::*;

#[salsa::query_group(DefDatabaseStorage)]
pub trait DefDatabase: SourceDatabase {
fn items(&self, file: FileId) -> Arc<Items>;
fn field(&self, res: FieldRes) -> Field;
fn implementations(&self, file: FileId, name: Name) -> Vec<ItemRes>;
fn item(&self, res: ItemRes) -> Item;
fn item_at(&self, file: FileId, at: Point) -> Option<Idx<Item>>;
fn item_map(&self, file: FileId) -> Arc<ItemMap>;
fn item_body(&self, res: ItemRes) -> Option<Arc<ItemBody>>;
fn item_map(&self, file: FileId) -> Arc<ItemMap>;
fn item_references(&self, res: ItemRes) -> References;
fn items(&self, file: FileId) -> Arc<Items>;
fn name_at(&self, file: FileId, at: Point) -> Option<Name>;
fn field(&self, res: FieldRes) -> Field;
fn references(&self, res: Res) -> References;
fn item_references(&self, res: ItemRes) -> References;
fn resolve(&self, file: FileId, at: Point) -> Option<Res>;
fn resolve_item(&self, file: FileId, name: Name) -> ItemResolutions;
}

fn implementations(db: &dyn DefDatabase, file: FileId, interface: Name) -> Vec<ItemRes> {
let mut implementations = vec![];
for project in db.projects_of(file) {
for &file in db.project_files(project).iter() {
let items = db.items(file);
for (idx, _) in items.items.iter() {
if items.implements(idx, &interface) {
implementations.push(ItemRes { file, idx });
}
}
}
}
implementations
}

fn items(db: &dyn DefDatabase, file: FileId) -> Arc<Items> {
let data = db.file_data(file);
lower::ItemCtxt::new(data.text).lower(data.tree)
Expand Down
15 changes: 13 additions & 2 deletions src/gqls-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use gqls_parse::{Node, NodeExt, Range};
use la_arena::IdxRange;
use smallvec::SmallVec;
use smol_str::SmolStr;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
Expand All @@ -36,6 +36,17 @@ impl Items {
ItemKind::DirectiveDefinition(_) => None,
}
}

pub fn implements(&self, idx: Idx<Item>, interface: &Name) -> bool {
match self.items[idx].kind {
ItemKind::TypeDefinition(typedef) => &self.types[typedef].implementations,
ItemKind::TypeExtension(type_ext) => &self.type_exts[type_ext].implementations,
ItemKind::DirectiveDefinition(_) => return false,
}
.as_ref()
.map(|implements| implements.contains(interface))
.unwrap_or_default()
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand All @@ -60,7 +71,7 @@ pub enum ItemKind {
DirectiveDefinition(Idx<DirectiveDefinition>),
}

pub type Implementations = Vec<Ty>;
pub type Implementations = HashSet<Name>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeDefinition {
Expand Down
2 changes: 1 addition & 1 deletion src/gqls-ir/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl ItemCtxt {
Some(
implementations
.children_of_kind(cursor, NodeKind::NAMED_TYPE)
.map(|node| self.lower_named_type(node))
.map(|node| self.lower_named_type(node).name())
.collect(),
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/gqls-ir/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,9 +425,9 @@ fn test_definitions() {
TypeExtension {
directives: [],
implementations: Some(
[
{
Iface,
],
},
),
},
],
Expand Down
2 changes: 1 addition & 1 deletion src/gqls/src/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl LanguageServer for Gqls {
self.with_ide(|ide| {
let path = ide.path(&position.text_document.uri)?;
let analysis = ide.analysis();
let locations = analysis.implementations(path, position.position.convert());
let locations = analysis.goto_implementation(path, position.position.convert());
Ok(convert::locations_to_goto_definition_response(&locations))
})
}
Expand Down
2 changes: 1 addition & 1 deletion vscode-gqls/src/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { dirname, join } from "path";
import { createGunzip } from "zlib";
import assert = require("assert");

const GQLS_VERSION = "v0.0.1";
const GQLS_VERSION = "v0.0.2";

export async function bootstrap(
context: vscode.ExtensionContext,
Expand Down

0 comments on commit c1d6f11

Please sign in to comment.