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: feature: add support for sniper mode #1927

Merged
merged 10 commits into from Sep 18, 2018

Conversation

pvojtechovsky
Copy link
Collaborator

@pvojtechovsky pvojtechovsky commented Mar 25, 2018

fix #1284

@pvojtechovsky pvojtechovsky force-pushed the refDJPP branch 3 times, most recently from fd61958 to 0ea3ea4 Compare April 2, 2018 20:48
@pvojtechovsky pvojtechovsky force-pushed the refDJPP branch 2 times, most recently from b39d22a to 10e9a2f Compare April 5, 2018 20:00
@pvojtechovsky pvojtechovsky changed the title WIP: refactor: DJPP uses #printList(...) WIP: feature: PrettyPrinter for changes only Apr 5, 2018
@pvojtechovsky
Copy link
Collaborator Author

Any idea how to test it?

There is actually PrintChangesTest#testPrintChanged, but it just renames a type member field and prints the modified class. I see that it behaves as expected, but the question is how to test more modifications (all possible modifications?) and how to assert about the printed result in some elegant way?

@monperrus
Copy link
Collaborator

super interesting. it seems to be simply the sniper mode? correct?

for testing, I propose the following contract:

for all tree x, if subtree y is changed to z, then 
  1) content_before_y_position is unchanged, 
  2) content_after_y_position is unchanged
  3) content_whole_x_before_modification != content_whole_x_after_modification
  4) content_whole_x_after_modification contains pretty_print(z)

For testing the forall, we can sample random subtrees in src/main and ideally we would have a tree generator, see #1960

@pvojtechovsky
Copy link
Collaborator Author

yes, is it sniper mode, but based on different concept then #1358. But similar like #1358 it is hard to implement it 100% correctly. Actually it supports printing of changes in type or method and in all other cases it falls back to normal printing. But even this is much better then nothing.

alloy tools

I never heard about that, but it sounds interesting. I will at least read some overview/tutorial to understand what is possible. Thanks for the tip.

for testing, I propose the following contract:

the problem I see in testing is that these tests must accept some degree of incorrectness - in case of unsupported element - when it will print correct java code, but with default formatting - not with origin formatting.

Also comments are not handled yet. But it looks it will be possible to handle them too. I read also the tests implemented for #1358, but there is no solution too.

@pvojtechovsky
Copy link
Collaborator Author

@monperrus, @surli , @tdurieux who would like to review that?

I would like to discuss next steps with reviewer. Note: this PR is somehow working and fully commented, but has still many todos (like comment handling, bug fixing, tests, etc.). I see these ways how to proceed with this PR:

A) to review and merge it as experimental nearly with the incomplete algorithms
B) to finish other features related to sniper mode

The case A) is nearly baby step. The case B) will produce another big PR and hard to review PR.

WDYT?

Note: first commit of this PR is #1950. So after that one is merged and after rebase, it will be little bit simpler too.

@tdurieux
Copy link
Collaborator

Personally, I think that this type of feature can only be tested by using it.
I think we will find out the problem just by writing some tests. At least I did not succeed when I was working on the sniper mode.

I think it is a good idea to merge like we did with the roles.

@tdurieux
Copy link
Collaborator

One question, how do you handle imports?

