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

VA_FORMAT_STRING_USES_NEWLINE handling of text blocks #2881

Merged
merged 6 commits into from
Mar 4, 2024

Conversation

gtoison
Copy link
Contributor

@gtoison gtoison commented Feb 29, 2024

The text blocks introduced in Java 15 pose problem when used in a formatter because the line endings are not platform specific and SpotBugs correctly raises a VA_FORMAT_STRING_USES_NEWLINE

Text blocks line endings should be escaped when used in a format (using %n\). The bug description should give that solution.

The String.formatted() method (added in Java 15) should also be checked as we are already checking the static version String.format()

This should fix #1877

Text blocks line endings should be escaped when used in a format, the
String.formatted() method should be checked as we are already checking
the static version String.format()
fix: check calls to String.formatted()
@gtoison gtoison changed the title test: reproducer for issue #1877 VA_FORMAT_STRING_USES_NEWLINE handling of text blocks Feb 29, 2024
@gtoison gtoison marked this pull request as ready for review February 29, 2024 13:27
@UngenuineGuineapig
Copy link

I'm clearly not an expert in this field by any means, but imho this is not a fix, but an ugly workaround which goes against the goal of the textblocks. JEP 378 clearly states that the goal is to not explicitliy write line breaks: "Simplify the task of writing Java programs by making it easy to express strings that span several lines of source code, while avoiding escape sequences in common cases."

Sprinkling %n everywhere does therefore not sound sane. Maybe this is more or less a bug for openjdk and such?

@gtoison
Copy link
Contributor Author

gtoison commented Feb 29, 2024

This rule is flagging issues when a string is fed into a formatter, in other cases (merely declaring a string via a text block) it shouldn't complain.

I agree it is ugly but you should write %n when using a format and when line endings matter.
In case this doesn't matter the detector can be disabled (or you can suppress the warning)

@JuditKnoll
Copy link
Collaborator

I'm clearly not an expert in this field by any means, but imho this is not a fix, but an ugly workaround which goes against the goal of the textblocks. JEP 378 clearly states that the goal is to not explicitliy write line breaks: "Simplify the task of writing Java programs by making it easy to express strings that span several lines of source code, while avoiding escape sequences in common cases."

Sprinkling %n everywhere does therefore not sound sane. Maybe this is more or less a bug for openjdk and such?

If you don't want to have line breaks in your string, then you can simply skip the line breaks at the end of the line with \ like this, you don't need to put %n:

String value = """
                first line\
                second line\
                """;

As far as I understand yes, this is rather a compiler problem, and since SpotBugs works on the compiled code, and I'm not sure whether we can differentiate a simple string literal and the text blocks introduced in Java 15 on the bytecode level (maybe from the line numbers). Also, this is rather about the programmer's intent, whether he/she wants a line break or not.

|| "java/io/PrintStream".equals(cl) && "printf".equals(nm)
|| cl.endsWith("Writer") && "format".equals(nm)
|| cl.endsWith("Writer") && "printf".equals(nm))
|| cl.endsWith("Logger") && nm.endsWith("fmt")) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for the formatting. It's much more readable 😄


if ("java/lang/String".equals(cl) && "formatted".equals(nm)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please check the signature as well?

if ("java/lang/String".equals(cl) && "formatted".equals(nm)) {
Object stackItem = stack.getStackItem(1).getConstant();
if (stackItem instanceof String) {
String string = (String) stackItem;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like formatString which is set in line 79 is exactly the same. Is there any reason not to use that?

bugReporter.reportBug(new BugInstance(this, "VA_FORMAT_STRING_USES_NEWLINE", NORMAL_PRIORITY)
.addClassAndMethod(this).addCalledMethod(this).addString(string)
.describe(StringAnnotation.FORMAT_STRING_ROLE).addSourceLine(this));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is the duplication of 117-121. I think it would be better if the check for java.lang.String.formatted() would be added to the condition from 107.

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've made changes to merge the check with the existing one, I think it addresses your remarks
Thank you for reviewing!

Copy link
Member

Choose a reason for hiding this comment

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

Think we were good going to merge.

@hazendaz
Copy link
Member

hazendaz commented Mar 1, 2024

Other than concerns on this raised, I think it looks ok. +1 from me.

@hazendaz hazendaz self-assigned this Mar 4, 2024
@hazendaz hazendaz added this to the SpotBugs 4.8.4 milestone Mar 4, 2024
@hazendaz hazendaz merged commit 2e7c256 into spotbugs:master Mar 4, 2024
12 of 15 checks passed
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.

VA_FORMAT_STRING_USES_NEWLINE - False positive in java 17 text block feature
4 participants