Skip to content
This repository was archived by the owner on Jul 3, 2024. It is now read-only.

Commit 4dfa570

Browse files
0xSwapFeeder0xmemorygrinder
authored andcommitted
feat(solidity/core/references-server): added references provider to osmium
1 parent e3c3d43 commit 4dfa570

File tree

8 files changed

+4383
-8
lines changed

8 files changed

+4383
-8
lines changed

toolchains/solidity/core/Cargo.lock

+96-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

toolchains/solidity/core/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ extension = { version = "0.1.0", path = "crates/extension", default-features = f
1919
solidhunter = { version = "0.2.1", path = "crates/solidhunter", default-features = false }
2020
linter-cli = { version = "0.2.0", path = "crates/linter-cli", default-features = false }
2121
linter-server = { version = "0.1.0", path = "crates/linter-server", default-features = false }
22-
foundry-compiler-server = { version = "0.1.0", path = "crates/foundry-compiler-server", default-features = false }
22+
slither-server = { version = "0.1.0", path = "crates/slither-server", default-features = false }
23+
tests-positions-server = { version = "0.1.0", path = "crates/tests-positions-server", default-features = false }
24+
references-server = { version = "0.1.0", path = "crates/references-server", default-features = false }
25+
foundry-compiler-server = { version = "0.1.0", path = "crates/foundry-compiler-server", default-features = false }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "references-server"
3+
version.workspace = true
4+
edition.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
exclude.workspace = true
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies]
12+
tokio = { version = "1.36.0", features = ["full"] }
13+
tower-lsp = "0.20.0"
14+
solc-references = { path = "../../../../../libs/solc-references" }
15+
glob = "0.3.1"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
mod utils;
2+
3+
use crate::utils::*;
4+
5+
use std::sync::Arc;
6+
use tokio::sync::Mutex;
7+
use tower_lsp::jsonrpc::Result;
8+
use tower_lsp::lsp_types::*;
9+
use tower_lsp::lsp_types::Location as LspLocation;
10+
use tower_lsp::{Client, LanguageServer, LspService, Server};
11+
use solc_references::*;
12+
13+
14+
struct Backend {
15+
client: Client,
16+
references_provider: Arc<Mutex<ReferencesProvider>>,
17+
}
18+
19+
impl Backend {
20+
pub fn new(client: Client) -> Self {
21+
Self { client, references_provider: Arc::new(Mutex::new(ReferencesProvider { files: Vec::new(), base_path: String::new()})) }
22+
}
23+
}
24+
25+
#[tower_lsp::async_trait]
26+
impl LanguageServer for Backend {
27+
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
28+
if let Some(workspace) = params.workspace_folders {
29+
self.references_provider.lock().await.set_base_path(normalize_path(workspace[0].uri.path()));
30+
} else {
31+
self.references_provider.lock().await.set_base_path(normalize_path(&params.root_uri.unwrap().path()));
32+
}
33+
Ok(InitializeResult {
34+
server_info: None,
35+
capabilities: ServerCapabilities {
36+
text_document_sync: Some(TextDocumentSyncCapability::Kind(
37+
TextDocumentSyncKind::INCREMENTAL,
38+
)),
39+
workspace: Some(WorkspaceServerCapabilities {
40+
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
41+
supported: Some(true),
42+
change_notifications: Some(OneOf::Left(true)),
43+
}),
44+
file_operations: None,
45+
}),
46+
definition_provider: Some(OneOf::Left(true)),
47+
references_provider: Some(OneOf::Left(true)),
48+
implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
49+
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
50+
..ServerCapabilities::default()
51+
},
52+
})
53+
}
54+
55+
async fn initialized(&self, _: InitializedParams) {
56+
self.client
57+
.log_message(MessageType::INFO, "osmium-solidity-references initialized!")
58+
.await;
59+
if let Err(e) = self.references_provider.lock().await.update_file_content() {
60+
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
61+
}
62+
}
63+
64+
async fn did_save(&self, _: DidSaveTextDocumentParams) {
65+
if let Err(e) = self.references_provider.lock().await.update_file_content() {
66+
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
67+
}
68+
}
69+
70+
async fn references(&self, params: ReferenceParams) -> Result<Option<Vec<LspLocation>>> {
71+
self.client.log_message(MessageType::INFO, "References requested").await;
72+
let uri = params.text_document_position.text_document.uri;
73+
let mut position = params.text_document_position.position;
74+
position.line += 1;
75+
position.character += 1;
76+
77+
let locations = self.references_provider.lock().await.get_references(&normalize_path(uri.path()), solc_references::Position { line: position.line, column: position.character });
78+
let ret: Vec<LspLocation> = locations.iter().map(|location| {
79+
let mut new_uri = uri.clone();
80+
new_uri.set_path(&escape_path(&location.uri));
81+
location_to_lsp_location(&new_uri, &location)
82+
}).collect();
83+
Ok(Some(ret))
84+
}
85+
86+
async fn goto_definition(&self, params: GotoDefinitionParams) -> Result<Option<GotoDefinitionResponse>> {
87+
self.client.log_message(MessageType::INFO, "Goto definition requested").await;
88+
let mut uri = params.text_document_position_params.text_document.uri;
89+
let mut position = params.text_document_position_params.position;
90+
position.line += 1;
91+
position.character += 1;
92+
93+
let location = self.references_provider.lock().await.get_definition(&normalize_path(uri.path()), solc_references::Position { line: position.line, column: position.character });
94+
95+
if let Some(location) = location {
96+
uri.set_path(&escape_path(&location.uri));
97+
return Ok(Some(GotoDefinitionResponse::Scalar(location_to_lsp_location(&uri, &location))));
98+
}
99+
self.client.log_message(MessageType::INFO, "No definition found").await;
100+
Ok(None)
101+
}
102+
103+
async fn shutdown(&self) -> Result<()> {
104+
Ok(())
105+
}
106+
107+
}
108+
109+
impl Backend {
110+
111+
}
112+
113+
#[tokio::main]
114+
async fn main() {
115+
/*
116+
117+
USE THIS CODE TO DEBUG
118+
119+
let listener = tokio::net::TcpListener::bind("127.0.0.1:9001").await?;
120+
let (stream, _) = listener.accept().await?;
121+
let (read, write) = tokio::io::split(stream);
122+
Server::new(read, write, socket).serve(service).await;
123+
*/
124+
125+
let (service, socket) = LspService::new(Backend::new);
126+
let stdin = tokio::io::stdin();
127+
let stdout = tokio::io::stdout();
128+
Server::new(stdin, stdout, socket).serve(service).await;
129+
130+
//Ok(())
131+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use tower_lsp::lsp_types::{Location as LspLocation, Position as LspPosition, Range as LspRange, Url};
2+
3+
#[cfg(target_family = "windows")]
4+
pub fn normalize_path(path: &str) -> String {
5+
let mut path = path.replace("%3A/", "://");
6+
path.remove(0);
7+
path.to_string()
8+
}
9+
10+
#[cfg(not(target_family = "windows"))]
11+
pub fn normalize_path(path: &str) -> String {
12+
path.to_string()
13+
}
14+
15+
#[cfg(target_family = "windows")]
16+
pub fn escape_path(path: &str) -> String {
17+
let mut path = path.replace("://", "%3A/");
18+
path.insert(0, '/');
19+
path.to_string()
20+
}
21+
22+
#[cfg(not(target_family = "windows"))]
23+
pub fn escape_path(path: &str) -> String {
24+
path.to_string()
25+
}
26+
27+
pub fn location_to_lsp_location(new_uri: &Url, location: &solc_references::Location) -> LspLocation {
28+
LspLocation {
29+
uri: new_uri.clone(),
30+
range: LspRange {
31+
start: LspPosition {
32+
line: location.start.line - 1,
33+
character: location.start.column - 1,
34+
},
35+
end: LspPosition {
36+
line: location.end.line - 1,
37+
character: location.end.column - 1,
38+
},
39+
},
40+
}
41+
}

toolchains/solidity/extension/src/extension.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,26 @@ import { createTestsPositionsClient } from './tests-positions';
99
import { registerGasEstimation } from './gas-estimation';
1010
import registerForgeFmtLinter from "./fmt-wrapper";
1111
import { TestManager } from './tests/test-manager';
12+
import { createReferencesClient } from './references';
1213

1314
let slitherClient: LanguageClient;
1415
let linterClient: LanguageClient;
1516
let foundryCompilerClient: LanguageClient;
1617
let testsPositionsClient: LanguageClient;
18+
let referencesClient: LanguageClient;
1719
let testManager: TestManager;
1820

1921
export async function activate(context: ExtensionContext) {
2022
linterClient = await createLinterClient(context);
2123
foundryCompilerClient = createFoundryCompilerClient(context);
2224
slitherClient = await createSlitherClient(context);
25+
referencesClient = await createReferencesClient(context);
2326
testsPositionsClient = await createTestsPositionsClient(context);
2427
if (workspace.workspaceFolders?.length) {
2528
testManager = new TestManager(testsPositionsClient, workspace.workspaceFolders[0].uri.fsPath);
2629
}
2730

28-
context.subscriptions.push(linterClient, foundryCompilerClient, slitherClient, testsPositionsClient, testManager.testController);
31+
context.subscriptions.push(linterClient, slitherClient, foundryCompilerClient, testsPositionsClient, testManager.testController, referencesClient);
2932

3033
registerForgeFmtLinter(context);
3134
registerGasEstimation();

0 commit comments

Comments
 (0)