Skip to content

Commit 6e54645

Browse files
committed
refactor(language_server): store LintService instead of Linter (#12016)
I tried a basic usage with `htop` and @react-three/fiber as an import. The test setup should be included. Run `npm install` in the fixture folder. The results are looking not good. 😢 Would like to know more how I can memory check the server. My first guess is to modify it to a `lib` and then run a custom program with the methods of the `impl LanguageServer`. Current main: ![memory-main](https://github.com/user-attachments/assets/f76dea0d-b620-4c9e-b031-2781763dd54d) This PR: ![memory-pr12016](https://github.com/user-attachments/assets/7cf37b8a-64c7-404f-9e2e-acce4b48c2a5) `oxc_resolver.clear_cache()` as the first call on `Runtime.run_source()`: ![memory-clear-cache](https://github.com/user-attachments/assets/951c767f-1a34-4a50-b39b-5753f684789b)
1 parent 113cf8c commit 6e54645

File tree

10 files changed

+97
-52
lines changed

10 files changed

+97
-52
lines changed

apps/oxlint/src/lint.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,15 @@ impl Runner for LintRunner {
303303

304304
// Spawn linting in another thread so diagnostics can be printed immediately from diagnostic_service.run.
305305
rayon::spawn(move || {
306-
let mut lint_service =
307-
LintService::new(&linter, allocator_pool, options).with_paths(paths);
306+
let mut lint_service = LintService::new(linter, allocator_pool, options);
307+
let _ = lint_service.with_paths(paths);
308308

309309
// Use `RawTransferFileSystem` if `oxlint2` feature is enabled.
310310
// This reads the source text into start of allocator, instead of the end.
311311
#[cfg(all(feature = "oxlint2", not(feature = "disable_oxlint2")))]
312312
{
313313
use crate::raw_fs::RawTransferFileSystem;
314-
lint_service = lint_service.with_file_system(Box::new(RawTransferFileSystem));
314+
let _ = lint_service.with_file_system(Box::new(RawTransferFileSystem));
315315
}
316316

317317
lint_service.run(&tx_error);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Canvas } from '@react-three/fiber';
2+
// PR status
3+
debugger;
4+
5+
export function ThreeDMain() {
6+
return (
7+
<Canvas
8+
frameloop="demand"
9+
resize={{ debounce: 2 }}
10+
shadows
11+
gl={{ antialias: true, preserveDrawingBuffer: true }}
12+
camera={{
13+
position: [1.5, 0.5, 3.2],
14+
fov: 10,
15+
near: 0.1,
16+
far: 50,
17+
}}
18+
key={1}
19+
>
20+
</Canvas>
21+
)
22+
}
23+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"devPackages": {},
3+
"devDependencies": {
4+
"@react-three/fiber": "^9.1.4",
5+
"three": "^0.178.0"
6+
}
7+
}

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use tower_lsp_server::{
1212

1313
use oxc_allocator::{Allocator, AllocatorPool};
1414
use oxc_linter::{
15-
LINTABLE_EXTENSIONS, LintService, LintServiceOptions, Linter, MessageWithPosition,
16-
loader::Loader, read_to_arena_str,
15+
ConfigStore, LINTABLE_EXTENSIONS, LintOptions, LintService, LintServiceOptions, Linter,
16+
MessageWithPosition, loader::Loader, read_to_arena_str,
1717
};
1818
use oxc_linter::{RuntimeFileSystem, read_to_string};
1919

@@ -29,8 +29,7 @@ pub struct IsolatedLintHandlerOptions {
2929
}
3030

3131
pub struct IsolatedLintHandler {
32-
linter: Linter,
33-
options: IsolatedLintHandlerOptions,
32+
service: LintService,
3433
}
3534

3635
pub struct IsolatedLintHandlerFileSystem {
@@ -63,11 +62,25 @@ impl RuntimeFileSystem for IsolatedLintHandlerFileSystem {
6362
}
6463

6564
impl IsolatedLintHandler {
66-
pub fn new(linter: Linter, options: IsolatedLintHandlerOptions) -> Self {
67-
Self { linter, options }
65+
pub fn new(
66+
lint_options: LintOptions,
67+
config_store: ConfigStore,
68+
options: &IsolatedLintHandlerOptions,
69+
) -> Self {
70+
let linter = Linter::new(lint_options, config_store);
71+
let lint_service_options = LintServiceOptions::new(options.root_path.clone())
72+
.with_cross_module(options.use_cross_module);
73+
74+
let service = LintService::new(linter, AllocatorPool::default(), lint_service_options);
75+
76+
Self { service }
6877
}
6978

70-
pub fn run_single(&self, uri: &Uri, content: Option<String>) -> Option<Vec<DiagnosticReport>> {
79+
pub fn run_single(
80+
&mut self,
81+
uri: &Uri,
82+
content: Option<String>,
83+
) -> Option<Vec<DiagnosticReport>> {
7184
let path = uri.to_file_path()?;
7285

7386
if !Self::should_lint_path(&path) {
@@ -124,7 +137,7 @@ impl IsolatedLintHandler {
124137
}
125138

126139
fn lint_path<'a>(
127-
&self,
140+
&mut self,
128141
allocator: &'a Allocator,
129142
path: &Path,
130143
source_text: Option<String>,
@@ -138,17 +151,14 @@ impl IsolatedLintHandler {
138151

139152
debug!("lint {}", path.display());
140153

141-
let lint_service_options = LintServiceOptions::new(self.options.root_path.clone())
142-
.with_cross_module(self.options.use_cross_module);
143-
144-
let mut lint_service =
145-
LintService::new(&self.linter, AllocatorPool::default(), lint_service_options)
146-
.with_file_system(Box::new(IsolatedLintHandlerFileSystem::new(
147-
path.to_path_buf(),
148-
source_text,
149-
)))
150-
.with_paths(vec![Arc::from(path.as_os_str())]);
151-
let result = lint_service.run_source(allocator);
154+
let result = self
155+
.service
156+
.with_file_system(Box::new(IsolatedLintHandlerFileSystem::new(
157+
path.to_path_buf(),
158+
source_text,
159+
)))
160+
.with_paths(vec![Arc::from(path.as_os_str())])
161+
.run_source(allocator);
152162

153163
Some(result)
154164
}

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ use globset::Glob;
55
use ignore::gitignore::Gitignore;
66
use log::{debug, warn};
77
use rustc_hash::{FxBuildHasher, FxHashMap};
8+
use tokio::sync::Mutex;
89
use tower_lsp_server::lsp_types::Uri;
910

10-
use oxc_linter::{
11-
AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, LintOptions, Linter, Oxlintrc,
12-
};
11+
use oxc_linter::{AllowWarnDeny, Config, ConfigStore, ConfigStoreBuilder, LintOptions, Oxlintrc};
1312
use tower_lsp_server::UriExt;
1413

1514
use crate::linter::{
@@ -22,7 +21,7 @@ use crate::{ConcurrentHashMap, OXC_CONFIG_FILE, Options};
2221
use super::config_walker::ConfigWalker;
2322

2423
pub struct ServerLinter {
25-
isolated_linter: Arc<IsolatedLintHandler>,
24+
isolated_linter: Arc<Mutex<IsolatedLintHandler>>,
2625
gitignore_glob: Vec<Gitignore>,
2726
pub extended_paths: Vec<PathBuf>,
2827
}
@@ -85,15 +84,14 @@ impl ServerLinter {
8584
},
8685
);
8786

88-
let linter = Linter::new(lint_options, config_store);
89-
9087
let isolated_linter = IsolatedLintHandler::new(
91-
linter,
92-
IsolatedLintHandlerOptions { use_cross_module, root_path: root_path.to_path_buf() },
88+
lint_options,
89+
config_store,
90+
&IsolatedLintHandlerOptions { use_cross_module, root_path: root_path.to_path_buf() },
9391
);
9492

9593
Self {
96-
isolated_linter: Arc::new(isolated_linter),
94+
isolated_linter: Arc::new(Mutex::new(isolated_linter)),
9795
gitignore_glob: Self::create_ignore_glob(&root_path, &oxlintrc),
9896
extended_paths,
9997
}
@@ -200,12 +198,16 @@ impl ServerLinter {
200198
false
201199
}
202200

203-
pub fn run_single(&self, uri: &Uri, content: Option<String>) -> Option<Vec<DiagnosticReport>> {
201+
pub async fn run_single(
202+
&self,
203+
uri: &Uri,
204+
content: Option<String>,
205+
) -> Option<Vec<DiagnosticReport>> {
204206
if self.is_ignored(uri) {
205207
return None;
206208
}
207209

208-
self.isolated_linter.run_single(uri, content)
210+
self.isolated_linter.lock().await.run_single(uri, content)
209211
}
210212
}
211213

crates/oxc_language_server/src/worker.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl WorkspaceWorker {
159159
return None;
160160
};
161161

162-
server_linter.run_single(uri, content)
162+
server_linter.run_single(uri, content).await
163163
}
164164

165165
fn update_diagnostics(&self, uri: &Uri, diagnostics: &[DiagnosticReport]) {
@@ -178,7 +178,8 @@ impl WorkspaceWorker {
178178
};
179179

180180
for uri in self.diagnostics_report_map.pin_owned().keys() {
181-
if let Some(diagnostics) = server_linter.run_single(&Uri::from_str(uri).unwrap(), None)
181+
if let Some(diagnostics) =
182+
server_linter.run_single(&Uri::from_str(uri).unwrap(), None).await
182183
{
183184
self.diagnostics_report_map.pin().insert(uri.clone(), diagnostics.clone());
184185
diagnostics_map.pin().insert(uri.clone(), diagnostics);

crates/oxc_linter/src/service/mod.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ impl LintServiceOptions {
6161
}
6262
}
6363

64-
pub struct LintService<'l> {
65-
runtime: Runtime<'l>,
64+
pub struct LintService {
65+
runtime: Runtime,
6666
}
6767

68-
impl<'l> LintService<'l> {
68+
impl LintService {
6969
pub fn new(
70-
linter: &'l Linter,
70+
linter: Linter,
7171
allocator_pool: oxc_allocator::AllocatorPool,
7272
options: LintServiceOptions,
7373
) -> Self {
@@ -77,16 +77,16 @@ impl<'l> LintService<'l> {
7777

7878
#[must_use]
7979
pub fn with_file_system(
80-
mut self,
80+
&mut self,
8181
file_system: Box<dyn RuntimeFileSystem + Sync + Send>,
82-
) -> Self {
83-
self.runtime = self.runtime.with_file_system(file_system);
82+
) -> &mut Self {
83+
self.runtime.with_file_system(file_system);
8484
self
8585
}
8686

8787
#[must_use]
88-
pub fn with_paths(mut self, paths: Vec<Arc<OsStr>>) -> Self {
89-
self.runtime = self.runtime.with_paths(paths);
88+
pub fn with_paths(&mut self, paths: Vec<Arc<OsStr>>) -> &mut Self {
89+
self.runtime.with_paths(paths);
9090
self
9191
}
9292

crates/oxc_linter/src/service/runtime.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ use crate::{
3434
#[cfg(feature = "language_server")]
3535
use crate::fixer::MessageWithPosition;
3636

37-
pub struct Runtime<'l> {
37+
pub struct Runtime {
3838
cwd: Box<Path>,
3939
/// All paths to lint
4040
paths: IndexSet<Arc<OsStr>, FxBuildHasher>,
41-
pub(super) linter: &'l Linter,
41+
pub(super) linter: Linter,
4242
resolver: Option<Resolver>,
4343

4444
pub(super) file_system: Box<dyn RuntimeFileSystem + Sync + Send>,
@@ -176,9 +176,9 @@ impl RuntimeFileSystem for OsFileSystem {
176176
}
177177
}
178178

179-
impl<'l> Runtime<'l> {
179+
impl Runtime {
180180
pub(super) fn new(
181-
linter: &'l Linter,
181+
linter: Linter,
182182
allocator_pool: AllocatorPool,
183183
options: LintServiceOptions,
184184
) -> Self {
@@ -196,14 +196,14 @@ impl<'l> Runtime<'l> {
196196
}
197197

198198
pub fn with_file_system(
199-
mut self,
199+
&mut self,
200200
file_system: Box<dyn RuntimeFileSystem + Sync + Send>,
201-
) -> Self {
201+
) -> &Self {
202202
self.file_system = file_system;
203203
self
204204
}
205205

206-
pub fn with_paths(mut self, paths: Vec<Arc<OsStr>>) -> Self {
206+
pub fn with_paths(&mut self, paths: Vec<Arc<OsStr>>) -> &Self {
207207
self.paths = paths.into_iter().collect();
208208
self
209209
}

crates/oxc_linter/src/tester.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ impl Tester {
538538
let cwd = self.current_working_directory.clone();
539539
let paths = vec![Arc::<OsStr>::from(path_to_lint.as_os_str())];
540540
let options = LintServiceOptions::new(cwd).with_cross_module(self.plugins.has_import());
541-
let mut lint_service = LintService::new(&linter, AllocatorPool::default(), options)
541+
let mut lint_service = LintService::new(linter, AllocatorPool::default(), options);
542+
let _ = lint_service
542543
.with_file_system(Box::new(TesterFileSystem::new(
543544
path_to_lint,
544545
source_text.to_string(),

0 commit comments

Comments
 (0)