if (e instanceof CtPackage) {
/*
* do not generate SourcePosition for package-info files, because
* 1) JDT compiler actually delivers 0,0 as source position of type package-info. Comments and annotations are not included
Copy link
Collaborator

Choose a reason for hiding this comment

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

Now, the package.info position contains the complete file, I don't know if it is more useful for you

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok, I will check it and may be remove that change. Thank you for information.

@tdurieux
Copy link
Collaborator

Personally, I struggled a lot to handle the CtCactch and CtSwitch that have really bad positions.
It is possible to add some test to add case and/or a catch

@pvojtechovsky
Copy link
Collaborator Author

One question, how do you handle imports?

I always generate them - never use origin source code. I want to focus on them later. I have not though about that deeper yet.

@monperrus monperrus changed the title WIP: feature: PrettyPrinter for changes only WIP: feature: add support for sniper mode Apr 15, 2018
@monperrus
Copy link
Collaborator

This feature will be great to do automatic fixing of SonarQube violations.

@pvojtechovsky
Copy link
Collaborator Author

missing "sniper mode" is the show stopper for usage of spoon for refactoring. Whenever I speak with my colleagues about Spoon, they are first excited ... until they hear that any transformed and then printed code will produce many useless changes in source code. It is not acceptable for projects, where history of changes is daily needed to detect who is author of what and why it is done as it is done...


new SourceFragmentsTreeCreatingChangeCollector().attachTo(f.getEnvironment());
//change the model
ctClass.getField("string").setSimpleName("modified");
Copy link
Contributor

Choose a reason for hiding this comment

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

Pavel, can you explain how can I add my own processor in sniper mode and how to use it on a directory with many files instead of a single class?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi Ashutosh,
Note: that this PR is experimental. I never tried it on real sources and I expect some problems which has to be solved first. So there is actually no easy way how to enable sniper mode in Spoon API. You have to do it manually in these steps:

  1. register one change listener SourceFragmentsTreeCreatingChangeCollector in spoon environment AFTER the model is loaded and BEFORE you start any changes.
  2. do changes on your model
  3. print changes (type by type) using new printer

Copy link
Contributor

Choose a reason for hiding this comment

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

Alright. Thanks a lot.

@ashutosh1598
Copy link
Contributor

ashutosh1598 commented May 29, 2018

When I'm analysing this simple class(without making changes) :

public class A
{
    public static void pong(String args)
    {
        System.out.println("Hello World");
    }
}

everything is fine, but if I change the argument of pong to String args[] , it is showing the following error :

spoon.SpoonException: The SourcePosition of elements are not consistent
parentFragment: |45, 56|String args|
otherFragment: |45, 58|String args[]|
	at spoon.reflect.visitor.printer.change.SourceFragment.addChild(SourceFragment.java:265)

String []args works fine though.

@pvojtechovsky
Copy link
Collaborator Author

pvojtechovsky commented May 29, 2018

Thank You for reporting that. It looks like a problem in computation of source positions. I will may be have time to have a look at that next week.

I made PR #2015 with failing test for this problem.

@pvojtechovsky
Copy link
Collaborator Author

Rebase was needed. I hope MavenLauncherTest will pass - there were many conflicts in that file

@monperrus
Copy link
Collaborator

I would suggest to first merge ##2461 to get rid of the problem with MavenLauncherTest and have cleaner diffs for subsequent PRs incl. this one.

@pvojtechovsky
Copy link
Collaborator Author

ok, I agree. No hurry is needed here

@spoon-bot
Copy link
Collaborator

API changes: 3 (Detected by Revapi)

Old API: fr.inria.gforge.spoon:spoon-core:jar:7.1.0-20180918.153340-173 / New API: fr.inria.gforge.spoon:spoon-core:jar:7.1.0-SNAPSHOT

Method was added to an interface.
Old none
New method Environment#createPrettyPrinter()
Breaking binary: non_breaking,
The return type changed from 'spoon.reflect.visitor.printer.internal.ElementSourceFragment' to 'spoon.support.sniper.internal.ElementSourceFragment'.
Old method SourcePositionHolder#getOriginalSourceFragment()
New method SourcePositionHolder#getOriginalSourceFragment()
Breaking binary: breaking,
Method was added to an interface.
Old none
New method Environment#setPrettyPrinterCreator(Supplier)
Breaking binary: non_breaking,

@monperrus
Copy link
Collaborator

We don't want to rebase this one. Are you OK if I reset the last commit on master and push force?

@pvojtechovsky
Copy link
Collaborator Author

yes, I am OK with reset and push force. I have no new code there

@monperrus
Copy link
Collaborator

pushed-force.

I propose to merge this one and move on later with #2461 and the @zielint0's styling PRs

WDYT?

@pvojtechovsky
Copy link
Collaborator Author

propose to merge this one

it is ok for me too. I just cannot do it, because I am author. I guess we need somebody else who will merge it.
@surli @tdurieux ?

Copy link
Collaborator

@monperrus monperrus left a comment

Choose a reason for hiding this comment

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

Champagne for the sniper mode!

Thanks a lot to @GerardPaligot for the initial work on modelobs, @tdurieux for having kept it in the attic, as well as the awesome contributions on positions and @pvojtechovsky for the final heavy-lifting.

That's impressive team work over time.

@stefanleh
Copy link

missing "sniper mode" is the show stopper for usage of spoon for refactoring. Whenever I speak with my colleagues about Spoon, they are first excited ... until they hear that any transformed and then printed code will produce many useless changes in source code. It is not acceptable for projects, where history of changes is daily needed to detect who is author of what and why it is done as it is done...

I've used javaparser for my first try with automated code refactoring and then got the hint to check out spoon. Its really great but the many useless code changes and especially the comment handling, their position is really important in my current project, are a showstopper for real code transformation. Therefore i use it only for analysis and do the plumbing then with simple regex code manipulation based on the collected information. Would be really nice to have a "minimal change impact" mode.

@monperrus
Copy link
Collaborator

Would be really nice to have a "minimal change impact" mode.

This is exactly what we have now. Have you tried the sniper mode? See http://spoon.gforge.inria.fr/launcher.html ("sniper mode")

@pvojtechovsky
Copy link
Collaborator Author

@stefanleh and let us know your experience - you will be probably the first brave client who tries that new toy on real project ;-)

@monperrus
Copy link
Collaborator

FYI a real pull-request made with the sniper mode by @HarisAdzemovic

apache/sling-org-apache-sling-discovery-impl#1

@tdurieux
Copy link
Collaborator

tdurieux commented Nov 6, 2019

Really cool!

@INRIA INRIA deleted a comment from tdurieux Nov 7, 2019
@tdurieux
Copy link
Collaborator

tdurieux commented Nov 7, 2019 via email

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

Successfully merging this pull request may close these issues.

feature: sniper mode (aka high fidelity code transformation)
6 participants