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: feat: add JLSViolation exception #4148

Merged
merged 12 commits into from
Sep 14, 2021

Conversation

MartinWitt
Copy link
Collaborator

As discussed in #4134 we need a more specific exception for JLS correctness. See the record pr for the reason behind this.

@MartinWitt MartinWitt changed the title WIP: feat: add JLSViolation exception Review: feat: add JLSViolation exception Sep 6, 2021
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.

Interesting and well-scoped baby PR.

  • see comment
  • we need a test case

Thanks!

* Throws an {@link spoon.JLSViolationException} if enabled, logs otherwise.
* @param reason the reason why this element is not compliant with the JLS.
*/
void throwJLSViolationException(String reason);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This method is not related to the element's state. I feel we should have it elsewhere.

Proposal: as static method in SpoonException?

Copy link
Collaborator Author

@MartinWitt MartinWitt Sep 7, 2021

Choose a reason for hiding this comment

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

The problem with moving it away form CtElement is that we need the environment or the factory for the check if we need(the user wants) to throw the exception. I'm unsure if passing a factory or environment to the exception creation produces good code.

public void throwJLSViolation(Factory fac, String reason)

looks a bit strange to me with the knowledge, the factory is not used for the exception message.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with @monperrus, this method should not be on CtElement. It's a helper method for Spoon internals, exposing it in the public API is not desirable.

I also don't really like the idea of having a method named throwX, that may not actually throw X. A better name would probably be something like handleJLSViolation, but I'm not entirely sold on the necessity for the method to begin with.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I moved the Exception to SpoonException in a static until method.

but I'm not entirely sold on the necessity for the method to begin with.

The goal of this method is to not repeat the check if the exception should be logged or thrown at every place we have JLSViolations.

Comment on lines 592 to 601
/**
* Whether Spoon currently ignores JLS correctness.
* @return true if spoon ignores JLS correctness, false if spoon throws {@link spoon.JLSViolationException} when it detects JLS violation.
*/
boolean isIgnoreJLSCorrectness();
/**
* Sets whether Spoon should ignore JLS violations.
* @param ignoreJLSCorrectness true if spoon should ignore JLS violations, false if spoon should throw {@link spoon.JLSViolationException} when it detects JLS violation.
*/
void setIgnoreJLSCorrectness(boolean ignoreJLSCorrectness);
Copy link
Collaborator

@slarse slarse Sep 7, 2021

Choose a reason for hiding this comment

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

This concept is extremely close to setIgnoreSyntaxErrors. A JLS violation is in most situations a syntax error. If this is to be added as a separate flag, it needs to be clearly distinguished from setIgnoreSyntaxErrors.

The key thing about setIgnoreSyntaxErrors is that it's a filter to ignore files with syntax errors in the input. This new proposed flag could perhaps distinguish itself by being explicitly about maintaining JLS compliance in the Spoon model.

What I'm trying to get across is that if I were to read these docs, the distinction between this flag and setIgnoreSyntaxErrors would not be clear to me.

Finally, I'd argue this should be called "ignore JLS violations" or "skip JLS correctness checks". I understand what "ignore correctness" is meant to imply, but it's a bit of a brain twister for me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

	/**
	 * Sets the option ignore-syntax-errors to remove files with any syntax errors from the compilation batch.
	 *
	 * @param ignoreSyntaxErrors whether Spoon should ignore files with any syntax errors or JLS violations
	 */
	void setIgnoreSyntaxErrors(boolean ignoreSyntaxErrors);

After reading these docs, I think there is a problem with merging these 2 flags, because building a model with a wrong identifier is possible, but the flag removes the file completely. I'm unsure if ignoring = removing is expected behavior.

@monperrus
Copy link
Collaborator

About the concept here there are two things.

  • introducing a new exception
  • having this as configurable behavior

The former is OK to me. We can already put in this PR some usages.

As @slarse I'm not enthusiastic about the latter because 1) configurable behavior is hard to understand for clients 2) configurable behavior is harder to test and maintain 2) configurable behavior for exceptions is especially caveat.

WDYT?

@MartinWitt
Copy link
Collaborator Author

MartinWitt commented Sep 9, 2021

My intention with allowing non JLS compliant code was that some (maybe existing) transformations have steps which produce non JLS code. I think we shouldn't remove the ability to write transformations freely. But as @slarse pointed out correctly, the JLS correctness is pretty close to tIgnoreSyntaxError and the existing flag should be used.

We can already put in this PR some usages.

This could be hard as Spoon ignores a lot of JLS restrictions and is more focused on building any model.
Edit: We could change the identifier checks to throw JLSViolation

Comment on lines 42 to 44
} else {
LOGGER.info("An element is not compliant to the JLS. See: {}", reason);
}
Copy link
Collaborator Author

@MartinWitt MartinWitt Sep 9, 2021

Choose a reason for hiding this comment

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

Here we could say ignoring means no logging at all. Any opinions on just log it, even if the user said ignoreSyntaxErrors?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's fine to log IMO.

@monperrus
Copy link
Collaborator

Thanks for the update. LGTM.

Copy link
Collaborator

@slarse slarse left a comment

Choose a reason for hiding this comment

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

See my comment on the code.

In addition, this changes the semantics of setIgnoreSyntaxErrors, and its docs must be updated. It's no longer only about ignoring syntax errors in files, but also in transformations, which must be expressed in the docs.

Comment on lines 42 to 44
} else {
LOGGER.info("An element is not compliant to the JLS. See: {}", reason);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's fine to log IMO.

* @param holder an object with access to factory and environment.
* @param reason the reason for the exception.
*/
public static void handleJLSViolation(FactoryAccessor holder, String reason) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this method belongs here either. This makes SpoonException dependent on its subtype, which is undesirable and IMO violates SRO (SpoonException might have to change if JLSViolation changes).

If this method should exist, and should be the prime way of throwing a JLSViolation, I would put it as a static method on JLSViolation and make its constructor private. I.e. like so:

public class JLSViolation extends SpoonException {

	private JLSViolation(String msg) {
		super(msg);
	}

	public static void throwIfSyntaxErrorsAreNotIgnored(FactoryAccessor holder, String reason) {
		// logic    
	}

}

Then usage becomes a bit easier to read, I think:

// current
SpoonException.handleJLSViolation(...);

// my proposition
JLSViolation.throwIfSyntaxErrorsAreNotIgnored(...);

What do you think? Agree, disagree?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

100% correct, I moved the method and changed the name to your better name.

Copy link
Collaborator

@slarse slarse left a comment

Choose a reason for hiding this comment

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

LGTM

I think using more specific exceptions is a step in the right direction for Spoon overall.

@slarse slarse merged commit 9ed619b into INRIA:master Sep 14, 2021
@slarse
Copy link
Collaborator

slarse commented Sep 14, 2021

Thanks @MartinWitt

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.

3 participants