Detect whitespace in property name#5672
Conversation
Forgind
left a comment
There was a problem hiding this comment.
Thanks for these changes! Would you mind making it more general by including all invalid characters rather than just whitespace?
|
Looking at the error, you might need to target it more precisely when someone uses property functions. |
|
Thank you both for the feedback! Taken most of your remarks into account, now working on
|
I have looked around a bit in docs and code, but I could not find such a list. What would you consider invalid characters? https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-special-characters?view=vs-2019? |
@danmosemsft, is there a list somewhere of all the invalid characters? |
|
I think this is the check to use: msbuild/src/Shared/XmlUtilities.cs Lines 118 to 129 in 091189a |
|
Hmmm It fails on the dot |
|
Good point. Maybe exclude Unless you have nested properties/items, in which case also @, $, %, (, and )... And also |
|
Including these extra valid character checks is failing a lot of tests, and the scope of the original PR is also quite larger than initially. There is an added perf consideration as well with this as mentioned in |
|
I would limit the fix to just whitespace since that’s the common mistake. I haven’t looked at the code recently, but there should be a place in the parser/scanner where encountering a close paren would complete a property name; in that place, it should reject space. |
|
We noticed that this only runs when looking at properties inside conditions. Would you mind making it work for all properties? After that, I think it's good. |
Could you please share an example of such a property that I could use as a test case? I may be wrong, but my understanding is that the whitespace check here is done from |
|
This is supposed to throw an error when seeing whitespace in a property correct? I'm not seeing it (for properties inside or outside conditions), unless you have to build a specific way? I tried building a bootstrap of this PR and building this (taken from #5615): Output when using standard No error is being thrown. Same for building within a test: Am I missing something? |
There was a problem hiding this comment.
is it worth adding a test for "$(x yz" and "$(x y z")?
There was a problem hiding this comment.
do you really mean "$(x yz" and "$(x y z") or actually "$(x yz)" and "$(x y z)"?
|
Thanks for your message.
Yes.
Indeed, I observe the same behavior with running
For me it works when building within a unit test e624312, I can't explain yet why this test passes but |
|
Interesting! So this is actually far more complicated than I'd imagined when I last commented here. Your unit test works unless you put quotes around the property, i.e., Noting that there are also quotes around every instance in which @benvillalobos used a malformed property, I suspect that this doesn't look inside strings, and that there are two ways MSBuild handles properties. (Why? I have no idea.) We may have to talk internally about what the best way forward is. I would say this PR is a clear improvement on what previously existed, but on the other hand, it doesn't cover all cases, and I don't know the easiest way to extend it to cover all cases. I imagine you could put something in Expander.cs to look at properties as they're expanded, but I don't think there's an easy way (or any way?) to get the position of the space in that case. |
|
@Forgind any updates from your internal discussions about this one? Would love to hear about what you've discovered. |
|
After talking it over, we think it best to take it roughly as-is. We think it should go behind a change wave (talk to @benvillalobos if you need help with that), and we should change the error code to something that isn't taken, but otherwise, this is about the best we can do. Does that sound reasonable to you, @mfkl? |
There was a problem hiding this comment.
| <value>MSB4151: Unexpected whitespace at position "{1}" of condition "{0}". Did you forget to remove a whitespace?</value> | |
| <comment>{StrBegin="MSB4151: "}</comment> | |
| <value>MSB4259: Unexpected whitespace at position "{1}" of condition "{0}". Did you forget to remove a whitespace?</value> | |
| <comment>{StrBegin="MSB4259: "}</comment> |
There was a problem hiding this comment.
(4151 was deprecated, but we should still avoid reusing error codes so people can search for them effectively online.)
|
On change waves, here's a dev doc: https://github.com/dotnet/msbuild/blob/master/documentation/wiki/ChangeWaves-Dev.md any feedback on it would be appreciated! |
This reverts commit e624312d9d86db0c53322ceedc0f5a123890e121.
rename MSB4151 to MSB4259
Thanks! I guess the doc is clear, though my initial reaction when reading it was "why was the opt-out strategy chosen over opt-in?". I picked |
|
Thanks for the feedback!
Fair question. Part of the drive for that is understanding the impact for some of these changes. If we hit a particularly hot path, it allows us to reevaluate the situation knowing that folks have a way out. It also gives us a better picture of how MSBuild is being used.
|
| using TestEnvironment env = TestEnvironment.Create(); | ||
| env.SetChangeWave(ChangeWaves.Wave17_0); | ||
|
|
||
| Scanner lexer = new Scanner("$(x )", ParserOptions.AllowProperties); | ||
| AdvanceToScannerError(lexer); | ||
| Assert.Null(lexer.UnexpectedlyFound); | ||
|
|
||
| lexer = new Scanner("$( x)", ParserOptions.AllowProperties); | ||
| AdvanceToScannerError(lexer); | ||
| Assert.Null(lexer.UnexpectedlyFound); |
There was a problem hiding this comment.
| using TestEnvironment env = TestEnvironment.Create(); | |
| env.SetChangeWave(ChangeWaves.Wave17_0); | |
| Scanner lexer = new Scanner("$(x )", ParserOptions.AllowProperties); | |
| AdvanceToScannerError(lexer); | |
| Assert.Null(lexer.UnexpectedlyFound); | |
| lexer = new Scanner("$( x)", ParserOptions.AllowProperties); | |
| AdvanceToScannerError(lexer); | |
| Assert.Null(lexer.UnexpectedlyFound); | |
| using (TestEnvironment env = TestEnvironment.Create()) | |
| { | |
| env.SetChangeWave(ChangeWaves.Wave17_0); | |
| Scanner lexer = new Scanner("$(x )", ParserOptions.AllowProperties); | |
| AdvanceToScannerError(lexer); | |
| Assert.Null(lexer.UnexpectedlyFound); | |
| lexer = new Scanner("$( x)", ParserOptions.AllowProperties); | |
| AdvanceToScannerError(lexer); | |
| Assert.Null(lexer.UnexpectedlyFound); | |
| } |
Having TestEnvironment call Dispose resets state for CI builds.
There was a problem hiding this comment.
The previous way actually calls Dispose, too, when env goes out of scope, and I think it's technically recommended, although it isn't something we use in MSBuild particularly.
There was a problem hiding this comment.
I can change it back to the old syntax if you folks prefer.
There was a problem hiding this comment.
So long as dispose is called I'm okay with its current state 👍
|
I'd suggest moving to an earlier wave, probably 16.8 or 16.10. We don't expect this to cause a problem 99% of the time, but someone theoretically could have properties with spaces that silently return empty strings and work around that, in which case this could break their build. If it were opt-in, we wouldn't find any customers like that, and we would never know whether there actually is anyone who relies on properties with spaces being turned into empty strings. |
Oh whoops, I meant |
| <comment>{StrBegin="MSB4110: "}</comment> | ||
| </data> | ||
| <data name="IllFormedPropertyWhitespaceInCondition" xml:space="preserve"> | ||
| <value>MSB4259: Unexpected whitespace at position "{1}" of condition "{0}". Did you forget to remove a whitespace?</value> |
There was a problem hiding this comment.
Nit, I don't think we normally would say a whitespace. Maybe a space. Suggest just ...forget to remove whitespace?
|
I'm having trouble analyzing the CI result, I can't find what is failing exactly or why. Is it something I did? |
|
Doesn't look like it. I kicked off a new run. Since it was mono that failed, I'm guessing this flakiness will be fixed by #5831. |
|
Thanks, @mfkl! |
|
Thanks for the change @mfkl |
Attempt at #5615
Any feedback welcome.