[Java. Logging] Improve completion for logger

IDEA-359199

GitOrigin-RevId: a3162b75c3fa4ed32b3b17bcbf0753cf01fe72db
This commit is contained in:
Georgii Ustinov
2024-09-14 11:16:22 +03:00
committed by intellij-monorepo-bot
parent e0ec1044aa
commit f7ff124bf1
26 changed files with 308 additions and 24 deletions

View File

@@ -5,22 +5,34 @@ import com.intellij.lang.logging.JvmLogger
import com.intellij.openapi.module.ModuleUtil
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.patterns.StandardPatterns
import com.intellij.psi.JavaTokenType
import com.intellij.psi.PsiExpressionStatement
import com.intellij.psi.PsiJavaToken
import com.intellij.psi.*
import com.intellij.util.ProcessingContext
class JvmLoggerCompletionContributor : CompletionContributor() {
init {
extend(CompletionType.BASIC,
StandardPatterns.or(
psiElement()
.withSuperParent(2, PsiExpressionStatement::class.java)
.afterLeaf(StandardPatterns.or(
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.SEMICOLON),
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.COLON),
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.LBRACE),
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.RBRACE),
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.ARROW),
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.RPARENTH).and(
StandardPatterns.or(
psiElement().withParent(PsiIfStatement::class.java),
psiElement().withParent(PsiForStatement::class.java),
psiElement().withParent(PsiForeachStatement::class.java),
psiElement().withParent(PsiWhileStatement::class.java)
)
)
)),
psiElement().withSuperParent(2, PsiLambdaExpression::class.java).afterLeaf(
psiElement(PsiJavaToken::class.java).withElementType(JavaTokenType.ARROW)
)
),
object : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
val javaResultWithSorting = JavaCompletionSorting.addJavaSorting(parameters, result)

View File

@@ -0,0 +1,6 @@
public class A {
public void f() {
f() lo<caret>;
}
}

View File

@@ -0,0 +1,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
log<caret>
}
}

View File

@@ -0,0 +1,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
if (true) {}
log<caret>
}
}

View File

@@ -0,0 +1,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
int x = 10;
log<caret>
}
}

View File

@@ -0,0 +1,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
Consumer<String> s = (param) -> log<caret>
}
}

View File

@@ -0,0 +1,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
int a[] = new int[10];
for (int b : a) log<caret>
}
}

View File

@@ -0,0 +1,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
for (int i = 0; i < 1; ++i) log<caret>
}
}

View File

@@ -0,0 +1,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
if (true) log<caret>
}
}

View File

@@ -0,0 +1,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
while (true) log<caret>
}
}

View File

@@ -0,0 +1,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
public static void main(String[] args) {
String x = "";
String s = switch(x) {
case "name" -> log<caret>
default -> "String";
};
}
}

View File

@@ -0,0 +1,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class A {
private static final Logger log = LoggerFactory.getLogger(A.class);
void foo() {
String x = "";
switch (x) {
case "name": log<caret>
default: throw new Throwable()
}
}
}

View File

@@ -0,0 +1,5 @@
public class A {
void foo() {
lo<caret>
}
}

View File

@@ -0,0 +1,6 @@
public class A {
void foo() {
if (true) {}
lo<caret>
}
}

View File

@@ -0,0 +1,6 @@
public class A {
void foo() {
int x = 10;
lo<caret>
}
}

View File

@@ -0,0 +1,5 @@
public class A {
void foo() {
Consumer<String> s = (param) -> lo<caret>
}
}

View File

@@ -0,0 +1,6 @@
public class A {
void foo() {
int a[] = new int[10];
for (int b : a) lo<caret>
}
}

View File

@@ -0,0 +1,5 @@
public class A {
void foo() {
for (int i = 0; i < 1; ++i) lo<caret>
}
}

View File

@@ -0,0 +1,5 @@
public class A {
void foo() {
if (true) lo<caret>
}
}

View File

@@ -0,0 +1,5 @@
public class A {
void foo() {
while (true) lo<caret>
}
}

View File

@@ -0,0 +1,9 @@
public class A {
public static void main(String[] args) {
String x = "";
String s = switch(x) {
case "name" -> lo<caret>
default -> "String";
};
}
}

View File

@@ -0,0 +1,9 @@
public class A {
void foo() {
String x = "";
switch (x) {
case "name": lo<caret>
default: throw new Throwable()
}
}
}

View File

@@ -1,6 +1,6 @@
public class A {
void foo() {
Na<caret>
Nam<caret>
}
}

View File

@@ -0,0 +1,6 @@
public class A {
public void f() {
int x = 10 + lo<caret>;
}
}

View File

@@ -0,0 +1,4 @@
public class A {
lo<caret>
}

View File

@@ -7,79 +7,84 @@ import com.intellij.codeInsight.completion.JvmLoggerLookupElement
import com.intellij.codeInsight.completion.LightFixtureCompletionTestCase
import com.intellij.java.codeInsight.JvmLoggerTestSetupUtil
import com.intellij.openapi.components.service
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.NeedsIndex
import com.intellij.ui.logging.JvmLoggingSettingsStorage
import junit.framework.TestCase
private const val SMART_MODE_REASON_MESSAGE = "Logger completion is not supported in the dumb mode"
class LoggerCompletionTest : LightFixtureCompletionTestCase() {
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_17
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testSlf4j() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLog4j2() {
JvmLoggerTestSetupUtil.setupLog4j2(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLog4j() {
JvmLoggerTestSetupUtil.setupLog4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testApacheCommons() {
JvmLoggerTestSetupUtil.setupApacheCommons(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testNestedClasses() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testMultipleLoggers() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
JvmLoggerTestSetupUtil.setupLog4j2(myFixture)
doTest(2, "long", "log", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLoggerAlreadyExistsSimple() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest()
doAntiTest("log", "long", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLoggerAlreadyExistsInheritance() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest()
doAntiTest("log", "long", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLoggerAlreadyExistsNestedClasses() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest()
doAntiTest("log", "long", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testLoggerAlreadyExistsNestedClassesWithInheritance() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest()
doAntiTest("log", "long", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testStaticQualifierWithLocalVariable() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(2, "log", "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionAfterDot() {
var isAutoComplete = true
try {
@@ -97,7 +102,7 @@ class LoggerCompletionTest : LightFixtureCompletionTestCase() {
}
}
@NeedsIndex.SmartMode(reason = "Logger completion is not supported in the dumb mode")
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testRespectCustomLoggerName() {
val state = project.service<JvmLoggingSettingsStorage>().state
val oldLoggerName = state.loggerName
@@ -105,19 +110,98 @@ class LoggerCompletionTest : LightFixtureCompletionTestCase() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
val newName = "NameLogger"
state.loggerName = newName
doTest(0, newName, "NavigableMap", "NegativeArraySizeException", "NoSuchAlgorithmException", "Runnable")
doTest(0, newName, "Name", "NamedParameterSpec", "NavigableMap")
}
finally {
state.loggerName = oldLoggerName
}
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testNoAutoCompletionInClassBody() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest("long", "protected Object clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testNoAutoCompletionAfterMethodInvocation() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest()
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testNoAutoCompletionInBinaryExpression() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doAntiTest("long", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionAfterSemicolon() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSwitchStatement() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSwitchExpression() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionAfterLBrace() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionAfterRBrace() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSingleIfStatement() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSingleWhileStatement() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSingleForStatement() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInSingleForEachStatement() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
@NeedsIndex.SmartMode(reason = SMART_MODE_REASON_MESSAGE)
fun testAutoCompletionInLambdaExpression() {
JvmLoggerTestSetupUtil.setupSlf4j(myFixture)
doTest(1, "long", "log", "clone")
}
override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/completion/logger"
override fun doAntiTest() {
private fun doAntiTest(vararg names: String) {
val name = getTestName(true)
configureByFile("$name.java")
assertStringItems("log", "long", "clone")
assertStringItems(*names)
TestCase.assertFalse(
lookup.items.any {
it is JvmLoggerLookupElement