Skip to content

Feat: Hover#225

Open
aurora0x27 wants to merge 3 commits intoclice-io:mainfrom
aurora0x27:main
Open

Feat: Hover#225
aurora0x27 wants to merge 3 commits intoclice-io:mainfrom
aurora0x27:main

Conversation

@aurora0x27
Copy link
Copy Markdown
Contributor

@aurora0x27 aurora0x27 commented Sep 3, 2025

In process

Summary by CodeRabbit

  • New Features

    • Richer hover content: types, sizes, alignment, offsets, bit-widths, field indices, literal values, source snippets, directive/macro info, and highlight ranges; language guessed for results.
    • Doxygen/comment parsing integrated into hover display with markdown support.
  • API

    • Hover requests now accept display options and return an optional result; display text may be omitted with fallbacks.
  • Tests

    • Expanded unit tests covering includes, macros, deduced/decltype types, comments, namespaces, and many declaration scenarios.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @aurora0x27, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors and enhances the hover functionality within the codebase. The changes aim to make the hover feature more robust, flexible, and capable of providing more comprehensive information by introducing optional return types, configurable options, and improved handling of various Abstract Syntax Tree (AST) node types, particularly TypeLocs.

Highlights

  • Hover Function Signature Update: The primary hover function in include/Feature/Hover.h and src/Feature/Hover.cpp has been updated to return std::optional<Hover> instead of Hover, indicating that hover information might not always be available. It also now accepts a config::HoverOptions parameter for more configurable behavior.
  • Improved Hover Information Retrieval: Internal helper functions like getHoverItems, getDocument, getQualifier, and getSourceCode have been refactored (e.g., getHoverItems renamed to get_hover_items and now accepts config::HoverOptions). New overloads for hover and get_hover_items have been added to specifically handle clang::TypeLoc nodes, expanding the types of symbols for which hover information can be generated.
  • Integration of Hover Options: The src/Server/Feature.cpp file now initializes and passes config::HoverOptions to the feature::hover call, enabling features like Doxygen parsing, Markdown comment parsing, and showing 'aka' information for hover results.
  • Enhanced AST Traversal and Logging: The hover implementation in src/Feature/Hover.cpp now includes more robust AST traversal logic, using src_loc_in_main_file and spelled_tokens_touch for better token identification. Debugging logs (clice::log::warn, clice::log::info) have been added to aid in development and understanding of the hover logic.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the hover feature, introducing std::optional for the return type and config::HoverOptions for configurability. The changes are a good step forward, but there are a few issues to address. Most critically, there's a potential crash in src/Server/Feature.cpp due to dereferencing an optional without checking if it has a value. I've also pointed out some leftover debugging code and unused parameters that should be cleaned up before merging. Overall, good progress on this feature.

Comment on lines 66 to 71
auto hover = feature::hover(*ast, offset, opt);
// TODO: Join comment with ast info, build structed text
proto::Hover result;
result.contents.kind = "markdown";
result.contents.value = std::format("{}: {}", hover.kind.name(), hover.name);
result.contents.value = std::format("{}: {}", hover->kind.name(), hover->name);
return json::serialize(result);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The function feature::hover now returns a std::optional<Hover>. However, the returned optional is dereferenced on line 70 (hover->kind.name()) without first checking if it contains a value. If feature::hover returns std::nullopt, this will cause a crash. You should check if hover has a value before accessing it.

        auto hover = feature::hover(*ast, offset, opt);
        if (!hover) {
            return json::Value(nullptr);
        }
        // TODO: Join comment with ast info, build structed text
        proto::Hover result;
        result.contents.kind = "markdown";
        result.contents.value = std::format("{}: {}", hover->kind.name(), hover->name);
        return json::serialize(result);

Comment on lines +68 to +69
// /// Generate the hover information for the given declaration(for test).
// Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl, const config::HoverOptions& opt);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

It's generally better to remove commented-out code rather than leaving it in the codebase. If this function is no longer needed, please remove it to improve code clarity. If it's intended for future use, a // TODO comment explaining the plan would be more informative.

Comment on lines +46 to +48
std::string getDocument(CompilationUnit& unit,
const clang::NamedDecl* decl,
config::HoverOptions opt) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The opt parameter of type config::HoverOptions has been added to this function but is not being used within the function body. This also applies to getQualifier and getSourceCode. Unused parameters can be misleading. Please either use this parameter to configure the function's behavior or remove it if it's not needed.

Comment on lines +116 to +118
for(auto& tk: tokens_under_cursor) {
clice::log::info("Hit token '{}'", tk.str());
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This loop appears to be for debugging purposes, as it logs every token under the cursor. This kind of verbose logging should be removed from the final code to avoid cluttering the logs in production.


clice::log::warn("Not selected");

node->data.dump(llvm::errs(), unit.context());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This line dumps AST node data directly to stderr. This is useful for debugging but should not be part of the final implementation. Please remove this line.

@16bit-ykiko
Copy link
Copy Markdown
Member

Any update?

@aurora0x27
Copy link
Copy Markdown
Contributor Author

Any update?

Handling typeloc and template params.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 24, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors hover to return optional results with configurable HoverOptions; expands HoverItem kinds/values; adds type-printing, advanced type deduction (auto/decltype), macro/include/directive handling, highlight ranges, richer hover rendering, and many new unit tests. Public hover API now returns std::optional and accepts HoverOptions.

Changes

Cohort / File(s) Summary
Hover Feature Header
include/Feature/Hover.h
Added Protocol/Basic.h; HoverItem gains kind and value; HoverKind extended (Size, Align, Offset, BitWidth, FieldIndex, Value); documentstd::optional<std::string>; added hl_range (std::optional<proto::Range>), lang and methods get_item_content() and display(); hover API now takes const config::HoverOptions& and returns std::optional<Hover>.
Hover Feature Implementation
src/Feature/Hover.cpp
Large implementation: proto range helper, proxy print policy, advanced type printers/desugaring, template-param printers, type-deduction machinery (DeducedTypeVisitor/getDeducedType), instantiation helpers, source/doc/qualifier extraction, selection-tree/AST node routing, macro/include/directive handling, collection of HoverItems (type/size/align/offset/bitwidth/field-index/value), and new hover overloads; exposes Hover::get_item_content and Hover::display.
Server Integration
src/Server/Feature.cpp
Creates local HoverOptions (doxygen parsing, markdown, show_aka), calls updated hover(..., opt), uses hover->display(opt) for result contents, maps hl_range into protocol range, and applies explicit fallbacks/logging when hover or display are absent.
Protocol/API Enhancement
include/Protocol/Feature/Hover.h
Added std::optional<Range> range; to protocol Hover to carry optional highlight ranges.
Tests
tests/unit/Feature/HoverTests.cpp
Adds extensive tests for includes, macros, deduced types (auto/decltype), comments/doxygen blocks, various C/C++ constructs and styles, and other hover scenarios; adds many new assertions and scaffolding.
Doxygen Handling
src/Support/Doxygen.cpp
Treats @b, @e, @c as inline commands in certain positions, routing them to normal line processing (control-flow tweak).

Sequence Diagram

sequenceDiagram
    participant User
    participant Server as Server (on_hover)
    participant HoverAPI as Hover Feature
    participant AST as Compiler/AST/SelectionTree
    participant Deducer as Type Deducer
    participant Renderer as Display Renderer

    User->>Server: hover request (file, offset)
    Server->>HoverAPI: hover(unit, offset, HoverOptions)
    HoverAPI->>AST: map offset → Node / SourceLocation
    alt Macro / Include / Directive
        HoverAPI->>AST: resolve macro/include & expansions
        HoverAPI->>HoverAPI: build directive/macro hover items
    else AST node
        HoverAPI->>HoverAPI: route by node kind (Decl / TypeLoc / Expr)
        alt auto / decltype / template-deduced
            HoverAPI->>Deducer: deduce concrete QualType
            Deducer->>AST: query instantiation/context
            Deducer->>HoverAPI: return deduced type
        end
        HoverAPI->>HoverAPI: collect HoverItems (name, type, size, offset, docs)
    end
    HoverAPI->>Server: return optional<Hover> (with hl_range)
    Server->>Renderer: hover.display(HoverOptions)
    Server->>User: formatted markdown + optional range
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested reviewers

  • 16bit-ykiko

Poem

🐇
I nibble tokens, chase each type,
unfold auto's sly delight,
hop through macros, ranges bright,
stitch docs, sizes, offsets tight.
A tiny rabbit, making hover light.

🚥 Pre-merge checks | ✅ 1 | ❌ 3
❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (11 files):

⚔️ .github/workflows/deploy-docs.yml (content)
⚔️ .github/workflows/main.yml (content)
⚔️ README.md (content)
⚔️ docs/.vitepress/config.ts (content)
⚔️ include/Feature/Hover.h (content)
⚔️ include/Protocol/Feature/Hover.h (content)
⚔️ pixi.toml (content)
⚔️ src/Feature/Hover.cpp (content)
⚔️ src/Server/Feature.cpp (content)
⚔️ src/Support/Doxygen.cpp (content)
⚔️ tests/unit/Feature/HoverTests.cpp (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
Title check ❓ Inconclusive The title 'Feat: Hover' is vague and generic, using non-descriptive terms that don't convey meaningful information about the specific changes made. Consider a more specific title that describes the main enhancement, such as 'Feat: Enhance hover information with type details and documentation support' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
include/Feature/Hover.h (1)

1-6: Header uses STL types without including their headers. Add required includes (and forward-declare CompilationUnit).

Public headers must be self-sufficient. Please include the STL headers you use and forward-declare CompilationUnit (or include its header).

Apply this diff near the top:

 #pragma once

-#include "AST/SymbolKind.h"
-#include "AST/SourceCode.h"
-#include "Index/Shared.h"
+#include "AST/SymbolKind.h"
+#include "Index/Shared.h"
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace clice {
+class CompilationUnit;
+}  // namespace clice

Optional: drop the unused include to reduce dependencies as shown above.

src/Feature/Hover.cpp (1)

15-35: Use wide types and consistent units for hover metrics (bytes vs bits).

  • getFieldOffset returns bits; your comment suggests “Offset” (commonly bytes). Convert to bytes.
  • Char/align sizes use CharUnits->getQuantity (signed 64). Avoid truncation to uint32_t.
-    auto addItem = [&items](HoverItem::HoverKind kind, uint32_t value) {
-        items.emplace_back(kind, llvm::Twine(value).str());
-    };
+    auto addItem = [&items](HoverItem::HoverKind kind, uint64_t value) {
+        items.emplace_back(kind, llvm::Twine(value).str());
+    };
@@
-        addItem(HoverItem::FieldIndex, FD->getFieldIndex());
-        addItem(HoverItem::Offset, Ctx.getFieldOffset(FD));
-        addItem(HoverItem::Size, Ctx.getTypeSizeInChars(FD->getType()).getQuantity());
-        addItem(HoverItem::Align, Ctx.getTypeAlignInChars(FD->getType()).getQuantity());
+        addItem(HoverItem::FieldIndex, static_cast<uint64_t>(FD->getFieldIndex()));
+        // Convert bits -> bytes for user-facing offset.
+        addItem(HoverItem::Offset,
+                static_cast<uint64_t>(Ctx.getFieldOffset(FD)) /
+                    static_cast<uint64_t>(Ctx.getCharWidth()));
+        addItem(HoverItem::Size,
+                static_cast<uint64_t>(Ctx.getTypeSizeInChars(FD->getType()).getQuantity()));
+        addItem(HoverItem::Align,
+                static_cast<uint64_t>(Ctx.getTypeAlignInChars(FD->getType()).getQuantity()));

Also clarify units in HoverItem comments if keeping bits anywhere.

♻️ Duplicate comments (4)
include/Feature/Hover.h (1)

68-70: Remove commented-out API or add TODO with rationale.

Dead commented code increases noise; delete it or replace with a clear TODO and target owner.

-// /// Generate the hover information for the given declaration(for test).
-// Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl, const config::HoverOptions&
-// opt);
src/Feature/Hover.cpp (2)

115-118: Reduce noisy token logging to debug or remove in release builds.
This was previously flagged; switch to debug or guard with a compile-time flag.

-    for(auto& tk: tokens_under_cursor) {
-        clice::logging::info("Hit token '{}'", tk.str());
-    }
+    for(auto& tk: tokens_under_cursor) {
+        clice::logging::debug("Hit token '{}'", tk.str());
+    }

138-138: Remove raw AST dump to stderr or guard it behind debug.
Keeps logs clean in production.

-        node->data.dump(llvm::errs(), unit.context());
+        // node->data.dump(llvm::errs(), unit.context()); // debug only
src/Server/Feature.cpp (1)

65-71: Check optional before use and capture by value to avoid lifetime hazards.

  • The optional is dereferenced without a has_value() check. Return null when no hover exists.
  • Avoid capturing stack locals by reference in async work; capture by value (both opt and ast pointer are small).
-    co_return co_await async::submit([kind = this->kind, offset, &ast, &opt] {
-        auto hover = feature::hover(*ast, offset, opt);
-        // TODO: Join comment with ast info, build structed text
-        proto::Hover result;
-        result.contents.kind = "markdown";
-        result.contents.value = std::format("{}: {}", hover->kind.name(), hover->name);
-        return json::serialize(result);
-    });
+    co_return co_await async::submit([kind = this->kind, offset, ast = ast, opt = opt] {
+        auto hover = feature::hover(*ast, offset, opt);
+        if(!hover) {
+            return json::Value(nullptr);
+        }
+        // TODO: Join comment with AST info; build structured text
+        proto::Hover result;
+        result.contents.kind = "markdown";
+        result.contents.value = std::format("{}: {}", hover->kind.name(), hover->name);
+        return json::serialize(result);
+    });
🧹 Nitpick comments (4)
include/Feature/Hover.h (1)

72-75: Public API looks good; consider documenting nullopt cases and option semantics.

Briefly document when nullopt is returned and how HoverOptions affects output for LSP clients.

src/Server/Feature.cpp (1)

60-64: Initialize HoverOptions from configuration once, not per request.

The in-function NOTE is correct. Plumb user/server settings and store defaults on Server; read here without reconstructing each call.

src/Feature/Hover.cpp (2)

46-76: Unify HoverOptions passing and silence unused warnings.

These helpers accept HoverOptions by value, unlike others by const-ref; also currently unused. Take by const-ref and mark maybe_unused to avoid warnings until options are applied.

-std::string getDocument(CompilationUnit& unit,
-                        const clang::NamedDecl* decl,
-                        config::HoverOptions opt) {
+std::string getDocument(CompilationUnit& unit,
+                        const clang::NamedDecl* decl,
+                        [[maybe_unused]] const config::HoverOptions& opt) {
@@
-std::string getQualifier(CompilationUnit& unit,
-                         const clang::NamedDecl* decl,
-                         config::HoverOptions opt) {
+std::string getQualifier(CompilationUnit& unit,
+                         const clang::NamedDecl* decl,
+                         [[maybe_unused]] const config::HoverOptions& opt) {
@@
-std::string getSourceCode(CompilationUnit& unit,
-                          const clang::NamedDecl* decl,
-                          config::HoverOptions opt) {
+std::string getSourceCode(CompilationUnit& unit,
+                          const clang::NamedDecl* decl,
+                          [[maybe_unused]] const config::HoverOptions& opt) {

Later, wire options into formatting/parsing behaviors.


98-104: TypeLoc path returns nullopt; consider minimal fallback content.

Even a simple spelling of the type under cursor would improve UX until full support is added.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a10908d and ff5e478.

📒 Files selected for processing (3)
  • include/Feature/Hover.h (1 hunks)
  • src/Feature/Hover.cpp (3 hunks)
  • src/Server/Feature.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
include/Feature/Hover.h (2)
src/Feature/Hover.cpp (6)
  • hover (85-96)
  • hover (85-87)
  • hover (98-104)
  • hover (98-100)
  • hover (106-154)
  • hover (106-108)
include/Compiler/CompilationUnit.h (1)
  • CompilationUnit (15-204)
src/Feature/Hover.cpp (2)
src/AST/Selection.cpp (12)
  • unit (718-727)
  • unit (718-721)
  • range (407-437)
  • range (407-407)
  • offset (592-606)
  • offset (592-592)
  • offset (1131-1136)
  • offset (1131-1131)
  • create_right (1233-1240)
  • create_right (1233-1233)
  • node (978-990)
  • node (978-978)
src/AST/Utility.cpp (2)
  • name_of (193-253)
  • name_of (193-193)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (6)
  • hover (85-96)
  • hover (85-87)
  • hover (98-104)
  • hover (98-100)
  • hover (106-154)
  • hover (106-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: linux (ubuntu-24.04, release)
  • GitHub Check: build (macos-15)
  • GitHub Check: build (windows-2025)
  • GitHub Check: build (ubuntu-24.04)
🔇 Additional comments (1)
src/Feature/Hover.cpp (1)

106-114: Return early on invalid loc is good; consider validating offset before building SelectionTree.

After adding the bounds check in src_loc_in_main_file, this is largely covered. Optional: also verify offset <= content size here for defense-in-depth.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (5)
src/Feature/Hover.cpp (3)

140-196: Consider reducing logging verbosity in node dispatch.

This function logs every node kind it encounters (lines 145, 168, 171, 177, 181, 184, 188). While useful during development, this level of logging will be very noisy in production. Consider moving to debug level or removing once the hover dispatching logic is stable.


205-207: Validate offset bounds before constructing SourceLocation.

The helper constructs a SourceLocation for any offset without checking if the offset is within the file bounds. Out-of-range offsets can produce invalid locations and cause downstream crashes.

Apply this diff to add bounds checking:

 auto src_loc_in_main_file = [&sm](uint32_t off) -> std::optional<clang::SourceLocation> {
+    auto fid = sm.getMainFileID();
+    auto size = sm.getFileIDSize(fid);
+    if(off >= size) {
+        return std::nullopt;
+    }
-    return sm.getLocForStartOfFile(sm.getMainFileID()).getLocWithOffset(off);
+    return sm.getLocForStartOfFile(fid).getLocWithOffset(off);
 };

130-138: Remove debug AST dump to stderr.

Line 135 dumps the TypeLoc AST to stderr on every type hover. This is useful for development but should be removed before merging, as it clutters stderr and exposes internal AST details.

 static std::optional<Hover> hover(CompilationUnit& unit,
                                   const clang::TypeLoc* typeloc,
                                   const config::HoverOptions& opt) {
     // TODO: Hover for type
     clice::logging::warn("Hit a typeloc");
-    typeloc->dump(llvm::errs(), unit.context());
     auto ty = typeloc->getType();
     return Hover{.kind = SymbolKind::Type, .name = ty.getAsString()};
 }
tests/unit/Feature/Hover.cpp (1)

173-187: The test scaffolding is incomplete (same issue as DeducedType_Auto).

The offsets vector is empty, so the loop doesn't test anything. Populate it with the position markers from annotation.offsets before merging.

include/Feature/Hover.h (1)

77-79: Remove the commented-out code.

Commented-out code should be removed to keep the codebase clean. If this declaration is needed in the future, it can be retrieved from version control history.

Apply this diff:

-// /// Generate the hover information for the given declaration(for test).
-// Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl, const config::HoverOptions&
-// opt);
-
 /// Generate the hover information for the symbol at the given offset.
🧹 Nitpick comments (2)
src/Server/Feature.cpp (1)

60-63: Consider making HoverOptions configurable.

The HoverOptions are hardcoded here. If hover behavior should be user-configurable (via LSP settings or workspace config), consider sourcing these options from a configuration manager rather than hardcoding them in the handler.

src/Feature/Hover.cpp (1)

29-56: Consider reducing debug logging verbosity.

Lines 30, 53-55 emit warnings on every field hover. These logs will be very noisy in production when users hover over struct members. Consider using debug level or removing them once the feature stabilizes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff5e478 and 5045bce.

📒 Files selected for processing (4)
  • include/Feature/Hover.h (3 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
tests/unit/Feature/Hover.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (250-257)
  • get_item_content (250-250)
  • display (259-272)
  • display (259-259)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
src/Feature/Hover.cpp (1)
src/AST/Selection.cpp (11)
  • unit (718-727)
  • unit (718-721)
  • kind (1185-1190)
  • kind (1185-1185)
  • os (1154-1154)
  • range (407-437)
  • range (407-407)
  • node (978-990)
  • node (978-978)
  • create_right (1233-1240)
  • create_right (1233-1233)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: linux (ubuntu-24.04, release)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: build (macos-15)
  • GitHub Check: build (windows-2025)
  • GitHub Check: build (ubuntu-24.04)
🔇 Additional comments (2)
src/Server/Feature.cpp (1)

68-78: Hover result handling looks correct.

The code properly checks the optional hover result and the optional display result before using them, with appropriate fallback messages. This addresses the previous review concern about null dereference.

src/Feature/Hover.cpp (1)

259-272: The display formatting is basic but functional.

The current implementation provides a straightforward text-based representation. This works for a WIP feature. If richer formatting is desired (collapsible sections, syntax highlighting hints, formatted tables), that can be deferred to a follow-up.

Comment on lines +98 to +109
std::vector<unsigned> offsets;
tester.compile();
expect(tester.unit.has_value());
for(auto offset: offsets) {
auto HI = clice::feature::hover(*tester.unit, offset, {});
if(HI.has_value()) {
auto msg = HI->display({});
// std::println("{}", *msg);
} else {
// std::println("No hover info");
}
}
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

The test scaffolding is incomplete.

The offsets vector is declared but never populated, so the loop at lines 101-109 iterates over an empty collection and doesn't exercise any hover functionality. Ensure you populate offsets from the annotation.offsets map (e.g., by extracting pos_0, pos_1, etc.) before merging this PR.

Apply this pattern to populate the offsets:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
+    std::vector<unsigned> offsets = {
+        annotation.offsets["pos_0"],
+        annotation.offsets["pos_1"],
+        // ... add remaining positions
+    };
     tester.compile();

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/unit/Feature/Hover.cpp around lines 98 to 109, the offsets vector is
declared but never populated so the hover loop never runs; populate offsets from
the test annotation's offsets map before calling tester.compile(), e.g. extract
entries like "pos_0", "pos_1", ... (or iterate all annotation.offsets keys) and
push their integer values into the offsets vector so the for-loop exercises
hover at those positions.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (10)
include/Feature/Hover.h (1)

77-79: Remove or document the commented-out function.

As noted in a past review, commented-out code should be removed to improve clarity. If this function is intended for future use, replace the comment with a // TODO explaining the plan.

src/Feature/Hover.cpp (6)

18-63: The opt parameter is unused in this function.

As noted in a past review, the config::HoverOptions& opt parameter is declared but not used within get_hover_items. Either use it to configure behavior (e.g., controlling which items to include) or remove it if it's not needed yet.


83-90: The opt parameter is unused.

As noted in a past review, the config::HoverOptions opt parameter is not used in get_qualifier. Consider removing it or using it to configure output formatting.


71-81: The function retrieves the comment but returns an empty string.

As flagged in a past review, line 79 retrieves raw_string but line 80 returns an empty string, so documentation is never shown in hover results.

Return the raw string until parsing is fully implemented:

     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;

130-138: Remove the debug dump to stderr.

As flagged in a past review, line 135 dumps the AST node to stderr. This debug output should be removed or conditionally compiled for production.

-    clice::logging::warn("Hit a typeloc");
-    typeloc->dump(llvm::errs(), unit.context());
     auto ty = typeloc->getType();

140-196: Excessive debug logging should be removed or reduced.

As noted in a past review, this function contains extensive clice::logging::warn calls that will clutter production logs. Either remove them, replace with debug-level logging, or conditionally compile them.


205-207: Validate offset bounds to prevent crashes.

As flagged in a past review, the lambda at lines 205-207 doesn't validate that off is within the main file's size, which can lead to invalid SourceLocation objects and downstream crashes.

Add bounds checking:

     auto src_loc_in_main_file = [&sm](uint32_t off) -> std::optional<clang::SourceLocation> {
-        return sm.getLocForStartOfFile(sm.getMainFileID()).getLocWithOffset(off);
+        auto fid = sm.getMainFileID();
+        auto buf = sm.getBufferData(fid);
+        if(off > buf.size()) {
+            return std::nullopt;
+        }
+        return sm.getLocForStartOfFile(fid).getLocWithOffset(off);
     };
tests/unit/Feature/Hover.cpp (3)

98-109: The offsets vector is never populated.

As flagged in the previous review, the offsets vector is declared but never populated from annotation.offsets, so the loop at lines 101-109 never runs and the test doesn't exercise hover functionality.

Populate the offsets vector before the loop:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
+    std::vector<unsigned> offsets;
+    for (const auto& [key, offset] : annotation.offsets) {
+        offsets.push_back(offset);
+    }
     tester.compile();

158-158: Fix the malformed token.

Line 158 contains decltyppos_13)ype(auto) which is syntactically incorrect. This should be declty$(pos_13)pe(auto) to match the annotation pattern used elsewhere.

Apply this fix:

-    decltyppos_13)ype(auto) r2 = get_ca();  // const int
+    declty$(pos_13)pe(auto) r2 = get_ca();  // const int

173-187: The offsets vector is never populated.

Same issue as in "DeducedType_Auto": the offsets vector at line 173 is declared but never populated from annotation.offsets, so the loop at lines 177-187 doesn't exercise any hover functionality.

Populate the offsets vector:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
+    std::vector<unsigned> offsets;
+    for (const auto& [key, offset] : annotation.offsets) {
+        offsets.push_back(offset);
+    }
     tester.compile();
🧹 Nitpick comments (3)
src/Server/Feature.cpp (2)

60-63: Consider externalizing the hover configuration.

The HoverOptions instance is hardcoded inline. If these settings are reused across multiple features or need to be user-configurable, consider moving them to a server-level configuration or a dedicated config file.


68-78: Improve fallback messages for production readiness.

The fallback messages "Cannot display hover info" and "Cannot get hover info" are appropriate for debugging but may confuse end users. Consider returning a more informative message or silently returning null to let the client handle the absence of hover data gracefully.

For example:

-            } else {
-                clice::logging::warn("Cannot display hover info");
-                result.contents.value = "Cannot display hover info";
-            }
+            } else {
+                clice::logging::warn("Cannot display hover info");
+                return json::Value(nullptr);
+            }
         } else {
             clice::logging::warn("Cannot get hover info");
-            result.contents.value = "Cannot get hover info";
+            return json::Value(nullptr);
         }
src/Feature/Hover.cpp (1)

110-115: The opt parameter is unused.

The config::HoverOptions opt parameter is not used in this overload of get_source_code. Consider removing it or using it to control source code formatting.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5045bce and b0dca97.

📒 Files selected for processing (4)
  • include/Feature/Hover.h (3 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
tests/unit/Feature/Hover.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (250-257)
  • get_item_content (250-250)
  • display (259-272)
  • display (259-259)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
src/Feature/Hover.cpp (2)
src/AST/Selection.cpp (15)
  • unit (718-727)
  • unit (718-721)
  • kind (1185-1190)
  • kind (1185-1185)
  • os (1154-1154)
  • range (407-437)
  • range (407-407)
  • node (978-990)
  • node (978-978)
  • offset (592-606)
  • offset (592-592)
  • offset (1131-1136)
  • offset (1131-1131)
  • create_right (1233-1240)
  • create_right (1233-1233)
src/AST/Utility.cpp (3)
  • os (375-375)
  • name_of (219-279)
  • name_of (219-219)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (macos-15)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: linux (ubuntu-24.04, release)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-2025)
🔇 Additional comments (6)
src/Server/Feature.cpp (1)

68-78: LGTM: Optional checking correctly implemented.

The code now properly checks both hover and hover->display(opt) before accessing their values, preventing the null-pointer dereference flagged in the past review.

tests/unit/Feature/Hover.cpp (1)

35-55: LGTM: Inclusion test is complete.

The "Inclusion" test properly extracts offsets from annotations and exercises the hover functionality for include directives.

include/Feature/Hover.h (3)

38-39: LGTM: Enum rename improves clarity.

Renaming EnumValue to Value broadens the semantic scope to cover variables, constants, and enum items, aligning with the updated comment.


68-74: LGTM: New methods support config-driven hover display.

The added hl_range, get_item_content, and display members enable flexible hover content retrieval and formatting, integrating well with the updated hover API.


82-84: LGTM: Public API updated to return optional and accept config.

The hover function signature now returns std::optional<Hover> and accepts config::HoverOptions, enabling guarded code paths and config-driven behavior.

src/Feature/Hover.cpp (1)

250-272: LGTM: Hover display methods are well-structured.

The get_item_content and display implementations provide clean accessors for hover data, enabling flexible presentation in the server layer.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (7)
tests/unit/Feature/Hover.cpp (3)

98-109: Test scaffolding still incomplete - offsets vector never populated.

The offsets vector is declared at line 98 but never populated with values from annotation.offsets. The loop at lines 101-109 iterates over an empty collection and doesn't exercise any hover functionality. This is the same issue flagged in the previous review.

Populate the offsets vector before the loop:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
+    std::vector<unsigned> offsets;
+    for(auto& [key, value] : annotation.offsets) {
+        offsets.push_back(value);
+    }
     tester.compile();

158-158: Fix malformed decltype syntax.

Line 158 contains decltyppos_13)ype(auto) which is malformed. This appears to be a typo mixing position marker annotation with the decltype keyword.

Fix the syntax:

-    decltyppos_13)ype(auto) r2 = get_ca();  // const int
+    decl$(pos_13)type(auto) r2 = get_ca();  // const int

173-187: Test scaffolding incomplete - offsets vector never populated.

The offsets vector at line 173 is declared but never populated with values from annotation.offsets. The loop at lines 177-187 iterates over an empty collection and doesn't test any hover functionality.

Populate the offsets vector:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
+    std::vector<unsigned> offsets;
+    for(auto& [key, value] : annotation.offsets) {
+        offsets.push_back(value);
+    }
     tester.compile();
include/Feature/Hover.h (1)

77-79: Remove commented-out code.

Rather than leaving the old function declaration commented out, please remove these lines entirely. If the signature needs to be referenced later, it will be available in version control history.

-// /// Generate the hover information for the given declaration(for test).
-// Hover hover(CompilationUnit& unit, const clang::NamedDecl* decl, const config::HoverOptions&
-// opt);
-
src/Feature/Hover.cpp (3)

71-81: Critical: Documentation is retrieved but never returned.

Line 79 successfully retrieves raw_string from the raw comment, but line 80 immediately returns an empty string without using it. This means hover will never display documentation even when comments are present. This critical issue from the previous review remains unresolved.

Return the raw string:

     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;

130-138: Remove debug output before merging.

Line 135 dumps AST node data directly to stderr via typeloc->dump(), and line 134 logs a warning. This debug instrumentation was flagged in the previous review and should be removed from the final implementation.

 static std::optional<Hover> hover(CompilationUnit& unit,
                                   const clang::TypeLoc* typeloc,
                                   const config::HoverOptions& opt) {
     // TODO: Hover for type
-    clice::logging::warn("Hit a typeloc");
-    typeloc->dump(llvm::errs(), unit.context());
     auto ty = typeloc->getType();
     return Hover{.kind = SymbolKind::Type, .name = ty.getAsString()};
 }

205-207: Critical: Validate offset bounds before constructing SourceLocation.

The lambda src_loc_in_main_file at lines 205-207 constructs a SourceLocation from an arbitrary offset without validating that the offset is within the file's bounds. Out-of-range offsets can produce invalid locations and cause downstream crashes. This critical issue from the previous review remains unresolved.

Add bounds checking:

     auto src_loc_in_main_file = [&sm](uint32_t off) -> std::optional<clang::SourceLocation> {
+        auto fid = sm.getMainFileID();
+        auto buf = sm.getBufferData(fid, /*Invalid=*/nullptr);
+        if(off > buf.size()) {
+            return std::nullopt;
+        }
-        return sm.getLocForStartOfFile(sm.getMainFileID()).getLocWithOffset(off);
+        return sm.getLocForStartOfFile(fid).getLocWithOffset(off);
     };

Verify this pattern is correct for Clang's SourceManager API:

#!/bin/bash
# Search for similar offset validation patterns in the codebase
rg -nP -C3 'getBufferData|getBuffer.*size|FileIDSize' --type=cpp
🧹 Nitpick comments (3)
src/Feature/Hover.cpp (3)

18-63: Consider reducing logging verbosity in production.

The function has several logging::warn calls (lines 30, 53-55, 58) that appear to be for development/debugging. While acceptable during active development, consider moving these to debug-level logging or removing them before the feature is finalized.


140-196: Consider reducing logging verbosity.

This function contains extensive logging::warn calls at lines 145, 168, 171, 177, 181, 184, and 188. While useful during development, this level of logging may be excessive for production. Consider reducing to debug-level or removing most of these before finalization.


215-248: Include hover logic looks good; consider reducing logging.

The logic for detecting and handling hover on include directives (lines 215-238) is well-structured. However, logging statements at lines 222 and 244 could be reduced or removed in the final version.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0dca97 and 392173c.

📒 Files selected for processing (4)
  • include/Feature/Hover.h (3 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
tests/unit/Feature/Hover.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (250-257)
  • get_item_content (250-250)
  • display (259-272)
  • display (259-259)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
src/Feature/Hover.cpp (1)
src/AST/Selection.cpp (15)
  • unit (718-727)
  • unit (718-721)
  • kind (1185-1190)
  • kind (1185-1185)
  • os (1154-1154)
  • range (407-437)
  • range (407-407)
  • node (978-990)
  • node (978-978)
  • offset (592-606)
  • offset (592-592)
  • offset (1131-1136)
  • offset (1131-1131)
  • create_right (1233-1240)
  • create_right (1233-1233)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (macos-15)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-2025)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: linux (ubuntu-24.04, release)
  • GitHub Check: linux (ubuntu-24.04, debug)
🔇 Additional comments (5)
src/Server/Feature.cpp (1)

60-80: Previous critical issue resolved - proper optional handling implemented.

The implementation now correctly checks both hover and hover->display(opt) before accessing their values, with appropriate fallback messages. This addresses the critical null-dereference concern from the previous review.

The hardcoded HoverOptions at lines 61-63 could be extracted to a configuration class or constant for better maintainability, but this is acceptable for now.

tests/unit/Feature/Hover.cpp (1)

35-55: Test exercises include hover functionality.

The test successfully exercises hover on include directives at two different positions. While it doesn't yet assert specific outcomes, this is reasonable for work-in-progress testing to validate the basic code path.

include/Feature/Hover.h (2)

6-6: API enhancements look good.

The additions are well-structured:

  • Protocol/Basic.h include supports the new hl_range field
  • Renamed enum value from EnumValue to Value with clearer documentation
  • New get_item_content and display methods provide a clean API for hover content retrieval and formatting

Also applies to: 38-39, 68-74


82-84: Updated signature aligns with refactoring goals.

The new signature returning std::optional<Hover> and accepting config::HoverOptions properly supports cases where hover information is unavailable and enables configurable hover behavior.

src/Feature/Hover.cpp (1)

250-272: Helper methods are well-implemented.

Both get_item_content and display methods provide clean, functional implementations:

  • get_item_content efficiently searches for items by kind
  • display produces well-structured, readable output with proper formatting

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
include/Feature/Hover.h (1)

77-79: Remove or document the commented code.

This was previously flagged: commented-out code should either be removed for clarity or accompanied by a TODO comment explaining its future purpose.

tests/unit/Feature/Hover.cpp (2)

98-109: The offsets vector remains unpopulated.

This issue was previously flagged: the offsets vector is declared but never populated, so the hover loop never runs. You need to extract positions from annotation.offsets (e.g., pos_0, pos_1, etc.) before the loop.


158-158: Fix the malformed token.

This typo was previously flagged: decltyppos_13)ype should be corrected to proper decltype syntax with an appropriate position marker.

src/Feature/Hover.cpp (2)

71-81: The get_document bug remains unfixed.

This critical issue was previously flagged: line 79 retrieves raw_string from the comment, but line 80 immediately returns an empty string, so documentation is never shown in hover. At minimum, return raw_string instead of "".


130-138: Remove the stderr dump.

Line 135 dumps AST data directly to stderr, which was previously flagged for removal. This debug artifact should not be in production code.

🧹 Nitpick comments (2)
src/Feature/Hover.cpp (2)

18-63: Consider using debug log level for routine operations.

Lines 30, 53-55, and 58 use warn level for normal hover item construction. Since these are routine operations (not warnings), consider using debug level to avoid cluttering production logs.


140-196: Consider reducing logging verbosity.

This function contains numerous warn-level logging statements (lines 145, 168, 171, 177, 181, 184, 188) that trace normal control flow. For production code, either remove these logs or change them to debug level to avoid cluttering logs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 392173c and 98027f7.

📒 Files selected for processing (4)
  • include/Feature/Hover.h (3 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
tests/unit/Feature/Hover.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (250-257)
  • get_item_content (250-250)
  • display (259-272)
  • display (259-259)
  • hover (117-128)
  • hover (117-119)
  • hover (130-138)
  • hover (130-132)
  • hover (140-196)
  • hover (140-142)
  • hover (200-248)
  • hover (200-202)
src/Feature/Hover.cpp (3)
src/AST/Selection.cpp (15)
  • unit (718-727)
  • unit (718-721)
  • kind (1185-1190)
  • kind (1185-1185)
  • os (1154-1154)
  • range (407-437)
  • range (407-407)
  • node (978-990)
  • node (978-978)
  • offset (592-606)
  • offset (592-592)
  • offset (1131-1136)
  • offset (1131-1131)
  • create_right (1233-1240)
  • create_right (1233-1233)
include/AST/SourceCode.h (2)
  • range (70-94)
  • clang (24-38)
src/Compiler/Directive.cpp (16)
  • loc (25-35)
  • loc (25-28)
  • loc (37-47)
  • loc (37-40)
  • loc (145-166)
  • loc (145-146)
  • loc (168-172)
  • loc (168-170)
  • loc (174-179)
  • loc (174-177)
  • loc (181-185)
  • loc (181-183)
  • loc (188-192)
  • loc (188-190)
  • loc (195-200)
  • loc (195-197)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: build (macos-15)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: build (windows-2025)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: linux (ubuntu-24.04, release)
🔇 Additional comments (2)
tests/unit/Feature/Hover.cpp (1)

35-55: The Inclusion test structure looks good.

The test correctly extracts offsets from annotations and exercises the hover feature for include directives. The unused HI variable is acceptable for work-in-progress testing.

src/Server/Feature.cpp (1)

60-80: LGTM! Proper null checks and error handling.

The hover implementation now correctly checks both the hover result and display result before dereferencing, with appropriate fallback messages. This addresses the previous review concern about missing null checks.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
include/Feature/Hover.h (1)

77-79: Remove the stale commented-out declaration.
Line 78 still carries the commented hover declaration. Either delete it or replace it with a documented TODO so it doesn’t linger as dead code.

src/Feature/Hover.cpp (3)

146-148: Drop the typeloc->dump debug print.
Line 147 dumps AST data to stderr during normal hover handling; this floods logs in production. Remove the dump (or gate it behind a debug knob).

-    clice::logging::warn("Hit a typeloc");
-    typeloc->dump(llvm::errs(), unit.context());
+    clice::logging::debug("Hit a TypeLoc");

262-264: Null-check getFileEntryForID.
Line 263 dereferences sm.getFileEntryForID(inclusion.fid) without verifying it’s non-null; missing entries will crash the server.

-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }

83-93: Return std::optional from get_document.
Lines 85-92 always return an empty string, so Hover::document becomes engaged even when no comment exists, producing empty “Document” blocks. change the helper to surface std::nullopt unless a non-empty comment is available.

-static std::string get_document(CompilationUnit& unit,
-                                const clang::NamedDecl* decl,
-                                config::HoverOptions opt) {
+static std::optional<std::string> get_document(CompilationUnit& unit,
+                                               const clang::NamedDecl* decl,
+                                               config::HoverOptions opt) {
     clang::ASTContext& Ctx = unit.context();
     const clang::RawComment* comment = Ctx.getRawCommentForAnyRedecl(decl);
-    if(!comment) {
-        return "";
-    }
-    auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    if(!comment) {
+        return std::nullopt;
+    }
+    auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
+    if(raw_string.empty()) {
+        return std::nullopt;
+    }
+    // TODO: respect opt.parse_comment_as_markdown when formatting
+    return raw_string;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98027f7 and 8cb52dc.

📒 Files selected for processing (6)
  • include/Feature/Hover.h (3 hunks)
  • include/Protocol/Feature/Hover.h (1 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • src/Server/Lifecycle.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/unit/Feature/Hover.cpp
  • src/Server/Feature.cpp
🧰 Additional context used
🧬 Code graph analysis (2)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (329-336)
  • get_item_content (329-329)
  • display (338-356)
  • display (338-338)
  • hover (129-140)
  • hover (129-131)
  • hover (142-151)
  • hover (142-144)
  • hover (153-220)
  • hover (153-155)
  • hover (224-327)
  • hover (224-226)
src/Feature/Hover.cpp (3)
include/AST/SourceCode.h (2)
  • range (70-94)
  • clang (24-38)
src/AST/Selection.cpp (18)
  • range (407-437)
  • range (407-407)
  • begin (565-589)
  • begin (565-565)
  • unit (718-727)
  • unit (718-721)
  • kind (1185-1190)
  • kind (1185-1185)
  • node (978-990)
  • node (978-978)
  • offset (592-606)
  • offset (592-592)
  • offset (1131-1136)
  • offset (1131-1131)
  • fid (513-562)
  • fid (513-514)
  • create_right (1233-1240)
  • create_right (1233-1233)
src/AST/Utility.cpp (2)
  • name_of (219-279)
  • name_of (219-219)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (4)
src/Server/Lifecycle.cpp (1)

38-39: The compile_commands.json loading remains disabled.

This change was flagged in previous reviews as critical. Commenting out the compilation database loading removes essential compiler context (include paths, flags, defines) needed for accurate hover information and other LSP features. Since this PR is marked "In process," ensure this line is restored before merging.

src/Feature/Hover.cpp (3)

36-38: The add_item lambda has a potential compilation issue.

The lambda calls items.emplace_back(kind, val), but HoverItem is an aggregate with no constructor taking (HoverKind, std::string). This was flagged in a previous review.

Apply this fix:

 auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-    items.emplace_back(kind, val);
+    items.emplace_back(HoverItem{kind, std::move(val)});
 };

83-93: The get_document function returns an empty string instead of the comment text.

Line 91 retrieves the raw comment but line 92 immediately returns an empty string, so documentation is never displayed. This was flagged in a previous review.

Apply this fix:

 static std::string get_document(CompilationUnit& unit,
                                 const clang::NamedDecl* decl,
                                 config::HoverOptions opt) {
     clang::ASTContext& Ctx = unit.context();
     const clang::RawComment* comment = Ctx.getRawCommentForAnyRedecl(decl);
     if(!comment) {
         return "";
     }
     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;
 }

253-267: Missing null check before dereferencing FileEntry.

Line 262 calls sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName() without checking if getFileEntryForID returns nullptr. This was flagged in a previous review.

Apply this defensive check:

             auto raw_name = get_source_code(unit, inclusion.filename_range);
             auto file_name = llvm::StringRef{raw_name}.trim("<>\"");
             Hover hi;
             hi.kind = SymbolKind::Directive;
             hi.name = file_name;
-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
             // TODO: Provides symbol
             return hi;
🧹 Nitpick comments (4)
src/Server/Feature.cpp (1)

60-63: Consider loading HoverOptions from server configuration.

The options are currently hardcoded inline. Moving these to the server's configuration structure would improve maintainability and allow users to customize hover behavior without code changes.

tests/unit/Feature/Hover.cpp (1)

156-156: The offsets vector is declared but never used.

The vector is initialized but the test directly extracts offsets from annotation.offsets in the loop below (lines 161-162). This variable can be removed.

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    std::vector<unsigned> offsets;
     tester.compile();
include/Feature/Hover.h (1)

77-79: Commenting out the test helper function is acceptable.

Since this function is for testing and may be re-enabled later, commenting it out is reasonable for a work-in-progress PR. Consider removing it entirely if it won't be used.

src/Feature/Hover.cpp (1)

42-42: Consider reducing debug logging verbosity.

The logging::warn calls throughout the implementation (lines 42, 65-67, 70, and many more below) are useful during development but should be reduced or removed before merging to avoid log clutter in production. Consider using logging::debug or removing them.

Also applies to: 65-67, 70-70

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb52dc and 2775db5.

📒 Files selected for processing (6)
  • include/Feature/Hover.h (3 hunks)
  • include/Protocol/Feature/Hover.h (1 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • src/Server/Lifecycle.cpp (1 hunks)
  • tests/unit/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (129-140)
  • hover (129-131)
  • hover (142-151)
  • hover (142-144)
  • hover (153-220)
  • hover (153-155)
  • hover (224-327)
  • hover (224-226)
include/Feature/Hover.h (2)
src/Feature/Hover.cpp (12)
  • get_item_content (329-336)
  • get_item_content (329-329)
  • display (338-356)
  • display (338-338)
  • hover (129-140)
  • hover (129-131)
  • hover (142-151)
  • hover (142-144)
  • hover (153-220)
  • hover (153-155)
  • hover (224-327)
  • hover (224-226)
include/Compiler/CompilationUnit.h (1)
  • CompilationUnit (15-204)
tests/unit/Feature/Hover.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (129-140)
  • hover (129-131)
  • hover (142-151)
  • hover (142-144)
  • hover (153-220)
  • hover (153-155)
  • hover (224-327)
  • hover (224-226)
src/Feature/Hover.cpp (1)
src/AST/Selection.cpp (11)
  • range (401-431)
  • range (401-401)
  • unit (712-721)
  • unit (712-715)
  • kind (1179-1184)
  • kind (1179-1179)
  • os (1148-1148)
  • node (972-984)
  • node (972-972)
  • create_right (1227-1234)
  • create_right (1227-1227)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: build (macos-15)
  • GitHub Check: macos (macos-15, release)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: build (windows-2025)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: linux (ubuntu-24.04, release)
🔇 Additional comments (18)
include/Protocol/Feature/Hover.h (1)

20-20: LGTM!

The addition of std::optional<Range> to support hover range visualization is well-documented and aligns with the broader hover feature enhancements.

src/Server/Feature.cpp (1)

68-82: Good defensive handling of optional hover results.

The code properly checks for std::nullopt before accessing hover data and provides clear fallback messages when hover information is unavailable or cannot be displayed. This addresses the past review concern about dereferencing without checking.

tests/unit/Feature/Hover.cpp (3)

35-82: LGTM!

The Inclusion tests properly exercise hover functionality for include directives with both PCH and non-PCH compilation paths, correctly extracting offsets from annotations and calling the hover API.


115-170: The DeducedType_Auto test looks good.

The test properly compiles annotated code and exercises hover at each annotated position with appropriate display handling.


172-245: The DeducedType_Decltype test looks good.

The test properly compiles annotated code and exercises hover at each annotated position with appropriate display handling.

include/Feature/Hover.h (4)

6-6: LGTM!

Adding the Protocol/Basic.h include is necessary for the proto::Range type used in hl_range.


38-39: LGTM!

Renaming EnumValue to Value with the updated comment better reflects the broader semantics for variables, constants, and enum items.


60-74: LGTM!

The structural changes are well-designed:

  • Making document optional is appropriate since not all symbols have documentation.
  • Adding hl_range supports range-based highlighting.
  • The new helper methods get_item_content() and display() provide clean interfaces for content extraction and rendering.

82-84: LGTM!

The updated signature returning std::optional<Hover> and accepting config::HoverOptions properly reflects that hover may not always be available and allows for configurable behavior.

src/Feature/Hover.cpp (9)

20-28: LGTM!

The to_proto_range helper cleanly converts Clang's SourceRange to the protocol's Range format using spelling locations.


41-72: Good implementation of hover items for fields and variables.

The code properly extracts type information, offsets, alignment, size, and bitfield data for field declarations, with appropriate checks for dependent types and unions.


95-127: LGTM!

The get_qualifier and get_source_code helper functions properly extract qualified names and source text using Clang's APIs.


129-140: LGTM!

The hover function for NamedDecl cleanly aggregates all hover information using the helper functions.


153-220: The node-based hover dispatch is well-structured.

The function properly dispatches to type-specific hover handlers based on AST node kind, with appropriate handling for auto/decltype types and fallbacks for unhandled node types.


229-236: LGTM!

The src_loc_in_main_file lambda now includes proper bounds checking, which addresses a previous review concern about validating offsets against file size.


270-313: Good implementation of macro hover support.

The code properly extracts macro names, definitions, and expansions with appropriate range information. The macro expansion text extraction is a nice feature.


315-327: LGTM!

The fallback to SelectionTree-based hover with proper range attachment is well-implemented.


329-356: LGTM!

The get_item_content and display member functions provide clean interfaces for extracting and rendering hover information. The markdown-like formatting is readable and informative.

Comment on lines +110 to +113
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {}
};
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

The Macros test loop body is empty.

The test sets up annotated code with macro positions but the loop at line 112 iterates over annotation.offsets.size() without actually calling the hover API or making any assertions. This test doesn't verify any behavior.

Populate the loop body to exercise hover functionality:

     auto annotation = AnnotatedSource::from(code);
     tester.add_main("main.cpp", annotation.content);
-    for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {}
+    tester.compile();
+    expect(tester.unit.has_value());
+    for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {
+        unsigned offset = annotation.offsets[std::format("pos_{}", idx)];
+        auto HI = clice::feature::hover(*tester.unit, offset, {});
+        if(HI.has_value()) {
+            auto msg = HI->display({});
+            std::println("```\n{}```\n", *msg);
+        } else {
+            std::println("No hover info for pos_{}", idx);
+        }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {}
};
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
tester.compile();
expect(tester.unit.has_value());
for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {
unsigned offset = annotation.offsets[std::format("pos_{}", idx)];
auto HI = clice::feature::hover(*tester.unit, offset, {});
if(HI.has_value()) {
auto msg = HI->display({});
std::println("
🤖 Prompt for AI Agents
In tests/unit/Feature/Hover.cpp around lines 110 to 113, the for-loop over
annotation.offsets is empty so the test never exercises hover behavior; update
the loop to iterate each annotated offset, convert each offset to a
file/position, call the hover API (via the existing tester helper), and assert
or check the returned hover response (e.g., expect non-empty hover or match
against annotation.expected content), otherwise print/log "No hover info for
pos_{idx}" to make failures visible; ensure any required file/URI/position
construction uses the same helpers as above and add appropriate assertions so
the test validates hover results.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (5)
src/Feature/Hover.cpp (5)

37-39: Fix aggregate construction in add_item lambda.

This issue was previously flagged: HoverItem has no constructor taking (HoverKind, std::string). The lambda must construct the aggregate explicitly.

Apply this diff:

 auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-    items.emplace_back(kind, val);
+    items.emplace_back(HoverItem{kind, std::move(val)});
 };

84-94: Fix the documentation retrieval logic.

This critical issue was previously flagged: Line 92 retrieves raw_string but Line 93 immediately returns an empty string, so hover will never display documentation.

Apply this diff to return the retrieved documentation:

 static std::string get_document(CompilationUnit& unit,
                                 const clang::NamedDecl* decl,
                                 config::HoverOptions opt) {
     clang::ASTContext& Ctx = unit.context();
     const clang::RawComment* comment = Ctx.getRawCommentForAnyRedecl(decl);
     if(!comment) {
         return "";
     }
     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;
 }

86-86: Address unused opt parameters.

This issue was previously flagged: The opt parameter of type config::HoverOptions is not used in get_document, get_qualifier, or get_source_code. Unused parameters can be misleading.

Either implement the configuration options (e.g., parse comments as markdown based on opt.parse_comment_as_markdown) or remove the parameters if they're not yet needed.

Also applies to: 98-98, 327-327


349-350: Remove debug dump to stderr.

This issue was previously flagged: Line 350 dumps AST data directly to stderr. This is useful for debugging but should not be part of the final implementation.

Apply this diff:

 static std::optional<Hover> hover(CompilationUnit& unit,
                                   const clang::TypeLoc* typeloc,
                                   const config::HoverOptions& opt) {
     // TODO: Hover for type
     LOGGING_WARN("Hit a typeloc");
-    typeloc->dump();
     auto ty = typeloc->getType();

467-468: Add null check for FileEntry before dereferencing.

This critical issue was previously flagged: Line 467 calls sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName() without checking if getFileEntryForID returns nullptr.

Apply this defensive check:

             Hover hi;
             hi.kind = SymbolKind::Directive;
             hi.name = file_name;
-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
             // TODO: Provides symbol
             return hi;
🧹 Nitpick comments (1)
src/Feature/Hover.cpp (1)

476-477: Remove or downgrade verbose logging.

This logging may be useful for development but should be removed or converted to debug-level logging for production.

     auto tokens_under_cursor = unit.spelled_tokens_touch(*loc);
     if(tokens_under_cursor.empty()) {
-        LOGGING_WARN("Cannot detect tokens");
         return std::nullopt;
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2775db5 and 54266f2.

📒 Files selected for processing (1)
  • src/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Feature/Hover.cpp (2)
src/AST/Selection.cpp (17)
  • range (401-431)
  • range (401-401)
  • begin (559-583)
  • begin (559-559)
  • unit (712-721)
  • unit (712-715)
  • kind (1179-1184)
  • kind (1179-1179)
  • os (1148-1148)
  • node (972-984)
  • node (972-972)
  • offset (586-600)
  • offset (586-586)
  • offset (1125-1130)
  • offset (1125-1125)
  • create_right (1227-1234)
  • create_right (1227-1227)
src/Compiler/CompilationUnit.cpp (2)
  • resolver (317-320)
  • resolver (317-317)
🔇 Additional comments (5)
src/Feature/Hover.cpp (5)

486-488: Verify the need to remove the last character from macro name.

Line 487 calls pop_back() on the macro name without explanation. This seems unusual and could indicate a workaround for an extraction issue.

Verify that this is intentional. If get_source_code consistently includes an unwanted trailing character, consider fixing the root cause in the extraction function rather than working around it here. Add a comment explaining why this is necessary if it's intentional.


118-155: Template helper functions look good.

The getContainedAutoParamType and template instantiation helpers are well-structured and handle the necessary type unwrapping and template specialization logic correctly.


165-303: DeducedTypeVisitor implementation is well-structured.

The visitor pattern correctly handles various auto/decltype type deduction scenarios including function returns, declarators, and template parameters. The logic for unwrapping types and finding instantiations appears sound.

Note the FIXME at line 191 regarding resolver usage for undeduced auto types in variable declarations.


434-441: Offset validation is correctly implemented.

The bounds checking added here addresses a previously flagged critical issue. The function now validates that the offset is within the file buffer before constructing a SourceLocation, preventing potential crashes from out-of-range offsets.


543-561: Display method provides good structured output.

The display method correctly formats hover information with items, documentation, and source code. The TODO comment appropriately indicates future markdown generation capability.

Comment on lines +397 to +417
LOGGING_WARN("Hit a `NestedNameSpecifierLoc`");
} else if(is_in_range(QualType, TypeLoc)) {
// Typeloc
LOGGING_WARN("Hit a `TypeLoc`");
if(auto typeloc = node->get<clang::TypeLoc>()) {
return hover(unit, typeloc, opt);
}
} else if(is_in_range(Decl, Stmt)) {
// Decl
LOGGING_WARN("Hit a `Decl`");
if(auto decl = node->get<clang::NamedDecl>()) {
return hover(unit, decl, opt);
} else {
LOGGING_WARN("Not intersted");
}
} else if(is_in_range(Attr, ObjCProtocolLoc)) {
LOGGING_WARN("Hit an `Attr`");
// TODO: Attr
} else {
// Not interested
LOGGING_WARN("Not interested");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Reduce verbose logging in node routing logic.

These logging statements appear to be for debugging the node kind routing logic. They should be removed or converted to debug-level logging to avoid cluttering production logs.

Consider removing these logging statements:

     if(is(NestedNameSpecifierLoc)) {
-        LOGGING_WARN("Hit a `NestedNameSpecifierLoc`");
     } else if(is_in_range(QualType, TypeLoc)) {
         // Typeloc
-        LOGGING_WARN("Hit a `TypeLoc`");
         if(auto typeloc = node->get<clang::TypeLoc>()) {
             return hover(unit, typeloc, opt);
         }
     } else if(is_in_range(Decl, Stmt)) {
         // Decl
-        LOGGING_WARN("Hit a `Decl`");
         if(auto decl = node->get<clang::NamedDecl>()) {
             return hover(unit, decl, opt);
         } else {
-            LOGGING_WARN("Not intersted");
         }
     } else if(is_in_range(Attr, ObjCProtocolLoc)) {
-        LOGGING_WARN("Hit an `Attr`");
         // TODO: Attr
     } else {
         // Not interested
-        LOGGING_WARN("Not interested");
     }
🤖 Prompt for AI Agents
In src/Feature/Hover.cpp around lines 397 to 417 the code emits multiple
LOGGING_WARN messages used only for routing/debugging; change these to a
debug-level logger (e.g., LOGGING_DEBUG) or remove them entirely to avoid
verbose production logs, keeping only meaningful warnings/errors; update the
messages consistently (or drop the "Not interested"/"Not intersted" ones) so
routing logic no longer floods warning logs.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (10)
src/Feature/Hover.cpp (10)

43-43: Remove verbose debug logging.

This development logging statement clutters production logs and was flagged in previous reviews.

Apply this diff:

     if(auto fd = llvm::dyn_cast<clang::FieldDecl>(decl)) {
-        LOGGING_WARN("Got a field decl");
         const auto record = fd->getParent();

66-68: Remove verbose debug logging.

This was flagged in previous reviews. Routine field processing should not emit warnings to production logs.

Apply this diff:

         if(fd->isBitField()) {
             add_item(HoverItem::BitWidth, llvm::Twine(fd->getBitWidthValue()).str());
-            LOGGING_WARN("Got bit field, name: {}, bitwidth: {}",
-                         fd->getName(),
-                         fd->getBitWidthValue());
         }

71-71: Remove verbose debug logging.

This development logging statement was flagged in previous reviews and should be removed.

Apply this diff:

     } else if(auto vd = llvm::dyn_cast<clang::VarDecl>(decl)) {
-        LOGGING_WARN("Got a var decl");
         add_item(HoverItem::Type, vd->getType().getAsString());

392-413: Reduce verbose logging in node routing logic.

These logging statements were flagged in a previous review. They clutter production logs and should be removed or converted to debug-level logging.

Consider removing or downgrading these logging statements:

     if(is(NestedNameSpecifierLoc)) {
-        LOGGING_WARN("Hit a `NestedNameSpecifierLoc`");
     } else if(is_in_range(QualType, TypeLoc)) {
-        LOGGING_WARN("Hit a `TypeLoc`");
         if(auto typeloc = node->get<clang::TypeLoc>()) {
             return hover(unit, typeloc->getType(), opt);
         }
     } else if(is_in_range(Decl, Stmt)) {
-        LOGGING_WARN("Hit a `Decl`");
         if(auto decl = node->get<clang::NamedDecl>()) {
             return hover(unit, decl, opt);
         } else {
-            LOGGING_WARN("Not intersted");
         }
     } else if(is_in_range(Attr, ObjCProtocolLoc)) {
-        LOGGING_WARN("Hit an `Attr`");
         // TODO: Attr
     } else {
-        LOGGING_WARN("Not interested");
     }

471-471: Remove verbose debug logging.

This was flagged in previous reviews and clutters production logs.

Apply this diff:

     auto tokens_under_cursor = unit.spelled_tokens_touch(*loc);
     if(tokens_under_cursor.empty()) {
-        LOGGING_WARN("Cannot detect tokens");
         return std::nullopt;
     }

516-524: Remove verbose debug logging.

These logging statements were flagged in a previous review and should be removed to keep production logs clean.

     auto tree = SelectionTree::create_right(unit, {offset, offset});
     if(auto node = tree.common_ancestor()) {
-        LOGGING_WARN("Got node: {}", node->kind());
         if(auto info = hover(unit, node, opt)) {
             info->hl_range = to_proto_range(sm, hl_range);
             return info;
         }
         return std::nullopt;
     } else {
-        LOGGING_WARN("Not an ast node");
     }

37-38: Fix add_item construction.

This was flagged in a previous review: HoverItem has no (HoverKind, std::string) constructor, so items.emplace_back(kind, val) will not compile. Build the aggregate explicitly.

Apply this diff:

-    auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-        items.emplace_back(kind, val);
+    auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
+        items.emplace_back(HoverItem{kind, std::move(val)});
     };

78-82: TypeLoc hover items implementation is empty.

This was flagged in a previous review. Add a TODO comment to track future work if this is planned.

Add a TODO comment:

 static std::vector<HoverItem> get_hover_items(CompilationUnit& unit,
                                               const clang::TypeLoc* typeloc,
                                               const config::HoverOptions& opt) {
+    // TODO: Implement hover items for TypeLoc (e.g., size, alignment)
     return {};
 }

84-94: Fix the logic bug in get_document.

This was flagged in a previous review. Line 92 retrieves the raw comment but line 93 returns an empty string, so documentation is never shown.

Apply this diff:

     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;
 }

462-463: Check for null FileEntry before dereferencing.

This was marked as addressed in previous commits, but the code still dereferences getFileEntryForID without checking for nullptr, which can crash.

Apply this defensive check:

             hi.kind = SymbolKind::Directive;
             hi.name = file_name;
-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
             // TODO: Provides symbol
🧹 Nitpick comments (1)
src/Feature/Hover.cpp (1)

47-48: Remove commented-out code.

Commented code marked for removal creates maintenance debt. Either delete it or move it behind a debug flag if needed for development.

Apply this diff:

         add_item(HoverItem::Type, fd->getType().getAsString());
 
-        /// Remove in release mode
-        /// add_item(HoverItem::FieldIndex, llvm::Twine(fd->getFieldIndex()).str());
         if(!record->isDependentType()) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54266f2 and c64516a.

📒 Files selected for processing (1)
  • src/Feature/Hover.cpp (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/Feature/Hover.cpp (2)
src/AST/Selection.cpp (17)
  • range (401-431)
  • range (401-401)
  • begin (559-583)
  • begin (559-559)
  • unit (712-721)
  • unit (712-715)
  • kind (1179-1184)
  • kind (1179-1179)
  • os (1148-1148)
  • node (972-984)
  • node (972-972)
  • offset (586-600)
  • offset (586-586)
  • offset (1125-1130)
  • offset (1125-1125)
  • create_right (1227-1234)
  • create_right (1227-1227)
src/Compiler/CompilationUnit.cpp (2)
  • resolver (317-320)
  • resolver (317-317)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (macos-15)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (windows-2025)
  • GitHub Check: macos (macos-15, debug)
  • GitHub Check: linux (ubuntu-24.04, release)
  • GitHub Check: linux (ubuntu-24.04, debug)
  • GitHub Check: windows (windows-2025)
  • GitHub Check: macos (macos-15, release)
🔇 Additional comments (1)
src/Feature/Hover.cpp (1)

480-482: Review comment remains valid—request manual verification of the pop_back() behavior.

The investigation confirms this is an unusual pattern. The token.range().toCharRange().getAsRange() conversion sequence appears only once in the codebase (line 480), and pop_back() is only applied here when extracting macro token names. Line 457 uses a different strategy—.trim() with known delimiters—suggesting these are intentional but unexplained differences.

The boundary calculation through clang::Lexer::getLocForEndOfToken() combined with CharSourceRange::getCharRange() and getAsRange() could plausibly result in an off-by-one character. However, without test execution or Clang API validation, the correctness cannot be definitively determined. The "TODO: Found macro" comment suggests this code may still be under development.

Please verify: (1) that macro names are extracted correctly with the pop_back() call, (2) whether test coverage exists for this code path, and (3) whether similar token range conversions elsewhere in the codebase should also apply this trimming.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (6)
include/Feature/Hover.h (1)

78-80: Remove commented-out code.

Per the past review comment, commented-out code should be removed. If this function is needed for testing, consider keeping it with appropriate visibility or adding a TODO explaining when it will be restored.

src/Feature/Hover.cpp (5)

155-160: Add TODO comment for unimplemented TypeLoc hover items.

Per past review, this empty implementation should have a TODO to track planned work.


618-626: Consider reducing verbose debug logging.

Per past reviews, LOG_WARN statements like "Got node", "Not an ast node" are development debugging aids. Consider removing or converting to debug-level logging before merging.


106-108: Fix add_item aggregate construction.

Per past review, HoverItem has no (HoverKind, std::string) constructor. Build the aggregate explicitly and move the value.

     auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-        items.emplace_back(kind, val);
+        items.emplace_back(HoverItem{kind, std::move(val)});
     };

162-173: Fix get_document to return the raw comment.

Per past review, this function retrieves the comment but returns an empty string. Return raw_string or add a TODO explaining why it's intentionally empty.

     auto raw_string = comment->getRawText(Ctx.getSourceManager()).str();
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;

566-567: Check for null FileEntry before dereferencing.

Per past review, getFileEntryForID can return nullptr. Add a null check.

-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
🧹 Nitpick comments (4)
include/Feature/Hover.h (1)

25-25: Fix typo in comment.

"drieved" should be "derived".

-    // NOTE: Use a set of drieved classes?
+    // NOTE: Use a set of derived classes?
tests/unit/Feature/HoverTests.cpp (1)

166-168: Prefer assertions over print statements in tests.

Using std::println for output doesn't validate correctness. Consider adding ASSERT_TRUE/EXPECT_* assertions to verify the hover results match expectations, or at minimum use proper test framework logging.

src/Feature/Hover.cpp (2)

148-150: Unused variable ty.

The variable ty is assigned but never used.

     } else if(auto vd = llvm::dyn_cast<clang::VarDecl>(decl)) {
-        auto ty = vd->getType();
+        // TODO: Add size/align info for VarDecl if non-dependent
     }

460-461: Remove unused variable wanted_node.

wanted_node is declared but never used.

-    auto wanted_node = node;
     auto Kind = node->data.getNodeKind();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c64516a and 7c3c815.

📒 Files selected for processing (5)
  • include/Feature/Hover.h (4 hunks)
  • include/Protocol/Feature/Hover.h (1 hunks)
  • src/Feature/Hover.cpp (1 hunks)
  • src/Server/Feature.cpp (1 hunks)
  • tests/unit/Feature/HoverTests.cpp (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • include/Protocol/Feature/Hover.h
  • src/Server/Feature.cpp
🧰 Additional context used
🧬 Code graph analysis (2)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (10)
  • display (640-658)
  • display (640-640)
  • hover (411-422)
  • hover (411-413)
  • hover (424-430)
  • hover (424-426)
  • hover (432-524)
  • hover (432-434)
  • hover (528-629)
  • hover (528-530)
tests/unit/Feature/HoverTests.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (411-422)
  • hover (411-413)
  • hover (424-430)
  • hover (424-426)
  • hover (432-524)
  • hover (432-434)
  • hover (528-629)
  • hover (528-530)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (macos-15, releasedbg)
  • GitHub Check: build (macos-15, debug)
  • GitHub Check: build (ubuntu-24.04, debug)
  • GitHub Check: build (ubuntu-24.04, releasedbg)
  • GitHub Check: build (windows-2025, releasedbg)
  • GitHub Check: build (ubuntu-24.04, Debug, clang-20, clang++-20)
  • GitHub Check: build (macos-15, Debug, clang, clang++)
  • GitHub Check: build (windows-2025, RelWithDebInfo, clang, clang++)
🔇 Additional comments (4)
include/Feature/Hover.h (3)

39-40: LGTM!

The rename from EnumValue to Value with an updated comment clarifying its broader use for variables (initialization/constant) and enum items is a sensible generalization.


68-75: LGTM!

The additions of hl_range for highlight range tracking, get_item_content for item lookup, and display for rendering are well-structured. The display method accepting config::HoverOptions by value is appropriate for a small options struct.


83-85: LGTM!

The updated API signature returning std::optional<Hover> with an additional config::HoverOptions parameter is a good design choice—it clearly signals when hover info may not be available and allows configurable behavior.

src/Feature/Hover.cpp (1)

631-658: LGTM!

The get_item_content and display implementations are straightforward and functional. The display output format is clear and includes proper markdown formatting for documentation and source code sections.

Comment on lines +473 to +489
if(is(NestedNameSpecifierLoc)) {
if(auto ns_specifier_loc = node->get<NestedNameSpecifierLoc>()) {
LOG_WARN("Hit a `NestedNameSpecifierLoc`");
if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
auto ns = ns_specifier->getAsNamespace();
assert(ns);
std::string name;
if(!ns->isAnonymousNamespace()) {
name = ns->getNameAsString();
} else {
name = "Anonymous";
}
return Hover{.kind = SymbolKind::Namespace, .name = name};
} else {
LOG_WARN("Cannot get namespace");
}
}
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

Handle null namespace gracefully instead of asserting.

getAsNamespace() can return null for non-namespace specifiers (e.g., type specifiers like Foo::). The assert(ns) will crash in release builds. Handle this case gracefully.

     if(is(NestedNameSpecifierLoc)) {
         if(auto ns_specifier_loc = node->get<NestedNameSpecifierLoc>()) {
             LOG_WARN("Hit a `NestedNameSpecifierLoc`");
             if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
                 auto ns = ns_specifier->getAsNamespace();
-                assert(ns);
+                if(!ns) {
+                    // Not a namespace specifier (could be a type specifier)
+                    return std::nullopt;
+                }
                 std::string name;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(is(NestedNameSpecifierLoc)) {
if(auto ns_specifier_loc = node->get<NestedNameSpecifierLoc>()) {
LOG_WARN("Hit a `NestedNameSpecifierLoc`");
if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
auto ns = ns_specifier->getAsNamespace();
assert(ns);
std::string name;
if(!ns->isAnonymousNamespace()) {
name = ns->getNameAsString();
} else {
name = "Anonymous";
}
return Hover{.kind = SymbolKind::Namespace, .name = name};
} else {
LOG_WARN("Cannot get namespace");
}
}
if(is(NestedNameSpecifierLoc)) {
if(auto ns_specifier_loc = node->get<NestedNameSpecifierLoc>()) {
LOG_WARN("Hit a `NestedNameSpecifierLoc`");
if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
auto ns = ns_specifier->getAsNamespace();
if(!ns) {
// Not a namespace specifier (could be a type specifier)
return std::nullopt;
}
std::string name;
if(!ns->isAnonymousNamespace()) {
name = ns->getNameAsString();
} else {
name = "Anonymous";
}
return Hover{.kind = SymbolKind::Namespace, .name = name};
} else {
LOG_WARN("Cannot get namespace");
}
}
🤖 Prompt for AI Agents
In src/Feature/Hover.cpp around lines 473-489, remove the assert(ns) and instead
check if ns is null; if getAsNamespace() returns nullptr, log a warning (e.g.,
LOG_WARN("NestedNameSpecifier is not a namespace")) and return a safe Hover
value (for example with SymbolKind::Unknown and an empty name) so the code does
not crash in release builds; otherwise proceed to build the namespace name and
return the Namespace Hover as before.

Comment on lines +36 to +83
TEST_CASE(Inclusion){{tester.clear();
constexpr auto code = R"CODE(
$(inc1)#include <iostream>

#include $(inc2)<assert.h>

int main(void) {
std::cout << "hello" << std::endl;
return 0;
}
)CODE";
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
auto inc1_off = annotation.offsets["inc1"];
auto inc2_off = annotation.offsets["inc2"];
tester.compile_with_pch();
ASSERT_TRUE(tester.unit.has_value());
auto HI = clice::feature::hover(*tester.unit, inc1_off, {});
HI = clice::feature::hover(*tester.unit, inc2_off, {});

} // TEST_SUITE(Hover)

{
tester.clear();
constexpr auto code = R"CODE(
#inc$(inc1)lude <assert.h>
#inc$(inc2)lude <stdio.h>

#define max(a, b) ((a) > (b) ? (a) : (b))

int main(int argc, char **argv) {
assert(argc <= 10);
int x = max(114, 514);
printf("%d", max(argc, x));
return 0;
}
)CODE";
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
auto inc1_off = annotation.offsets["inc1"];
auto inc2_off = annotation.offsets["inc2"];
tester.compile();
ASSERT_TRUE(tester.unit.has_value());
auto HI = clice::feature::hover(*tester.unit, inc1_off, {});
HI = clice::feature::hover(*tester.unit, inc2_off, {});
}

}; // namespace
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 | 🔴 Critical

Critical: Fix malformed test case structure.

The brace structure here is broken. TEST_CASE(Inclusion) appears to end prematurely at line 56 with } // TEST_SUITE(Hover), but then there's a dangling code block from lines 58-81 followed by }; // namespace at line 83. This will likely cause compilation errors or unintended test behavior.

Consider restructuring:

-TEST_CASE(Inclusion){{tester.clear();
+TEST_CASE(Inclusion) {
+    tester.clear();
 constexpr auto code = R"CODE(
 ...
-}  // TEST_SUITE(Hover)
-
-{
+    // Second inclusion test case
     tester.clear();
     ...
-};  // namespace
+}

Alternatively, split this into two separate TEST_CASE blocks with descriptive names.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/unit/Feature/HoverTests.cpp around lines 36 to 83 the
TEST_CASE(Inclusion) block is prematurely closed (line ~56) leaving a dangling
standalone code block and mismatched closing comment/brace at line 83; fix by
restoring proper brace structure: either merge the dangling block into the
original TEST_CASE by removing the stray closing brace/comment so a single
TEST_CASE contains both code sections, or convert the dangling block into its
own TEST_CASE with an appropriate name and ensure each TEST_CASE has matching
opening and closing braces and that the file-level namespace/test-suite closures
remain balanced. Ensure comments reflect the corrected boundaries.

return ca;
};
declt$(pos_12)ype(auto) r1 = get_a(); // int&
decltyp$(pos_13)ype(auto) r2 = get_ca(); // const int
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 | 🟡 Minor

Typo in annotation placeholder.

decltyp$(pos_13)ype has an extra "ype" creating "decltypeype" after placeholder substitution. Should be decltype$(pos_13) or the placeholder positioned differently.

🤖 Prompt for AI Agents
In tests/unit/Feature/HoverTests.cpp around line 218, the token
"decltyp$(pos_13)ype" contains a typo where the placeholder split leaves an
extra "ype" producing "decltypeype"; replace the whole token with
"decltype$(pos_13)" so the placeholder surrounds the complete keyword (i.e.,
change decltyp$(pos_13)ype to decltype$(pos_13)) and keep the rest of the line
as-is.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (10)
tests/unit/Feature/HoverTests.cpp (4)

36-83: Critical: Fix malformed test case structure.

The brace structure is broken:

  1. Line 36 has double opening braces {{
  2. Line 56 has a premature closing comment // TEST_SUITE(Hover) but still inside the test
  3. Line 58 has a dangling { block
  4. Line 83 has }; with incorrect namespace comment

This will cause compilation errors or unintended test behavior.

Consider restructuring into proper separate test cases:

-TEST_CASE(Inclusion){{tester.clear();
+TEST_CASE(Inclusion) {
+    tester.clear();
 constexpr auto code = R"CODE(
 ...
-}  // TEST_SUITE(Hover)
-
-{
+}
+
+TEST_CASE(Inclusion_WithMacros) {
     tester.clear();
     ...
-};  // namespace
+}

113-114: Empty loop body does nothing.

The loop iterates over annotation.offsets but the body is empty, making the iteration pointless. Either add hover assertions inside the loop or remove it.

-    for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {}
+    for(unsigned idx = 0; idx < annotation.offsets.size(); ++idx) {
+        unsigned offset = annotation.offsets[std::format("pos_{}", idx)];
+        auto HI = clice::feature::hover(*tester.unit, offset, {});
+        ASSERT_TRUE(HI.has_value());
+    }
 };

218-218: Typo in annotation placeholder.

decltyp$(pos_13)ype has an extra "ype" which will produce "decltypeype" after placeholder substitution. This should be decltype$(pos_13) to correctly annotate the keyword.

-    decltyp$(pos_13)ype(auto) r2 = get_ca();  // const int
+    decltype$(pos_13)(auto) r2 = get_ca();  // const int

684-686: Mismatched namespace closing comments and extra semicolon.

Line 684 has }; (semicolon after closing brace) and the comment // namespace clice::testing is on the wrong line. The anonymous namespace closes at line 685, and clice::testing closes at line 686.

-};  // namespace clice::testing
-}  // namespace
+}  // anonymous namespace
 }  // namespace clice::testing
src/Feature/Hover.cpp (6)

47-53: Logic bug: condition should check !qt.isNull().

The condition qt.isNull() && opt.show_aka will never produce the "a.k.a" output because qt.print(os, pp) was just called on line 46, implying qt is valid. If qt were null, desugaring would be meaningless. This should be !qt.isNull().

-    if(qt.isNull() && opt.show_aka) {
+    if(!qt.isNull() && opt.show_aka) {
         bool should_aka = false;
         auto desugared_ty = clang::desugarForDiagnostic(ctx, qt, should_aka);
         if(should_aka) {
             os << "(a.k.a " << desugared_ty.getAsString(pp) << ")";
         }
     }

106-108: Fix add_item construction.

items.emplace_back(kind, val) will fail if HoverItem is an aggregate without a matching two-argument constructor. Build the aggregate explicitly and move the value.

     auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-        items.emplace_back(kind, val);
+        items.emplace_back(HoverItem{kind, std::move(val)});
     };

162-174: Logic bug: get_document returns empty string after retrieving comment.

Line 171 retrieves the formatted comment into raw_string, but line 173 immediately returns an empty string. Documentation will never be displayed.

     auto raw_string = comment->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
     LOG_WARN("Got comment:\n```\n{}\n```\n", raw_string);
-    return "";
+    return raw_string;
 }

476-492: Handle null namespace gracefully instead of asserting.

getAsNamespace() can return null for non-namespace specifiers (e.g., type specifiers like Foo::). The assert(ns) will be stripped in release builds, leading to null dereference.

             if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
                 auto ns = ns_specifier->getAsNamespace();
-                assert(ns);
+                if(!ns) {
+                    // Not a namespace specifier (could be a type specifier)
+                    return std::nullopt;
+                }
                 std::string name;

569-570: Check for null FileEntry before dereferencing.

getFileEntryForID can return nullptr if the file entry is not found. This will crash.

             hi.kind = SymbolKind::Directive;
             hi.name = file_name;
-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
             // TODO: Provides symbol
             return hi;

587-588: Guard against empty string before pop_back().

pop_back() on an empty string is undefined behavior.

                     auto macro_name = get_source_code(unit, name_range);
-                    macro_name.pop_back();
+                    if(!macro_name.empty()) {
+                        macro_name.pop_back();
+                    }
🧹 Nitpick comments (1)
src/Feature/Hover.cpp (1)

621-628: Consider reducing verbose debug logging before merge.

Multiple LOG_WARN calls (lines 472, 478, 490, 495, 501, 505, 508, 515, 519, 578, 621, 628) emit warnings during normal operation. These should be removed or downgraded to debug/trace level to avoid cluttering production logs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c3c815 and 5cfea60.

📒 Files selected for processing (2)
  • src/Feature/Hover.cpp (1 hunks)
  • tests/unit/Feature/HoverTests.cpp (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (ubuntu-24.04, releasedbg)
  • GitHub Check: build (ubuntu-24.04, debug)
  • GitHub Check: build (windows-2025, releasedbg)
  • GitHub Check: build (macos-15, debug)
  • GitHub Check: build (macos-15, releasedbg)
  • GitHub Check: build (ubuntu-24.04, Debug, clang-20, clang++-20)
  • GitHub Check: build (macos-15, Debug, clang, clang++)
  • GitHub Check: build (windows-2025, RelWithDebInfo, clang, clang++)

Comment on lines +138 to +143
if(record->isUnion()) {
add_item(HoverItem::Size,
llvm::Twine(ctx.getTypeSizeInChars(fd->getType()).getQuantity()).str());
add_item(HoverItem::Align,
llvm::Twine(ctx.getTypeAlignInChars(fd->getType()).getQuantity()).str());
}
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 | 🟡 Minor

Duplicate Size and Align items for union fields.

For union fields, lines 139-142 add Size and Align items, but for non-dependent non-union records, lines 131-135 already add Offset, Align, and Size. If a union field is in a non-dependent context, both blocks execute, resulting in duplicate Size and Align entries.

-        if(record->isUnion()) {
+        if(record->isUnion() && record->isDependentType()) {
             add_item(HoverItem::Size,
                      llvm::Twine(ctx.getTypeSizeInChars(fd->getType()).getQuantity()).str());
             add_item(HoverItem::Align,
                      llvm::Twine(ctx.getTypeAlignInChars(fd->getType()).getQuantity()).str());
         }

Alternatively, restructure the logic so that union fields don't go through both branches.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(record->isUnion()) {
add_item(HoverItem::Size,
llvm::Twine(ctx.getTypeSizeInChars(fd->getType()).getQuantity()).str());
add_item(HoverItem::Align,
llvm::Twine(ctx.getTypeAlignInChars(fd->getType()).getQuantity()).str());
}
if(record->isUnion() && record->isDependentType()) {
add_item(HoverItem::Size,
llvm::Twine(ctx.getTypeSizeInChars(fd->getType()).getQuantity()).str());
add_item(HoverItem::Align,
llvm::Twine(ctx.getTypeAlignInChars(fd->getType()).getQuantity()).str());
}
🤖 Prompt for AI Agents
In src/Feature/Hover.cpp around lines 131 to 143, the union-specific block
(lines 139-142) and the non-dependent/non-union block (lines 131-135) can both
run, causing duplicate Size and Align entries for union fields; make the union
path mutually exclusive by restructuring the conditionals — either check
record->isUnion() first and handle/add Size/Align then skip the non-union
branch, or change the later non-union if to an else/else-if that excludes unions
(or return/continue after adding union items) so Size and Align are only added
once.


// auto vs decltype(auto)
auto x1 = (a); // int
de$(pos_13)cltype(auto) x2 = (a); // int&
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 | 🟡 Minor

Duplicate placeholder name pos_13.

pos_13 is used on both line 218 and line 222, which will cause offset conflicts or overwrites in the annotation map.

-    de$(pos_13)cltype(auto) x2 = (a);  // int&
+    de$(pos_16)cltype(auto) x2 = (a);  // int&
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
de$(pos_13)cltype(auto) x2 = (a); // int&
de$(pos_16)cltype(auto) x2 = (a); // int&
🤖 Prompt for AI Agents
In tests/unit/Feature/HoverTests.cpp around line 222, the placeholder name
pos_13 is duplicated (also used at line 218) causing annotation map conflicts;
rename the placeholder at line 222 to a unique identifier (e.g., pos_14) and
update any matching annotation/expectation entries that reference pos_13 for
that occurrence so each placeholder maps to a distinct offset.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (15)
include/Feature/Hover.h (1)

78-80: Remove commented-out code.

Commented-out function declarations add noise. If the test hover API is needed, it should be properly implemented or tracked with a TODO/issue reference.

src/Feature/Hover.cpp (10)

619-629: Consider reducing log verbosity or using debug level.

Multiple LOG_WARN statements throughout the hover logic are appropriate for development but should be removed or converted to debug-level logging before release to avoid cluttering production logs.


47-53: Logic bug: condition should check !qt.isNull().

The condition qt.isNull() && opt.show_aka will never be true when qt is valid (which it is after qt.print() on line 46). This should be !qt.isNull().

🔎 Proposed fix
-    if(qt.isNull() && opt.show_aka) {
+    if(!qt.isNull() && opt.show_aka) {
         bool should_aka = false;
         auto desugared_ty = clang::desugarForDiagnostic(ctx, qt, should_aka);
         if(should_aka) {
             os << "(a.k.a " << desugared_ty.getAsString(pp) << ")";
         }
     }

106-108: Fix add_item construction - aggregate initialization required.

items.emplace_back(kind, val) won't compile because HoverItem is an aggregate with no constructor. Use aggregate initialization explicitly.

🔎 Proposed fix
     auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
-        items.emplace_back(kind, val);
+        items.emplace_back(HoverItem{kind, std::move(val)});
     };

127-143: Duplicate Size and Align items for union fields.

When a union field is in a non-dependent context, both the non-dependent block (lines 131-136) and the union block (lines 138-143) execute, resulting in duplicate Size and Align entries.

🔎 Proposed fix: make branches mutually exclusive
     if(auto fd = llvm::dyn_cast<clang::FieldDecl>(decl)) {
         const auto record = fd->getParent();
-        if(!record->isDependentType()) {
+        if(!record->isDependentType() && !record->isUnion()) {
             add_item(HoverItem::Offset, llvm::Twine(ctx.getFieldOffset(fd)).str());
             add_item(HoverItem::Align,
                      llvm::Twine(ctx.getTypeAlignInChars(fd->getType()).getQuantity()).str());
             add_item(HoverItem::Size,
                      llvm::Twine(ctx.getTypeSizeInChars(fd->getType()).getQuantity()).str());
         }

-        if(record->isUnion()) {
+        if(record->isUnion() && !record->isDependentType()) {
             add_item(HoverItem::Size,

148-150: Dead code: VarDecl type is captured but never used.

The variable ty is assigned but never utilized. Either remove the branch or add the intended hover item.


162-174: get_document retrieves comment but returns empty string.

Line 171 retrieves the formatted comment text, but line 173 returns an empty string, so hover never displays documentation.

🔎 Proposed fix
     auto raw_string = comment->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
-    LOG_WARN("Got comment:\n```\n{}\n```\n", raw_string);
-    return "";
+    // TODO: Parse comment according to opt.parse_comment_as_markdown
+    return raw_string;

476-492: Handle null namespace gracefully instead of asserting.

getAsNamespace() can return null for non-namespace specifiers (e.g., type specifiers). The assert(ns) will crash in debug builds and is stripped in release.

🔎 Proposed fix
             if(auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier()) {
                 auto ns = ns_specifier->getAsNamespace();
-                assert(ns);
+                if(!ns) {
+                    // Not a namespace specifier (could be a type specifier)
+                    return std::nullopt;
+                }
                 std::string name;

507-513: Null check before dyn_cast result is passed to hover().

llvm::dyn_cast<NamedDecl>(vd) may return nullptr if vd is not a NamedDecl. Passing nullptr to hover() is unsafe.

🔎 Proposed fix
     } else if(is(DeclRefExpr)) {
         LOG_WARN("Hit an `DeclRef`, Unhandled");
         if(auto dr = node->get<DeclRefExpr>()) {
             auto vd = dr->getDecl();
-            assert(vd);
-            return hover(unit, llvm::dyn_cast<NamedDecl>(vd), opt);
+            if(auto nd = llvm::dyn_cast_or_null<NamedDecl>(vd)) {
+                return hover(unit, nd, opt);
+            }
         }

586-588: Guard against empty string before pop_back().

Calling pop_back() on an empty string is undefined behavior.

🔎 Proposed fix
                     auto macro_name = get_source_code(unit, name_range);
-                    macro_name.pop_back();
+                    if(!macro_name.empty()) {
+                        macro_name.pop_back();
+                    }

560-574: Check for null FileEntry before dereferencing.

sm.getFileEntryForID(inclusion.fid) can return nullptr. The current code dereferences it directly without checking.

🔎 Proposed fix
             auto file_name = llvm::StringRef{raw_name}.trim("<>\"");
             Hover hi;
             hi.kind = SymbolKind::Directive;
             hi.name = file_name;
-            auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
-            hi.source = dir;
+            if(auto file_entry = sm.getFileEntryForID(inclusion.fid)) {
+                hi.source = file_entry->tryGetRealPathName();
+            }
             // TODO: Provides symbol
             return hi;
tests/unit/Feature/HoverTests.cpp (4)

36-83: Malformed test case structure with broken braces.

The TEST_CASE(Inclusion) block has an incorrect brace structure. Line 56 prematurely ends with } // TEST_SUITE(Hover), followed by an orphaned code block (lines 58-81) and a mismatched closing at line 83.

🔎 Suggested restructuring

Either merge both test blocks into a single TEST_CASE(Inclusion) with proper braces, or split them into two distinct test cases (e.g., TEST_CASE(Inclusion_PCH) and TEST_CASE(Inclusion_Basic)).


113-114: Empty loop body renders test ineffective.

The loop iterates over offsets but performs no assertions or hover calls, making the test a no-op.


218-222: Duplicate placeholder pos_13 and typo in annotation.

Line 218 uses decltyp$(pos_13)ype which produces "decltypeype" after substitution (extra "ype"). Line 222 reuses pos_13, causing offset map conflicts.


684-686: Mismatched namespace closing comments and stray semicolon.

Line 684 has }; (semicolon after brace) with incorrect comment. The comment structure is inverted relative to the actual namespace closures.

🧹 Nitpick comments (2)
src/Server/Feature.cpp (1)

61-64: Consider moving configuration to server-level settings.

The inline NOTE correctly identifies that these options should be initialized from server configuration rather than hardcoded. This can be addressed in a follow-up once the hover feature stabilizes.

src/Feature/Hover.cpp (1)

643-661: LGTM on display() implementation.

The method correctly formats hover content with items, document, and source code. Consider whether the std::optional return type is needed since the method always returns content.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cfea60 and a678366.

📒 Files selected for processing (5)
  • include/Feature/Hover.h
  • include/Protocol/Feature/Hover.h
  • src/Feature/Hover.cpp
  • src/Server/Feature.cpp
  • tests/unit/Feature/HoverTests.cpp
🧰 Additional context used
🧬 Code graph analysis (4)
src/Server/Feature.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (412-423)
  • hover (412-414)
  • hover (425-433)
  • hover (425-427)
  • hover (435-527)
  • hover (435-437)
  • hover (531-632)
  • hover (531-533)
tests/unit/Feature/HoverTests.cpp (1)
src/Feature/Hover.cpp (8)
  • hover (412-423)
  • hover (412-414)
  • hover (425-433)
  • hover (425-427)
  • hover (435-527)
  • hover (435-437)
  • hover (531-632)
  • hover (531-533)
src/Feature/Hover.cpp (1)
include/AST/Resolver.h (1)
  • clang (6-10)
include/Feature/Hover.h (1)
src/Feature/Hover.cpp (12)
  • get_item_content (634-641)
  • get_item_content (634-634)
  • display (643-661)
  • display (643-643)
  • hover (412-423)
  • hover (412-414)
  • hover (425-433)
  • hover (425-427)
  • hover (435-527)
  • hover (435-437)
  • hover (531-632)
  • hover (531-533)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: cmake / build (macos-15, Debug)
  • GitHub Check: xmake / build (macos-15, releasedbg)
  • GitHub Check: xmake / build (macos-15, debug)
  • GitHub Check: xmake / build (windows-2025, releasedbg)
  • GitHub Check: xmake / build (ubuntu-24.04, releasedbg)
  • GitHub Check: cmake / build (windows-2025, RelWithDebInfo)
  • GitHub Check: xmake / build (ubuntu-24.04, debug)
  • GitHub Check: cmake / build (ubuntu-24.04, Debug)
  • GitHub Check: clice / publish-clice (macos-15, clice.tar.gz, clice-arm64-macos-darwin.tar.gz, clice-symbol.tar.gz, clic...
  • GitHub Check: clice / publish-clice (windows-2025, clice.zip, clice-x64-windows-msvc.zip, clice-symbol.zip, clice-x64-w...
🔇 Additional comments (2)
include/Protocol/Feature/Hover.h (1)

19-20: LGTM!

The optional range field aligns with the LSP specification for hover responses and integrates well with the hl_range handling introduced in the feature layer.

include/Feature/Hover.h (1)

61-75: LGTM on the Hover struct extensions.

The additions of optional document, hl_range, and the get_item_content/display methods are well-structured and align with the implementation in src/Feature/Hover.cpp.

Comment on lines +24 to +25
struct HoverItem {
// NOTE: Use a set of drieved classes?
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 | 🟡 Minor

Minor typo in comment.

"drieved" should be "derived".

🔎 Proposed fix
-    // NOTE: Use a set of drieved classes?
+    // NOTE: Use a set of derived classes?
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
struct HoverItem {
// NOTE: Use a set of drieved classes?
struct HoverItem {
// NOTE: Use a set of derived classes?
🤖 Prompt for AI Agents
In include/Feature/Hover.h around lines 24-25, the comment contains a typo:
replace "drieved" with "derived" so the note reads "NOTE: Use a set of derived
classes?" and keep punctuation/spacing consistent.

Comment on lines 61 to 85
// NOTE: Should be initialized somewhere else
config::HoverOptions opt = {.enable_doxygen_parsing = true,
.parse_comment_as_markdown = true,
.show_aka = true};

co_return co_await async::submit([kind = this->kind, offset, &ast, &opt] {
proto::Hover result;
result.contents.kind = "markdown";
result.contents.value = std::format("{}: {}", hover.kind.name(), hover.name);
if(auto hover = feature::hover(*ast, offset, opt)) {
if(auto info = hover->display(opt)) {
result.contents.value = *info;
} else {
clice::logging::warn("Cannot display hover info");
result.contents.value = "Cannot display hover info";
}
if(!hover->hl_range) {
clice::logging::warn("Not available range");
}
result.range = hover->hl_range;
} else {
clice::logging::warn("Cannot get hover info");
result.contents.value = "Cannot get hover info";
}
return json::serialize(result);
});
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

Potential dangling reference: opt captured by reference in async lambda.

The local variable opt is captured by reference (&opt) in the lambda passed to async::submit. If the async task executes after on_hover returns, accessing opt would be undefined behavior.

🔎 Proposed fix: capture `opt` by value
-    co_return co_await async::submit([kind = this->kind, offset, &ast, &opt] {
+    co_return co_await async::submit([kind = this->kind, offset, &ast, opt] {
         proto::Hover result;
         result.contents.kind = "markdown";
         if(auto hover = feature::hover(*ast, offset, opt)) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// NOTE: Should be initialized somewhere else
config::HoverOptions opt = {.enable_doxygen_parsing = true,
.parse_comment_as_markdown = true,
.show_aka = true};
co_return co_await async::submit([kind = this->kind, offset, &ast, &opt] {
proto::Hover result;
result.contents.kind = "markdown";
result.contents.value = std::format("{}: {}", hover.kind.name(), hover.name);
if(auto hover = feature::hover(*ast, offset, opt)) {
if(auto info = hover->display(opt)) {
result.contents.value = *info;
} else {
clice::logging::warn("Cannot display hover info");
result.contents.value = "Cannot display hover info";
}
if(!hover->hl_range) {
clice::logging::warn("Not available range");
}
result.range = hover->hl_range;
} else {
clice::logging::warn("Cannot get hover info");
result.contents.value = "Cannot get hover info";
}
return json::serialize(result);
});
// NOTE: Should be initialized somewhere else
config::HoverOptions opt = {.enable_doxygen_parsing = true,
.parse_comment_as_markdown = true,
.show_aka = true};
co_return co_await async::submit([kind = this->kind, offset, &ast, opt] {
proto::Hover result;
result.contents.kind = "markdown";
if(auto hover = feature::hover(*ast, offset, opt)) {
if(auto info = hover->display(opt)) {
result.contents.value = *info;
} else {
clice::logging::warn("Cannot display hover info");
result.contents.value = "Cannot display hover info";
}
if(!hover->hl_range) {
clice::logging::warn("Not available range");
}
result.range = hover->hl_range;
} else {
clice::logging::warn("Cannot get hover info");
result.contents.value = "Cannot get hover info";
}
return json::serialize(result);
});
🤖 Prompt for AI Agents
In src/Server/Feature.cpp around lines 61-85, the local variable opt is
currently captured by reference in the lambda passed to async::submit which can
dangle when on_hover returns; update the lambda to capture opt by value (i.e.
make a copy in the capture list or move it into the lambda) so the async task
owns its own copy and cannot access freed stack memory, then recompile and run
tests to ensure no lifetime issues remain.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@src/Feature/Hover.cpp`:
- Line 480: The local variable wanted_node is assigned from node in Hover.cpp
but never used; remove the unused variable assignment (the line creating
wanted_node) or, if the intent was to operate on a separate copy, replace uses
of node with wanted_node where appropriate—search for wanted_node and node in
the Hover-related functions (e.g., any hover handling logic) and either delete
the wanted_node declaration or use it consistently so the symbol is referenced.
- Around line 692-733: In Hover::display remove the unused debug variables and
paragraph: delete the local variables "content" and "os" (they are unused), and
remove the temporary debug paragraph created after the ruler (the
head_segment.add_paragraph() call that appends "Contains {} items" and the
subsequent append_newline_char()), leaving the bullet-list logic intact; ensure
you also remove the "// FIX: Delete later" comment so the function contains no
leftover debug artifacts.

In `@src/Support/Doxygen.cpp`:
- Around line 145-148: The condition currently uses bitwise OR between boolean
expressions (if(command == "b" | command == "e" | command == "c")) which
prevents short-circuiting; update the conditional to use logical OR (||) so
comparisons short-circuit correctly and maintain intended semantics for the
check on the variable command in the same block that jumps to normal_line.

In `@tests/unit/Feature/HoverTests.cpp`:
- Around line 116-184: The test DeducedType_Auto (and similar cases
DeducedType_Decltype and Comments) only prints hover results and never asserts
correctness; update the loops that call clice::feature::hover(*) storing the
result in HI to include explicit assertions (e.g., ASSERT_TRUE(HI.has_value())
before using HI->display()) for offsets where hover info is expected (the
annotated positions like pos_0..pos_7 and pos_0_i..pos_7_i), and add additional
ASSERT_EQ/ASSERT_NE on the returned display string when specific text is
expected to validate hover contents; ensure you modify both loops that iterate
over annotation.offsets and reference HI and msg so the tests fail when hover is
missing or incorrect.
🧹 Nitpick comments (1)
src/Support/Doxygen.cpp (1)

145-148: goto across scopes is a code smell; consider restructuring.

The goto normal_line jumps out of a nested if block to a label in the enclosing function scope. While valid C++, this makes control flow harder to follow. A simple restructuring (e.g., extracting the command-dispatch into a helper, or falling through with a flag) would improve readability.

Also applies to: 238-241


#define is_in_range(LHS, RHS) (!((Kind < Flag##LHS) && is(LHS)) && (Kind < Flag##RHS))

auto wanted_node = node;
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 | 🟡 Minor

Unused variable wanted_node.

wanted_node is assigned on line 480 but never referenced.

Proposed fix
-    auto wanted_node = node;
     auto Kind = node->data.getNodeKind();
🤖 Prompt for AI Agents
In `@src/Feature/Hover.cpp` at line 480, The local variable wanted_node is
assigned from node in Hover.cpp but never used; remove the unused variable
assignment (the line creating wanted_node) or, if the intent was to operate on a
separate copy, replace uses of node with wanted_node where appropriate—search
for wanted_node and node in the Hover-related functions (e.g., any hover
handling logic) and either delete the wanted_node declaration or use it
consistently so the symbol is referenced.

Comment on lines 692 to 733
std::optional<std::string> Hover::display(config::HoverOptions opt) {
std::string content;
llvm::raw_string_ostream os(content);
// TODO: generate markdown
StructedText out{};
StructedText head_segment{};
head_segment.add_heading(3).append_text(std::format("{}: {}", this->kind.name(), this->name));
// TODO: provider
head_segment.add_ruler();
// FIX: Delete later
head_segment.add_paragraph()
.append_text(std::format("Contains {} items", this->items.size()))
.append_newline_char();
if(this->items.size()) {
auto& bl = head_segment.add_bullet_list();
for(auto& hi: this->items) {
bl.add_item().add_paragraph().append_text(
std::format("{}: {}", clice::refl::enum_name(hi.kind), hi.value));
}
}
out.append(head_segment);
if(this->document && opt.enable_doxygen_parsing) {
StructedText st{};
auto& raw = *this->document;
auto [di, rest_] = strip_doxygen_info(raw);
if(auto rest = llvm::StringRef(rest_); !rest.trim().empty()) {
st.add_paragraph().append_text(rest.rtrim().str());
st.add_ruler();
}
auto bcc = di.get_block_command_comments();
for(const auto [tag, content]: bcc) {
st.add_paragraph().append_text(tag.str(), Paragraph::Kind::Bold);
st.add_ruler();
}
st.add_ruler();
out.append(st);
}
if(!source.empty()) {
out.add_code_block(source + '\n', lang);
}
return out.as_markdown();
}
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 | 🟡 Minor

Dead code and leftover debug artifacts in display().

  1. Line 693–694: content and os are created but never used.
  2. Line 701: // FIX: Delete later — the paragraph displaying item count (lines 702–704) is explicitly marked as temporary debug output that should be removed before merge.
Proposed cleanup
 std::optional<std::string> Hover::display(config::HoverOptions opt) {
-    std::string content;
-    llvm::raw_string_ostream os(content);
-    // TODO: generate markdown
     StructedText out{};
     StructedText head_segment{};
     head_segment.add_heading(3).append_text(std::format("{}: {}", this->kind.name(), this->name));
     // TODO: provider
     head_segment.add_ruler();
-    // FIX: Delete later
-    head_segment.add_paragraph()
-        .append_text(std::format("Contains {} items", this->items.size()))
-        .append_newline_char();
     if(this->items.size()) {
🤖 Prompt for AI Agents
In `@src/Feature/Hover.cpp` around lines 692 - 733, In Hover::display remove the
unused debug variables and paragraph: delete the local variables "content" and
"os" (they are unused), and remove the temporary debug paragraph created after
the ruler (the head_segment.add_paragraph() call that appends "Contains {}
items" and the subsequent append_newline_char()), leaving the bullet-list logic
intact; ensure you also remove the "// FIX: Delete later" comment so the
function contains no leftover debug artifacts.

Comment on lines +145 to +148
if(command == "b" | command == "e" | command == "c") {
// Just start with inline command leave it.
goto normal_line;
}
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 | 🟡 Minor

Use logical OR (||) instead of bitwise OR (|).

Line 145 uses bitwise OR | between bool operands. While this happens to produce the correct result for bool, it prevents short-circuit evaluation and is almost certainly a typo. Use || for logical disjunction.

Proposed fix
-        if(command == "b" | command == "e" | command == "c") {
+        if(command == "b" || command == "e" || command == "c") {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if(command == "b" | command == "e" | command == "c") {
// Just start with inline command leave it.
goto normal_line;
}
if(command == "b" || command == "e" || command == "c") {
// Just start with inline command leave it.
goto normal_line;
}
🤖 Prompt for AI Agents
In `@src/Support/Doxygen.cpp` around lines 145 - 148, The condition currently uses
bitwise OR between boolean expressions (if(command == "b" | command == "e" |
command == "c")) which prevents short-circuiting; update the conditional to use
logical OR (||) so comparisons short-circuit correctly and maintain intended
semantics for the check on the variable command in the same block that jumps to
normal_line.

Comment on lines +116 to +184
TEST_CASE(DeducedType_Auto) {
tester.clear();
constexpr auto code = R"CODE(
struct A {
int a;
int b;
int c;
float d;
};

struct A1 : A {};

template <typename T>
struct B {
T *inner;

template <typename S>
B(S *s) {
inner = s;
}

template <typename S>
auto get_as() {
return *static_cast<S *>(inner);
}
};

int main(void) {
au$(pos_0)to $(pos_0_i)a = A{};
au$(pos_1)to $(pos_1_i)b = B<A>(&a);
au$(pos_2)to $(pos_2_i)a1 = b.get_as<A1>();
au$(pos_3)to $(pos_3_i)msg = "hello world";
au$(pos_4)to $(pos_4_i)c1 = 'c';
au$(pos_5)to $(pos_5_i)c2 = 0;
au$(pos_6)to $(pos_6_i)c3 = 114514;
au$(pos_7)to $(pos_7_i)c4 = 11451419198101919810;
return 0;
}
)CODE";
auto annotation = AnnotatedSource::from(code);
tester.add_main("main.cpp", annotation.content);
std::vector<unsigned> offsets;
tester.compile();
ASSERT_TRUE(tester.unit.has_value());
const unsigned count = annotation.offsets.size();
for(unsigned i = 0; i < count / 2; ++i) {
unsigned offset = annotation.offsets[std::format("pos_{}", i)];
auto HI = clice::feature::hover(*tester.unit, offset, {});
std::println("Hover at pos_{}", i);
if(HI.has_value()) {
auto msg = HI->display({});
std::println("```\n{}```\n", *msg);
} else {
std::println("No hover info");
}
}

for(unsigned i = 0; i < count / 2; ++i) {
unsigned offset = annotation.offsets[std::format("pos_{}_i", i)];
auto HI = clice::feature::hover(*tester.unit, offset, {});
std::println("Hover at pos_{}_i", i);
if(HI.has_value()) {
auto msg = HI->display({});
std::println("```\n{}```\n", *msg);
} else {
std::println("No hover info");
}
}
};
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

Tests print results but assert nothing.

All the DeducedType_Auto, DeducedType_Decltype, and Comments test cases only call std::println with hover results. There are no ASSERT_* or EXPECT_* checks on the hover output, so these tests will always pass regardless of correctness. At minimum, assert that HI.has_value() is true for positions where hover is expected.

Also applies to: 186-260, 262-326

🤖 Prompt for AI Agents
In `@tests/unit/Feature/HoverTests.cpp` around lines 116 - 184, The test
DeducedType_Auto (and similar cases DeducedType_Decltype and Comments) only
prints hover results and never asserts correctness; update the loops that call
clice::feature::hover(*) storing the result in HI to include explicit assertions
(e.g., ASSERT_TRUE(HI.has_value()) before using HI->display()) for offsets where
hover info is expected (the annotated positions like pos_0..pos_7 and
pos_0_i..pos_7_i), and add additional ASSERT_EQ/ASSERT_NE on the returned
display string when specific text is expected to validate hover contents; ensure
you modify both loops that iterate over annotation.offsets and reference HI and
msg so the tests fail when hover is missing or incorrect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants