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

Add filter for bytecode that javac generates for String in switch #596

Merged
merged 1 commit into from
Sep 24, 2017

Conversation

Godin
Copy link
Member

@Godin Godin commented Sep 21, 2017

I propose to do one more baby step in story of filtering - add filter for bytecode that javac generates for String in switch. And modify it for ECJ separately a bit later since it is a bit more tricky.

@Godin Godin added this to the 0.8.0 milestone Sep 21, 2017
@Godin Godin self-assigned this Sep 21, 2017
@Godin Godin force-pushed the issue-596 branch 3 times, most recently from d415157 to c277fc4 Compare September 21, 2017 23:06
@Godin Godin requested a review from marchof September 21, 2017 23:20
Copy link
Member

@marchof marchof left a comment

Choose a reason for hiding this comment

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

Beside minor naming issues I think this filter is not specific enough: It filters every switch on String.hashCode(), e.g.

	switch (s.hashCode()) { // $line-falsePositive.switch$
	case 42:
		nop(); // $line-falsePositive.case42$
	case 123:
		nop(); // $line-falsePositive.case123$
	}

I don't think it is very likely that we find such cases in real code but I think the filter could be more specific.

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

public class StringSwitchTest implements IFilterOutput {
Copy link
Member

@marchof marchof Sep 23, 2017

Choose a reason for hiding this comment

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

Should be called StringSwitchFilterTest as target is StringSwitchFilter. Or StringSwitchFilterJavacTest.

Copy link
Member Author

Choose a reason for hiding this comment

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

This explains why switching between code and test wasn't working in IDE 😆 Fixed.

/**
* Filters code that is generated by javac for a switch statement with a String.
*/
public final class StringSwitchFilter implements IFilter {
Copy link
Member

Choose a reason for hiding this comment

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

As this filter is specific for javac we should call it StringSwitchJavacFilter.

Copy link
Member Author

Choose a reason for hiding this comment

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

Haven't used Javac prefix, thinking to update it for ECJ later, but you're right. Done.

@marchof
Copy link
Member

marchof commented Sep 23, 2017

@Godin BTW, +1 for moving on with baby steps, thanks!

@Godin Godin force-pushed the issue-596 branch 2 times, most recently from 2a71fe9 to 094686f Compare September 23, 2017 20:57
@Godin
Copy link
Member Author

Godin commented Sep 23, 2017

I think this filter is not specific enough: It filters every switch on String.hashCode()
I don't think it is very likely that we find such cases in real code but I think the filter could be more specific.

Well, was about to do push-back and say "if unlikely, then why complexify? This will make step bigger and harder than baby". But actually making it more specific wasn't that hard thanks to previously implemented AbstractMatcher and implementation with it is quite nice. So lets say that I was lazy 😉
Please re-review.

Copy link
Member

@marchof marchof left a comment

Choose a reason for hiding this comment

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

Nice, thx!
Have two minor suggestions for the Matcher. Not mandatory though.

for (int i = 0; cursor != null && i < 4; i++) {
cursor = cursor.getPrevious();
}
if (cursor == null || cursor.getOpcode() != Opcodes.ICONST_M1) {
Copy link
Member

Choose a reason for hiding this comment

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

Couldn't that be nextIs(Opcodes.ICONST_M1) followed by if (cursor == null) return;?

Copy link
Member Author

Choose a reason for hiding this comment

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

@marchof Unfortunately no: nextIs first moves to next instruction and then checks, so can't be used to verify current instruction, and we can't place cursor before very first instruction of method.

Copy link
Member Author

@Godin Godin Sep 23, 2017

Choose a reason for hiding this comment

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

@marchof this is kind of catch 22 - either we need to special case checking of beginning, or will have problem with end of methods, i.e. if we change semantic and cursor will be pointing to instruction for checking and moved after checking, then null can not be used to represent no-match as it is now, because next of last instruction is null. Maybe we can represent no-match by a special non-null value, but will be better to do this separately from this PR as it requires change of semantics of next methods and cursor.

Copy link
Member Author

Choose a reason for hiding this comment

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

@marchof another option is to have fake instruction at the beginning:

private void moveBack(int num) {
	for (int i = 0; i < num; i++) {
		if (cursor.getPrevious() == null) {
			cursor = new InsnNode(Opcodes.NOP) {
				final AbstractInsnNode next = cursor;
				@Override
				public AbstractInsnNode getNext() {
					return next;
				}
			};
		} else {
			cursor = cursor.getPrevious();
		}
	}
}

But I doubt that this is a good idea in general and definitely too much of complexity if done only here, compared to current handling of beginning.

boolean match(final AbstractInsnNode start,
final AbstractInsnNode secondSwitchLabel) {
cursor = start;
for (int i = 0; cursor != null && i < 4; i++) {
Copy link
Member

Choose a reason for hiding this comment

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

Would be nice to have a fluent API for this in Matcher

moveBack(4);

or something like this.

Copy link
Member Author

Choose a reason for hiding this comment

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

@marchof I would prefer to leave this as is and extract only if will be used somewhere else, otherwise IDE complains that value of parameter is always 4.

Copy link
Member

@marchof marchof left a comment

Choose a reason for hiding this comment

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

OK, then good to me!

@marchof marchof merged commit 04f923c into master Sep 24, 2017
@marchof marchof deleted the issue-596 branch September 24, 2017 05:28
@jacoco jacoco locked as resolved and limited conversation to collaborators Jan 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants