Skip to main content

Tool Examples — Real Output, Self-Verifying

Every tool example on this page is executed at docs build time by the real Scala 3.8.4 analyzer — no hand-written JSON. If a tool call fails, the docs build fails, so this page cannot rot. Each example's exact tool/args/result triple is also pinned as a golden-file test in the mcp module (DocsToolExamplesGoldenSuite / DocsEnrichingExamplesGoldenSuite), so a change to tool output shows up as a reviewable diff there too, not just a silent docs rebuild.

Quick reference

ToolAnswers
Exploration tools
find_symbolResolve a name to its definition
find_usagesAll references to a symbol
class_hierarchySupertypes and subtypes
find_overloadsAll overloads of a method
membersDeclared and inherited members
call_pathWhether method A reaches method B
method_call_hierarchyAll callers or callees
value_flowTrace a value through the call graph
rename_planEdit ranges for a safe rename
move_planMove a symbol to a new package
extract_method_planExtract a code range into a method
structureDependency graph and cycles
smart_code_duplicationsStructurally identical blocks
Enriching tools
annotated_sourceCompiler-visible facts and inferred types
method_signatureFull signature with implicit/using params
document_outlineFile structure with compiler-rendered names
resolve_implicitsWhich givens/implicits apply
trace_implicit_chainPath of implicit dependencies
type_at_positionType of code at a source location

Exploration / edit-plan tools

These tools return precise semantic answers — a symbol, a usage set, a hierarchy, an edit plan — replacing whole-file reads and grep guesswork.

find_symbol

Answers: resolve a name to its definition.

Grep transform returns 5+ matches across comments and strings. find_symbol returns 1 definition.

Request: find_symbol

Arguments:

  • query: transform
{
"query": "transform",
"count": 1,
"symbols": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"name": "transform",
"kind": "METHOD"
}
]
}

Replaces: Grepping → exact definition lookup.


class_hierarchy

Answers: supertypes and subtypes.

Request: class_hierarchy

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Processor#
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#",
"name": "Processor",
"parents": [
"Object"
],
"linearization": [
"Object"
],
"knownSubtypes": [
"ReverseProcessor",
"UpperProcessor"
]
}

Replaces: Reading files + grepping for extends/implements.


find_overloads

Answers: all overloads of a method.

Request: find_overloads

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Overloading$package.format().
{
"name": "format",
"overloads": [
"def format(x: String): String",
"def format(x: Int): String",
"def format(x: Boolean): String"
]
}

Replaces: Reading code for all overloads.


find_usages

Answers: all references to a symbol.

Request: find_usages

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"name": "transform",
"definitions": [
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:13:4"
],
"referenceCount": 2,
"references": [
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:2",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:16"
]
}

Replaces: Grepping all files → exact reference list.


members

Answers: declared and inherited members.

Request: members

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/UpperProcessor#
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/UpperProcessor#",
"name": "UpperProcessor",
"declared": [
"<init>",
"process"
]
}

Replaces: Reading class + all superclass definitions.


call_path

Answers: whether method A reaches method B.

pipeline never calls process directly, but reaches it through compose and transform. The tool returns the shortest path and the call-site of every edge.

Request: call_path

Arguments:

  • from: com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().
  • to: com/github/mercurievv/scalasemantic/docexamples/Processor#process().
  • detailed: true
{
"from": "pipeline",
"to": "process",
"reachable": true,
"path": [
"pipeline",
"compose",
"transform",
"process"
],
"edges": [
"pipeline->compose@docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:22:2",
"compose->transform@docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:2",
"transform->process@docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:14:4"
]
}

Replaces: Manually reading through call sites to prove reachability.


method_call_hierarchy

Answers: all callers or callees.

Outgoing from pipeline: compose, then the two transform calls, then process — the whole fan-out in one call.

Request: method_call_hierarchy

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().
  • direction: callees
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().",
"name": "pipeline",
"direction": "callees",
"depth": 3,
"hierarchy": {
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().",
"name": "pipeline",
"children": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().",
"name": "compose",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:22:2",
"children": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"name": "transform",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:2",
"children": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().",
"name": "process",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:14:4"
}
]
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"name": "transform",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:16",
"children": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().",
"name": "process",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:14:4"
}
]
}
]
}
]
}
}

Replaces: Opening each callee in turn to build the tree by hand.


value_flow

Answers: trace a value through the call graph.

The input parameter of pipeline flows into compose's input, then transform's input, then process's x — a rename at every hop that text search cannot follow.

Request: value_flow

Arguments:

  • file: docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala
  • line: 19
  • column: 13
{
"root": {
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
"name": "input",
"type": "String",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:19:13",
"depth": 0,
"enclosingMethod": "pipeline",
"kind": "PARAMETER"
},
"nodes": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
"name": "input",
"type": "String",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:19:13",
"depth": 0,
"enclosingMethod": "pipeline",
"kind": "PARAMETER"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
"name": "input",
"type": "String",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:16:42",
"depth": 1,
"enclosingMethod": "compose",
"kind": "PARAMETER"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
"name": "input",
"type": "String",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:13:28",
"depth": 2,
"enclosingMethod": "transform",
"kind": "PARAMETER"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
"name": "x",
"type": "String",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:3:14",
"depth": 3,
"enclosingMethod": "process",
"kind": "PARAMETER"
}
],
"edges": [
{
"from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
"to": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
"relation": "passed_as_arg",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:22:22",
"paramName": "input",
"coParameters": [
"p1",
"p2"
]
},
{
"from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
"to": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
"relation": "passed_as_arg",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:30",
"paramName": "input",
"coParameters": [
"p"
]
},
{
"from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
"to": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
"relation": "passed_as_arg",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:14:12",
"paramName": "x"
}
],
"stoppedAt": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
"classification": "discarded",
"at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:3:14"
}
]
}

Replaces: Manually chasing a value through renamed parameters across files.


rename_plan

Answers: edit ranges for a safe rename.

The tool returns exact line and character ranges for every reference. No over-matching strings or comments.

Request: rename_plan

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().
  • newName: apply
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"rename": "transform -> apply",
"editCount": 3,
"edits": [
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:13:4-13",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:2-11",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:16-25"
]
}

Replaces: Grepping + manual editing → exact edit ranges.


move_plan

Answers: move a symbol to a new package.

Request: move_plan

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Refactor$package.calculateTotal().
  • newOwner: com/example/math/
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Refactor$package.calculateTotal().",
"move": "com.github.mercurievv.scalasemantic.docexamples.Refactor$package..calculateTotal -> com.example.math.calculateTotal",
"definition": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:2:4",
"referenceCount": 2,
"references": [
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:14:18",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:15:18"
]
}

Replaces: Manual refactoring and import management.


extract_method_plan

Answers: extract a code range into a method.

The tool analyzes the range, identifies local variables and scope, returns exact edits.

Request: extract_method_plan

Arguments:

  • uri: docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala
  • startLine: 5
  • startCharacter: 20
  • endLine: 8
  • endCharacter: 9

signature:

def extracted(tax: Double, total: Double): Unit
Raw JSON

Arguments:

{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala",
"startLine": 5,
"startCharacter": 20,
"endLine": 8,
"endCharacter": 9
}

Result:

{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala",
"enclosingMethod": "calculateTotal",
"signature": "def extracted(tax: Double, total: Double): Unit",
"call": "extracted(tax, total)",
"parameters": [
"tax: Double",
"total: Double"
],
"returnType": "Unit"
}

Replaces: Manual method extraction and variable management.


structure

Answers: dependency graph and cycles.

A snapshot of entire dependency structure in one call.

Request: structure

Arguments:

(no parameters)

{
"dimension": "combined",
"sort": "afferent",
"modules": [
{
"module": "docExamples",
"types": 6,
"layer": 0,
"ca": 0,
"ce": 0,
"instability": 0
}
],
"symbols": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#",
"name": "Processor",
"module": "docExamples",
"layer": 0,
"ca": 2,
"ce": 0,
"instability": 0,
"centrality": 0.068
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"name": "Show",
"module": "docExamples",
"layer": 0,
"ca": 1,
"ce": 0,
"instability": 0,
"centrality": 0.046
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Invoice#",
"name": "Invoice",
"module": "docExamples",
"layer": 0,
"ca": 0,
"ce": 0,
"instability": 0,
"centrality": 0.025
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/ReverseProcessor#",
"name": "ReverseProcessor",
"module": "docExamples",
"layer": 1,
"ca": 0,
"ce": 1,
"instability": 1,
"centrality": 0.025
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.",
"name": "Show",
"module": "docExamples",
"layer": 1,
"ca": 0,
"ce": 1,
"instability": 1,
"centrality": 0.025
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/UpperProcessor#",
"name": "UpperProcessor",
"module": "docExamples",
"layer": 1,
"ca": 0,
"ce": 1,
"instability": 1,
"centrality": 0.025
}
]
}

Replaces: Manual dependency graph construction.


smart_code_duplications

Answers: structurally identical blocks.

The tool finds structural duplicates (same pattern, different names), ignoring syntactic noise.

Request: smart_code_duplications

Arguments:

  • minSize: 15
{
"groupsCount": 1,
"groups": [
{
"occurrencesCount": 2,
"astNodeCount": 41,
"occurrences": [
{
"location": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Duplication.scala:2:0"
},
{
"location": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Duplication.scala:9:0"
}
]
}
]
}

Replaces: Manual code review for duplication.


Enriching tools

These tools show the LLM what the compiler sees but the source text does not — inferred types, synthesized implicit arguments and conversions, resolved signatures. Every example below runs against the same source file, executed at docs build time by the real Scala 3.8.4 analyzer.

Source under analysis

Enrich.scala — a small typeclass (Show), two given instances, and two calls to a generic render method that hides its resolved implicit argument. Read straight from the fixture file the tool calls below actually analyze, so this block can never drift from what's shown as "Original" further down.

package com.github.mercurievv.scalasemantic.docexamples

/** A small type class + derivations that deliberately exercise the compiler insertions a plain-text
* read cannot see. Each line is here to trigger a DISTINCT invisible insertion: given summons,
* context-bound desugaring, inferred result/value types, inferred type arguments (on plain calls,
* on named calls, and on method selects), nested implicit arguments, implicit conversions,
* ordering summons, numeric widening, extension resolution, and for-comprehension desugaring.
*/
trait Show[A]:
def show(a: A): String

object Show:
/** Summoner: a bare `Show[A]` at a use site expands to `(using <given>)`. */
def apply[A](using s: Show[A]): Show[A] = s

given intShow: Show[Int] with
def show(a: Int) = a.toString

given stringShow: Show[String] with
def show(a: String) = a

// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with
def show(a: List[A]) =
a.map(Show[A].show).mkString("[", ", ", "]")

// `[A: Show]` again — the using-param and the `Show[A]` summon are both invisible in the text
def render[A: Show](a: A): String = Show[A].show(a)

extension (n: Int) def shown(using Show[Int]): String = render(n)

val nums = List(1, 2, 3)
val out = render(nums)
val sorted = nums.sorted
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1)
val labeled = nums.map(n => n -> render(n))
val total = nums.foldLeft(0)(_ + _)
val ratio: Double = nums.size
val shownFive = 5.shown
val firstTwo =
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b)

None of the (using ...) arguments or inferred return types above are written in the source — the tools below make them visible.

annotated_source

Answers: compiler-visible facts and inferred types.

The compiler injects (using intShow) and (using listShow(...)) into the render calls, and infers the return type : String on the out and num bindings — none visible in source text.

Request: annotated_source

Arguments:

  • uri: docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala
  • format: compilable
  • annotationsOnly: false

Original

package com.github.mercurievv.scalasemantic.docexamples

/** A small type class + derivations that deliberately exercise the compiler insertions a plain-text
* read cannot see. Each line is here to trigger a DISTINCT invisible insertion: given summons,
* context-bound desugaring, inferred result/value types, inferred type arguments (on plain calls,
* on named calls, and on method selects), nested implicit arguments, implicit conversions,
* ordering summons, numeric widening, extension resolution, and for-comprehension desugaring.
*/
trait Show[A]:
def show(a: A): String

object Show:
/** Summoner: a bare `Show[A]` at a use site expands to `(using <given>)`. */
def apply[A](using s: Show[A]): Show[A] = s

given intShow: Show[Int] with
def show(a: Int) = a.toString

given stringShow: Show[String] with
def show(a: String) = a

// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with
def show(a: List[A]) =
a.map(Show[A].show).mkString("[", ", ", "]")

// `[A: Show]` again — the using-param and the `Show[A]` summon are both invisible in the text
def render[A: Show](a: A): String = Show[A].show(a)

extension (n: Int) def shown(using Show[Int]): String = render(n)

val nums = List(1, 2, 3)
val out = render(nums)
val sorted = nums.sorted
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1)
val labeled = nums.map(n => n -> render(n))
val total = nums.foldLeft(0)(_ + _)
val ratio: Double = nums.size
val shownFive = 5.shown
val firstTwo =
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b)

Enriched (compiler view)

package com.github.mercurievv.scalasemantic.docexamples

/** A small type class + derivations that deliberately exercise the compiler insertions a plain-text
* read cannot see. Each line is here to trigger a DISTINCT invisible insertion: given summons,
* context-bound desugaring, inferred result/value types, inferred type arguments (on plain calls,
* on named calls, and on method selects), nested implicit arguments, implicit conversions,
* ordering summons, numeric widening, extension resolution, and for-comprehension desugaring.
*/
trait Show[A]:
def show(a: A): String

object Show:
/** Summoner: a bare `Show[A]` at a use site expands to `(using <given>)`. */
def apply[A](using s: Show[A]): Show[A] = s

given intShow: Show[Int] with
def show(a: Int) = a.toString // ⟹ : String

given stringShow: Show[String] with
def show(a: String) = a // ⟹ : String

// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with // ⟹ : Show[A]
def show(a: List[A]) = // ⟹ : String
a.map(Show[A].show).mkString("[", ", ", "]") // ⟹ a.map[String]; (using Show[A])

// `[A: Show]` again — the using-param and the `Show[A]` summon are both invisible in the text
def render[A: Show](a: A): String = Show[A].show(a) // ⟹ (using Show[A])

extension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ (using Show[Int]); render[Int]

val nums = List(1, 2, 3) // ⟹ : List[Int]; List.apply[Int]
val out = render(nums) // ⟹ : String; (using listShow); render[List[Int]]; (using intShow)
val sorted = nums.sorted // ⟹ : List[Int]; (using Ordering[Int]); nums.sorted[Int]
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1) // ⟹ : List[Tuple2[String, Int]]; (using Ordering[String]); .sortBy[String]; List.apply[Tuple2[String, Int]]; ArrowAssoc("b"); "b" ->[Int]; ArrowAssoc("a"); "a" ->[Int]
val labeled = nums.map(n => n -> render(n)) // ⟹ : List[Tuple2[Int, String]]; nums.map[Tuple2[Int, String]]; ArrowAssoc(n); n ->[String]; (using intShow); render[Int]
val total = nums.foldLeft(0)(_ + _) // ⟹ : Int; nums.foldLeft[Int]
val ratio: Double = nums.size // ⟹ int2double(nums.size)
val shownFive = 5.shown // ⟹ : String; (using intShow)
val firstTwo = // ⟹ : Option[String]
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b) // ⟹ (using intShow); render[Int]; (using intShow); render[Int]

Raw JSON

Arguments:

{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "compilable",
"annotationCount": 42,
"legend": "Valid Scala: each note is a trailing `// ⟹` comment, no line-number gutter. Notes show compiler insertions invisible in the source: `(using …)` implicit args, `name(…)` implicit conversion, `[…]` inferred type args, `: T` inferred type. symbols=on adds a type→package legend.",
"source": "package com.github.mercurievv.scalasemantic.docexamples\n\n/** A small type class + derivations that deliberately exercise the compiler insertions a plain-text\n * read cannot see. Each line is here to trigger a DISTINCT invisible insertion: given summons,\n * context-bound desugaring, inferred result/value types, inferred type arguments (on plain calls,\n * on named calls, and on method selects), nested implicit arguments, implicit conversions,\n * ordering summons, numeric widening, extension resolution, and for-comprehension desugaring.\n */\ntrait Show[A]:\n def show(a: A): String\n\nobject Show:\n /** Summoner: a bare `Show[A]` at a use site expands to `(using <given>)`. */\n def apply[A](using s: Show[A]): Show[A] = s\n\n given intShow: Show[Int] with\n def show(a: Int) = a.toString // ⟹ : String\n\n given stringShow: Show[String] with\n def show(a: String) = a // ⟹ : String\n\n // context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes\n given listShow[A: Show]: Show[List[A]] with // ⟹ : Show[A]\n def show(a: List[A]) = // ⟹ : String\n a.map(Show[A].show).mkString(\"[\", \", \", \"]\") // ⟹ a.map[String]; (using Show[A])\n\n// `[A: Show]` again — the using-param and the `Show[A]` summon are both invisible in the text\ndef render[A: Show](a: A): String = Show[A].show(a) // ⟹ (using Show[A])\n\nextension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ (using Show[Int]); render[Int]\n\nval nums = List(1, 2, 3) // ⟹ : List[Int]; List.apply[Int]\nval out = render(nums) // ⟹ : String; (using listShow); render[List[Int]]; (using intShow)\nval sorted = nums.sorted // ⟹ : List[Int]; (using Ordering[Int]); nums.sorted[Int]\nval ranked = List(\"b\" -> 2, \"a\" -> 1).sortBy(_._1) // ⟹ : List[Tuple2[String, Int]]; (using Ordering[String]); .sortBy[String]; List.apply[Tuple2[String, Int]]; ArrowAssoc(\"b\"); \"b\" ->[Int]; ArrowAssoc(\"a\"); \"a\" ->[Int]\nval labeled = nums.map(n => n -> render(n)) // ⟹ : List[Tuple2[Int, String]]; nums.map[Tuple2[Int, String]]; ArrowAssoc(n); n ->[String]; (using intShow); render[Int]\nval total = nums.foldLeft(0)(_ + _) // ⟹ : Int; nums.foldLeft[Int]\nval ratio: Double = nums.size // ⟹ int2double(nums.size)\nval shownFive = 5.shown // ⟹ : String; (using intShow)\nval firstTwo = // ⟹ : Option[String]\n for\n a <- nums.headOption\n b <- sorted.headOption\n yield render(a) + render(b) // ⟹ (using intShow); render[Int]; (using intShow); render[Int]\n"
}

Result:

{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "compilable",
"annotationsOnly": false
}

Replaces: Reading 15 lines of source → 10 lines with compiler-visible facts.


method_signature

Answers: full signature with implicit/using params.

The render calls in the source read render(List(1, 2, 3)) — the Show instance is invisible there. The signature makes the whole contract explicit.

Request: method_signature

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render().

signature:

def render[A](a: A)(implicit evidence$1: Show[A]): String
Raw JSON

Arguments:

{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render()."
}

Result:

{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render().",
"signature": "def render[A](a: A)(implicit evidence$1: Show[A]): String"
}

Replaces: Reading the definition and hand-tracing the implicit list → one resolved signature.


document_outline

Answers: file structure with compiler-rendered names.

The tool returns a tree with compiler-rendered names instead of a text scan. For a 50-line file, the outline is 5–10 lines; for 1000 lines, still manageable.

Request: document_outline

