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 | What it tells you |
|---|---|
| Find & resolve symbols | |
find_symbol | Resolve a name to its definition |
symbol_source | Source of ONE symbol's definition, enriched |
source_around_position | Source of the definition enclosing a position |
| References & call graph | |
find_usages | All references to a symbol (optional contextLines for surrounding source) |
call_path | Whether method A reaches method B |
method_call_hierarchy | All callers or callees |
value_flow | Trace a value through the call graph |
| Hierarchy & members | |
class_hierarchy | Supertypes and subtypes |
find_overloads | All overloads of a method |
members | Declared and inherited members |
| Search & analysis | |
search_text | Scoped text/regex search over .scala files (string literals/comments) |
structure | Dependency graph and cycles |
smart_code_duplications | Structurally identical blocks |
document_outline | File structure with compiler-rendered names |
| Implicits | |
resolve_implicits | Which givens/implicits apply |
trace_implicit_chain | Path of implicit dependencies |
| Edit plans | |
rename_plan | Edit ranges for a safe rename |
batch_rename_plan | Edit ranges for multiple renames, reporting range conflicts |
move_plan | Move a symbol to a new package |
extract_method_plan | Extract a code range into a method |
| Compiler view | |
annotated_source | Compiler view — inferred types, implicits, exploded imports, diff (tabbed) |
method_signature | Full signature with implicit/using params |
type_at_position | Type of code at a source location |
Find & resolve symbols
Resolve names to their definitions, locate enriched source and surrounding context.
find_symbol
What it tells you: 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.
symbol_source
Answers: the source of ONE symbol's definition — enriched like annotated_source, but scoped to just that method/class/val instead of the whole file.
Same render symbol as below, but this time only its own signature+body come back — not Show, not the givens, not anything else in Enrich.scala. The gutter keeps the file's real (absolute) line numbers, so the result still tells you exactly where in the file to look.
Request: symbol_source
Arguments:
symbol:com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render().
source:
28 def render[A: Show](a: A): String = Show[A].show(a) ⟹ elaborated: Show[A](using Show[A]) 29
Raw JSON
Arguments:
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.render()."
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "annotated",
"annotationCount": 1,
"legend": "READ-ONLY view, NOT valid Scala — do NOT paste into code; edit the real file at uri (gutter line numbers map 1:1). ⟹ marks each note. 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": " 28 def render[A: Show](a: A): String = Show[A].show(a) ⟹ elaborated: Show[A](using Show[A])
29 "
}A dotted FQN works too, so callers who only know the name (not the SemanticDB symbol grammar) can still use the tool:
Request: symbol_source
Arguments:
symbol:com.github.mercurievv.scalasemantic.docexamples.render()
source:
28 def render[A: Show](a: A): String = Show[A].show(a) ⟹ elaborated: Show[A](using Show[A]) 29
Raw JSON
Arguments:
{
"symbol": "com.github.mercurievv.scalasemantic.docexamples.render()"
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "annotated",
"annotationCount": 1,
"legend": "READ-ONLY view, NOT valid Scala — do NOT paste into code; edit the real file at uri (gutter line numbers map 1:1). ⟹ marks each note. 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": " 28 def render[A: Show](a: A): String = Show[A].show(a) ⟹ elaborated: Show[A](using Show[A])
29 "
}Replaces: annotated_source on the whole file plus manually scrolling to the one definition you actually wanted → the definition alone, absolute line numbers intact.
source_around_position
Answers: the source of the definition ENCLOSING a source position — like symbol_source, but keyed by file+line+column (0-based) instead of a resolved symbol, for when you only have a cursor position (e.g. from type_at_position or a stack trace).
Position line=27,column=40 sits inside Show[A].show(a) — a REFERENCE, not a definition — on render's single-line body. The tool anchors to render's enclosing definition rather than jumping to Show's own (unrelated) definition:
Request: source_around_position
Arguments:
file:docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scalaline:27column:40format:plain
source:
28 def render[A: Show](a: A): String = Show[A].show(a) 29
Raw JSON
Arguments:
{
"file": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"line": 27,
"column": 40,
"format": "plain"
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "plain",
"annotationCount": 1,
"legend": "The raw file with a 1-based line-number gutter (a READ-ONLY view — edit the real file at uri, not this). No annotations in this format.",
"source": " 28 def render[A: Show](a: A): String = Show[A].show(a)
29 "
}When no enclosing definition exists at the position (e.g. a blank line before any declaration), the tool falls back to a fixed ±15-line window and notes the fallback in legend.
Replaces: manually re-deriving "what method/class am I inside" from a line/column → the enclosing definition's source, resolved and enriched, in one call.
References & call graph
Who calls what, value flow, and reachability.
find_usages
What it tells you: 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"
]
}
Pass contextLines to get a few lines of source around each hit — no more piping the reference
list to rg -A5 for context. Each file backing a hit is read once, however many references it
holds.
Request: find_usages
Arguments:
symbol:com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().contextLines:1
{
"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"
],
"definitionsWithContext": [
{
"location": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:13:4",
"context": [
"",
"def transform(p: Processor, input: String): String =",
" p.process(input)"
]
}
],
"referencesWithContext": [
{
"location": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:2",
"context": [
"def compose(p1: Processor, p2: Processor, input: String): String =",
" transform(p2, transform(p1, input))",
""
]
},
{
"location": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:16",
"context": [
"def compose(p1: Processor, p2: Processor, input: String): String =",
" transform(p2, transform(p1, input))",
""
]
}
]
}
Replaces: Grepping all files → exact reference list.
call_path
What it tells you: 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
What it tells you: 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
Raw JSON
Arguments:
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().",
"direction": "callees"
}Result:
{
"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
What it tells you: 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. The BFS also follows a value into an implicit/using parameter (relation: "passed_as_implicit", whether the call site writes an explicit given/using arg, a using clause, or a context bound [A: TC] — all three desugar to the same implicit-parameter occurrence), terminating at "implicit_boundary" when that implicit has no further in-project references.
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.
Hierarchy & members
Types, supertypes, subtypes, overloads, and member lists.
class_hierarchy
What it tells you: 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
What it tells you: all overloads of a method sharing its owner, plus same-named methods
inherited from parent types (inheritedOverloads, each suffixed (from <Parent>)) — the full
overload set visible on the type, not just the ones declared locally.
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, including a manual walk up the class hierarchy.
members
What it tells you: 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.
Search & analysis
Full-text search, structural patterns, and dependencies.
search_text
What it tells you: plain text/regex hits (file + line) over .scala files — string literals
and comments, the one case SemanticDB has no symbol model for.
This is the sanctioned in-MCP replacement for shelling out to grep/rg on Scala sources; it is
not symbol-aware (no rename/re-export/implicit resolution) and can over-match comments/strings
like grep does. Use find_symbol/find_usages for identifiers instead.
Request: search_text
Arguments:
query:context boundpathFilter:*docexamples/Enrich.scala*
{
"query": "context bound",
"count": 1,
"hits": [
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"line": 21,
"text": " // context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes"
}
]
}
Replaces: grep/rg on .scala files for non-symbol text, kept inside MCP tooling.
structure
What it tells you: dependency graph and cycles.
A snapshot of the product modules' dependency structure in one call.
Metric values:
types: number of in-project types in a module.layer: longest dependency-chain depth after cycles are condensed;0means a foundation type/module, larger numbers sit above deeper dependencies.ca: afferent coupling, the number of incoming dependencies; higher values mean more project symbols depend on this symbol/module.ce: efferent coupling, the number of outgoing dependencies; higher values mean this symbol/module depends on more project symbols.instability:ce / (ca + ce), from0to1;0is stable/foundation-like,1is leaf/consumer-like.centrality: PageRank-style importance; higher values mean the symbol is more structurally central because important symbols depend on it.dependenciesweight: number of semantic dependency observations collapsed into one symbol-to-symbol edge; thicker graph edges mean higher weight.moduleEdgesweight: number of symbol-level dependency edges crossing from one module to another.
Request: structure
Arguments:
limit:20
Raw JSON
Arguments:
{
"limit": 20
}Result:
{
"dimension": "combined",
"sort": "afferent",
"modules": [
{
"module": "analysis",
"types": 69,
"layer": 1,
"ca": 1,
"ce": 1,
"instability": 0.5
},
{
"module": "core",
"types": 2,
"layer": 0,
"ca": 2,
"ce": 0,
"instability": 0
},
{
"module": "mcp",
"types": 10,
"layer": 2,
"ca": 0,
"ce": 2,
"instability": 1
},
{
"module": "out",
"types": 1,
"layer": 0,
"ca": 0,
"ce": 0,
"instability": 0
}
],
"dependencies": [
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"dimensions": [
"call",
"memberType"
],
"weight": 95
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/DimensionMetrics#",
"dimensions": [
"memberType"
],
"weight": 3
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/DuplicationsResult#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/InputTypes.SemanticDbSymbol#",
"dimensions": [
"memberType"
],
"weight": 4
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/Location#",
"dimensions": [
"memberType"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/SourceAnnotation#",
"dimensions": [
"call",
"memberType"
],
"weight": 4
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"to": "com/github/mercurievv/scalasemantic/semanticdb/SemanticIndex#",
"dimensions": [
"call",
"memberType"
],
"weight": 68
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/analysis/PureKernels.",
"dimensions": [
"call"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/model/Location#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/model/MemberInfo#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/model/SourceAnnotation#",
"dimensions": [
"memberType"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolKind#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"to": "com/github/mercurievv/scalasemantic/semanticdb/SemanticIndex#",
"dimensions": [
"call",
"memberType"
],
"weight": 33
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpTools.",
"to": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"dimensions": [
"call",
"memberType"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpTools.",
"to": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"dimensions": [
"call"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpTools.",
"to": "com/github/mercurievv/scalasemantic/mcp/Tool#",
"dimensions": [
"call",
"memberType"
],
"weight": 3
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"dimensions": [
"call",
"memberType"
],
"weight": 15
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/mcp/Tool#",
"dimensions": [
"memberType"
],
"weight": 2
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/InputTypes.SemanticDbSymbol#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/Location#",
"dimensions": [
"memberType"
],
"weight": 3
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/MemberInfo#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/ModuleEdge#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/SourceAnnotation#",
"dimensions": [
"call"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/SymbolKind#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"to": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"dimensions": [
"memberType"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/model/ImplicitCandidate#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"dimensions": [
"memberType"
],
"weight": 5
},
{
"from": "com/github/mercurievv/scalasemantic/model/InputTypes.SemanticDbSymbol#",
"to": "com/github/mercurievv/scalasemantic/model/InputTypes.NonEmptyString#",
"dimensions": [
"typeRef"
],
"weight": 1
},
{
"from": "com/github/mercurievv/scalasemantic/model/Location#",
"to": "com/github/mercurievv/scalasemantic/model/Range#",
"dimensions": [
"memberType"
],
"weight": 5
},
{
"from": "com/github/mercurievv/scalasemantic/model/MemberInfo#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolKind#",
"dimensions": [
"memberType"
],
"weight": 5
},
{
"from": "com/github/mercurievv/scalasemantic/model/MemberInfo#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"dimensions": [
"memberType"
],
"weight": 5
},
{
"from": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"to": "com/github/mercurievv/scalasemantic/model/SymbolKind#",
"dimensions": [
"memberType"
],
"weight": 5
}
],
"moduleEdges": [
"analysis->core (5)",
"mcp->analysis (23)",
"mcp->core (2)"
],
"symbols": [
{
"symbol": "com/github/mercurievv/scalasemantic/model/Location#",
"name": "Location",
"module": "analysis",
"layer": 2,
"ca": 14,
"ce": 1,
"instability": 0.07,
"centrality": 0.023
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/SymbolRef#",
"name": "SymbolRef",
"module": "analysis",
"layer": 1,
"ca": 13,
"ce": 1,
"instability": 0.07,
"centrality": 0.017
},
{
"symbol": "com/github/mercurievv/scalasemantic/analysis/Analyzer#",
"name": "Analyzer",
"module": "analysis",
"layer": 7,
"ca": 7,
"ce": 36,
"instability": 0.84,
"centrality": 0.005
},
{
"symbol": "com/github/mercurievv/scalasemantic/mcp/Tool#",
"name": "Tool",
"module": "mcp",
"layer": 0,
"ca": 7,
"ce": 0,
"instability": 0,
"centrality": 0.005
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/SymbolKind#",
"name": "SymbolKind",
"module": "analysis",
"layer": 0,
"ca": 7,
"ce": 0,
"instability": 0,
"centrality": 0.023
},
{
"symbol": "com/github/mercurievv/scalasemantic/mcp/McpToolsSupport.",
"name": "McpToolsSupport",
"module": "mcp",
"layer": 8,
"ca": 6,
"ce": 18,
"instability": 0.75,
"centrality": 0.005
},
{
"symbol": "com/github/mercurievv/scalasemantic/semanticdb/SemanticIndex#",
"name": "SemanticIndex",
"module": "core",
"layer": 0,
"ca": 6,
"ce": 0,
"instability": 0,
"centrality": 0.006
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/InputTypes.NonEmptyString#",
"name": "NonEmptyString",
"module": "analysis",
"layer": 0,
"ca": 4,
"ce": 0,
"instability": 0,
"centrality": 0.012
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/InputTypes.SemanticDbSymbol#",
"name": "SemanticDbSymbol",
"module": "analysis",
"layer": 1,
"ca": 4,
"ce": 1,
"instability": 0.2,
"centrality": 0.006
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/Range#",
"name": "Range",
"module": "analysis",
"layer": 1,
"ca": 4,
"ce": 1,
"instability": 0.2,
"centrality": 0.027
},
{
"symbol": "com/github/mercurievv/scalasemantic/analysis/graph/GraphMetrics.Graph#",
"name": "Graph",
"module": "analysis",
"layer": 0,
"ca": 3,
"ce": 0,
"instability": 0,
"centrality": 0.004
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/DimensionMetrics#",
"name": "DimensionMetrics",
"module": "analysis",
"layer": 0,
"ca": 3,
"ce": 0,
"instability": 0,
"centrality": 0.004
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/MemberInfo#",
"name": "MemberInfo",
"module": "analysis",
"layer": 2,
"ca": 3,
"ce": 2,
"instability": 0.4,
"centrality": 0.004
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/ModuleEdge#",
"name": "ModuleEdge",
"module": "analysis",
"layer": 0,
"ca": 3,
"ce": 0,
"instability": 0,
"centrality": 0.003
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/SourceAnnotation#",
"name": "SourceAnnotation",
"module": "analysis",
"layer": 0,
"ca": 3,
"ce": 0,
"instability": 0,
"centrality": 0.002
},
{
"symbol": "com/github/mercurievv/scalasemantic/analysis/AnalyzerHelpers#",
"name": "AnalyzerHelpers",
"module": "analysis",
"layer": 3,
"ca": 2,
"ce": 9,
"instability": 0.82,
"centrality": 0.003
},
{
"symbol": "com/github/mercurievv/scalasemantic/analysis/PureKernels.",
"name": "PureKernels",
"module": "analysis",
"layer": 0,
"ca": 2,
"ce": 0,
"instability": 0,
"centrality": 0.003
},
{
"symbol": "com/github/mercurievv/scalasemantic/mcp/McpTools.",
"name": "McpTools",
"module": "mcp",
"layer": 10,
"ca": 2,
"ce": 7,
"instability": 0.78,
"centrality": 0.003
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/DuplicationsResult#",
"name": "DuplicationsResult",
"module": "analysis",
"layer": 5,
"ca": 2,
"ce": 1,
"instability": 0.33,
"centrality": 0.003
},
{
"symbol": "com/github/mercurievv/scalasemantic/model/ImplicitCandidate#",
"name": "ImplicitCandidate",
"module": "analysis",
"layer": 2,
"ca": 2,
"ce": 1,
"instability": 0.33,
"centrality": 0.004
}
]
}Replaces: Manual dependency graph construction.
smart_code_duplications
What it tells you: 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"
}
]
}
]
}
Pass showSource: true to also get a groupsSource field with the duplicated lines for every
occurrence, gutter-numbered like annotated_source's plain format — handy for eyeballing what a
clone group actually looks like without a second annotated_source round trip.
Replaces: Manual code review for duplication.
document_outline
What it tells you: 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
- ShowTRAIT
- showMETHOD
def show(a: A): String
- ShowOBJECT
- applyMETHOD
def apply[A](implicit s: Show[A]): Show[A] - intShowOBJECT
- showMETHOD
def show(a: Int): String
- stringShowOBJECT
- showMETHOD
def show(a: String): String
- listShowMETHOD
def listShow[A](implicit evidence$1: Show[A]): listShow[A]
- evidence$1METHOD
: Show[A] - showMETHOD
def show(a: List[A]): String - renderMETHOD
def render[A](a: A)(implicit evidence$1: Show[A]): String - shownMETHOD
def shown(n: Int)(implicit x$2: Show[Int]): String - InstancesOBJECT
- doubleShowOBJECT
- showMETHOD
def show(a: Double): String
- floatShowOBJECT
- showMETHOD
def show(a: Float): String
- numsMETHOD
: List[Int] - piMETHOD
: String - floMETHOD
: String - outMETHOD
: String - sortedMETHOD
: List[Int] - rankedMETHOD
: List[Tuple2[String, Int]] - labeledMETHOD
: List[Tuple2[Int, String]] - totalMETHOD
: Int - ratioMETHOD
: Double - shownFiveMETHOD
: String - firstTwoMETHOD
: Option[String]
Raw JSON
Arguments:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala"
}Result:
{
"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": "Instances",
"kind": "OBJECT",
"line": 31,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.",
"children": [
{
"name": "doubleShow",
"kind": "OBJECT",
"line": 32,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.doubleShow.",
"children": [
{
"name": "show",
"kind": "METHOD",
"line": 33,
"signature": "def show(a: Double): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.doubleShow.show()."
}
]
},
{
"name": "floatShow",
"kind": "OBJECT",
"line": 34,
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.floatShow.",
"children": [
{
"name": "show",
"kind": "METHOD",
"line": 35,
"signature": "def show(a: Float): String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.floatShow.show()."
}
]
}
]
},
{
"name": "nums",
"kind": "METHOD",
"line": 42,
"signature": ": List[Int]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.nums."
},
{
"name": "pi",
"kind": "METHOD",
"line": 43,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.pi."
},
{
"name": "flo",
"kind": "METHOD",
"line": 44,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.flo."
},
{
"name": "out",
"kind": "METHOD",
"line": 45,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.out."
},
{
"name": "sorted",
"kind": "METHOD",
"line": 46,
"signature": ": List[Int]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.sorted."
},
{
"name": "ranked",
"kind": "METHOD",
"line": 47,
"signature": ": List[Tuple2[String, Int]]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.ranked."
},
{
"name": "labeled",
"kind": "METHOD",
"line": 48,
"signature": ": List[Tuple2[Int, String]]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.labeled."
},
{
"name": "total",
"kind": "METHOD",
"line": 49,
"signature": ": Int",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.total."
},
{
"name": "ratio",
"kind": "METHOD",
"line": 50,
"signature": ": Double",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.ratio."
},
{
"name": "shownFive",
"kind": "METHOD",
"line": 51,
"signature": ": String",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.shownFive."
},
{
"name": "firstTwo",
"kind": "METHOD",
"line": 52,
"signature": ": Option[String]",
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.firstTwo."
}
]
}Replaces: Scanning files → structured outline.
Implicits
Given/implicit resolution and chains.
resolve_implicits
What it tells you: which givens/implicits apply.
resolve_implicits returns the flat candidate set: every given/implicit in the index that can produce some Show[X]. For Show#, that includes intShow, stringShow, listShow, and the imported doubleShow/floatShow instances. This is the candidate set before a call-site selection, not a scope-filtered proof that one instance was applied; chosen is filled only when exactly one candidate exists.
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/Instances.doubleShow.",
"type": "Show[Double]"
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Instances.floatShow.",
"type": "Show[Float]"
},
{
"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 givens exist → the compiler's candidate set.
trace_implicit_chain
What it tells you: path of implicit dependencies.
trace_implicit_chain returns the same candidate set plus each candidate's own implicit dependencies. listShow produces Show[List[A]] only given a Show[A], so its step lists Show# as a dependency; that dependency edge is what distinguishes it from resolve_implicits.
Use resolve_implicits when you need the flat candidate set; use trace_implicit_chain when you also need the transitive dependencies each candidate would require.
Request: trace_implicit_chain
Arguments:
type:com/github/mercurievv/scalasemantic/docexamples/Show#
{
"type": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"steps": [
{
"given": "doubleShow",
"type": "Show[Double]"
},
{
"given": "floatShow",
"type": "Show[Float]"
},
{
"given": "intShow",
"type": "Show[Int]"
},
{
"given": "listShow",
"type": "Show[List[A]]",
"dependsOn": [
"com/github/mercurievv/scalasemantic/docexamples/Show#"
]
},
{
"given": "stringShow",
"type": "Show[String]"
}
]
}
For a concrete wanted type, pass appliedType. Here Show[List[Int]] resolves to listShow, whose nested dependency resolves to intShow.
Request: trace_implicit_chain
Arguments:
type:com/github/mercurievv/scalasemantic/docexamples/Show#appliedType:Show[List[Int]]
Raw JSON
Arguments:
{
"type": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"appliedType": "Show[List[Int]]"
}Result:
{
"type": "com/github/mercurievv/scalasemantic/docexamples/Show#",
"appliedType": "Show[List[Int]]",
"steps": [
{
"given": "doubleShow",
"type": "Show[Double]"
},
{
"given": "floatShow",
"type": "Show[Float]"
},
{
"given": "intShow",
"type": "Show[Int]"
},
{
"given": "listShow",
"type": "Show[List[A]]",
"dependsOn": [
"com/github/mercurievv/scalasemantic/docexamples/Show#"
]
},
{
"given": "stringShow",
"type": "Show[String]"
}
],
"resolved": {
"type": "Show[List[Int]]",
"chosen": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow().",
"candidates": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.listShow().",
"type": "Show[List[A]]"
}
],
"children": [
{
"type": "Show[Int]",
"chosen": "com/github/mercurievv/scalasemantic/docexamples/Show.intShow.",
"candidates": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Show.intShow.",
"type": "Show[Int]"
}
]
}
]
}
}Replaces: Manually following each given's own implicit needs → the whole chain.
Edit plans
Refactoring assistance: rename, move, extract.
rename_plan
What it tells you: 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.
batch_rename_plan
What it tells you: edit ranges for renaming multiple symbols in one request, so a project-wide
rename batch doesn't get done by hand one rename_plan call at a time.
transform and calculateTotal live in different files and never touch the same edit range, so
combinedEditCount is just the sum of the two individual plans' edit counts and conflictCount is
0. The tool only detects literal edit-range overlaps between the requested renames — two
different symbols renamed to the same new name (a semantic collision at a call site) is out of
scope and remains the caller's responsibility.
Request: batch_rename_plan
Arguments:
renames:[{"symbol":"com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().","newName":"apply"},{"symbol":"com/github/mercurievv/scalasemantic/docexamples/Refactor$package.calculateTotal().","newName":"total"}]
{
"perSymbol": [
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().",
"rename": "transform -> apply",
"editCount": 3
},
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Refactor$package.calculateTotal().",
"rename": "calculateTotal -> total",
"editCount": 3
}
],
"combinedEditCount": 6,
"combinedEdits": [
"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",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:2:4-18",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:14:18-32",
"docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Refactor.scala:15:18-32"
],
"conflictCount": 0
}
Replaces: Running rename_plan once per symbol and manually reconciling edits by hand.
move_plan
What it tells you: 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
What it tells you: 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
{
"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.
Compiler view
Inferred types, implicit insertions, signatures, and types at positions.
annotated_source
What it tells you: compiler-visible facts and inferred types — everything the compiler sees that the source text does not.
Enrich.scala is a small file with a Show typeclass, several given instances, a context-bound render, an extension method, collection calls, a for-comprehension, and numeric widening. The tabs run the real analyzer against it at build time:
- compilable shows compiler insertions as a patch against the original source.
- symbols=on adds symbol/package details and expands relevant wildcard
givenimports as a patch. - docs=strip shows comment stripping and compiler insertions as a patch.
- All (diff) shows every enrichment against the original as a literal patch.
- Original is the raw source.
The request below is shared by every tab; each tab lists only the argument values it changes.
Request: annotated_source
Arguments:
uri:docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scalaannotationsOnly:false
- compilable
- symbols=on
- docs=strip
- All (diff)
- Original
Compiler insertions as a patch.
compilable — format = diff
def apply[A](using s: Show[A]): Show[A] = s
given intShow: Show[Int] with
def show(a: Int) = a.toString // ⟹ type: String
given stringShow: Show[String] with
def show(a: String) = a // ⟹ type: String
// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with // ⟹ type: Show[A]; elaborated: (using Show[A])
def show(a: List[A]) = // ⟹ type: String
a.map(Show[A].show).mkString("[", ", ", "]") // ⟹ elaborated: Show[A](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) // ⟹ elaborated: Show[A](using Show[A])
extension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ elaborated: render[Int](n)(using Show[Int])
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString // ⟹ type: String
given floatShow: Show[Float] with
def show(a: Float) = a.toString // ⟹ type: String
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given
val nums = List(1, 2, 3) // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)
val pi = render(3.14) // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)
val flo = render(1.0f) // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)
val out = render(nums) // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))
val sorted = nums.sorted // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1) // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])
val labeled = nums.map(n => n -> render(n)) // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)
val total = nums.foldLeft(0)(_ + _) // ⟹ type: Int; nums.foldLeft[Int]
val ratio: Double = nums.size // ⟹ elaborated: int2double(nums.size)
val shownFive = 5.shown // ⟹ type: String; elaborated: 5.shown(using intShow)
val firstTwo = // ⟹ type: Option[String]
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b) // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)
Raw JSON
Arguments:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationsOnly": false
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationCount": 33,
"legend": "Unified diff, source-as-written → enriched: `-` lines are the original, `+` lines add the compiler's inline `// ⟹` insertions and explode wildcard/`given` imports (with symbols=on). Render in any diff viewer for green/red. 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": "--- docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (original)
+++ docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (enriched)
@@ -14,45 +14,45 @@
def apply[A](using s: Show[A]): Show[A] = s
given intShow: Show[Int] with
def show(a: Int) = a.toString{+ // ⟹ type: String+}
given stringShow: Show[String] with
def show(a: String) = a{+ // ⟹ type: String+}
// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with{+ // ⟹ type: Show[A]; elaborated: (using Show[A])+}
def show(a: List[A]) ={+ // ⟹ type: String+}
a.map(Show[A].show).mkString("[", ", ", "]"){+ // ⟹ elaborated: Show[A](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){+ // ⟹ elaborated: Show[A](using Show[A])+}
extension (n: Int) def shown(using Show[Int]): String = render(n){+ // ⟹ elaborated: render[Int](n)(using Show[Int])+}
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString{+ // ⟹ type: String+}
given floatShow: Show[Float] with
def show(a: Float) = a.toString{+ // ⟹ type: String+}
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given
val nums = List(1, 2, 3){+ // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)+}
val pi = render(3.14){+ // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)+}
val flo = render(1.0f){+ // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)+}
val out = render(nums){+ // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))+}
val sorted = nums.sorted{+ // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])+}
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1){+ // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])+}
val labeled = nums.map(n => n -> render(n)){+ // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)+}
val total = nums.foldLeft(0)(_ + _){+ // ⟹ type: Int; nums.foldLeft[Int]+}
val ratio: Double = nums.size{+ // ⟹ elaborated: int2double(nums.size)+}
val shownFive = 5.shown{+ // ⟹ type: String; elaborated: 5.shown(using intShow)+}
val firstTwo ={+ // ⟹ type: Option[String]+}
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b){+ // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)+}
"
}Inline enrichment plus symbol details as a patch.
symbols=on — format = diff, symbols = true
def apply[A](using s: Show[A]): Show[A] = s
given intShow: Show[Int] with
def show(a: Int) = a.toString // ⟹ type: String
given stringShow: Show[String] with
def show(a: String) = a // ⟹ type: String
// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with // ⟹ type: Show[A]; elaborated: (using Show[A])
def show(a: List[A]) = // ⟹ type: String
a.map(Show[A].show).mkString("[", ", ", "]") // ⟹ elaborated: Show[A](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) // ⟹ elaborated: Show[A](using Show[A])
extension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ elaborated: render[Int](n)(using Show[Int])
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString // ⟹ type: String
given floatShow: Show[Float] with
def show(a: Float) = a.toString // ⟹ type: String
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given{doubleShow, floatShow}
val nums = List(1, 2, 3) // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)
val pi = render(3.14) // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)
val flo = render(1.0f) // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)
val out = render(nums) // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))
val sorted = nums.sorted // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1) // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])
val labeled = nums.map(n => n -> render(n)) // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)
val total = nums.foldLeft(0)(_ + _) // ⟹ type: Int; nums.foldLeft[Int]
val ratio: Double = nums.size // ⟹ elaborated: int2double(nums.size)
val shownFive = 5.shown // ⟹ type: String; elaborated: 5.shown(using intShow)
val firstTwo = // ⟹ type: Option[String]
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b) // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)
+
+// symbols:
+// List → scala.collection.immutable.List
+// Show → com.github.mercurievv.scalasemantic.docexamples.Show
Raw JSON
Arguments:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationsOnly": false,
"symbols": true
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationCount": 33,
"legend": "Unified diff, source-as-written → enriched: `-` lines are the original, `+` lines add the compiler's inline `// ⟹` insertions and explode wildcard/`given` imports (with symbols=on). Render in any diff viewer for green/red. 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": "--- docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (original)
+++ docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (enriched)
@@ -14,45 +14,49 @@
def apply[A](using s: Show[A]): Show[A] = s
given intShow: Show[Int] with
def show(a: Int) = a.toString{+ // ⟹ type: String+}
given stringShow: Show[String] with
def show(a: String) = a{+ // ⟹ type: String+}
// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with{+ // ⟹ type: Show[A]; elaborated: (using Show[A])+}
def show(a: List[A]) ={+ // ⟹ type: String+}
a.map(Show[A].show).mkString("[", ", ", "]"){+ // ⟹ elaborated: Show[A](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){+ // ⟹ elaborated: Show[A](using Show[A])+}
extension (n: Int) def shown(using Show[Int]): String = render(n){+ // ⟹ elaborated: render[Int](n)(using Show[Int])+}
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString{+ // ⟹ type: String+}
given floatShow: Show[Float] with
def show(a: Float) = a.toString{+ // ⟹ type: String+}
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.[-given-]{+{doubleShow, floatShow}+}
val nums = List(1, 2, 3){+ // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)+}
val pi = render(3.14){+ // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)+}
val flo = render(1.0f){+ // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)+}
val out = render(nums){+ // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))+}
val sorted = nums.sorted{+ // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])+}
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1){+ // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])+}
val labeled = nums.map(n => n -> render(n)){+ // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)+}
val total = nums.foldLeft(0)(_ + _){+ // ⟹ type: Int; nums.foldLeft[Int]+}
val ratio: Double = nums.size{+ // ⟹ elaborated: int2double(nums.size)+}
val shownFive = 5.shown{+ // ⟹ type: String; elaborated: 5.shown(using intShow)+}
val firstTwo ={+ // ⟹ type: Option[String]+}
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b){+ // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)+}
+
+// symbols:
+// List → scala.collection.immutable.List
+// Show → com.github.mercurievv.scalasemantic.docexamples.Show"
}Compiler insertions with comments removed, shown as a patch.
docs=strip — format = diff, docs = strip
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 // ⟹ type: String
given stringShow: Show[String] with
def show(a: String) = a // ⟹ type: String
- // context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with // ⟹ type: Show[A]; elaborated: (using Show[A])
def show(a: List[A]) = // ⟹ type: String
a.map(Show[A].show).mkString("[", ", ", "]") // ⟹ elaborated: Show[A](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) // ⟹ elaborated: Show[A](using Show[A])
extension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ elaborated: render[Int](n)(using Show[Int])
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString // ⟹ type: String
given floatShow: Show[Float] with
def show(a: Float) = a.toString // ⟹ type: String
-// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
-// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
-// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given
val nums = List(1, 2, 3) // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)
val pi = render(3.14) // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)
val flo = render(1.0f) // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)
val out = render(nums) // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))
val sorted = nums.sorted // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1) // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])
val labeled = nums.map(n => n -> render(n)) // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)
val total = nums.foldLeft(0)(_ + _) // ⟹ type: Int; nums.foldLeft[Int]
val ratio: Double = nums.size // ⟹ elaborated: int2double(nums.size)
val shownFive = 5.shown // ⟹ type: String; elaborated: 5.shown(using intShow)
val firstTwo = // ⟹ type: Option[String]
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b) // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)
Raw JSON
Arguments:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationsOnly": false,
"docs": "strip"
}Result:
{
"uri": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala",
"format": "diff",
"annotationCount": 33,
"legend": "Unified diff, source-as-written → enriched: `-` lines are the original, `+` lines add the compiler's inline `// ⟹` insertions and explode wildcard/`given` imports (with symbols=on). Render in any diff viewer for green/red. 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": "--- docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (original)
+++ docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scala (enriched)
@@ -1,58 +1,58 @@
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{+ // ⟹ type: String+}
given stringShow: Show[String] with
def show(a: String) = a{+ // ⟹ type: String+}
- // context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with{+ // ⟹ type: Show[A]; elaborated: (using Show[A])+}
def show(a: List[A]) ={+ // ⟹ type: String+}
a.map(Show[A].show).mkString("[", ", ", "]"){+ // ⟹ elaborated: Show[A](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){+ // ⟹ elaborated: Show[A](using Show[A])+}
extension (n: Int) def shown(using Show[Int]): String = render(n){+ // ⟹ elaborated: render[Int](n)(using Show[Int])+}
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString{+ // ⟹ type: String+}
given floatShow: Show[Float] with
def show(a: Float) = a.toString{+ // ⟹ type: String+}
-// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
-// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
-// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given
val nums = List(1, 2, 3){+ // ⟹ type: List[Int]; elaborated: List.apply[Int](1, 2, 3)+}
val pi = render(3.14){+ // ⟹ type: String; elaborated: render[Double](3.14)(using doubleShow)+}
val flo = render(1.0f){+ // ⟹ type: String; elaborated: render[Float](1.0f)(using floatShow)+}
val out = render(nums){+ // ⟹ type: String; elaborated: render[List[Int]](nums)(using listShow(using intShow))+}
val sorted = nums.sorted{+ // ⟹ type: List[Int]; elaborated: nums.sorted[Int](using Ordering[Int])+}
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1){+ // ⟹ type: List[Tuple2[String, Int]]; elaborated: List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])+}
val labeled = nums.map(n => n -> render(n)){+ // ⟹ type: List[Tuple2[Int, String]]; elaborated: ArrowAssoc[Int](n); elaborated: render[Int](n)(using intShow)+}
val total = nums.foldLeft(0)(_ + _){+ // ⟹ type: Int; nums.foldLeft[Int]+}
val ratio: Double = nums.size{+ // ⟹ elaborated: int2double(nums.size)+}
val shownFive = 5.shown{+ // ⟹ type: String; elaborated: 5.shown(using intShow)+}
val firstTwo ={+ // ⟹ type: Option[String]+}
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b){+ // ⟹ elaborated: render[Int](a)(using intShow); elaborated: render[Int](b)(using intShow)+}
"
}Unified diff from source to enriched source.
All (diff) — format = diff, symbols = true, detail = full, docs = keep
def apply[A](using s: Show[A]): Show[A] = s
given intShow: Show[Int] with
def show(a: Int) = a.toString // ⟹ type: String
given stringShow: Show[String] with
def show(a: String) = a // ⟹ type: String
// context bound `A: Show` desugars to a `(using Show[A])` parameter the source never writes
given listShow[A: Show]: Show[List[A]] with // ⟹ type: Show[A]
def show(a: List[A]) = // ⟹ type: String
a.map(Show[A].show).mkString("[", ", ", "]") // ⟹ Show[A](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) // ⟹ Show[A](using Show[A])
extension (n: Int) def shown(using Show[Int]): String = render(n) // ⟹ render[Int](n)(using Show[Int])
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString // ⟹ type: String
given floatShow: Show[Float] with
def show(a: Float) = a.toString // ⟹ type: String
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given{doubleShow, floatShow}
val nums = List(1, 2, 3) // ⟹ type: List[Int]; List.apply[Int](1, 2, 3)
val pi = render(3.14) // ⟹ type: String; render[Double](3.14)(using doubleShow)
val flo = render(1.0f) // ⟹ type: String; render[Float](1.0f)(using floatShow)
val out = render(nums) // ⟹ type: String; render[List[Int]](nums)(using listShow(using intShow))
val sorted = nums.sorted // ⟹ type: List[Int]; nums.sorted[Int](using Ordering[Int])
val ranked = List("b" -> 2, "a" -> 1).sortBy(_._1) // ⟹ type: List[Tuple2[String, Int]]; List.apply[Tuple2[String, Int]]("b" ->[Int] 2, "a" ->[Int][String] 1).sortBy(_._1)(using Ordering[String])
val labeled = nums.map(n => n -> render(n)) // ⟹ type: List[Tuple2[Int, String]]; ArrowAssoc[Int](n); render[Int](n)(using intShow)
val total = nums.foldLeft(0)(_ + _) // ⟹ type: Int
val ratio: Double = nums.size // ⟹ int2double(nums.size)
val shownFive = 5.shown // ⟹ type: String; 5.shown(using intShow)
val firstTwo = // ⟹ type: Option[String]
for
a <- nums.headOption
b <- sorted.headOption
yield render(a) + render(b) // ⟹ render[Int](a)(using intShow); render[Int](b)(using intShow)
+
+// symbols:
+// List → scala.collection.immutable.List
+// Show → com.github.mercurievv.scalasemantic.docexamples.Show
The source exactly as written.
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)
object Instances:
given doubleShow: Show[Double] with
def show(a: Double) = a.toString
given floatShow: Show[Float] with
def show(a: Float) = a.toString
// wildcard `given` import: the givens enter scope with NO written name at the summon site — only
// the symbols legend can say which given `render(3.14)` picked, and format=compilable explodes this
// line to the explicit `import Instances.{doubleShow, floatShow}` of just the givens actually used
import Instances.given
val nums = List(1, 2, 3)
val pi = render(3.14)
val flo = render(1.0f)
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)
Replaces: reading the source and hand-tracing every implicit/inferred insertion → one compiler-visible view where green marks exactly what the compiler added.
method_signature
What it tells you: 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().
{
"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.
type_at_position
What it tells you: type of code at a source location.
The source writes no type annotation on ranked; the compiler inferred List[(String, Int)]. type_at_position returns exactly that — no hand-inference.
Request: type_at_position
Arguments:
uri:docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Enrich.scalaline:47character:4
{
"symbol": "com/github/mercurievv/scalasemantic/docexamples/Enrich$package.ranked.",
"name": "ranked",
"type": "List[Tuple2[String, Int]]"
}
Replaces: Hand type inference → compiler's answer.
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 evidence$1: Show[A]): String
+def render[A](a: A)(implicit sh: Show[A], prefix: String): String
Replaces: Recompiling just to ask a question about half-finished code.