Skip to content

Conversation

@v4rgas
Copy link
Contributor

@v4rgas v4rgas commented Feb 25, 2025

No description provided.

@v4rgas v4rgas merged commit d509c6a into main Feb 25, 2025
4 checks passed
@blar-app blar-app bot added size XL Pull Request size is Extra Large Impact XL The PR impact is very high labels Feb 25, 2025
@blar-app
Copy link

blar-app bot commented Feb 25, 2025

PR Summary

This pull request focuses on the integration and restructuring of the multilspy library within the project, transitioning it to a vendor dependency, and updating the import paths accordingly. It also introduces configurations for various language servers to accommodate different programming languages.

Key Findings

  • The import paths for SyncLanguageServer, MultilspyConfig, and MultilspyLogger were updated to reflect new locations under the blarify.vendor namespace, indicating a restructuring of the multilspy integration.
  • multilspy is now included as a local vendor dependency, with added import statements and MIT License text for legal compliance.
  • New modules and updates in package structure are provided to support local source paths and vendor dependencies, enhancing project modularity and integration.
  • New language server implementations were added, including:
    • EclipseJDTLS for Java, providing a Java-specific language server setup with runtime dependency management.
    • Gopls for Go, a Go-specific language server setup handling LSP notifications and requests.
    • JediServer for Python, facilitating Python support via the JEDI language server.
    • OmniSharp for C#, with methods for setting up dependencies and handling C# specific server requests.
    • RustAnalyzer for Rust, managing Rust-specific server interactions and dependency setup.
    • Solargraph for Ruby, implementing a Ruby-specific server setup using the Solargraph library.
  • Updates were made to runtime dependencies and configurations to support various language servers, indicating efforts to enhance the project's compatibility with multiple programming languages.

Pull Request Impact: 108
We measure the impact of a Pull Request on the codebase by counting the number of references to the changed code.

