skip to content

How do you attach a source location to a structured problem so an IDE can point the user at the exact file and line?

level: middleimportance: must knowfreq 30%

answer

  1. fileLocation(path)
  2. lineInFileLocation(path, line, col, length)
  3. offsetInFileLocation(path, offset, length)
  4. pluginLocation(pluginId)
  5. each call appends — multiple locations allowed

basics

~10 s

On the ProblemSpec you call location methods like spec.fileLocation(path) or spec.lineInFileLocation(path, line, column). These attach a typed location object so IDEs can render a clickable link to the offending file/line.

solid answer

~50 s

A structured problem can carry one or more **locations** describing where in the user's sources it originates. On the `ProblemSpec` you add them with builder calls such as `fileLocation(String path)` for a whole-file pointer, and `lineInFileLocation(String path, int line)` or the richer `lineInFileLocation(path, line, column, length)` to pinpoint a line (and optionally a column and span). There are also offset-based variants (`offsetInFileLocation(path, offset, length)`) and a `pluginLocation(pluginId)` to blame a plugin rather than a source file. Each call appends a location, so a single problem may have several. Consumers — especially IDEs via the Tooling API — turn these typed locations into clickable navigation, which is the whole point: you're handing the IDE structured coordinates instead of embedding `"at build.gradle.kts:12"` inside a log string it would have to parse. Paths are typically the absolute or project-relative path of the file being diagnosed.

code

kotlin · 6 lines
kotlin
reporter.report(problemId) { spec ->
    spec.severity(Severity.WARNING)
        .lineInFileLocation("settings.gradle.kts", 8, 1, 24)
        .pluginLocation("com.example.myplugin")
        .details("Repository declared without a name")
}

go deeper

for a junior

Know that fileLocation / lineInFileLocation exist to point at a file/line.

for a middle

List the line/column/length and offset variants and pluginLocation, and that calls append.

for a senior

Explain the IDE/Tooling-API navigation payoff and when to choose offset vs line vs plugin locations.

for a principal

Position typed locations as the contract that makes diagnostics machine-navigable across IDEs and CI dashboards, replacing brittle log parsing.

## Why locations exist The value of structured diagnostics is that a consumer can **navigate** to the cause. A plain `logger.warn("problem in build.gradle.kts line 12")` forces an IDE to regex the console. The Problems API instead lets you attach **typed location objects** to a problem, which the Tooling API delivers to IDEs (IntelliJ, Eclipse Buildship) and which the HTML problems report renders. ## The location builder methods on ProblemSpec Locations are added through `ProblemSpec` builder calls; each call **appends** another location (a problem can have many): - **`fileLocation(String path)`** — points at an entire file, no line. - **`lineInFileLocation(String path, int line)`** — file + 1-based line. - **`lineInFileLocation(String path, int line, int column)`** — adds a column. - **`lineInFileLocation(String path, int line, int column, int length)`** — adds a span length so the IDE can underline a range. - **`offsetInFileLocation(String path, int offset, int length)`** — character-offset based, for tools that think in offsets rather than line/column. - **`pluginLocation(String pluginId)`** — attributes the problem to a plugin instead of a user file (useful when there's no source line, e.g. a misconfiguration produced by a plugin). ```kotlin reporter.report(problemId) { spec -> spec.severity(Severity.WARNING) .lineInFileLocation("build.gradle.kts", 12, 5, 18) .details("Property 'foo' is deprecated") } ``` ## Choosing a location type - Use **`lineInFileLocation`** when you parsed a DSL/config file and know the exact line — best UX. - Use **`fileLocation`** when you can identify the file but not the line. - Use **`offsetInFileLocation`** when your tooling works in character offsets (parsers, language servers). - Use **`pluginLocation`** when the fault is conceptually "this plugin's behaviour" and there is no user source coordinate. ## Multiple locations Because each call appends, you can attach, say, both the offending `build.gradle.kts` line and a `pluginLocation` to say which plugin raised it. Consumers decide how to present several locations. ## Relationship to severity and solutions Location, severity, and solution are independent facets of the same `ProblemSpec`. A high-quality problem usually sets all three: *how serious* (severity), *where* (location), and *what to do* (solution/documentedAt). Together they make the diagnostic actionable in an IDE without the user reading the console.

  • Can a single problem carry more than one location?
    Yes — each location call appends, so you can attach, e.g., both a lineInFileLocation and a pluginLocation to the same problem.
  • When would you use pluginLocation instead of a file location?
    When the fault has no user-source coordinate — it's the plugin's own behaviour/misconfiguration — so you blame the plugin id rather than a line in a build script.
  • What does the extra 'length' argument on lineInFileLocation enable?
    It gives the span length so an IDE can underline/highlight a precise range rather than just placing a caret at the line:column.

saying these in an interview costs you the question

  • Embedding the location as text in details() instead of using the typed location methods — defeats IDE navigation.
  • Assuming only one location is allowed; multiple appended locations are supported.

context