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 DefaultLocale check to discourage use of the default locale #4487

Closed
wants to merge 3 commits into from

Conversation

tbroyer
Copy link
Contributor

@tbroyer tbroyer commented Jul 20, 2024

Fixes #632

Copy link
Collaborator

@cushon cushon left a comment

Choose a reason for hiding this comment

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

Thanks very much for this, it looks great.

I left a few minor comments, I'm going to run it over Google's codebase and see if that turns up any interesting false positives or other issues, and then will plan on getting this merged soon.


/** A {@link BugChecker}; see the associated {@link BugPattern} annotation for details. */
@BugPattern(
summary =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would you be willing to also add a brief .md to this directory? https://github.com/google/error-prone/tree/master/docs/bugpattern

I think it'd be helpful to have a few sentences to characterize why this is bad, and some guidance on how to choose between the different possible fixes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tbroyer thoughts on this? This can also happen as a follow up if you don't have time right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Might I let you (or someone else) do it? 😇

I started drafting something but couldn't clearly articulate my thoughts 😞


private boolean containsSomeFormattableArgument(
List<? extends ExpressionTree> arguments, VisitorState state) {
return arguments.stream().anyMatch(tree -> mightBeFormattable(tree, state));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I noticed this is reporting errors for any String.format arguments that implement an interface (the example I noticed was List<String>), since any interface is castable to Formattable. Was that deliberate?

I think at Google we probably won't apply that approach as-is, because it would result in a large number of findings and false positives. I think there are a few ways to reconcile that. We could make the check less strict, or add configuration to control how strict it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, that's going to match quite wide, but it's the "most correct" kind of match, right?
I mean, if you have List<String> it might actually be an instance of class L<T> implements List<T>, Formattable, that could then be locale-dependent.

I suppose there are ways to detect a bunch of cases where this cannot happen (e.g. a local variable List<String> list = new ArrayList<>() is guaranteed to not implement Formattable) but this is beyond my skills I'm afraid.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, agree it's the most correct option. I see a tradeoff between correctness and false positives here. I think it's reasonable to want the check to be as correct as possible, and e.g. report a match for String.format("%s", someInterface). Partly I wanted to double-check: for your usage, do you want the most correct/sound version of the check, even if that results in false positives?

For Google's codebase the current version reports a lot of findings, and the ratio of String.format to everything else is about 9:1. I'm not sure we'll want to use the most correct version of the check. But that's also something I can look at as a follow-up. If you want the stricter version I'm happy to get this merged and then consider maybe adding flags to make it more lenient or something as a follow-up.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have no idea how much Formattable is being used in the wild, and whether I might be affected by this (whether things I format implement Formattable or not, I definitely never implemented Formattable myself ever). Off the cuff I'd say the risk is rather low so I think I'd be OK with a more lenient check; but on the other hand it's not that hard to provide an explicit locale (even if Locale.getDefault()) "just in case".

So maybe make it strict by default (even if "too strict") and have a flag to make it more lenient?
(or if you prefer, start by making it lenient by default, with a flag to make it stricter, then later –possibly only after changes to have fewer false positives– switch the default behavior, with a flag to get back to the more lenient check, and eventually remove the flag)

Fwiw, I'm currently using Forbidden APIs which is even stricter as it flags all String.format(String,Object...) invocations irrespective of the pattern being used, so I'm already providing an explicit locale "just in case" everywhere, and even the strict behavior here would be better than Forbidden APIs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I took a quick look at Formattable usage and it seems to be very rare. For Google's internal usage we might be OK not worrying about that case to reduce the number of noise from adding default locales just in case.

Anyway, I'm happy to merge the current version of this. Partly I wanted to confirm how strict a check you wanted for your usage. I'll think more about what I want to enable at Google, and if that ends up being slightly different we can express the difference with flags.

…ble and only fail when they're known to be Formattables
return prependLocales(tree, tree.getMethodSelect(), tree.getArguments(), state, localeFixes);
}

private Description prependLocales(
Copy link
Collaborator

Choose a reason for hiding this comment

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

FYI I think this method is unused

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.

BugPattern for using the default system Locale
2 participants