forked from detekt/detekt
/
Location.kt
102 lines (93 loc) · 3.49 KB
/
Location.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package io.gitlab.arturbosch.detekt.api
import io.github.detekt.psi.FilePath
import io.github.detekt.psi.toFilePath
import org.jetbrains.kotlin.com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import java.nio.file.Paths
/**
* Specifies a position within a source code fragment.
*/
data class Location
@Deprecated("Consider relative path by passing a [FilePath]")
@JvmOverloads
constructor(
val source: SourceLocation,
val text: TextLocation,
@Deprecated(
"Use filePath instead",
ReplaceWith(
"filePath.absolutePath.toString()"
)
)
val file: String,
val filePath: FilePath = FilePath.fromAbsolute(Paths.get(file))
) : Compactable {
@Suppress("DEPRECATION")
constructor(
source: SourceLocation,
text: TextLocation,
filePath: FilePath
) : this(source, text, filePath.absolutePath.toString(), filePath)
@Suppress("DEPRECATION")
@Deprecated(
"""
locationString was removed and won't get passed to the main constructor.
Use queries on 'ktElement' instead.
""",
ReplaceWith(
"Location(source, text, file)",
"io.gitlab.arturbosch.detekt.api.Location"
)
)
constructor(
source: SourceLocation,
text: TextLocation,
@Suppress("UNUSED_PARAMETER") locationString: String,
file: String
) : this(source, text, file)
override fun compact(): String = "${filePath.absolutePath}:$source"
companion object {
/**
* Creates a [Location] from a [PsiElement].
* If the element can't be determined, the [KtFile] with a character offset can be used.
*/
fun from(element: PsiElement, offset: Int = 0): Location {
val start = startLineAndColumn(element, offset)
val sourceLocation = SourceLocation(start.line, start.column)
val textLocation = TextLocation(element.startOffset + offset, element.endOffset + offset)
return Location(sourceLocation, textLocation, element.containingFile.toFilePath())
}
/**
* Determines the line and column of a [PsiElement] in the source file.
*/
fun startLineAndColumn(element: PsiElement, offset: Int = 0): PsiDiagnosticUtils.LineAndColumn {
return try {
val range = element.textRange
DiagnosticUtils.getLineAndColumnInPsiFile(
element.containingFile,
TextRange(range.startOffset + offset, range.endOffset + offset)
)
} catch (@Suppress("SwallowedException", "TooGenericExceptionCaught") e: IndexOutOfBoundsException) {
// #3317 If any rule mutates the PsiElement, searching the original PsiElement may throw exception.
PsiDiagnosticUtils.LineAndColumn(-1, -1, null)
}
}
}
}
/**
* Stores line and column information of a location.
*/
data class SourceLocation(val line: Int, val column: Int) {
override fun toString(): String = "$line:$column"
}
/**
* Stores character start and end positions of a text file.
*/
data class TextLocation(val start: Int, val end: Int) {
override fun toString(): String = "$start:$end"
}