Arguments:

  • uri: docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"outline": [
{
"name": "Show",
"kind": "TRAIT",
"line": 8,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"children": [
{
"name": "show",
"kind": "METHOD",
"line": 9,
"signature": "def show(a: A): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show#show()."
}
]
},
{
"name": "Show",
"kind": "OBJECT",
"line": 11,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.",
"children": [
{
"name": "apply",
"kind": "METHOD",
"line": 13,
"signature": "def apply[A](implicit s: Show[A]): Show[A]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.apply()."
},
{
"name": "intShow",
"kind": "OBJECT",
"line": 15,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.intShow.",
"children": [
{
"name": "show",
"kind": "METHOD",
"line": 16,
"signature": "def show(a: Int): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.intShow.show()."
}
]
},
{
"name": "stringShow",
"kind": "OBJECT",
"line": 18,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.stringShow.",
"children": [
{
"name": "show",
"kind": "METHOD",
"line": 19,
"signature": "def show(a: String): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.stringShow.show()."
}
]
},
{
"name": "listShow",
"kind": "METHOD",
"line": 22,
"signature": "def listShow[A](implicit evidence$1: Show[A]): listShow[A]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow()."
}
]
},
{
"name": "evidence$1",
"kind": "METHOD",
"line": 22,
"signature": ": Show[A]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow#evidence$1."
},
{
"name": "show",
"kind": "METHOD",
"line": 23,
"signature": "def show(a: List[A]): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow#show()."
},
{
"name": "render",
"kind": "METHOD",
"line": 27,
"signature": "def render[A](a: A)(implicit evidence$1: Show[A]): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render()."
},
{
"name": "shown",
"kind": "METHOD",
"line": 29,
"signature": "def shown(n: Int)(implicit x$2: Show[Int]): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.shown()."
},
{
"name": "nums",
"kind": "METHOD",
"line": 31,
"signature": ": List[Int]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.nums."
},
{
"name": "out",
"kind": "METHOD",
"line": 32,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.out."
},
{
"name": "sorted",
"kind": "METHOD",
"line": 33,
"signature": ": List[Int]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.sorted."
},
{
"name": "ranked",
"kind": "METHOD",
"line": 34,
"signature": ": List[Tuple2[String, Int]]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.ranked."
},
{
"name": "labeled",
"kind": "METHOD",
"line": 35,
"signature": ": List[Tuple2[Int, String]]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.labeled."
},
{
"name": "total",
"kind": "METHOD",
"line": 36,
"signature": ": Int",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.total."
},
{
"name": "ratio",
"kind": "METHOD",
"line": 37,
"signature": ": Double",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.ratio."
},
{
"name": "shownFive",
"kind": "METHOD",
"line": 38,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.shownFive."
},
{
"name": "firstTwo",
"kind": "METHOD",
"line": 39,
"signature": ": Option[String]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.firstTwo."
}
]
}

Replaces: Scanning files → structured outline.


type_at_position

Answers: type of code at a source location.

No inference needed by hand; the tool returns the exact type the compiler assigned. For complex generics and implicit resolution, invaluable.

Request: type_at_position

Arguments:

  • uri: docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala
  • line: 14
  • character: 6
{
"found": false
}

Replaces: Hand type inference → compiler's answer.


resolve_implicits

Answers: which givens/implicits apply.

For Show[_], two givens qualify: intShow directly and listShow (itself parameterized on another Show).

Request: resolve_implicits

Arguments:

  • type: com/github/mercurievv/scalasemantic/docexamples/Show#
{
"type": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"candidates": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.intShow.",
"type": "Show[Int]"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow().",
"type": "Show[List[A]]"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.stringShow.",
"type": "Show[String]"
}
]
}

Replaces: Guessing which given applies → the compiler's candidate set.


trace_implicit_chain

Answers: path of implicit dependencies.

listShow produces Show[List[A]] only by depending on a Show[A]; the chain makes that dependency explicit.

Request: trace_implicit_chain

Arguments:

  • type: com/github/mercurievv/scalasemantic/docexamples/Show#
{
"type": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"steps": [
{
"given": "intShow",
"type": "Show[Int]"
},
{
"given": "listShow",
"type": "Show[List[A]]",
"dependsOn": [
"com/github/mercurievv/scalasemantic/docexamples/Show#"
]
},
{
"given": "stringShow",
"type": "Show[String]"
}
]
}

Replaces: Manually following each given's own implicit needs → the whole chain.


Tools on modified code

The tools above read the last compiled SemanticDB. But ScalaSemantic can also answer against a buffer that was edited but never recompiled: pass the current file text as source and the presentation compiler regenerates the analysis in memory. This is what makes the tools correct on a dirty working buffer.

Below, the only change to Enrich.scala is a new prefix: String using-parameter on render:

-def render[A](a: A)(using sh: Show[A]): String =
- sh.show(a)
+def render[A](a: A)(using sh: Show[A], prefix: String): String =
+ prefix + sh.show(a)

method_signature runs on the same render symbol, with the same arguments, three ways: against the committed index, against the unmodified file through the presentation compiler (proving the two agree), and against the edited buffer — which reports the new parameter without any recompile.

Request: method_signature

Arguments:

  • symbol: com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render().

DB (committed)

def render[A](a: A)(implicit evidence$1: Show[A]): String

PC (same code)

def render[A](a: A)(implicit evidence$1: Show[A]): String

PC (modified)

def render[A](a: A)(implicit sh: Show[A], prefix: String): String

Replaces: Recompiling just to ask a question about half-finished code.