Skip to main content

Tool Examples — Real Output, Self-Verifying

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

Quick reference

ToolWhat it tells you
Find & resolve symbols
find_symbolResolve a name to its definition
symbol_sourceSource of ONE symbol's definition, enriched
source_around_positionSource of the definition enclosing a position
References & call graph
find_usagesAll references to a symbol (optional contextLines for surrounding source)
call_pathWhether method A reaches method B
method_call_hierarchyAll callers or callees
value_flowTrace a value through the call graph
Hierarchy & members
class_hierarchySupertypes and subtypes
find_overloadsAll overloads of a method
membersDeclared and inherited members
Search & analysis
search_textScoped text/regex search over .scala files (string literals/comments)
structureDependency graph and cycles
smart_code_duplicationsStructurally identical blocks
document_outlineFile structure with compiler-rendered names
Implicits
resolve_implicitsWhich givens/implicits apply
trace_implicit_chainPath of implicit dependencies
Edit plans
rename_planEdit ranges for a safe rename
batch_rename_planEdit ranges for multiple renames, reporting range conflicts
move_planMove a symbol to a new package
extract_method_planExtract a code range into a method
Compiler view
annotated_sourceCompiler view — inferred types, implicits, exploded imports, diff (tabbed)
method_signatureFull signature with implicit/using params
type_at_positionType 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.scala
  • line: 27
  • column: 40
  • format: 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.scala
  • line: 19
  • column: 13
{
  "root": {
    "symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
    "name": "input",
    "type": "String",
    "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:19:13",
    "depth": 0,
    "enclosingMethod": "pipeline",
    "kind": "PARAMETER"
  },
  "nodes": [
    {
      "symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
      "name": "input",
      "type": "String",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:19:13",
      "depth": 0,
      "enclosingMethod": "pipeline",
      "kind": "PARAMETER"
    },
    {
      "symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
      "name": "input",
      "type": "String",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:16:42",
      "depth": 1,
      "enclosingMethod": "compose",
      "kind": "PARAMETER"
    },
    {
      "symbol": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
      "name": "input",
      "type": "String",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:13:28",
      "depth": 2,
      "enclosingMethod": "transform",
      "kind": "PARAMETER"
    },
    {
      "symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
      "name": "x",
      "type": "String",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:3:14",
      "depth": 3,
      "enclosingMethod": "process",
      "kind": "PARAMETER"
    }
  ],
  "edges": [
    {
      "from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.pipeline().(input)",
      "to": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
      "relation": "passed_as_arg",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:22:22",
      "paramName": "input",
      "coParameters": [
        "p1",
        "p2"
      ]
    },
    {
      "from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.compose().(input)",
      "to": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
      "relation": "passed_as_arg",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:17:30",
      "paramName": "input",
      "coParameters": [
        "p"
      ]
    },
    {
      "from": "com/github/mercurievv/scalasemantic/docexamples/Navigate$package.transform().(input)",
      "to": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
      "relation": "passed_as_arg",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:14:12",
      "paramName": "x"
    }
  ],
  "stoppedAt": [
    {
      "symbol": "com/github/mercurievv/scalasemantic/docexamples/Processor#process().(x)",
      "classification": "discarded",
      "at": "docExamples/src/main/scala/com/github/mercurievv/scalasemantic/docexamples/Navigate.scala:3:14"
    }
  ]
}

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


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 bound
  • pathFilter: *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; 0 means 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), from 0 to 1; 0 is stable/foundation-like, 1 is leaf/consumer-like.
  • centrality: PageRank-style importance; higher values mean the symbol is more structurally central because important symbols depend on it.
  • dependencies weight: number of semantic dependency observations collapsed into one symbol-to-symbol edge; thicker graph edges mean higher weight.
  • moduleEdges weight: number of symbol-level dependency edges crossing from one module to another.

Request: structure

Arguments:

  • limit: 20
analysis16 shown | I 0.20mcp3 shown | I 0.51core1 shown | I 0.00call, typetypetypetypetypecall, typecall, typetypecalltypetypeLocationCa 14 | Ce 1 | 0.023SymbolRefCa 13 | Ce 1 | 0.017AnalyzerCa 7 | Ce 36 | 0.005ToolCa 7 | Ce 0 | 0.005SymbolKindCa 7 | Ce 0 | 0.023McpToolsSupportCa 6 | Ce 18 | 0.005SemanticIndexCa 6 | Ce 0 | 0.006NonEmptyStringCa 4 | Ce 0 | 0.012SemanticDbSymbolCa 4 | Ce 1 | 0.006RangeCa 4 | Ce 1 | 0.027GraphCa 3 | Ce 0 | 0.004DimensionMetricsCa 3 | Ce 0 | 0.004MemberInfoCa 3 | Ce 2 | 0.004ModuleEdgeCa 3 | Ce 0 | 0.003SourceAnnotationCa 3 | Ce 0 | 0.002AnalyzerHelpersCa 2 | Ce 9 | 0.003PureKernelsCa 2 | Ce 0 | 0.003McpToolsCa 2 | Ce 7 | 0.003DuplicationsResultCa 2 | Ce 1 | 0.003ImplicitCandidateCa 2 | Ce 1 | 0.004
Colored areas are modules; modules with higher aggregate centrality are placed closer to the center.Redder backgrounds mean higher instability for both modules and classes.Classes with higher centrality sit closer to the center of their module area.Arrows point from a dependent type to the type it depends on.
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
    • showMETHODdef show(a: A): String
  • ShowOBJECT
    • applyMETHODdef apply[A](implicit s: Show[A]): Show[A]
    • intShowOBJECT
      • showMETHODdef show(a: Int): String
    • stringShowOBJECT
      • showMETHODdef show(a: String): String
    • listShowMETHODdef listShow[A](implicit evidence$1: Show[A]): listShow[A]
  • evidence$1METHOD: Show[A]
  • showMETHODdef show(a: List[A]): String
  • renderMETHODdef render[A](a: A)(implicit evidence$1: Show[A]): String
  • shownMETHODdef shown(n: Int)(implicit x$2: Show[Int]): String
  • InstancesOBJECT
    • doubleShowOBJECT
      • showMETHODdef show(a: Double): String
    • floatShowOBJECT
      • showMETHODdef 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.scala
  • startLine: 5
  • startCharacter: 20
  • endLine: 8
  • endCharacter: 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 given imports 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.scala
  • annotationsOnly: false

Compiler insertions as a patch.

compilableformat = diff

--- 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)
 

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)+}
 "
}

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.scala
  • line: 47
  • character: 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.