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

Rename param to match signature code fix #917

Merged
merged 3 commits into from Apr 25, 2022

Conversation

Booksbaum
Copy link
Contributor

@Booksbaum Booksbaum commented Apr 15, 2022

Code Fix to rename parameter in implementation (in fs file) to match its signature (in fsi file)

RenameParamToMatchSignature

Port of dotnet/fsharp (VS) -> RenameParamToMatchSignature

(Note: if you try the example above yourself, you'll see an additional Add explicit type annotation CodeFix -- which is incorrect. Fix will come soon (Uses Test helper introduced in this PR))



But there are situations this CodeFix will not produce the correct result (suggests wrong name):

  • When diag message is english and sig param name contains ' and implementation '
    • Reason: I use this phrase to extract sig name from diag message
  • When diag message is not english and sig or impl param name contains ' (except last position)
    • Reason: When not english -> cannot match exact diag message -> fallback to matching between 's with Regex -> incorrect match when param name contains additional '
    • Note: This is currently how VS extracts param name

(-> algo for getting sig param name: First try exact match in english, then fall back to regex between ')

I think that's acceptable:
Extra Signature is extremely unlike to contain ' and implementation '.
Fallback (not english) is more likely to fail. But even one ' (especially not at end of name) in signature name is quite unlikely too. Might occur in impl name, but probably not inside param name (just at end).
-> I think it's good enough and not worth doing something more complicated

Note:
Matching based on localization is an issue for tests: Multiple tests will fail when FCS returns diag messages in something other than english.
(Does FCS even auto-localize? Compilers and their tools that use local language by default are just horrible. Even just googling an error message becomes complicated....)


Edit:
Missing CodeFixes from VS:

  • ProposeUppercaseLabel: Required changes might span multiple documents, but current Fix in FSAC only handles single doc (same for tests) -> requires changes
    (-> not now -- maybe sometime later)
  • FixIndexerAccess: arr[2] -> arr.[2]. Isn't an error any more -- even recommended now -> would only apply to old F# compiler versions
    -> I don't think it's worth implementing this CodeFix
    (other direction might be worth it: remove .)

Fix capitalization
Rename parameter name to match its signature (in fsi file) ("The argument names in the signature 'xxx' and implementation 'yyy' do not match.")

Note: sig name is extracted from diag message. But this fails when:
* diag message is english and sig name contains `' and implementation '`
* diag message isn't english and sig or impl name contains `'` (excluding last position)

I think that's acceptable:
Sig name is public -> unlikely to contain exact phrase with `'` and spaces

Port of `dotnet/fsharp` (VS) -> [`RenameParamToMatchSignature`](https://github.com/dotnet/fsharp/blob/main/vsintegration/src/FSharp.Editor/CodeFix/RenameParamToMatchSignature.fs)

Add tests for `RenameParamToMatchSignature`
Note: Tests are a bit more complicated than other CodeFix tests: Don't work with untitled script files, but instead require a `fsi` and corresponding `fs` file.
-> Slight hack to be able to specify source in each test: Open existing `fsi` and `fs` file, but with text specified in each test.

Add `itestCaseAsync`: `ignore testCaseAsync`:
Like `testCaseAsync`, but test gets completely ignored.
Unlike `ptestCaseAsync` (pending), `itestCaseAsync` doesn't even show up in Expecto summary.
-> Used to mark issues & shortcomings in CodeFixes, but without any (immediate) intention to fix (vs. `pending` -> marked for fixing)
-> ~ uncommenting tests without actual uncommenting
* Example: used to ignore test with sig `' and implementation '`
  -> shortcoming gets highlighted, but unlike `pending` it's considered "ok for now"

Uncomment unused tests with `itestCaseAsync` instead of `//`
let private renameParamToMatchSignatureTests state =
let selectCodeFix expectedName = CodeFix.withTitle (RenameParamToMatchSignature.title expectedName)

// requires `fsi` and corresponding `fs` file (and a project!)
Copy link
Contributor

Choose a reason for hiding this comment

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

you could potentially generate this at test-time to a random directory instead of being forced to check in empty data?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The "complex" part here is the project file.
Which of course can be written to file too -- but now it's either content of fsproj in tests or adjusting a freshly created project (with dotnet new ... in some dir).
And would require getting a dir, and then writing all necessary files....but that adds additional complexity

We're now way more complex than just loading an existing project -- even when just project just contains empty "dummy" files

Copy link
Contributor

Choose a reason for hiding this comment

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

Not a need for now, but I've been looking at this library for defining project files in code

@baronfel
Copy link
Contributor

Forcing a specific localization can be done via environment variable, but we should definitely take care to force the InvariantCulture at Program.fs for the apps and the tests (though dotnet test doesn't run the main of the test program, so we should take care to ensure it there).

This is a good fix :) Regarding some of the questions you bring up - is this a problem with the error code not being unique enough to only use the code as a determining factor?

@Booksbaum
Copy link
Contributor Author

is this a problem with the error code not being unique enough to only use the code as a determining factor?

The diag is unique.
But the issue is: how to get parameter name in signature file? Looking that up via AST is complicated (param doesn't point to signature, but instead just the function. Getting sig param name would require: What function does this param belong to, get its signature, then match params in impl & sig)

BUT: the error message contains the signature name:

The argument names in the signature 'value' and implementation 'x' do not match. [...]

-> CodeFix (here and in VS) extracts name from diag message

I just added the additional match for exact english match because there are issues when param name contains ' (-> ' is used to extract parameter name...)

@Booksbaum
Copy link
Contributor Author

Fix will come soon (Uses Test helper introduced in this PR)

Fixed in #926 without anything from this PR
(I wanted to use introduced ignore test case -- but ended up implementing it....)

-> PR is done

(though 2 Runs failed? usually just windows is out of line 😞 )

@baronfel
Copy link
Contributor

Generally macos/ubuntu failures are transient, and the windows failure is transient with one specific test (that I think is due to running multiple tests from the same data directory). It's something to look at, but haven't found the time yet. Usually a poke fixes it up, like it did here.

@baronfel
Copy link
Contributor

Again, thank you for one more wonderfully detailed and thoroughly-tested PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants