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 refactor: getBoundingType now returns Object by default #1672

Merged
merged 10 commits into from
Nov 6, 2017

Conversation

surli
Copy link
Collaborator

@surli surli commented Oct 30, 2017

Instead of returning null, default behaviour of getBoundingType is to return Object.
This PR is an alternative to #1661

Fix #1670
Fix #1666

@surli surli changed the title refactor: getBoundingType now returns Object by default WiP refactor: getBoundingType now returns Object by default Oct 30, 2017
@@ -50,6 +50,7 @@

public CtTypeParameterReferenceImpl() {
super();
this.setBoundingType(getFactory().Type().objectType()); // by default set bounding type to object
Copy link
Collaborator

Choose a reason for hiding this comment

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

we should create new CtTypeReference, because AST should not share nodes

Copy link
Collaborator Author

@surli surli Oct 31, 2017

Choose a reason for hiding this comment

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

Actually the methods already create a clone of OBJECT in TypeFactory, see:

So I assume the nodes are not shared.

Copy link
Collaborator

Choose a reason for hiding this comment

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

you are right. I did not knew that. So it is OK

// ugly but else make testSetterInNodes failed
if (superType == null) { // if null, set bounding type to object
superType = getFactory().Type().objectType();
superType.setParent(this);
Copy link
Collaborator

Choose a reason for hiding this comment

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

use new CtTypeReference too

@pvojtechovsky
Copy link
Collaborator

This PR is compatible with algorithms, which needed fast fix #1661. This solution is on good way. I like it!

@monperrus
Copy link
Collaborator

I like it too! return null is always such a bad idea!

@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

Any help is welcome for that PR!

The changes are done for passing the current Spoon test suite, but I don't manage to fix #1670 or to reproduce it in a small unit test.
The bug occured when using the script https://github.com/INRIA/spoon/blob/master/doc/jenkins/build.sh on assertj-core project. I now got the following error:

Failed to execute goal fr.inria.gforge.spoon:spoon-maven-plugin:2.4:generate (default) on project assertj-core: Exception during the spoonify of the target project.: Type mismatch: cannot convert from AbstractListAssert<capture#76-of ?,List,Object,ObjectAssert> to AbstractListAssert,Object,ObjectAssert> at /Users/urli/Github/assertj-core/src/main/java/org/assertj/core/api/AbstractIterableAssert.java:491

I manage to fix the bug manually by changing

AbstractListAssert<?,List<?>,Object,ObjectAssert<Object>>

to

AbstractListAssert<?,List<? extends java.lang.Object>,Object,ObjectAssert<Object>>

manually in the code, but I don't completely understand why explicitely extending the wildcard to object in the source code fix the bug.
I think it's because this method use another method which have the following return signature:
AbstractListAssert<?,List<? extends E>,Object,ObjectAssert<E>> and JDT does not manage to make the binding properly, but I still did not manage to reproduce the bug yet.

Still, my manual bug fix seems to show that sometimes we need to explicitely output an extends Object. Then I may need to know when there was an explicit extends object in source, and when it was implicit. Any idea to fix that?

@@ -618,7 +618,7 @@ public void visitCtTypeParameter(CtTypeParameter typeParameter) {
} else {
printer.writeIdentifier(ref.getSimpleName());
}
if (ref.getBoundingType() != null) {
if (ref.getBoundingType() != null && !ref.getBoundingType().equals(ref.getFactory().Type().OBJECT)) { // we ignore printing "extends Object"
Copy link
Collaborator

Choose a reason for hiding this comment

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

one solution may be to simply remove this and always write "extends Object"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

one solution may be to simply remove this and always write "extends Object"

Yes, in fact it's the one on WildcardReference that we should remove (https://github.com/INRIA/spoon/pull/1672/files/ed1cf1264233fa60a055032c286b682b0562362c#diff-5f33bf5d1f38230de815e4c60a67a215R1573).
Indeed it works for assertj, but it means that everytime you use Something<?> it will be written Something<? extends java.lang.Object> which is ugly.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I vote for shorter printed source code. So never print "... extends Object"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So never print "... extends Object"

And then I have a bug with assertj-core.

@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

So... in fact as here as in #1202 the bug is related to JDT own interpretation of wildcard generics in Java.
If you take this line https://github.com/joel-costigliola/assertj-core/blob/9d45e93be7f41da5c0709fc852bebd4ef79f6162/src/main/java/org/assertj/core/api/AbstractIterableAssert.java#L1435

in Intellij Idea it shows a warning on ? extends Object saying its redundant, and in Eclipse it shows an error when you remove the extends.
Then as I already said, here the only way to fix the bug is to have a way to know if this extends belongs to the original source code or not.

@monperrus
Copy link
Collaborator

monperrus commented Oct 31, 2017 via email

@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

We have isImplicit that we can put in the bounding type.

I'll take a look on that.

…e impliciteness to tell DJPP if it must be printed or not
@surli surli changed the title WiP refactor: getBoundingType now returns Object by default review refactor: getBoundingType now returns Object by default Oct 31, 2017
@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

The last changes now fix the error in #1670 we use the isImplicit to tell DJPP if it must be output or not.

* Returns true if the given typeReference is the default bounding type (i.e. java.lang.Object)
*/
@DerivedProperty
boolean isDefaultBoundingType(CtTypeReference typeReference);
Copy link
Collaborator

Choose a reason for hiding this comment

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

parameter needed? could be simply isDefaultBound() with no parameter?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The parameter is needed for case like https://github.com/INRIA/spoon/pull/1672/files#diff-e14ef777963d781b479e6fdd3e8d419dR79 where we want to check before setting the boundingType.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The code on the link will work if object is sent to adapt method too. Only check for null is needed.
The implementation of is default bounding type can be made static. May be we do not need such method at all.


reference.addBound(factory.Type().createReference(String.class));

assertNotNull(reference.getBoundingType());

reference.setBounds(new ArrayList<>());

assertNull(reference.getBoundingType());
assertEquals(factory.Type().OBJECT, reference.getBoundingType());
assertTrue(reference.isDefaultBoundingType(reference.getBoundingType()));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

add a test corresponding to the assert4j problem?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

add a test corresponding to the assert4j problem?

I cannot reproduce exactly the assert4j problem, but we already have in our test a case with an explicit "? super Object", I changed the assert accordingly: https://github.com/INRIA/spoon/pull/1672/files#diff-c20710bb8ee877d0eae2d22578a8f010R506

@monperrus
Copy link
Collaborator

monperrus commented Oct 31, 2017 via email

@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

I'm not convinced by the design and the encapsulation of this new method. Can the the test be rewritten?

You're talking about CtTypeParameterReference#isDefaultBoundingType, right?
I'm completely open to redesign it, but I'm not sure to understand what you want.

@monperrus
Copy link
Collaborator

monperrus commented Oct 31, 2017

I'd propose to remove the parameter of the method. the "is" applies to "this" not to the parameter.

@surli
Copy link
Collaborator Author

surli commented Oct 31, 2017

I'd propose to remove the parameter of the method. the "is" applies to "this" not to the parameter.

I'm ok with that but I also want to have a place where the default value of boundingType is defined and that I can use without creating a new CtTypeParameterReference object. This will allow me to do some checks with a single point of definition for the default value of bounding type.

Where do you think I can create such a method?

@monperrus
Copy link
Collaborator

monperrus commented Nov 1, 2017 via email

@spoon-bot
Copy link
Collaborator

Revapi Analysis results

Old API: fr.inria.gforge.spoon:spoon-core:jar:6.0.0-20171105.234530-142

New API: fr.inria.gforge.spoon:spoon-core:jar:6.0.0-SNAPSHOT

Detected changes: 1.

Change 1

Name Element
Old none
New method boolean spoon.reflect.reference.CtTypeParameterReference::isDefaultBoundingType()
Code java.method.addedToInterface
Description Method was added to an interface.
Breaking binary: non_breaking

@INRIA INRIA deleted a comment from spoon-bot Nov 6, 2017
@surli
Copy link
Collaborator Author

surli commented Nov 6, 2017

It's ready for merging

@monperrus monperrus merged commit dc6fbc7 into INRIA:master Nov 6, 2017
@monperrus
Copy link
Collaborator

Thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants