Skip to content

Commit 39df293

Browse files
committed
wip: groovy logger detector
1 parent 0e0eeb1 commit 39df293

File tree

2 files changed

+99
-5
lines changed

2 files changed

+99
-5
lines changed

marker/jvm-marker/src/main/kotlin/spp/jetbrains/marker/jvm/psi/JVMLoggerDetector.kt

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ import com.intellij.openapi.project.Project
2222
import com.intellij.openapi.util.Computable
2323
import com.intellij.psi.PsiDocumentManager
2424
import com.intellij.psi.PsiElement
25+
import com.intellij.psi.PsiRecursiveElementVisitor
2526
import com.intellij.refactoring.suggested.endOffset
2627
import com.intellij.refactoring.suggested.startOffset
28+
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral
29+
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression
30+
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
2731
import org.jetbrains.uast.UCallExpression
2832
import org.jetbrains.uast.ULiteralExpression
2933
import org.jetbrains.uast.UMethod
@@ -58,11 +62,15 @@ class JVMLoggerDetector(val project: Project) : LoggerDetector {
5862
}
5963

6064
override fun determineLoggerStatements(guideMark: MethodGuideMark): List<DetectedLogger> {
61-
val uMethod = ApplicationManager.getApplication().runReadAction(Computable {
62-
guideMark.getPsiMethod().toUElementOfType<UMethod>()
63-
})
64-
if (uMethod != null) {
65-
determineLoggerStatements(uMethod, guideMark.sourceFileMarker)
65+
if (guideMark.language.id == "Groovy") {
66+
determineLoggerStatements(guideMark.getPsiMethod() as GrMethod, guideMark.sourceFileMarker)
67+
} else {
68+
val uMethod = ApplicationManager.getApplication().runReadAction(Computable {
69+
guideMark.getPsiMethod().toUElementOfType<UMethod>()
70+
})
71+
if (uMethod != null) {
72+
determineLoggerStatements(uMethod, guideMark.sourceFileMarker)
73+
}
6674
}
6775
return guideMark.getChildren().mapNotNull { it.getUserData(DETECTED_LOGGER) }
6876
}
@@ -111,6 +119,54 @@ class JVMLoggerDetector(val project: Project) : LoggerDetector {
111119
return loggerStatements
112120
}
113121

122+
/**
123+
* Unsure why, but Groovy UAST visitors don't work here. Have to use Groovy PSI.
124+
*/
125+
fun determineLoggerStatements(grMethod: GrMethod, fileMarker: SourceFileMarker): List<DetectedLogger> {
126+
val loggerStatements = mutableListOf<DetectedLogger>()
127+
ApplicationManager.getApplication().runReadAction {
128+
grMethod.acceptChildren(object : PsiRecursiveElementVisitor() {
129+
override fun visitElement(element: PsiElement) {
130+
if (element is GrMethodCallExpression) {
131+
val loggerClass = element.resolveMethod()?.containingClass?.qualifiedName
132+
if (loggerClass != null && LOGGER_CLASSES.contains(loggerClass)) {
133+
val methodName = element.resolveMethod()?.name
134+
if (methodName != null && LOGGER_METHODS.contains(methodName)) {
135+
val logTemplate = element.argumentList.expressionArguments.firstOrNull()?.run {
136+
(this as? GrLiteral)?.value as? String
137+
}
138+
139+
if (logTemplate != null) {
140+
log.debug("Found log statement: $logTemplate")
141+
val detectedLogger = DetectedLogger(
142+
logTemplate, methodName, getLineNumber(element) + 1
143+
)
144+
loggerStatements.add(detectedLogger)
145+
146+
//create expression guide mark for the log statement
147+
val guideMark = fileMarker.createExpressionSourceMark(
148+
element, SourceMark.Type.GUIDE
149+
)
150+
if (!fileMarker.containsSourceMark(guideMark)) {
151+
guideMark.putUserData(DETECTED_LOGGER, detectedLogger)
152+
guideMark.apply(true)
153+
} else {
154+
fileMarker.getSourceMark(guideMark.artifactQualifiedName, SourceMark.Type.GUIDE)
155+
?.putUserData(DETECTED_LOGGER, detectedLogger)
156+
}
157+
} else {
158+
log.warn("No log template argument available for expression: $element")
159+
}
160+
}
161+
}
162+
}
163+
super.visitElement(element)
164+
}
165+
})
166+
}
167+
return loggerStatements
168+
}
169+
114170
private fun getLineNumber(element: PsiElement, start: Boolean = true): Int {
115171
val document = element.containingFile.viewProvider.document
116172
?: PsiDocumentManager.getInstance(element.project).getDocument(element.containingFile)

marker/jvm-marker/src/test/kotlin/spp/jetbrains/marker/jvm/psi/JVMLoggerDetectorTest.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import io.vertx.core.Vertx
3333
import org.intellij.lang.annotations.Language
3434
import org.jetbrains.kotlin.idea.core.util.toPsiFile
3535
import org.jetbrains.kotlin.psi.KtFile
36+
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
37+
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
3638
import org.jetbrains.uast.UFile
3739
import org.jetbrains.uast.toUElement
3840
import spp.jetbrains.UserData
@@ -192,4 +194,40 @@ class JVMLoggerDetectorTest : LightJavaCodeInsightFixtureTestCase() {
192194
assertContainsOrdered(result, "trace {}", "debug {}", "info {}", "warn {}", "error {}")
193195
}
194196
}
197+
198+
fun testGroovyLogbackLogger() {
199+
@Language("Groovy") val code = """
200+
import ch.qos.logback.classic.Logger
201+
class TestLogback {
202+
var log = new Logger()
203+
void loggers() {
204+
log.trace("trace {}", "trace")
205+
log.debug("debug {}", "debug")
206+
log.info("info {}", "info")
207+
log.warn("warn {}", "warn")
208+
log.error("error {}", "error")
209+
}
210+
}
211+
""".trimIndent()
212+
213+
ApplicationManager.getApplication().runReadAction {
214+
val sourceFile = myFixture.createFile("TestLogback.groovy", code).toPsiFile(project)
215+
assertNotNull(sourceFile)
216+
217+
val uFile = sourceFile.toUElement() as UFile
218+
assertEquals(1, uFile.classes.size)
219+
assertEquals(1, uFile.classes[0].methods.size)
220+
221+
JVMMarker.setup()
222+
SourceFileMarker.SUPPORTED_FILE_TYPES.add(GroovyFile::class.java)
223+
val fileMarker = SourceMarker.getInstance(project).getSourceFileMarker(sourceFile!!)
224+
assertNotNull(fileMarker)
225+
226+
val result = JVMLoggerDetector(project.apply { UserData.vertx(this, Vertx.vertx()) })
227+
.determineLoggerStatements(uFile.classes[0].methods[0].sourcePsi as GrMethod, fileMarker!!)
228+
.map { it.logPattern }
229+
assertEquals(5, result.size)
230+
assertContainsOrdered(result, "trace {}", "debug {}", "info {}", "warn {}", "error {}")
231+
}
232+
}
195233
}

0 commit comments

Comments
 (0)