mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-12 18:16:43 +00:00
Fixed diagnostics files uri handling, added low-level tests
This commit is contained in:
1 parent
d198d67a9f
commit
bd7e64e85a
91 files changed
+958
-72
No files matched your search
+3
-1
@@ -79,6 +79,8 @@ downloads/
|
|||||||
eggs/
|
eggs/
|
||||||
.eggs/
|
.eggs/
|
||||||
lib/
|
lib/
|
||||||
|
!test/resources/repos/dart/test_repo/lib/
|
||||||
|
!test/resources/repos/dart/test_repo/lib/diagnostics_sample.dart
|
||||||
lib64/
|
lib64/
|
||||||
parts/
|
parts/
|
||||||
sdist/
|
sdist/
|
||||||
@@ -271,4 +273,4 @@ cabal.project.local*
|
|||||||
zz-misc/
|
zz-misc/
|
||||||
vue-implementation/
|
vue-implementation/
|
||||||
|
|
||||||
news/news.json
|
news/news.json
|
||||||
@@ -28,6 +28,7 @@ project_name: "serena"
|
|||||||
languages:
|
languages:
|
||||||
- python
|
- python
|
||||||
- typescript
|
- typescript
|
||||||
|
- clojure
|
||||||
|
|
||||||
# whether to use project's .gitignore files to ignore files
|
# whether to use project's .gitignore files to ignore files
|
||||||
ignore_all_files_in_gitignore: true
|
ignore_all_files_in_gitignore: true
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from serena.tools import (
|
|||||||
JetBrainsFindSymbolTool,
|
JetBrainsFindSymbolTool,
|
||||||
JetBrainsGetSymbolsOverviewTool,
|
JetBrainsGetSymbolsOverviewTool,
|
||||||
JetBrainsInlineSymbol,
|
JetBrainsInlineSymbol,
|
||||||
|
JetBrainsRunInspectionsTool,
|
||||||
JetBrainsSafeDeleteTool,
|
JetBrainsSafeDeleteTool,
|
||||||
SearchForPatternTool,
|
SearchForPatternTool,
|
||||||
)
|
)
|
||||||
@@ -35,12 +36,13 @@ if __name__ == "__main__":
|
|||||||
overview_tool = agent.get_tool(JetBrainsGetSymbolsOverviewTool)
|
overview_tool = agent.get_tool(JetBrainsGetSymbolsOverviewTool)
|
||||||
safe_delete_tool = agent.get_tool(JetBrainsSafeDeleteTool)
|
safe_delete_tool = agent.get_tool(JetBrainsSafeDeleteTool)
|
||||||
inline_symbol = agent.get_tool(JetBrainsInlineSymbol)
|
inline_symbol = agent.get_tool(JetBrainsInlineSymbol)
|
||||||
|
diagnostics_in_file_tool = agent.get_tool(GetDiagnosticsForFileTool)
|
||||||
|
jb_inspections_tool = agent.get_tool(JetBrainsRunInspectionsTool)
|
||||||
|
|
||||||
result = agent.execute_task(
|
result = agent.execute_task(
|
||||||
lambda: overview_tool.apply(
|
lambda: overview_tool.apply(
|
||||||
# name_path_pattern="SerenaAgent",
|
# name_path_pattern="SerenaAgent",
|
||||||
relative_path="src/serena/agent.py",
|
relative_path="test/resources/repos/clojure/test_repo/src/test_app/diagnostics_sample.clj",
|
||||||
depth=2,
|
|
||||||
# keep_definition=True,
|
# keep_definition=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -689,7 +689,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
|||||||
request_data["startLine"] = start_line
|
request_data["startLine"] = start_line
|
||||||
if end_line is not None:
|
if end_line is not None:
|
||||||
request_data["endLine"] = end_line
|
request_data["endLine"] = end_line
|
||||||
return cast(jb.RunInspectionsResponse, self._make_request("POST", "/runInspections", request_data))
|
return cast(jb.RunInspectionsResponse, self._make_request("POST", "/runInspectionsOnFile", request_data))
|
||||||
|
|
||||||
def list_inspections(
|
def list_inspections(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
Creates an ElmLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
Creates an ElmLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||||
"""
|
"""
|
||||||
elm_lsp_executable_path = self._setup_runtime_dependencies(config, solidlsp_settings)
|
elm_lsp_executable_path = self._setup_runtime_dependencies(config, solidlsp_settings)
|
||||||
|
managed_bin_dir = os.path.join(self.ls_resources_dir(solidlsp_settings), "elm-lsp", "node_modules", ".bin")
|
||||||
|
|
||||||
# Resolve ELM_HOME to absolute path if it's set to a relative path
|
# Resolve ELM_HOME to absolute path if it's set to a relative path
|
||||||
env = {}
|
env = {"PATH": managed_bin_dir + os.pathsep + os.environ.get("PATH", "")}
|
||||||
elm_home = os.environ.get("ELM_HOME")
|
elm_home = os.environ.get("ELM_HOME")
|
||||||
if elm_home:
|
if elm_home:
|
||||||
if not os.path.isabs(elm_home):
|
if not os.path.isabs(elm_home):
|
||||||
@@ -65,9 +66,15 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
"""
|
"""
|
||||||
Setup runtime dependencies for Elm Language Server and return the command to start the server.
|
Setup runtime dependencies for Elm Language Server and return the command to start the server.
|
||||||
"""
|
"""
|
||||||
# Check if elm-language-server is already installed globally
|
elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM)
|
||||||
|
elm_language_server_version = elm_config.get("elm_language_server_version", "2.8.0")
|
||||||
|
elm_compiler_version = elm_config.get("elm_compiler_version", "0.19.1-6")
|
||||||
|
npm_registry = elm_config.get("npm_registry")
|
||||||
|
|
||||||
|
# Check if elm-language-server and elm are already installed globally
|
||||||
system_elm_ls = shutil.which("elm-language-server")
|
system_elm_ls = shutil.which("elm-language-server")
|
||||||
if system_elm_ls:
|
system_elm = shutil.which("elm")
|
||||||
|
if system_elm_ls and system_elm:
|
||||||
log.info(f"Found system-installed elm-language-server at {system_elm_ls}")
|
log.info(f"Found system-installed elm-language-server at {system_elm_ls}")
|
||||||
return [system_elm_ls, "--stdio"]
|
return [system_elm_ls, "--stdio"]
|
||||||
|
|
||||||
@@ -76,10 +83,6 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
|
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
|
||||||
is_npm_installed = shutil.which("npm") is not None
|
is_npm_installed = shutil.which("npm") is not None
|
||||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||||
elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM)
|
|
||||||
elm_language_server_version = elm_config.get("elm_language_server_version", "2.8.0")
|
|
||||||
npm_registry = elm_config.get("npm_registry")
|
|
||||||
|
|
||||||
deps = RuntimeDependencyCollection(
|
deps = RuntimeDependencyCollection(
|
||||||
[
|
[
|
||||||
RuntimeDependency(
|
RuntimeDependency(
|
||||||
@@ -88,6 +91,12 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
command=build_npm_install_command("@elm-tooling/elm-language-server", elm_language_server_version, npm_registry),
|
command=build_npm_install_command("@elm-tooling/elm-language-server", elm_language_server_version, npm_registry),
|
||||||
platform_id="any",
|
platform_id="any",
|
||||||
),
|
),
|
||||||
|
RuntimeDependency(
|
||||||
|
id="elm",
|
||||||
|
description="Elm compiler package",
|
||||||
|
command=build_npm_install_command("elm", elm_compiler_version, npm_registry),
|
||||||
|
platform_id="any",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -98,6 +107,10 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
log.info(f"Elm Language Server executable not found at {elm_ls_executable_path}. Installing...")
|
log.info(f"Elm Language Server executable not found at {elm_ls_executable_path}. Installing...")
|
||||||
with LogTime("Installation of Elm language server dependencies", logger=log):
|
with LogTime("Installation of Elm language server dependencies", logger=log):
|
||||||
deps.install(elm_ls_dir)
|
deps.install(elm_ls_dir)
|
||||||
|
elif not system_elm:
|
||||||
|
log.info("Elm compiler not found on PATH. Installing a managed Elm compiler...")
|
||||||
|
with LogTime("Installation of Elm compiler dependency", logger=log):
|
||||||
|
deps.install(elm_ls_dir)
|
||||||
|
|
||||||
if not os.path.exists(elm_ls_executable_path):
|
if not os.path.exists(elm_ls_executable_path):
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
@@ -128,6 +141,7 @@ class ElmLanguageServer(SolidLanguageServer):
|
|||||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||||
"codeAction": {"dynamicRegistration": True},
|
"codeAction": {"dynamicRegistration": True},
|
||||||
"rename": {"dynamicRegistration": True},
|
"rename": {"dynamicRegistration": True},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ class FortranLanguageServer(SolidLanguageServer):
|
|||||||
"formatting": {"dynamicRegistration": True},
|
"formatting": {"dynamicRegistration": True},
|
||||||
"rangeFormatting": {"dynamicRegistration": True},
|
"rangeFormatting": {"dynamicRegistration": True},
|
||||||
"codeAction": {"dynamicRegistration": True},
|
"codeAction": {"dynamicRegistration": True},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ class Lean4LanguageServer(SolidLanguageServer):
|
|||||||
"documentationFormat": ["markdown", "plaintext"],
|
"documentationFormat": ["markdown", "plaintext"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -777,6 +777,14 @@ class PascalLanguageServer(SolidLanguageServer):
|
|||||||
if value:
|
if value:
|
||||||
initialization_options[var] = value
|
initialization_options[var] = value
|
||||||
|
|
||||||
|
initialization_options.update(
|
||||||
|
{
|
||||||
|
"checkSyntax": True,
|
||||||
|
"publishDiagnostics": True,
|
||||||
|
"showSyntaxErrors": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
initialize_params = {
|
initialize_params = {
|
||||||
"locale": "en",
|
"locale": "en",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
@@ -831,6 +839,7 @@ class PascalLanguageServer(SolidLanguageServer):
|
|||||||
},
|
},
|
||||||
"formatting": {"dynamicRegistration": True},
|
"formatting": {"dynamicRegistration": True},
|
||||||
"rangeFormatting": {"dynamicRegistration": True},
|
"rangeFormatting": {"dynamicRegistration": True},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ class SolidityLanguageServer(SolidLanguageServer):
|
|||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"contentFormat": ["markdown", "plaintext"], # type: ignore[list-item]
|
"contentFormat": ["markdown", "plaintext"], # type: ignore[list-item]
|
||||||
},
|
},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
|||||||
self.server_ready = threading.Event()
|
self.server_ready = threading.Event()
|
||||||
self.initialize_searcher_command_available = threading.Event()
|
self.initialize_searcher_command_available = threading.Event()
|
||||||
|
|
||||||
# Progress tracking for $/progress notifications (project indexing, etc.)
|
# tracking asynchronous diagnostics publication
|
||||||
|
self._published_diagnostics_timeout = 5.0
|
||||||
|
|
||||||
|
# tracking project indexing progress
|
||||||
self._progress_lock = threading.Lock()
|
self._progress_lock = threading.Lock()
|
||||||
self._active_progress_tokens: set[str] = set()
|
self._active_progress_tokens: set[str] = set()
|
||||||
self._indexing_complete = threading.Event()
|
self._indexing_complete = threading.Event()
|
||||||
@@ -243,9 +246,11 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
|||||||
"signatureHelp": {"dynamicRegistration": True},
|
"signatureHelp": {"dynamicRegistration": True},
|
||||||
"codeAction": {"dynamicRegistration": True},
|
"codeAction": {"dynamicRegistration": True},
|
||||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
"configuration": True,
|
||||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||||
"symbol": {"dynamicRegistration": True},
|
"symbol": {"dynamicRegistration": True},
|
||||||
},
|
},
|
||||||
@@ -293,6 +298,10 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
|||||||
def execute_client_command_handler(params: dict) -> list:
|
def execute_client_command_handler(params: dict) -> list:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def configuration_handler(params: dict) -> list:
|
||||||
|
items = params.get("items", [])
|
||||||
|
return [{} for _ in items]
|
||||||
|
|
||||||
def do_nothing(params: dict) -> None:
|
def do_nothing(params: dict) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -352,6 +361,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
|||||||
self._indexing_complete.set()
|
self._indexing_complete.set()
|
||||||
|
|
||||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||||
|
self.server.on_request("workspace/configuration", configuration_handler)
|
||||||
self.server.on_notification("window/logMessage", window_log_message)
|
self.server.on_notification("window/logMessage", window_log_message)
|
||||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||||
self.server.on_request("window/workDoneProgress/create", work_done_progress_create)
|
self.server.on_request("window/workDoneProgress/create", work_done_progress_create)
|
||||||
@@ -397,6 +407,20 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
|||||||
self.INDEXING_PROGRESS_TIMEOUT,
|
self.INDEXING_PROGRESS_TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def _get_published_diagnostics_uri(self, request_uri: str) -> str:
|
||||||
|
if os.name != "nt" or not request_uri.startswith("file:///"):
|
||||||
|
return request_uri
|
||||||
|
|
||||||
|
path_part = request_uri[len("file:///") :]
|
||||||
|
if len(path_part) >= 2 and path_part[0].isalpha() and path_part[1] == ":":
|
||||||
|
return f"file:///{path_part[0].lower()}%3A{path_part[2:]}"
|
||||||
|
return request_uri
|
||||||
|
|
||||||
|
@override
|
||||||
|
def _get_published_diagnostics_wait_timeout(self, pull_diagnostics_failed: bool) -> float:
|
||||||
|
return self._published_diagnostics_timeout
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def _get_wait_time_for_cross_file_referencing(self) -> float:
|
def _get_wait_time_for_cross_file_referencing(self) -> float:
|
||||||
return 2
|
return 2
|
||||||
|
|||||||
@@ -426,6 +426,18 @@ class VueLanguageServer(SolidLanguageServer):
|
|||||||
with self._ts_server.open_file(relative_file_path):
|
with self._ts_server.open_file(relative_file_path):
|
||||||
return self._ts_server.request_rename_symbol_edit(relative_file_path, line, column, new_name)
|
return self._ts_server.request_rename_symbol_edit(relative_file_path, line, column, new_name)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def request_text_document_diagnostics(
|
||||||
|
self,
|
||||||
|
relative_file_path: str,
|
||||||
|
start_line: int = 0,
|
||||||
|
end_line: int = -1,
|
||||||
|
min_severity: int = 4,
|
||||||
|
) -> list[ls_types.Diagnostic]:
|
||||||
|
self._ensure_ls_operational()
|
||||||
|
assert self._ts_server is not None
|
||||||
|
return self._ts_server.request_text_document_diagnostics(relative_file_path, start_line, end_line, min_severity)
|
||||||
|
|
||||||
def _forward_edit_to_ts_server_if_needed(self, relative_file_path: str, edit_fn: Callable[[], object]) -> None:
|
def _forward_edit_to_ts_server_if_needed(self, relative_file_path: str, edit_fn: Callable[[], object]) -> None:
|
||||||
"""
|
"""
|
||||||
Calls ``edit_fn`` on the TypeScript server if the file is open there.
|
Calls ``edit_fn`` on the TypeScript server if the file is open there.
|
||||||
@@ -598,6 +610,7 @@ class VueLanguageServer(SolidLanguageServer):
|
|||||||
"signatureHelp": {"dynamicRegistration": True},
|
"signatureHelp": {"dynamicRegistration": True},
|
||||||
"codeAction": {"dynamicRegistration": True},
|
"codeAction": {"dynamicRegistration": True},
|
||||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class ZigLanguageServer(SolidLanguageServer):
|
|||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"contentFormat": ["markdown", "plaintext"],
|
"contentFormat": ["markdown", "plaintext"],
|
||||||
},
|
},
|
||||||
|
"publishDiagnostics": {"relatedInformation": True},
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"workspaceFolders": True,
|
"workspaceFolders": True,
|
||||||
|
|||||||
+67
-12
@@ -13,7 +13,7 @@ from collections.abc import Hashable, Iterator
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
from time import perf_counter, sleep
|
from time import monotonic, perf_counter, sleep
|
||||||
from typing import Any, Self, Union, cast
|
from typing import Any, Self, Union, cast
|
||||||
|
|
||||||
import pathspec
|
import pathspec
|
||||||
@@ -754,21 +754,77 @@ class SolidLanguageServer(ABC):
|
|||||||
:return: the published diagnostics, or ``None`` if no diagnostics are available.
|
:return: the published diagnostics, or ``None`` if no diagnostics are available.
|
||||||
"""
|
"""
|
||||||
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
||||||
|
published_uri = self._get_published_diagnostics_uri(uri)
|
||||||
diagnostics: list[ls_types.Diagnostic] | None = None
|
diagnostics: list[ls_types.Diagnostic] | None = None
|
||||||
|
|
||||||
# keeping the document open
|
# keeping the document open
|
||||||
with self.open_file(relative_file_path):
|
with self.open_file(relative_file_path):
|
||||||
diagnostics = self._wait_for_published_diagnostics(uri=uri, after_generation=after_generation, timeout=timeout)
|
diagnostics = self._wait_for_relevant_published_diagnostics(
|
||||||
|
uri=published_uri,
|
||||||
# falling back to cached diagnostics
|
after_generation=after_generation,
|
||||||
if diagnostics is None and allow_cached:
|
timeout=timeout,
|
||||||
diagnostics = self._get_cached_published_diagnostics(uri)
|
allow_cached=allow_cached,
|
||||||
|
)
|
||||||
|
|
||||||
if diagnostics is None:
|
if diagnostics is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self._filter_diagnostics(diagnostics, start_line, end_line, min_severity)
|
return self._filter_diagnostics(diagnostics, start_line, end_line, min_severity)
|
||||||
|
|
||||||
|
def _get_published_diagnostics_uri(self, request_uri: str) -> str:
|
||||||
|
"""
|
||||||
|
Gets the URI under which published diagnostics should be looked up.
|
||||||
|
"""
|
||||||
|
return request_uri
|
||||||
|
|
||||||
|
def _get_published_diagnostics_wait_timeout(self, pull_diagnostics_failed: bool) -> float:
|
||||||
|
"""
|
||||||
|
Gets the timeout for waiting on published diagnostics after a diagnostics request.
|
||||||
|
"""
|
||||||
|
return 2.5
|
||||||
|
|
||||||
|
def _accept_published_diagnostics(self, diagnostics: list[ls_types.Diagnostic]) -> bool:
|
||||||
|
"""
|
||||||
|
Determines whether a published diagnostics payload should satisfy the current wait.
|
||||||
|
"""
|
||||||
|
return bool(diagnostics)
|
||||||
|
|
||||||
|
def _wait_for_relevant_published_diagnostics(
|
||||||
|
self,
|
||||||
|
uri: str,
|
||||||
|
after_generation: int,
|
||||||
|
timeout: float,
|
||||||
|
allow_cached: bool = True,
|
||||||
|
) -> list[ls_types.Diagnostic] | None:
|
||||||
|
"""
|
||||||
|
Waits for a published diagnostics payload that is relevant for the current request.
|
||||||
|
"""
|
||||||
|
deadline = monotonic() + timeout
|
||||||
|
current_after_generation = after_generation
|
||||||
|
|
||||||
|
while True:
|
||||||
|
remaining_timeout = deadline - monotonic()
|
||||||
|
if remaining_timeout <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
diagnostics = self._wait_for_published_diagnostics(
|
||||||
|
uri=uri,
|
||||||
|
after_generation=current_after_generation,
|
||||||
|
timeout=remaining_timeout,
|
||||||
|
)
|
||||||
|
if diagnostics is None:
|
||||||
|
break
|
||||||
|
if self._accept_published_diagnostics(diagnostics):
|
||||||
|
return diagnostics
|
||||||
|
current_after_generation = self._get_published_diagnostics_generation(uri)
|
||||||
|
|
||||||
|
if allow_cached:
|
||||||
|
diagnostics = self._get_cached_published_diagnostics(uri)
|
||||||
|
if diagnostics is not None and self._accept_published_diagnostics(diagnostics):
|
||||||
|
return diagnostics
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def request_text_document_diagnostics(
|
def request_text_document_diagnostics(
|
||||||
self,
|
self,
|
||||||
relative_file_path: str,
|
relative_file_path: str,
|
||||||
@@ -789,7 +845,8 @@ class SolidLanguageServer(ABC):
|
|||||||
:return: A list of diagnostics for the file
|
:return: A list of diagnostics for the file
|
||||||
"""
|
"""
|
||||||
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
||||||
diagnostics_before_request = self._get_published_diagnostics_generation(uri)
|
published_uri = self._get_published_diagnostics_uri(uri)
|
||||||
|
diagnostics_before_request = self._get_published_diagnostics_generation(published_uri)
|
||||||
ret: list[ls_types.Diagnostic] | None = None
|
ret: list[ls_types.Diagnostic] | None = None
|
||||||
pull_diagnostics_failed = False
|
pull_diagnostics_failed = False
|
||||||
|
|
||||||
@@ -825,13 +882,11 @@ class SolidLanguageServer(ABC):
|
|||||||
ret.append(ls_types.Diagnostic(**new_item))
|
ret.append(ls_types.Diagnostic(**new_item))
|
||||||
|
|
||||||
if not ret:
|
if not ret:
|
||||||
published_diagnostics = self._wait_for_published_diagnostics(
|
published_diagnostics = self._wait_for_relevant_published_diagnostics(
|
||||||
uri=uri,
|
uri=published_uri,
|
||||||
after_generation=diagnostics_before_request,
|
after_generation=diagnostics_before_request,
|
||||||
timeout=2.5 if pull_diagnostics_failed else 0.5,
|
timeout=self._get_published_diagnostics_wait_timeout(pull_diagnostics_failed),
|
||||||
)
|
)
|
||||||
if published_diagnostics is None:
|
|
||||||
published_diagnostics = self._get_cached_published_diagnostics(uri)
|
|
||||||
if published_diagnostics is not None:
|
if published_diagnostics is not None:
|
||||||
ret = published_diagnostics
|
ret = published_diagnostics
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
if then
|
||||||
|
echo "$missingGreeting"
|
||||||
|
fi
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
def broken_factory : String
|
||||||
|
missingGreeting
|
||||||
|
end
|
||||||
|
|
||||||
|
broken_consumer = missingConsumerValue
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
String brokenFactory() {
|
||||||
|
return 'broken'
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
defmodule DiagnosticsSample do
|
||||||
|
def broken_factory do
|
||||||
|
missing_greeting
|
||||||
|
end
|
||||||
|
|
||||||
|
def broken_consumer do
|
||||||
|
value = broken_factory()
|
||||||
|
{value, missing_consumer_value}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module DiagnosticsSample exposing (brokenFactory)
|
||||||
|
|
||||||
|
brokenFactory : String
|
||||||
|
brokenFactory =
|
||||||
|
"unterminated
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-module(diagnostics_sample).
|
||||||
|
-export([broken_factory/0, broken_consumer/0]).
|
||||||
|
|
||||||
|
broken_factory() -> MissingGreeting.
|
||||||
|
broken_consumer() -> MissingConsumerValue.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
program diagnostics_sample
|
||||||
|
implicit none
|
||||||
|
integer :: duplicated_value
|
||||||
|
real :: duplicated_value
|
||||||
|
end program diagnostics_sample
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example
|
||||||
|
|
||||||
|
class DiagnosticsSample {
|
||||||
|
static String brokenFactory() {
|
||||||
|
missingGreeting
|
||||||
|
}
|
||||||
|
|
||||||
|
static void brokenConsumer() {
|
||||||
|
def value = brokenFactory()
|
||||||
|
println(value)
|
||||||
|
println(missingConsumerValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
module DiagnosticsSample where
|
||||||
|
|
||||||
|
brokenFactory :: String
|
||||||
|
brokenFactory = missingGreeting
|
||||||
|
|
||||||
|
brokenConsumer :: String
|
||||||
|
brokenConsumer = missingConsumerValue
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class DiagnosticsSample {
|
||||||
|
static function brokenFactory():String {
|
||||||
|
return missingGreeting;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function brokenConsumer():Void {
|
||||||
|
trace(brokenFactory());
|
||||||
|
trace(missingConsumerValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
float4 main() : SV_Target {
|
||||||
|
return missingGreeting;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"name": "diagnostics",
|
||||||
|
"value":
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
function broken_factory(
|
||||||
|
value = 1
|
||||||
|
end
|
||||||
@@ -1,6 +1 @@
|
|||||||
def brokenFactory : Nat :=
|
def brokenFactory : Nat :=
|
||||||
missingGreeting
|
|
||||||
|
|
||||||
def brokenConsumer : Nat :=
|
|
||||||
let value := brokenFactory
|
|
||||||
value + missingConsumerValue
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
function value = diagnostics_sample()
|
||||||
|
value = missingGreeting;
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
greeting = missingGreeting;
|
||||||
|
consumer = missingConsumerValue;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
let broken_factory (
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
(library
|
(library
|
||||||
(public_name test_repo)
|
(public_name test_repo)
|
||||||
(name test_repo))
|
(name test_repo)
|
||||||
|
(modules test_repo))
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
program DiagnosticsSample;
|
||||||
|
begin
|
||||||
|
writeln(
|
||||||
|
end.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
print $missingGreeting;
|
||||||
|
print $missingConsumerValue;
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
function Invoke-BrokenFactory {
|
function Invoke-BrokenFactory {
|
||||||
Invoke-MissingGreeting
|
if ($true) {
|
||||||
}
|
Write-Output "broken"
|
||||||
|
|
||||||
function Invoke-BrokenConsumer {
|
|
||||||
$value = Invoke-BrokenFactory
|
|
||||||
Write-Output $value
|
|
||||||
Invoke-MissingConsumerValue
|
|
||||||
}
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.example
|
||||||
|
|
||||||
|
object DiagnosticsSample {
|
||||||
|
def brokenFactory(): String = missingGreeting
|
||||||
|
def brokenConsumer(): Unit = {
|
||||||
|
println(brokenFactory())
|
||||||
|
println(missingConsumerValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
contract DiagnosticsSample {
|
||||||
|
function brokenFactory() pure returns (string memory) {
|
||||||
|
return "broken";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ let package = Package(
|
|||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
name: "test_repo",
|
name: "test_repo",
|
||||||
dependencies: []),
|
dependencies: [],
|
||||||
|
path: "src"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
func brokenFactory() -> String {
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module diagnostics_sample;
|
||||||
|
initial begin
|
||||||
|
if (
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
resource "aws_instance" "broken" {
|
||||||
|
ami =
|
||||||
|
instance_type = "t2.micro"
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[diagnostics]
|
||||||
|
value =
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const value: string =
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
name: diagnostics
|
||||||
|
value:
|
||||||
|
- good
|
||||||
|
-
|
||||||
|
broken: [
|
||||||
@@ -28,4 +28,4 @@ pub fn build(b: *std.Build) void {
|
|||||||
const run_lib_tests = b.addRunArtifact(lib_tests);
|
const run_lib_tests = b.addRunArtifact(lib_tests);
|
||||||
const test_step = b.step("test", "Run unit tests");
|
const test_step = b.step("test", "Run unit tests");
|
||||||
test_step.dependOn(&run_lib_tests.step);
|
test_step.dependOn(&run_lib_tests.step);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn brokenFactory() void {
|
||||||
|
const value =
|
||||||
|
}
|
||||||
@@ -29,4 +29,4 @@ pub fn main() !void {
|
|||||||
|
|
||||||
pub fn greeting(name: []const u8) []const u8 {
|
pub fn greeting(name: []const u8) []const u8 {
|
||||||
return std.fmt.allocPrint(std.heap.page_allocator, "Hello, {s}!", .{name}) catch "Hello!";
|
return std.fmt.allocPrint(std.heap.page_allocator, "Hello, {s}!", .{name}) catch "Hello!";
|
||||||
}
|
}
|
||||||
@@ -68,13 +68,13 @@
|
|||||||
# name: test_delete_symbol[test_case1]
|
# name: test_delete_symbol[test_case1]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
@@ -521,7 +521,7 @@
|
|||||||
# name: test_insert_in_rel_to_symbol[test_case1-after]
|
# name: test_insert_in_rel_to_symbol[test_case1-after]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
export class DemoClass {
|
export class DemoClass {
|
||||||
value: number;
|
value: number;
|
||||||
constructor(value: number) {
|
constructor(value: number) {
|
||||||
@@ -539,7 +539,7 @@
|
|||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
@@ -555,7 +555,7 @@
|
|||||||
# name: test_insert_in_rel_to_symbol[test_case1-before]
|
# name: test_insert_in_rel_to_symbol[test_case1-before]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
function newFunctionAfterClass(): void {
|
function newFunctionAfterClass(): void {
|
||||||
console.log("This function is after DemoClass.");
|
console.log("This function is after DemoClass.");
|
||||||
}
|
}
|
||||||
@@ -573,7 +573,7 @@
|
|||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
@@ -589,7 +589,7 @@
|
|||||||
# name: test_insert_in_rel_to_symbol[test_case2-after]
|
# name: test_insert_in_rel_to_symbol[test_case2-after]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
export class DemoClass {
|
export class DemoClass {
|
||||||
value: number;
|
value: number;
|
||||||
constructor(value: number) {
|
constructor(value: number) {
|
||||||
@@ -603,7 +603,7 @@
|
|||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
@@ -623,7 +623,7 @@
|
|||||||
# name: test_insert_in_rel_to_symbol[test_case2-before]
|
# name: test_insert_in_rel_to_symbol[test_case2-before]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
export class DemoClass {
|
export class DemoClass {
|
||||||
value: number;
|
value: number;
|
||||||
constructor(value: number) {
|
constructor(value: number) {
|
||||||
@@ -641,7 +641,7 @@
|
|||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
@@ -1712,7 +1712,7 @@
|
|||||||
# name: test_replace_body[test_case1]
|
# name: test_replace_body[test_case1]
|
||||||
'''
|
'''
|
||||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||||
|
|
||||||
export class DemoClass {
|
export class DemoClass {
|
||||||
value: number;
|
value: number;
|
||||||
constructor(value: number) {
|
constructor(value: number) {
|
||||||
@@ -1727,7 +1727,7 @@
|
|||||||
export function helperFunction() {
|
export function helperFunction() {
|
||||||
const demo = new DemoClass(42);
|
const demo = new DemoClass(42);
|
||||||
demo.printValue();
|
demo.printValue();
|
||||||
|
|
||||||
const greeter: Greeter = new ConsoleGreeter();
|
const greeter: Greeter = new ConsoleGreeter();
|
||||||
console.log(greeter.formatGreeting("World"));
|
console.log(greeter.formatGreeting("World"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.bash
|
||||||
|
class TestBashDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.BASH], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.sh",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -13,8 +13,8 @@ def _test_clojure_cli() -> bool:
|
|||||||
|
|
||||||
CLI_FAIL = _test_clojure_cli()
|
CLI_FAIL = _test_clojure_cli()
|
||||||
TEST_APP_PATH = Path("src") / "test_app"
|
TEST_APP_PATH = Path("src") / "test_app"
|
||||||
CORE_PATH = str(TEST_APP_PATH / "core.clj").replace("\\", "/")
|
CORE_PATH = str(TEST_APP_PATH / "core.clj")
|
||||||
UTILS_PATH = str(TEST_APP_PATH / "utils.clj").replace("\\", "/")
|
UTILS_PATH = str(TEST_APP_PATH / "utils.clj")
|
||||||
|
|
||||||
|
|
||||||
def is_clojure_cli_available() -> bool:
|
def is_clojure_cli_available() -> bool:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.clojure
|
||||||
|
class TestClojureDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
os.path.join("src", "test_app", "diagnostics_sample.clj"),
|
||||||
|
("missing-greeting", "missing-consumer-value"),
|
||||||
|
min_count=2,
|
||||||
|
)
|
||||||
@@ -5,6 +5,12 @@ from solidlsp.ls_types import SymbolKind, UnifiedSymbolInformation
|
|||||||
PYTHON_BACKEND_LANGUAGES = [Language.PYTHON, Language.PYTHON_TY]
|
PYTHON_BACKEND_LANGUAGES = [Language.PYTHON, Language.PYTHON_TY]
|
||||||
|
|
||||||
|
|
||||||
|
def is_diagnostics_test_file(relative_path: str) -> bool:
|
||||||
|
normalized_path = relative_path.replace("\\", "/")
|
||||||
|
filename = normalized_path.rsplit("/", 1)[-1].lower()
|
||||||
|
return filename.startswith(("diagnosticssample.", "diagnostics_sample."))
|
||||||
|
|
||||||
|
|
||||||
def has_malformed_name(
|
def has_malformed_name(
|
||||||
symbol: UnifiedSymbolInformation,
|
symbol: UnifiedSymbolInformation,
|
||||||
whitespace_allowed: bool = False,
|
whitespace_allowed: bool = False,
|
||||||
@@ -36,6 +42,9 @@ def request_all_symbols(language_server: SolidLanguageServer) -> list[UnifiedSym
|
|||||||
result: list[UnifiedSymbolInformation] = []
|
result: list[UnifiedSymbolInformation] = []
|
||||||
|
|
||||||
def visit(symbol: UnifiedSymbolInformation) -> None:
|
def visit(symbol: UnifiedSymbolInformation) -> None:
|
||||||
|
relative_path = symbol.get("location", {}).get("relativePath", "")
|
||||||
|
if relative_path and is_diagnostics_test_file(relative_path):
|
||||||
|
return
|
||||||
result.append(symbol)
|
result.append(symbol)
|
||||||
for child in symbol.get("children", []):
|
for child in symbol.get("children", []):
|
||||||
visit(child)
|
visit(child)
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.cpp
|
||||||
|
class TestCppDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.CPP], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.cpp",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import shutil
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
pytestmark = [
|
||||||
|
pytest.mark.crystal,
|
||||||
|
pytest.mark.skipif(shutil.which("crystalline") is None, reason="Crystalline is not installed"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TestCrystalDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/diagnostics_sample.cr",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.csharp
|
||||||
|
class TestCsharpDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"DiagnosticsSample.cs",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.dart
|
||||||
|
class TestDartDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.DART], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"lib/diagnostics_sample.dart",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -13,6 +13,7 @@ from solidlsp import SolidLanguageServer
|
|||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from solidlsp.ls_types import SymbolKind
|
from solidlsp.ls_types import SymbolKind
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
from . import EXPERT_UNAVAILABLE, EXPERT_UNAVAILABLE_REASON
|
from . import EXPERT_UNAVAILABLE, EXPERT_UNAVAILABLE_REASON
|
||||||
|
|
||||||
@@ -138,3 +139,12 @@ class TestElixirBasic:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"lib/diagnostics_sample.ex",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import shutil
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.elm
|
||||||
|
@pytest.mark.skipif(shutil.which("node") is None or shutil.which("npm") is None, reason="Elm diagnostics require Node.js and npm")
|
||||||
|
class TestElmDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.ELM], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"DiagnosticsSample.elm",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -10,6 +10,7 @@ import pytest
|
|||||||
from solidlsp import SolidLanguageServer
|
from solidlsp import SolidLanguageServer
|
||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
from . import ERLANG_LS_UNAVAILABLE, ERLANG_LS_UNAVAILABLE_REASON
|
from . import ERLANG_LS_UNAVAILABLE, ERLANG_LS_UNAVAILABLE_REASON
|
||||||
|
|
||||||
@@ -55,3 +56,12 @@ class TestErlangLanguageServerBasics:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/diagnostics_sample.erl",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.fortran
|
||||||
|
class TestFortranDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.f90",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -9,6 +9,7 @@ from solidlsp.ls_config import Language
|
|||||||
from solidlsp.ls_utils import SymbolUtils
|
from solidlsp.ls_utils import SymbolUtils
|
||||||
from test.conftest import find_identifier_position, get_repo_path, is_ci, language_has_verified_implementation_support
|
from test.conftest import find_identifier_position, get_repo_path, is_ci, language_has_verified_implementation_support
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
# Currently, most F# tests fail, there seems to be a regression or instability.
|
# Currently, most F# tests fail, there seems to be a regression or instability.
|
||||||
@@ -196,21 +197,13 @@ class TestFSharpLanguageServer:
|
|||||||
assert isinstance(result["value"], list), "Completions should be a list"
|
assert isinstance(result["value"], list), "Completions should be a list"
|
||||||
|
|
||||||
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
||||||
def test_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
"""Test getting diagnostics (errors, warnings) from F# files."""
|
assert_file_diagnostics(
|
||||||
file_path = os.path.join("Program.fs")
|
language_server,
|
||||||
|
"DiagnosticsSample.fs",
|
||||||
# FsAutoComplete uses publishDiagnostics notifications instead of textDocument/diagnostic requests
|
(),
|
||||||
# So we'll test that the language server can handle files without crashing
|
min_count=1,
|
||||||
# In real usage, diagnostics would come through the publishDiagnostics notification handler
|
)
|
||||||
|
|
||||||
# Test that we can at least work with the file (open/close cycle)
|
|
||||||
with language_server.open_file(file_path) as _:
|
|
||||||
# If we can open and close the file without errors, basic diagnostics support is working
|
|
||||||
pass
|
|
||||||
|
|
||||||
# This is a successful test - FsAutoComplete is working with F# files
|
|
||||||
assert True, "F# language server can handle files successfully"
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
||||||
def test_bare_symbol_names(self, language_server) -> None:
|
def test_bare_symbol_names(self, language_server) -> None:
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.go
|
||||||
|
class TestGoDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.GO], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.go",
|
||||||
|
("missingGreeting", "missingConsumerValue"),
|
||||||
|
min_count=2,
|
||||||
|
)
|
||||||
@@ -9,6 +9,7 @@ from solidlsp.ls_config import Language, LanguageServerConfig
|
|||||||
from solidlsp.ls_utils import SymbolUtils
|
from solidlsp.ls_utils import SymbolUtils
|
||||||
from solidlsp.settings import SolidLSPSettings
|
from solidlsp.settings import SolidLSPSettings
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.groovy
|
@pytest.mark.groovy
|
||||||
@@ -117,3 +118,12 @@ class TestGroovyLanguageServer:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_file_diagnostics(self) -> None:
|
||||||
|
assert self.language_server is not None
|
||||||
|
assert_file_diagnostics(
|
||||||
|
self.language_server,
|
||||||
|
"src/main/groovy/com/example/DiagnosticsSample.groovy",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -21,6 +21,7 @@ from solidlsp.ls import SolidLanguageServer
|
|||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from solidlsp.ls_types import SymbolKind
|
from solidlsp.ls_types import SymbolKind
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.haskell
|
@pytest.mark.haskell
|
||||||
@@ -240,3 +241,12 @@ class TestHaskellLanguageServer:
|
|||||||
for sym in malformed_symbols
|
for sym in malformed_symbols
|
||||||
]
|
]
|
||||||
pytest.fail(f"Found malformed symbols: {diagnostics}", pytrace=False)
|
pytest.fail(f"Found malformed symbols: {diagnostics}", pytrace=False)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/DiagnosticsSample.hs",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.haxe
|
||||||
|
class TestHaxeDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/DiagnosticsSample.hx",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.hlsl
|
||||||
|
class TestHlslDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.hlsl",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.java
|
||||||
|
class TestJavaDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/main/java/test_repo/DiagnosticsSample.java",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.json
|
||||||
|
class TestJsonDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.JSON], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.json",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -6,6 +6,7 @@ from solidlsp.ls import SolidLanguageServer
|
|||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from test.conftest import is_ci
|
from test.conftest import is_ci
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(shutil.which("julia") is None and not is_ci, reason="Julia is not available")
|
@pytest.mark.skipif(shutil.which("julia") is None and not is_ci, reason="Julia is not available")
|
||||||
@@ -66,3 +67,12 @@ class TestJuliaLanguageServer:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.jl",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.kotlin
|
||||||
|
class TestKotlinDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/main/kotlin/test_repo/DiagnosticsSample.kt",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.lean4
|
||||||
|
class TestLean4Diagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"DiagnosticsSample.lean",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -17,6 +17,7 @@ import pytest
|
|||||||
from solidlsp import SolidLanguageServer
|
from solidlsp import SolidLanguageServer
|
||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
# Skip all tests if MATLAB is not available
|
# Skip all tests if MATLAB is not available
|
||||||
pytestmark = pytest.mark.matlab
|
pytestmark = pytest.mark.matlab
|
||||||
@@ -129,3 +130,12 @@ class TestMatlabLanguageServerReferences:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.m",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -13,6 +13,7 @@ from solidlsp.ls_config import Language
|
|||||||
from solidlsp.ls_types import SymbolKind
|
from solidlsp.ls_types import SymbolKind
|
||||||
from test.conftest import is_ci
|
from test.conftest import is_ci
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
# Skip all Nix tests on Windows as Nix doesn't support Windows
|
# Skip all Nix tests on Windows as Nix doesn't support Windows
|
||||||
pytestmark = pytest.mark.skipif(platform.system() == "Windows", reason="Nix and nil are not available on Windows")
|
pytestmark = pytest.mark.skipif(platform.system() == "Windows", reason="Nix and nil are not available on Windows")
|
||||||
@@ -250,3 +251,12 @@ class TestNixLanguageServer:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.NIX], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.nix",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.ocaml
|
||||||
|
class TestOcamlDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"lib/diagnostics_sample.ml",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import shutil
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.conftest import language_tests_enabled
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
pytestmark = [
|
||||||
|
pytest.mark.pascal,
|
||||||
|
pytest.mark.skipif(not language_tests_enabled(Language.PASCAL), reason="Pascal tests are disabled"),
|
||||||
|
pytest.mark.skipif(shutil.which("fpc") is None, reason="Pascal diagnostics require the Free Pascal compiler"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TestPascalDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.pas",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -6,6 +6,7 @@ import pytest
|
|||||||
from solidlsp import SolidLanguageServer
|
from solidlsp import SolidLanguageServer
|
||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.perl
|
@pytest.mark.perl
|
||||||
@@ -88,3 +89,12 @@ class TestPerlLanguageServer:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.PERL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.pl",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.php
|
||||||
|
class TestPhpDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.php",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.powershell
|
||||||
|
class TestPowershellDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.ps1",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from test.conftest import PYTHON_LANGUAGE_BACKENDS
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.python
|
||||||
|
class TestPythonDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", PYTHON_LANGUAGE_BACKENDS, indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
os.path.join("test_repo", "diagnostics_sample.py"),
|
||||||
|
("missing_user", "undefined_name"),
|
||||||
|
min_count=2,
|
||||||
|
)
|
||||||
@@ -90,7 +90,7 @@ class TestRustLanguageServer:
|
|||||||
all_symbols = request_all_symbols(language_server)
|
all_symbols = request_all_symbols(language_server)
|
||||||
malformed_symbols = []
|
malformed_symbols = []
|
||||||
for s in all_symbols:
|
for s in all_symbols:
|
||||||
if has_malformed_name(s):
|
if has_malformed_name(s, whitespace_allowed=True):
|
||||||
malformed_symbols.append(s)
|
malformed_symbols.append(s)
|
||||||
if malformed_symbols:
|
if malformed_symbols:
|
||||||
pytest.fail(
|
pytest.fail(
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.rust
|
||||||
|
class TestRustDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.RUST], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/diagnostics_sample.rs",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -6,6 +6,7 @@ import pytest
|
|||||||
from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
|
from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
|
||||||
from solidlsp.ls_config import Language, LanguageServerConfig
|
from solidlsp.ls_config import Language, LanguageServerConfig
|
||||||
from solidlsp.settings import SolidLSPSettings
|
from solidlsp.settings import SolidLSPSettings
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
pytest.skip("Scala must be compiled for these tests to run through, which is a huge hassle", allow_module_level=True)
|
pytest.skip("Scala must be compiled for these tests to run through, which is a huge hassle", allow_module_level=True)
|
||||||
|
|
||||||
@@ -62,3 +63,12 @@ def test_scala_find_definition_and_references_across_files(scala_ls):
|
|||||||
assert first_def["range"]["start"]["character"] == 6
|
assert first_def["range"]["start"]["character"] == 6
|
||||||
assert first_def["range"]["end"]["line"] == 7
|
assert first_def["range"]["end"]["line"] == 7
|
||||||
assert first_def["range"]["end"]["character"] == 14
|
assert first_def["range"]["end"]["character"] == 14
|
||||||
|
|
||||||
|
|
||||||
|
def test_file_diagnostics(scala_ls) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
scala_ls,
|
||||||
|
"src/main/scala/com/example/DiagnosticsSample.scala",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.solidity
|
||||||
|
class TestSolidityDiagnostics:
|
||||||
|
@pytest.mark.xfail(
|
||||||
|
sys.platform == "darwin",
|
||||||
|
reason="Unknown — passes on Ubuntu but consistently fails on macOS CI; root cause not yet identified.",
|
||||||
|
strict=False,
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"contracts/DiagnosticsSample.sol",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -16,6 +16,7 @@ from solidlsp import SolidLanguageServer
|
|||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from test.conftest import is_ci
|
from test.conftest import is_ci
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
# Skip Swift tests on Windows due to complex GitHub Actions configuration
|
# Skip Swift tests on Windows due to complex GitHub Actions configuration
|
||||||
WINDOWS_SKIP = platform.system() == "Windows"
|
WINDOWS_SKIP = platform.system() == "Windows"
|
||||||
@@ -238,3 +239,12 @@ class TestSwiftProjectBasics:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/diagnostics_sample.swift",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.systemverilog
|
||||||
|
class TestSystemverilogDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.sv",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.terraform
|
||||||
|
class TestTerraformDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.tf",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.toml
|
||||||
|
class TestTomlDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.TOML], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.toml",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.typescript
|
||||||
|
class TestTypeScriptDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.ts",
|
||||||
|
("missingGreeting", "missingConsumerValue"),
|
||||||
|
min_count=2,
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
|
||||||
|
|
||||||
|
def assert_file_diagnostics(
|
||||||
|
language_server: SolidLanguageServer,
|
||||||
|
relative_file_path: str,
|
||||||
|
expected_message_fragments: Sequence[str],
|
||||||
|
min_count: int = 1,
|
||||||
|
) -> None:
|
||||||
|
diagnostics = language_server.request_text_document_diagnostics(relative_file_path, min_severity=1)
|
||||||
|
|
||||||
|
assert isinstance(diagnostics, list), diagnostics
|
||||||
|
assert len(diagnostics) >= min_count, diagnostics
|
||||||
|
|
||||||
|
diagnostic_messages = [diagnostic["message"] for diagnostic in diagnostics]
|
||||||
|
for fragment in expected_message_fragments:
|
||||||
|
assert any(fragment in message for message in diagnostic_messages), diagnostic_messages
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.vue
|
||||||
|
class TestVueDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.VUE], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/DiagnosticsSample.vue",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from solidlsp import SolidLanguageServer
|
||||||
|
from solidlsp.ls_config import Language
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.yaml
|
||||||
|
class TestYamlDiagnostics:
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.YAML], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"diagnostics_sample.yaml",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
@@ -14,6 +14,7 @@ from solidlsp import SolidLanguageServer
|
|||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
from solidlsp.ls_types import SymbolKind
|
from solidlsp.ls_types import SymbolKind
|
||||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||||
|
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.zig
|
@pytest.mark.zig
|
||||||
@@ -355,3 +356,12 @@ class TestZigLanguageServer:
|
|||||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||||
pytrace=False,
|
pytrace=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True)
|
||||||
|
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||||
|
assert_file_diagnostics(
|
||||||
|
language_server,
|
||||||
|
"src/diagnostics_sample.zig",
|
||||||
|
(),
|
||||||
|
min_count=1,
|
||||||
|
)
|
||||||
Reference in new issue
Block a user