🔄 File Changes Overview
File Description
blarify/code_references/lsp_helper.py The import paths for SyncLanguageServer, MultilspyConfig, and MultilspyLogger were updated to reflect their new locations under the 'blarify.vendor' namespace, indicating a restructuring of the multilspy integration within the project.
blarify/vendor/multilspy.pyi Added an import statement for the multilspy module, indicating a change in the source path to use a local version.
blarify/vendor/multilspy/LICENSE Added the MIT License text to the file.
blarify/vendor/multilspy/init.py Added a new module for the multilspy API that imports types and language server classes, and defines an all attribute for public API exposure.
blarify/vendor/multilspy/language_server.py The file introduces a new implementation for a Language Server interface, defining a class structure for managing communication with language specific language servers. It includes classes for LSP file buffering and methods for handling file operations such as opening, inserting, and deleting text. Various LSP-related functionalities, like obtaining definitions, references, completions, and document symbols, are implemented. Additionally, updates were made to the package structure to support local source paths and vendor dependencies.
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py Added a new class EclipseJDTLS that extends the LanguageServer class, providing a Java-specific implementation. This class includes methods for setting up runtime dependencies, initializing parameters for the language server, and starting the server. The code also introduces a new RuntimeDependencyPaths dataclass for managing paths to required runtime dependencies, and implements various dependency management operations. Additionally, it updates import paths for several components related to the multilspy project.
blarify/vendor/multilspy/language_servers/gopls/gopls.py The new class Gopls was added as a Go-specific implementation of the LanguageServer class. It includes methods for checking the installed versions of Go and gopls, a runtime dependency checker, and server initialization parameters specific to the gopls server. Additionally, the server is set up to handle various LSP notifications and requests. The changes also included adjustments in import paths to accommodate the local multilspy implementation.
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py The diff introduces a new class JediServer which extends the LanguageServer class for Python. It includes the __init__ method for initialization, a private method _get_initialize_params for loading and modifying initialization parameters from a JSON file, and an asynchronous context manager start_server that starts the JEDI language server and handles various LSP requests and notifications. The class is designed to configure and run the JEDI language server which provides Python language support.
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py A new file was introduced that implements the OmniSharp class for the C# language server integration. It includes methods for setting up runtime dependencies, scanning for solution files, and starting the server with specific configurations for handling requests and responses.
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py A new RustAnalyzer class was added, providing a Rust-specific instantiation of the LanguageServer. The implementation includes methods for setting up runtime dependencies, initializing parameters for the server, and methods to start the server with various handlers for requests and notifications specific to Rust. The file now defines how to interact with Rust language services, including downloading necessary binaries and setting their execution permissions.
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py The file introduces a new Solargraph class that implements a Ruby-specific Language Server using Solargraph. It includes methods for setting up runtime dependencies for Solargraph, checking for Ruby installation, and configuring the Language Server's parameters. Several imports are added to accommodate functionality, and the server's initialization process is detailed, including the handling of capability registration and logging.
📃 Unreviewed files The following files were not reviewed by the agent:
File path
.gitignore
blarify/vendor/multilspy/language_servers/eclipse_jdtls/initialize_params.json
blarify/vendor/multilspy/language_servers/eclipse_jdtls/runtime_dependencies.json
blarify/vendor/multilspy/language_servers/gopls/initialize_params.json
blarify/vendor/multilspy/language_servers/jedi_language_server/initialize_params.json
blarify/vendor/multilspy/language_servers/omnisharp/initialize_params.json
blarify/vendor/multilspy/language_servers/omnisharp/runtime_dependencies.json
blarify/vendor/multilspy/language_servers/omnisharp/workspace_did_change_configuration.json
blarify/vendor/multilspy/language_servers/rust_analyzer/initialize_params.json
blarify/vendor/multilspy/language_servers/rust_analyzer/runtime_dependencies.json
blarify/vendor/multilspy/language_servers/solargraph/initialize_params.json
blarify/vendor/multilspy/language_servers/solargraph/runtime_dependencies.json
blarify/vendor/multilspy/language_servers/typescript_language_server/initialize_params.json
blarify/vendor/multilspy/language_servers/typescript_language_server/runtime_dependencies.json
blarify/vendor/multilspy/language_servers/typescript_language_server/static/ts-lsp/node_modules/.bin/tsc
blarify/vendor/multilspy/language_servers/typescript_language_server/static/ts-lsp/node_modules/.bin/tsserver
blarify/vendor/multilspy/language_servers/typescript_language_server/static/ts-lsp/node_modules/.bin/typescript-language-server
blarify/vendor/multilspy/language_servers/typescript_language_server/static/ts-lsp/node_modules/.package-lock.json
blarify/vendor/multilspy/language_servers/typescript_language_server/static/ts-lsp/node_modules/typescript-language-server/CHANGELOG.md
📊 Impact Summary This tables shows the impact of the changes in the codebase
File path Name Impact Type of impact
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py workspace_configuration_handler 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py Gopls 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py EclipseJDTLS 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py RuntimeDependencyPaths 2 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py setupRuntimeDependencies 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py JediServer 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py _get_gopls_version 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py RustAnalyzer 1 Added
blarify/vendor/multilspy/language_server.py SyncLanguageServer 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py execute_client_command_handler 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py register_capability_handler 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py lang_status_handler 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py _get_go_version 1 Added
blarify/vendor/multilspy/language_server.py LSPFileBuffer 1 Added
blarify/vendor/multilspy/language_server.py LanguageServer 10 Added
blarify/vendor/multilspy/language_server.py create 1 Added
blarify/vendor/multilspy/language_server.py init 6 Added
blarify/vendor/multilspy/language_server.py logging_fn 1 Added
blarify/vendor/multilspy/language_server.py start_server 7 Added
blarify/vendor/multilspy/language_server.py open_file 6 Added
blarify/vendor/multilspy/language_server.py insert_text_at_position 1 Added
blarify/vendor/multilspy/language_server.py delete_text_between_positions 1 Added
blarify/vendor/multilspy/language_server.py get_open_file_text 1 Added
blarify/vendor/multilspy/language_server.py request_definition 1 Added
blarify/vendor/multilspy/language_server.py request_references 1 Added
blarify/vendor/multilspy/language_server.py request_completions 1 Added
blarify/vendor/multilspy/language_server.py request_document_symbols 1 Added
blarify/vendor/multilspy/language_server.py visit_tree_nodes_and_build_tree_repr 1 Added
blarify/vendor/multilspy/language_server.py request_hover 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py setup_runtime_dependency 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py register_capability_handler 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/gopls/gopls.py do_nothing 2 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py Solargraph 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py setup_runtime_dependencies 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py register_capability_handler 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py lang_status_handler 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py execute_client_command_handler 1 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py do_nothing 3 Added
blarify/vendor/multilspy/language_servers/solargraph/solargraph.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py execute_client_command_handler 1 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py do_nothing 5 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py check_experimental_status 1 Added
blarify/vendor/multilspy/language_servers/jedi_language_server/jedi_server.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py breadth_first_file_scan 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py find_least_depth_sln_file 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py OmniSharp 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py setupRuntimeDependencies 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py register_capability_handler 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py lang_status_handler 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py execute_client_command_handler 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py do_nothing 3 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py check_experimental_status 1 Added
blarify/vendor/multilspy/language_servers/omnisharp/omnisharp.py window_log_message 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py setup_runtime_dependencies 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py _get_initialize_params 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py register_capability_handler 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py lang_status_handler 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py execute_client_command_handler 1 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py do_nothing 3 Added
blarify/vendor/multilspy/language_servers/rust_analyzer/rust_analyzer.py check_experimental_status 1 Added
blarify/vendor/multilspy/language_servers/eclipse_jdtls/eclipse_jdtls.py do_nothing 3 Added
📜 Blar Instructions

Blar Commands

  • Comment -blar --review triggers a review of the Pull Request, analyzing only the unreviewed commits since the last review.
  • Comment -blar --review --force to receive a complete review of the entire Pull Request, reanalyzing all commits.
  • Make an issue comment or reply to it with -blar --add-wiki to save a code guideline rule in the wiki. It will be used to review the code with the design pattern agent 🎨

Tags Explanation

  • 🐛 Debugger Agent Issues:
    These issues are identified by our Debugger Agent, which focuses on detecting bugs and errors in your code.
    Solutions for 🐛 issues are available upon request using the -blar --fix command.

  • ⚡ Optimizer Agent Issues:
    These issues focus on identifying inefficient database queries that can impact performance.
    Solutions for ⚡ issues are available upon request using the -blar --fix command.

  • 🛡️ Cyber Security Agent Issues:
    These issues focus on identifying potential security vulnerabilities in your code.
    Solutions for 🛡️ issues are available upon request using the -blar --fix command.

  • 🎨 Design Pattern Reviewer Agent Issues:
    These issues highlight concerns related to improper or suboptimal use of design patterns, evaluated based on rules set in the wiki.
    Solutions for 🎨 issues are available upon request using the -blar --add-wiki command.

Comment on lines +84 to +106
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
"""
Returns the initialize params for the TypeScript Language Server.
"""
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r") as f:
d = json.load(f)

del d["_description"]

d["processId"] = os.getpid()
assert d["rootPath"] == "$rootPath"
d["rootPath"] = repository_absolute_path

assert d["rootUri"] == "$rootUri"
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()

assert d["workspaceFolders"][0]["uri"] == "$uri"
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()

assert d["workspaceFolders"][0]["name"] == "$name"
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)

return d
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Warning 🐛 Bug

  • The method _get_initialize_params in gopls.py asserts the presence of specific placeholders in the JSON file before replacing them.
  • The placeholders checked are '$rootPath', '$rootUri', '$uri', and '$name'.
  • If these placeholders do not match the hardcoded values exactly or if the JSON content changes, a Runtime AssertionError will occur.
  • This tight coupling between the JSON content and hardcoded values can lead to potential runtime issues when the JSON structure is modified.
    with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r") as f:
        d = json.load(f)

    del d["_description"]

    d["processId"] = os.getpid()
    assert d["rootPath"] == "$rootPath"
    d["rootPath"] = repository_absolute_path

    assert d["rootUri"] == "$rootUri"
    d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()

    assert d["workspaceFolders"][0]["uri"] == "$uri"
    d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()

    assert d["workspaceFolders"][0]["name"] == "$name"
    d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)

Comment on lines +67 to +80
slnfilename = find_least_depth_sln_file(repository_root_path)
if slnfilename is None:
logger.log("No *.sln file found in repository", logging.ERROR)
raise MultilspyException("No SLN file found in repository")

cmd = " ".join(
[
omnisharp_executable_path,
"-lsp",
"--encoding",
"ascii",
"-z",
"-s",
slnfilename,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🛡️ Cyber Security

  • The value of slnfilename is obtained from the function find_least_depth_sln_file(repository_root_path), which scans the repository for solution files.
  • This value is concatenated directly into the command string without any sanitization.
  • Using unsanitized input from potentially user-controlled file names poses a security risk, specifically a command injection vulnerability when the command is executed.

Here is the relevant code snippet:

   slnfilename = find_least_depth_sln_file(repository_root_path)
   if slnfilename is None:
       logger.log("No *.sln file found in repository", logging.ERROR)
       raise MultilspyException("No SLN file found in repository")

   cmd = " ".join(
       [
           omnisharp_executable_path,
           "-lsp",
           "--encoding",
           "ascii",
           "-z",
           "-s",
           slnfilename,
           "--hostPID",
           str(os.getpid()),
           "DotNet:enablePackageRestore=false",
           "--loglevel",
           "trace",
           "--plugin",
           dll_path,
           "FileOptions:SystemExcludeSearchPatterns:0=**/.git",
           "FileOptions:SystemExcludeSearchPatterns:1=**/.svn",
           "FileOptions:SystemExcludeSearchPatterns:2=**/.hg",
           "FileOptions:SystemExcludeSearchPatterns:3=**/CVS",
           "FileOptions:SystemExcludeSearchPatterns:4=**/.DS_Store",
           "FileOptions:SystemExcludeSearchPatterns:5=**/Thumbs.db",
           "RoslynExtensionsOptions:EnableAnalyzersSupport=true",
           "FormattingOptions:EnableEditorConfigSupport=true",
           "RoslynExtensionsOptions:EnableImportCompletion=true",
           "Sdk:IncludePrereleases=true",
           "RoslynExtensionsOptions:AnalyzeOpenDocumentsOnly=true",
           "formattingOptions:useTabs=false",
           "formattingOptions:tabSize=4",
           "formattingOptions:indentationSize=4",
       ]
   )

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The function check_experimental_status calls self.server_ready.set() when params['quiescent'] is True.
  • self.server_ready is not defined in the OmniSharp class.
  • This absence means that referencing self.server_ready.set() will result in an AttributeError during execution.

Code Snippet:

async def check_experimental_status(params):
    if params["quiescent"] == True:
        self.server_ready.set()  # self.server_ready is not defined anywhere in OmniSharp

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The method register_capability_handler calls self.completions_available.set() when the registration method is textDocument/completion.
  • self.completions_available is not defined or initialized anywhere in the OmniSharp class.
  • This absence results in an AttributeError when self.completions_available.set() is invoked.
  • The attributes self.definition_available and self.references_available are defined and set appropriately, but self.completions_available is missing.

Code snippet:

            for registration in params["registrations"]:
                if registration["method"] == "textDocument/definition":
                    self.definition_available.set()
                if registration["method"] == "textDocument/references":
                    self.references_available.set()
                if registration["method"] == "textDocument/completion":
                    self.completions_available.set()

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The _get_initialize_params method includes four assert statements:
    • assert d["rootPath"] == "$rootPath"
    • assert d["rootUri"] == "$rootUri"
    • assert d["workspaceFolders"][0]["uri"] == "$uri"
    • assert d["workspaceFolders"][0]["name"] == "$name"
  • These assertions explicitly check that specific JSON fields match expected placeholder strings.
  • If 'initialize_params.json' does not contain these exact values, AssertionErrors will be raised.
  • Other parts of the code rely on the modified initialization parameters after these checks.

Comment on lines +82 to +84
async def check_experimental_status(params):
if params["quiescent"] == True:
self.completions_available.set()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The check_experimental_status async function directly accesses params['quiescent'] without verifying if the key exists.
  • If the 'quiescent' key is absent in the params dictionary, this results in a KeyError.
  • Implementing a check for the existence of 'quiescent' is necessary to prevent runtime errors in scenarios where the key may not be provided.
async def check_experimental_status(params):
    if params["quiescent"] == True:
        self.completions_available.set()

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Warning 🐛 Bug

  • The _get_initialize_params method directly accesses d['workspaceFolders'][0].
  • There is no verification for the existence of the 'workspaceFolders' key.
  • No checks are performed to ensure the list is non-empty before indexing.
  • This can lead to an IndexError if 'workspaceFolders' is absent or empty.
assert d["workspaceFolders"][0]["uri"] == "$uri"
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()
assert d["workspaceFolders"][0]["name"] == "$name"
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)

Comment on lines +120 to +126
async def register_capability_handler(params):
assert "registrations" in params
for registration in params["registrations"]:
if registration["method"] == "workspace/executeCommand":
self.initialize_searcher_command_available.set()
self.resolve_main_method_available.set()
return
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Warning 🐛 Bug

  • The function 'register_capability_handler' asserts that 'registrations' exists in 'params' without validating its type.
  • It directly iterates over 'params["registrations"]', which may lead to runtime errors if 'registrations' is not an iterable.
  • No checks are performed to ensure that 'params["registrations"]' is indeed iterable before iteration.
  • Lack of type validation could result in exceptions if the expected data type is not correctly provided.

Code Snippet:

async def register_capability_handler(params):
    assert "registrations" in params
    for registration in params["registrations"]:
        if registration["method"] == "workspace/executeCommand":
            self.initialize_searcher_command_available.set()
            self.resolve_main_method_available.set()
    return

Comment on lines +81 to +103
def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
"""
Returns the initialize params for the Rust Analyzer Language Server.
"""
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r") as f:
d = json.load(f)

del d["_description"]

d["processId"] = os.getpid()
assert d["rootPath"] == "$rootPath"
d["rootPath"] = repository_absolute_path

assert d["rootUri"] == "$rootUri"
d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()

assert d["workspaceFolders"][0]["uri"] == "$uri"
d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()

assert d["workspaceFolders"][0]["name"] == "$name"
d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)

return d
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

The _get_initialize_params method poses a risk of raising exceptions due to several assumptions about the JSON data structure:

  • The function expects the JSON loaded from initialize_params.json to contain specific placeholder values:

    • rootPath must be equal to '$rootPath'.
    • rootUri must be equal to '$rootUri'.
    • The first element of workspaceFolders must have uri equal to '$uri' and name equal to '$name'.
  • The workspaceFolders list must contain at least one element, as the code directly accesses the first index.

If the JSON file structure is altered or misconfigured, the assert statements or direct indexing could lead to runtime errors, potentially causing the application to fail.

Here is the relevant code snippet:

def _get_initialize_params(self, repository_absolute_path: str) -> InitializeParams:
    with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r") as f:
        d = json.load(f)
    del d["_description"]

    d["processId"] = os.getpid()
    assert d["rootPath"] == "$rootPath"
    d["rootPath"] = repository_absolute_path

    assert d["rootUri"] == "$rootUri"
    d["rootUri"] = pathlib.Path(repository_absolute_path).as_uri()

    assert d["workspaceFolders"][0]["uri"] == "$uri"
    d["workspaceFolders"][0]["uri"] = pathlib.Path(repository_absolute_path).as_uri()

    assert d["workspaceFolders"][0]["name"] == "$name"
    d["workspaceFolders"][0]["name"] = os.path.basename(repository_absolute_path)

    return d

