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
2 changes: 1 addition & 1 deletion cmake/package.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
kotatsu
GIT_REPOSITORY https://github.com/clice-io/kotatsu
GIT_TAG 2a8c147579d36d33ff50f31d0bce49b0ab67381b
GIT_TAG 60661c15e0a13e29e59443b470e83c3b2b60fb0d
)

set(KOTA_ENABLE_ZEST ON)
Expand Down
6 changes: 5 additions & 1 deletion src/compile/diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ std::optional<std::string> DiagnosticID::diagnostic_document_uri() const {
}

case DiagnosticSource::Clice: {
/// TODO: Add diagnostic for clice.
// clice's own guidance diagnostics link to the setup guide that
// explains how to provide a compilation database.
if(name == "inferred-compile-command") {
return "https://clice.io/en/guide/quick-start";
}
return std::nullopt;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/feature/code_completion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ class CodeCompletionCollector final : public clang::CodeCompleteConsumer {

PositionMapper converter(content, encoding);
auto replace_range = protocol::Range{
.start = *converter.to_position(prefix.range.begin),
.end = *converter.to_position(prefix.range.end),
.start = to_position(converter, prefix.range.begin),
.end = to_position(converter, prefix.range.end),
};

std::vector<protocol::CompletionItem> collected;
Expand Down
4 changes: 2 additions & 2 deletions src/feature/diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ auto diagnostics(CompilationUnitRef unit, PositionEncoding encoding)
auto offset = unit.file_offset(include_location);
auto end_offset = offset + unit.token_spelling(include_location).size();
diagnostic.range = protocol::Range{
.start = *main_converter.to_position(offset),
.end = *main_converter.to_position(end_offset),
.start = to_position(main_converter, offset),
.end = to_position(main_converter, end_offset),
};

current = std::move(diagnostic);
Expand Down
18 changes: 16 additions & 2 deletions src/feature/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "compile/compilation.h"
#include "compile/compilation_unit.h"
#include "semantic/symbol_kind.h"
#include "support/anomaly.h"
#include "support/markup.h"

#include "kota/ipc/lsp/position.h"
Expand All @@ -21,10 +22,23 @@ using kota::ipc::lsp::PositionEncoding;
using kota::ipc::lsp::PositionMapper;
using kota::ipc::lsp::parse_position_encoding;

/// Map an internally-produced byte offset to a protocol position. Offsets
/// here come from clice's own analysis of the same content the mapper was
/// built from, so a failed mapping is a clice bug: report an anomaly and
/// clamp to the document start instead of dereferencing an empty optional.
inline auto to_position(const PositionMapper& converter, std::uint32_t offset)
-> protocol::Position {
if(auto position = converter.to_position(offset)) {
return *position;
}
LOG_ANOMALY(PositionMapFail, "offset {} cannot be mapped to a position", offset);
return protocol::Position{.line = 0, .character = 0};
Comment on lines +29 to +35

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don’t clamp failed mappings to document start.

Line 35 turns every mapping failure into (0, 0), which breaks downstream ordering assumptions in release mode. A concrete case is src/feature/semantic_tokens.cpp Lines 503-506: the relative encoder subtracts unsigned line/column deltas from the previous token, so a late failure here underflows and corrupts the semantic-token payload instead of degrading one item cleanly. Please return an optional/error and let callers drop the affected artifact after logging, or clamp to a monotonic boundary such as EOF rather than the document start.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/feature/feature.h` around lines 29 - 35, The to_position function
currently returns a default (0,0) on mapping failure which breaks downstream
unsigned delta math; change its contract to return
std::optional<protocol::Position> (i.e., inline auto to_position(...) ->
std::optional<protocol::Position>), log the anomaly via
LOG_ANOMALY(PositionMapFail, ...) and return std::nullopt on failure instead of
protocol::Position{.line=0,.character=0}; then update callers (notably the
consumer in semantic_tokens.cpp around the relative encoder) to check the
optional, drop or skip the affected artifact when mapping fails, or otherwise
handle the error path so no unsigned underflow occurs.

}

inline auto to_range(const PositionMapper& converter, LocalSourceRange range) -> protocol::Range {
return protocol::Range{
.start = *converter.to_position(range.begin),
.end = *converter.to_position(range.end),
.start = to_position(converter, range.begin),
.end = to_position(converter, range.end),
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/feature/folding_ranges.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ auto folding_ranges(CompilationUnitRef unit, PositionEncoding encoding)
result.reserve(collected.size());

for(const auto& item: collected) {
auto start = *converter.to_position(item.range.begin);
auto end = *converter.to_position(item.range.end);
auto start = to_position(converter, item.range.begin);
auto end = to_position(converter, item.range.end);

protocol::FoldingRange range{
.start_line = start.line,
Expand Down
4 changes: 2 additions & 2 deletions src/feature/formatting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ auto document_format(llvm::StringRef file,

for(const auto& replacement: *replacements) {
protocol::TextEdit edit;
edit.range.start = *converter.to_position(replacement.getOffset());
edit.range.end = *converter.to_position(replacement.getOffset() + replacement.getLength());
edit.range.start = to_position(converter, replacement.getOffset());
edit.range.end = to_position(converter, replacement.getOffset() + replacement.getLength());
edit.new_text = replacement.getReplacementText().str();
edits.push_back(std::move(edit));
}
Expand Down
2 changes: 1 addition & 1 deletion src/feature/inlay_hints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ auto inlay_hints(CompilationUnitRef unit,

for(const auto& hint: collected) {
protocol::InlayHint out{
.position = *converter.to_position(hint.offset),
.position = to_position(converter, hint.offset),
.label = hint.label,
};

Expand Down
4 changes: 2 additions & 2 deletions src/feature/semantic_tokens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,8 @@ class SemanticTokenEncoder {

auto begin = token.range.begin;
auto end = token.range.end;
auto begin_position = *converter.to_position(begin);
auto end_position = *converter.to_position(end);
auto begin_position = to_position(converter, begin);
auto end_position = to_position(converter, end);
auto begin_line = static_cast<std::uint32_t>(begin_position.line);
auto begin_char = static_cast<std::uint32_t>(begin_position.character);
auto end_line = static_cast<std::uint32_t>(end_position.line);
Expand Down
Loading
Loading