create compact constructor light parameter list, make parameter list optional

GitOrigin-RevId: a8f67df9897d8adfece17d6d376c40776f25476d
This commit is contained in:
Roman.Ivanov
2019-12-24 08:41:04 +00:00
committed by intellij-monorepo-bot
parent 338430777b
commit 158abe45b8
10 changed files with 109 additions and 16 deletions
@@ -51,7 +51,7 @@ public class JavaPsiRecordUtil {
* regardless whether it's declared in the record or not
*/
public static boolean isCompactConstructor(@NotNull PsiMethod method) {
return method.isConstructor() && method.getParameterList().textMatches("");
return method.isConstructor() && method.getParameterList().getText() == null;
}
/**
@@ -342,7 +342,6 @@ public class DeclarationParser {
return parseMethodFromLeftParenth(builder, declaration, false, true);
}
else if (builder.getTokenType() == JavaTokenType.LBRACE) { // compact constructor
emptyElement(builder, JavaElementType.PARAMETER_LIST);
emptyElement(builder, JavaElementType.THROWS_LIST);
return parseMethodBody(builder, declaration, false);
}
@@ -0,0 +1,36 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.light;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiRecordComponent;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
public class LightCompactConstructorParameter extends LightParameter implements LightRecordMember {
private final @NotNull PsiRecordComponent myRecordComponent;
public LightCompactConstructorParameter(@NotNull String name,
@NotNull PsiType type,
@NotNull PsiElement declarationScope,
@NotNull PsiRecordComponent component) {
super(name, type, declarationScope);
myRecordComponent = component;
}
@Override
@NotNull
public PsiRecordComponent getRecordComponent() {
return myRecordComponent;
}
@Override
public int getTextOffset() {
return myRecordComponent.getTextOffset();
}
@NotNull
@Override
public PsiElement getNavigationElement() {
return myRecordComponent.getNavigationElement();
}
}
@@ -14,6 +14,8 @@ import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiMethodStub;
import com.intellij.psi.impl.light.LightCompactConstructorParameter;
import com.intellij.psi.impl.light.LightParameterListBuilder;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.JavaSharedImplUtil;
@@ -207,7 +209,24 @@ public class PsiMethodImpl extends JavaStubPsiElement<PsiMethodStub> implements
@Override
@NotNull
public PsiParameterList getParameterList() {
return getRequiredStubOrPsiChild(JavaStubElementTypes.PARAMETER_LIST);
PsiParameterList list = getStubOrPsiChild(JavaStubElementTypes.PARAMETER_LIST);
if (list == null) {
return CachedValuesManager.getCachedValue(this, () -> {
final LightParameterListBuilder lightList = new LightParameterListBuilder(this.getManager(), this.getLanguage());
PsiClass aClass = this.getContainingClass();
if (aClass != null) {
PsiRecordComponent[] recordComponents = aClass.getRecordComponents();
for (PsiRecordComponent component : recordComponents) {
String name = component.getName();
if (name == null) continue;
lightList.addParameter(new LightCompactConstructorParameter(name, component.getType(), this, component));
}
}
return CachedValueProvider.Result.create(lightList, this, PsiModificationTracker.MODIFICATION_COUNT);
});
}
return list;
}
@Override
@@ -36,16 +36,15 @@ record NotInitialized(int x,
}
}
record TwoCompacts(int x, int y) {
<error descr="'TwoCompacts()' is already defined in 'TwoCompacts'">public TwoCompacts </error>{}
<error descr="'TwoCompacts()' is already defined in 'TwoCompacts'">public TwoCompacts </error>{}
<error descr="'TwoCompacts(int, int)' is already defined in 'TwoCompacts'">public TwoCompacts</error> {}
<error descr="'TwoCompacts(int, int)' is already defined in 'TwoCompacts'">public TwoCompacts</error> {}
}
record CompactAndCanonical(int x, int y) {
// TODO
public CompactAndCanonical(int x, int y) {
<error descr="'CompactAndCanonical(int, int)' is already defined in 'CompactAndCanonical'">public CompactAndCanonical(int x, int y)</error> {
this.x = x;
this.y = y;
}
public CompactAndCanonical {
<error descr="'CompactAndCanonical(int, int)' is already defined in 'CompactAndCanonical'">public CompactAndCanonical</error> {
}
}
@@ -0,0 +1,5 @@
record A(int value) {
A {
<caret>value
}
}
@@ -0,0 +1,7 @@
package pack;
record MyRecord (String s) {
MyRecord {
String x = s();
}
}
@@ -3,12 +3,10 @@ package com.intellij.java.codeInsight.folding
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import org.junit.Ignore
class JavaFolding14Test : JavaFoldingTestCase() {
override fun getProjectDescriptor(): LightProjectDescriptor = LightJavaCodeInsightFixtureTestCase.JAVA_14
@Ignore
fun testRecord() {
val text = """
class B {}
@@ -28,9 +26,7 @@ class JavaFolding14Test : JavaFoldingTestCase() {
assertEquals("""
FoldRegion -(20:44), placeholder='(...)'
FoldRegion -(45:81), placeholder='{...}'
FoldRegion +(51:57), placeholder=' { '
FoldRegion -(51:65), placeholder='{...}'
FoldRegion +(61:65), placeholder=' }'
""".trimIndent(), regions.joinToString("\n"))
}
}
@@ -1,6 +1,7 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.psi.resolve;
import com.intellij.lang.jvm.JvmParameter;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightRecordMethod;
import com.intellij.testFramework.LightProjectDescriptor;
@@ -46,11 +47,32 @@ public class ResolveRecordMethodsTest extends LightResolveTestCase {
PsiJavaFile file = (PsiJavaFile)getFile();
PsiClass record = file.getClasses()[0];
assertNavigatesToFirstRecordComponent(record, target);
assertTrue(targetField.hasAnnotation("F"));
assertFalse(targetField.hasAnnotation("M"));
}
public void testCompactConstructor() {
PsiElement target = resolve();
assertTrue(target instanceof PsiParameter);
PsiParameter parameter = (PsiParameter)target;
assertEquals(PsiType.INT, parameter.getType());
PsiJavaFile file = (PsiJavaFile)getFile();
PsiClass record = file.getClasses()[0];
assertNavigatesToFirstRecordComponent(record, target);
PsiMethod[] constructors = record.getConstructors();
assertEquals(1, constructors.length);
JvmParameter[] parameters = constructors[0].getParameters();
assertEquals(1, parameters.length);
assertEquals(parameters[0], parameter);
}
private static void assertNavigatesToFirstRecordComponent(PsiClass record, PsiElement target) {
PsiRecordComponent[] components = record.getRecordComponents();
assertSize(1, components);
assertEquals(target.getTextOffset(), components[0].getTextOffset());
assertTrue(targetField.hasAnnotation("F"));
assertFalse(targetField.hasAnnotation("M"));
}
public void testExistingMethod() {
@@ -44,12 +44,22 @@ class FindUsagesJava14Test : JavaPsiTestCase() {
""".trimIndent())
}
private fun testReferences(elementToSearch: PsiElement, expectedText: String) {
fun testCompactConstructor() {
val record = myJavaFacade.findClass("pack.MyRecord", GlobalSearchScope.moduleScope(myModule))!!
TestCase.assertTrue(record.isRecord)
testReferences(record.recordComponents[0], """
5 String x = s();
^
""".trimIndent())
}
private fun testReferences(elementToSearch: PsiElement, expectedText: String): Array<out PsiElement> {
val elements = ReferencesSearch.search(elementToSearch, GlobalSearchScope.moduleScope(myModule), false)
.mapping { reference: PsiReference -> reference.element }
.toArray(PsiElement.EMPTY_ARRAY)
.toArray(PsiElement.EMPTY_ARRAY);
val actualText = elements.sortedBy { it.textRange.startOffset }.joinToString("\n\n") { createSnippet(it) }
assertEquals(expectedText, actualText)
return elements
}
private fun createSnippet(element: PsiElement) : String {