forked from detekt/detekt
/
Location.kt
127 lines (115 loc) · 4.47 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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 {
var endSource: SourceLocation = source
private set
@Suppress("DEPRECATION")
constructor(
source: SourceLocation,
text: TextLocation,
filePath: FilePath
) : this(source, text, filePath.absolutePath.toString(), filePath)
@Suppress("DEPRECATION")
constructor(
source: SourceLocation,
endSource: SourceLocation,
text: TextLocation,
filePath: FilePath,
) : this(source, text, filePath.absolutePath.toString(), filePath) {
this.endSource = endSource
}
@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 end = endLineAndColumn(element, offset)
val endSourceLocation = SourceLocation(end.line, end.column)
val textLocation = TextLocation(element.startOffset + offset, element.endOffset + offset)
return Location(sourceLocation, endSourceLocation, textLocation, element.containingFile.toFilePath())
}
/**
* Determines the start line and column of a [PsiElement] in the source file.
*/
fun startLineAndColumn(element: PsiElement, offset: Int = 0): PsiDiagnosticUtils.LineAndColumn =
lineAndColumn(
element,
TextRange(element.textRange.startOffset + offset, element.textRange.endOffset + offset)
)
/**
* Determines the end line and column of a [PsiElement] in the source file.
*/
private fun endLineAndColumn(element: PsiElement, offset: Int = 0): PsiDiagnosticUtils.LineAndColumn =
lineAndColumn(
element,
TextRange(element.textRange.endOffset + offset, element.textRange.endOffset + offset)
)
private fun lineAndColumn(element: PsiElement, range: TextRange): PsiDiagnosticUtils.LineAndColumn {
return try {
DiagnosticUtils.getLineAndColumnInPsiFile(element.containingFile, range)
} 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"
}