Skip to content

Commit

Permalink
fix: getTypeDeclaration() on nested record type
Browse files Browse the repository at this point in the history
Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
Co-authored-by: Martin Wittlinger <wittlinger.martin@gmail.com>
  • Loading branch information
3 people committed Nov 17, 2022
1 parent 53eb011 commit 42ae027
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 33 deletions.
70 changes: 37 additions & 33 deletions src/main/java/spoon/support/reflect/declaration/CtTypeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,20 @@
import spoon.reflect.code.CtBlock;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtAnnotationType;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtCompilationUnit;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtEnum;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtFormalTypeDeclarer;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtModifiable;
import spoon.reflect.declaration.CtNamedElement;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtRecord;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypeMember;
Expand Down Expand Up @@ -347,7 +352,7 @@ public <T> CtType<T> getTopLevelType() {
public <N extends CtType<?>> N getNestedType(final String name) {
class NestedTypeScanner extends EarlyTerminatingScanner<CtType<?>> {

private boolean checkType(CtType<?> type) {
private boolean typeIsTarget(CtType<?> type) {
if (type.getSimpleName().equals(name) && CtTypeImpl.this.equals(type.getDeclaringType())) {
setResult(type);
terminate();
Expand All @@ -357,49 +362,48 @@ private boolean checkType(CtType<?> type) {
}

@Override
public <U> void visitCtClass(spoon.reflect.declaration.CtClass<U> ctClass) {
if (!checkType(ctClass)) {
final List<CtTypeMember> typeMembers = new ArrayList<>();
for (CtTypeMember typeMember : ctClass.getTypeMembers()) {
if (typeMember instanceof CtType || typeMember instanceof CtConstructor || typeMember instanceof CtMethod) {
typeMembers.add(typeMember);
}
}
scan(typeMembers);
}
public <U> void visitCtClass(CtClass<U> ctClass) {
visitType(ctClass);
}

@Override
public <U> void visitCtInterface(spoon.reflect.declaration.CtInterface<U> intrface) {
if (!checkType(intrface)) {
final List<CtTypeMember> typeMembers = new ArrayList<>();
for (CtTypeMember typeMember : intrface.getTypeMembers()) {
if (typeMember instanceof CtType || typeMember instanceof CtMethod) {
typeMembers.add(typeMember);
}
}
scan(typeMembers);
}
public <U> void visitCtInterface(CtInterface<U> intrface) {
visitType(intrface);
}

@Override
public <U extends java.lang.Enum<?>> void visitCtEnum(spoon.reflect.declaration.CtEnum<U> ctEnum) {
if (!checkType(ctEnum)) {
final List<CtTypeMember> typeMembers = new ArrayList<>();
for (CtTypeMember typeMember : ctEnum.getTypeMembers()) {
if (typeMember instanceof CtType || typeMember instanceof CtConstructor || typeMember instanceof CtMethod) {
typeMembers.add(typeMember);
}
}
scan(typeMembers);
}
public <U extends Enum<?>> void visitCtEnum(CtEnum<U> ctEnum) {
visitType(ctEnum);
}

@Override
public <A extends Annotation> void visitCtAnnotationType(CtAnnotationType<A> annotationType) {
if (!checkType(annotationType)) {
scan(annotationType.getNestedTypes());
visitType(annotationType);
}

@Override
public void visitCtRecord(CtRecord recordType) {
visitType(recordType);
}

@Override
protected void enter(CtElement e) {
if (e instanceof CtType) {
throw new SpoonException("Unknown type, extend scanner: " + e.getClass());
}
}

private void visitType(CtType<?> type) {
if (typeIsTarget(type)) {
return;
}
final List<CtTypeMember> typeMembers = new ArrayList<>();
for (CtTypeMember typeMember : type.getTypeMembers()) {
if (typeMember instanceof CtType || typeMember instanceof CtConstructor || typeMember instanceof CtMethod) {
typeMembers.add(typeMember);
}
}
scan(typeMembers);
}
}
NestedTypeScanner scanner = new NestedTypeScanner();
Expand Down
23 changes: 23 additions & 0 deletions src/test/java/spoon/test/ctType/CtTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.filter.NamedElementFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.compiler.VirtualFile;
import spoon.test.ctType.testclasses.X;
import spoon.testing.utils.ModelTest;

Expand Down Expand Up @@ -305,4 +306,26 @@ public void testEnumPackage() {
assertThat(types.stream().findFirst().get(), notNullValue());
assertThat(types.stream().findFirst().get().getQualifiedName(), is("keywordCompliance.enum.Foo"));
}

@Test
void testRecordInnerClassesHaveDefinition() {
// contract: Record inner classes should have a definition
Launcher launcher = new Launcher();
launcher.addInputResource(new VirtualFile("class Foo {\n" +
" class Inner {\n" +
" record Inner2(String name) {\n" +
" }\n" +
" }\n" +
"}"));
launcher.getEnvironment().setComplianceLevel(17);
CtType<?> foo = launcher.buildModel().getAllTypes().iterator().next();
assertEquals(foo, foo.getReference().getTypeDeclaration());

for (CtType<?> nestedType : foo.getNestedTypes()) {
assertEquals(nestedType, nestedType.getReference().getTypeDeclaration());
for (CtType<?> type : nestedType.getNestedTypes()) {
assertEquals(type, type.getReference().getTypeDeclaration());
}
}
}
}

0 comments on commit 42ae027

Please sign in to comment.