Comment on lines +166 to +172
init_response = await self.server.send.initialize(initialize_params)
assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
assert "completionProvider" in init_response["capabilities"]
assert init_response["capabilities"]["completionProvider"] == {
"resolveProvider": True,
"triggerCharacters": [":", ".", "'", "("],
"completionItem": {"labelDetailsSupport": True},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The code contains hardcoded assertions that check the structure of the init_response from the server.
  • It asserts that init_response["capabilities"]["textDocumentSync"]["change"] equals 2.
  • Additionally, it verifies that completionProvider exists and matches a specific structure.
  • These checks impose strict requirements on the server's response format.
  • Any deviation from the expected structure can lead to assertion failures, causing the client to terminate unexpectedly.

Here is the relevant code snippet:

        init_response = await self.server.send.initialize(initialize_params)
        assert init_response["capabilities"]["textDocumentSync"]["change"] == 2
        assert "completionProvider" in init_response["capabilities"]
        assert init_response["capabilities"]["completionProvider"] == {
            "resolveProvider": True,
            "triggerCharacters": [":" , ".", "'", "("],
            "completionItem": {"labelDetailsSupport": True},
        }

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The attributes self.initialize_searcher_command_available and self.resolve_main_method_available are used in the nested register_capability_handler function within the start_server method of the Solargraph class.
  • There is no evidence that these attributes are defined in the Solargraph class's __init__ method or anywhere else in the provided code snippet.
  • The LanguageServer class, from which Solargraph inherits, also does not define these attributes in its __init__ method or any other methods.
  • Without being defined, their use in register_capability_handler can lead to an AttributeError at runtime.
  • Other attributes in the class are explicitly defined, reinforcing that these two attributes are missing from the code context.

Code snippet example:

def __init__(
        self,
        config: MultilspyConfig,
        logger: MultilspyLogger,
        repository_root_path: str,
        process_launch_info: ProcessLaunchInfo,
        language_id: str,
    ):
    if type(self) == LanguageServer:
        raise MultilspyException(
            "LanguageServer is an abstract class and cannot be instantiated directly. Use LanguageServer.create method instead."
        )
    self.logger = logger
    self.server_started = False
    self.repository_root_path: str = repository_root_path
    self.completions_available = asyncio.Event()
    …  # Additional attribute initialization follows, but not for the two attributes in question.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Warning 🐛 Bug

  • The start_server method references self.completions_available through a call to set() after sending the initialization request.
  • There is no initialization of self.completions_available in the __init__ method or elsewhere in the provided code snippet.
  • This implies that if self.completions_available is not defined in any omitted part of the class, it may lead to an AttributeError when accessed.
  • The absence of evidence for initialization means that the reference to self.completions_available occurs before it may potentially be initialized.
def __init__(self, config: MultilspyConfig, logger: MultilspyLogger, repository_root_path: str):
    """
    Creates a Solargraph instance. This class is not meant to be instantiated directly.
    Use LanguageServer.create() instead.
    """
    solargraph_executable_path = self.setup_runtime_dependencies(logger, config, repository_root_path)
    super().__init__(
        config,
        logger,
        repository_root_path,
        ProcessLaunchInfo(cmd=f"{solargraph_executable_path} stdio", cwd=repository_root_path),
        "ruby",
    )
    self.server_ready = asyncio.Event()

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The function setup_runtime_dependencies deletes the _description key from the loaded JSON object before checking the content of the runtimeDependencies key.
  • Following the deletion, the code accesses the first element of runtimeDependencies without verifying if the list is non-empty.
  • This can lead to potential KeyError if the _description key is missing in the JSON, or an IndexError if runtimeDependencies is an empty array.
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r") as f:
    d = json.load(f)
    del d["_description"]
dependency = d["runtimeDependencies"][0]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Error 🐛 Bug

  • The method start_server() includes a call to self.completions_available.set() within the inner function register_capability_handler.
  • The attribute completions_available is not defined or initialized anywhere in the EclipseJDTLS class.
  • This will lead to an AttributeError at runtime since completions_available is referenced without prior initialization.
  • Other attributes such as service_ready_event and intellicode_enable_command_available are properly initialized in the class constructor, indicating an inconsistency in attribute management.

Code Snippet:

  if registration["method"] == "textDocument/completion":
      assert registration["registerOptions"]["resolveProvider"] == True
      assert registration["registerOptions"]["triggerCharacters"] == [".", "@", "#", "*", " "]
      self.completions_available.set()

rysweet pushed a commit to rysweet/cue that referenced this pull request Aug 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Impact XL The PR impact is very high size XL Pull Request size is Extra Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants