Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

review fix: Object[]::new references resolution #1945

Merged
merged 9 commits into from
Jun 15, 2018
5 changes: 5 additions & 0 deletions src/main/java/spoon/reflect/factory/CoreFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ public interface CoreFactory {
*/
<T> CtConstructor<T> createConstructor();

/**
* Creates an invisible array constructor.
*/
<T> CtConstructor<T> createInvisibleArrayConstructor();

/**
* Creates a <code>continue</code> statement.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/spoon/reflect/factory/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,11 @@ public interface Factory {
*/
<T> CtConstructor<T> createConstructor();

/**
* @see CoreFactory#createInvisibleArrayConstructor() ()
*/
<T> CtConstructor<T> createInvisibleArrayConstructor();

/**
* @see CoreFactory#createEnumValue()
*/
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/spoon/reflect/factory/FactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,11 @@ public <T> CtConstructor<T> createConstructor() {
return Core().createConstructor();
}

@Override
public <T> CtConstructor<T> createInvisibleArrayConstructor() {
return Core().createInvisibleArrayConstructor();
}

@Override
public <T> CtEnumValue<T> createEnumValue() {
return Core().createEnumValue();
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/spoon/support/DefaultCoreFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
import spoon.support.reflect.declaration.CtParameterImpl;
import spoon.support.reflect.declaration.CtTypeParameterImpl;
import spoon.support.reflect.declaration.CtUsedServiceImpl;
import spoon.support.reflect.declaration.InvisibleArrayConstructor;
import spoon.support.reflect.reference.CtArrayTypeReferenceImpl;
import spoon.support.reflect.reference.CtCatchVariableReferenceImpl;
import spoon.support.reflect.reference.CtExecutableReferenceImpl;
Expand Down Expand Up @@ -321,6 +322,12 @@ public <T> CtConstructor<T> createConstructor() {
return e;
}

public <T> CtConstructor<T> createInvisibleArrayConstructor() {
CtConstructor<T> e = new InvisibleArrayConstructor<>();
e.setFactory(getMainFactory());
return e;
}

public CtContinue createContinue() {
CtContinue e = new CtContinueImpl();
e.setFactory(getMainFactory());
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VoidTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
import spoon.reflect.code.CtLambda;
import spoon.reflect.declaration.CtModule;
Expand Down Expand Up @@ -369,7 +370,13 @@ <T> CtExecutableReference<T> getExecutableReference(MethodBinding exec) {
final CtExecutableReference ref = this.jdtTreeBuilder.getFactory().Core().createExecutableReference();
if (exec.isConstructor()) {
ref.setSimpleName(CtExecutableReference.CONSTRUCTOR_NAME);
ref.setType(getTypeReference(exec.declaringClass));

// in case of constructor of an array, it's the return type that we want
if (exec.returnType instanceof VoidTypeBinding) {
ref.setType(getTypeReference(exec.declaringClass));
} else {
ref.setType(getTypeReference(exec.returnType));
}
} else {
ref.setSimpleName(new String(exec.selector));
ref.setType(getTypeReference(exec.returnType));
Expand All @@ -389,7 +396,11 @@ <T> CtExecutableReference<T> getExecutableReference(MethodBinding exec) {
}
ref.setStatic(true);
} else {
ref.setDeclaringType(getTypeReference(exec.declaringClass));
if (exec.isConstructor() && !(exec.returnType instanceof VoidTypeBinding)) {
ref.setDeclaringType(getTypeReference(exec.returnType));
} else {
ref.setDeclaringType(getTypeReference(exec.declaringClass));
}
ref.setStatic(exec.isStatic());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.support.reflect.declaration;

/**
* This class is used to represent the constructor of an array when calling with an expression like
* <pre>
* String[]::new
* </pre>
*/
public class InvisibleArrayConstructor<T> extends CtConstructorImpl<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By convention, should end by Impl: InvisibleArrayConstructorImpl, and should be in spoon.support.reflect.declaration (all implementation classes are in spoon.support)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in spoon.support. I will rename it.


}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.path.CtRole;
import spoon.reflect.reference.CtActualTypeContainer;
import spoon.reflect.reference.CtArrayTypeReference;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtVisitor;
Expand Down Expand Up @@ -170,17 +171,27 @@ public CtExecutable<T> getExecutableDeclaration() {
if (declaringType == null) {
return null;
}

if (declaringType instanceof CtArrayTypeReference && this.isConstructor()) {
CtConstructor constructor = this.getFactory().createInvisibleArrayConstructor();
constructor.setType(declaringType);
return constructor;
}

return getCtExecutable(declaringType.getTypeDeclaration());
}

private CtExecutable<T> getCtExecutable(CtType<?> typeDecl) {
if (typeDecl == null) {
return null;
}
CtExecutable<T> method = typeDecl.getMethod(getSimpleName(), parameters.toArray(new CtTypeReferenceImpl<?>[parameters.size()]));
if ((method == null) && (typeDecl instanceof CtClass) && (getSimpleName().equals(CtExecutableReference.CONSTRUCTOR_NAME))) {
CtTypeReference<?>[] arrayParameters = parameters.toArray(new CtTypeReferenceImpl<?>[parameters.size()]);
CtExecutable<T> method = typeDecl.getMethod(getSimpleName(), arrayParameters);
if ((method == null) && (typeDecl instanceof CtClass) && this.isConstructor()) {
try {
return (CtExecutable<T>) ((CtClass<?>) typeDecl).getConstructor(parameters.toArray(new CtTypeReferenceImpl<?>[parameters.size()]));
CtClass<?> zeClass = (CtClass) typeDecl;
CtConstructor<?> constructor = zeClass.getConstructor(arrayParameters);
return (CtExecutable<T>) constructor;
} catch (ClassCastException e) {
Launcher.LOGGER.error(e.getMessage(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import spoon.reflect.visitor.filter.TypeFilter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -181,7 +182,7 @@ public boolean matches(CtConstructorCall element) {
@Test
public void metamodelPackageRule() throws Exception {
// all implementations of the metamodel classes have a corresponding interface in the appropriate package
List<String> exceptions = Collections.singletonList("CtWildcardStaticTypeMemberReferenceImpl");
List<String> exceptions = Arrays.asList("CtWildcardStaticTypeMemberReferenceImpl", "InvisibleArrayConstructor");

SpoonAPI implementations = new Launcher();
implementations.addInputResource("src/main/java/spoon/support/reflect/declaration");
Expand Down
22 changes: 22 additions & 0 deletions src/test/java/spoon/test/reference/ExecutableReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.ReferenceTypeFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.reference.testclasses.Bar;
import spoon.test.reference.testclasses.Burritos;
import spoon.test.reference.testclasses.EnumValue;
import spoon.test.reference.testclasses.Kuu;
import spoon.test.reference.testclasses.Stream;
import spoon.test.reference.testclasses.SuperFoo;

import java.util.List;
Expand All @@ -24,6 +26,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class ExecutableReferenceTest {
Expand Down Expand Up @@ -204,4 +207,23 @@ public void testHashcodeWorksWithReference() {

assertNotEquals(hashCode1, hashCode2);
}

@Test
public void testPbWithStream() {
// contract: array constructor references are well represented
Copy link
Collaborator

@monperrus monperrus Jun 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add assert on type of element (instanceof InvisibleArrayConstructorImpl)?
add assert on toString of element?


final Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/java/spoon/test/reference/testclasses/Stream.java");
launcher.buildModel();

CtClass klass = launcher.getFactory().Class().get(Stream.class);
List<CtExecutableReference> executableReferenceList = klass.getElements(new TypeFilter<>(CtExecutableReference.class));

for (CtExecutableReference execRef : executableReferenceList) {
String refString = execRef.toString();
CtExecutable executable = execRef.getExecutableDeclaration();
assertNotNull(refString, executable);
}
}

}
9 changes: 9 additions & 0 deletions src/test/java/spoon/test/reference/testclasses/Stream.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package spoon.test.reference.testclasses;

import java.util.ArrayList;

public class Stream {
public Stream() {
new ArrayList().stream().toArray(Bar[]::new);
}
}