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
| Tool | Answers |
|---|---|
| Exploration tools | |
find_symbol | Resolve a name to its definition |
find_usages | All references to a symbol |
class_hierarchy | Supertypes and subtypes |
find_overloads | All overloads of a method |
members | Declared and inherited members |
call_path | Whether method A reaches method B |
method_call_hierarchy | All callers or callees |
value_flow | Trace a value through the call graph |
rename_plan | Edit ranges for a safe rename |
move_plan | Move a symbol to a new package |
extract_method_plan | Extract a code range into a method |
structure | Dependency graph and cycles |
smart_code_duplications | Structurally identical blocks |
| Enriching tools | |
annotated_source | Compiler-visible facts and inferred types |
method_signature | Full signature with implicit/using params |
document_outline | File structure with compiler-rendered names |
resolve_implicits | Which givens/implicits apply |
trace_implicit_chain | Path of implicit dependencies |
type_at_position | Type 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.scalaline:19column: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.scalastartLine:5startCharacter:20endLine:8endCharacter: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.scalaformat:compilableannotationsOnly: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.scalaline:14character: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.