Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion api/analyzers/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ def resolve(self, files: dict[Path, File], lsp: SyncLanguageServer, file_path: P
try:
locations = lsp.request_definition(str(file_path), node.start_point.row, node.start_point.column)
return [(files[Path(self.resolve_path(location['absolutePath'], path))], files[Path(self.resolve_path(location['absolutePath'], path))].tree.root_node.descendant_for_point_range(Point(location['range']['start']['line'], location['range']['start']['character']), Point(location['range']['end']['line'], location['range']['end']['character']))) for location in locations if location and Path(self.resolve_path(location['absolutePath'], path)) in files]
except Exception:
except Exception as e:
import logging
logging.getLogger(__name__).warning(
"resolve() failed for %s @%d:%d: %s",
file_path, node.start_point.row, node.start_point.column, e,
)
return []

@abstractmethod
Expand Down
33 changes: 31 additions & 2 deletions api/analyzers/source_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,27 @@ def second_pass(self, graph: Graph, files: list[Path], path: Path) -> None:
else:
lsps[".java"] = NullLanguageServer()
if any(path.rglob('*.py')):
config = MultilspyConfig.from_dict({"code_language": "python", "environment_path": f"{path}/venv"})
import sys
py_venv = path / "venv"
py_dotvenv = path / ".venv"
if py_venv.is_dir() and (py_venv / "bin" / "python").exists():
env_path = str(py_venv)
elif py_dotvenv.is_dir() and (py_dotvenv / "bin" / "python").exists():
env_path = str(py_dotvenv)
else:
# Fall back to the host's Python environment so jedi has a
# valid interpreter to introspect; otherwise every
# request_definition() raises InvalidPythonEnvironment and
# we'd silently produce a graph with zero CALLS edges.
env_path = str(Path(sys.executable).resolve().parent.parent)
logging.info(
"No venv at %s; falling back to host env %s for jedi LSP",
path, env_path,
)
config = MultilspyConfig.from_dict({
"code_language": "python",
"environment_path": env_path,
})
lsps[".py"] = SyncLanguageServer.create(config, logger, str(path))
else:
lsps[".py"] = NullLanguageServer()
Expand All @@ -160,7 +180,16 @@ def second_pass(self, graph: Graph, files: list[Path], path: Path) -> None:
# Skip symbol resolution when no real LSP is available
if isinstance(lsps.get(file_path.suffix), NullLanguageServer):
continue
file = self.files[file_path]
file = self.files.get(file_path)
if file is None:
# first_pass skipped this file (e.g. parse error, empty,
# or ignored after entering the candidate list). Skip
# in second_pass too instead of crashing the whole index.
logging.warning(
"second_pass: %s not in files map (first_pass skipped it); skipping",
file_path,
)
continue
logging.info(f'Processing file ({i + 1}/{files_len}): {file_path}')
for _, entity in file.entities.items():
entity.resolved_symbol(lambda key, symbol, fp=file_path: analyzers[fp.suffix].resolve_symbol(self.files, lsps[fp.suffix], fp, path, key, symbol))
Expand Down
Loading