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

yet another strict null checks branch #1605

Merged
merged 22 commits into from
Mar 20, 2022

Conversation

corasaurus-hex
Copy link
Contributor

@corasaurus-hex corasaurus-hex commented Mar 18, 2022

What has Changed?

More strict null checks changes. Nothing drastic, so it should be an easy merge.

My Calva PR Checklist

I have:

  • Read How to Contribute.
  • Directed this pull request at the dev branch. (Or have specific reasons to target some other branch.)
  • Made sure I have changed the PR base branch, so that it is not published. (Sorry for the nagging.)
  • Updated the [Unreleased] entry in CHANGELOG.md, linking the issue(s) that the PR is addressing.
  • Figured if anything about the fix warrants tests on Mac/Linux/Windows/Remote/Whatever, and either tested it there if so, or mentioned it in the PR.
  • Added to or updated docs in this branch, if appropriate
  • Tests
    • Tested the particular change
    • Figured if the change might have some side effects and tested those as well.
    • Smoke tested the extension as such.
    • Tested the VSIX built from the PR (so, after you've submitted the PR). You'll find the artifacts by clicking Show all checks in the CI section of the PR page, and then Details on the ci/circleci: build test.
  • [~] Referenced the issue I am fixing/addressing in a commit message for the pull request.
    • [~] If I am fixing the issue, I have used GitHub's fixes/closes syntax
    • [~] If I am fixing just part of the issue, I have just referenced it w/o any of the "fixes” keywords.
  • [~] Created the issue I am fixing/addressing, if it was not present.
  • Formatted all JavaScript and TypeScript code that was changed. (use the prettier extension or run npm run prettier-format)
  • Confirmed that there are no linter warnings or errors (use the eslint extension, run npm run eslint before creating your PR, or run npm run eslint-watch to eslint as you go).

src/lsp/main.ts Outdated
if (client) {
resolve(client);
} else if (error) {
reject(new Error('clojure-lsp: ' + error));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this section is just a refactoring to prevent multiple fetches and not repeat ourselves as much. plus it makes the condition branching here a lot clearer

@corasaurus-hex corasaurus-hex force-pushed the cora/yasncb-yet-another-strict-null-checks-branch branch from a78ead4 to 3ab4ccb Compare March 20, 2022 04:48
const newID = uuid.uuid();
void this.store.update(KEY, newID);
return newID;
} else {
return this.store.get(KEY);
return value;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have established that value is not undefined at this point and the other conditional branch also returns a string and so we have removed the possibility of undefined.

'format-as-you-type': workspaceConfig.get<boolean>('formatAsYouType'),
'keep-comment-forms-trail-paren-on-own-line?': workspaceConfig.get<boolean>(
'format-as-you-type': !!workspaceConfig.get<boolean>('formatAsYouType'),
'keep-comment-forms-trail-paren-on-own-line?': !!workspaceConfig.get<boolean>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using !! to ensure we return booleans instead of undefined.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I thought I had removed the format-as-you-type setting, relying on VS Code's setting for this... But that was probably in the old failed Parinfer branches... Note to self to remove this setting at some point soon.

return false;
}

wsEdit.set(document.uri, edits);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, if edits is undefined we log an error and return false instead of trying to apply undefined edits.

if (isUndefined(r.edits)) {
console.error('Edits were undefined!', cloneDeep({ editBuilder, r, editor }));
return;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, log an error and return if there are no edits because there is nothing to do if that is the case.

'edit.text was undefined!',
cloneDeep({ edit, editBuilder, r, editor })
);
return;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Skip applying undefined edit text since that makes no sense.

if (isUndefined(r.character)) {
console.error('Expected result character to be defined!', { r });
return;
}
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 don't know if, in practice, these will ever actually be undefined or not. It would be nice to have the types reflect that if that's the case.

Copy link
Collaborator

Choose a reason for hiding this comment

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

They will never be undefined. This is the code we use to calculate them:

(defn raplacement-edits-for-diffing-lines
  "Returns a list of replacement edits to apply to `old-text` to get `new-text`.
   Edits will be in the form `[:replace [range] text]`,
   where `range` is in the form `[[start-line start-char] [end-line end-char]]`.
   NB: The two versions need to have the same amount of lines."
  [old-text new-text]
  (let [old-lines (util/split-into-lines old-text)
        new-lines (util/split-into-lines new-text)]
    (->> (map vector (range) old-lines new-lines)
         (remove (fn [[line o n]] (= o n)))
         (mapv (fn [[line o n]]
                 {:edit "replace"
                  :start {:line line
                          :character 0}
                  :end {:line line
                        :character (count o)}
                  :text n})))))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cool, I'll modify these to use non-null-assertions (!) then

} else {
throw new Error('Expected a uri to be passed in or a config to exist at .calva/config.edn');
}
const data = await vscode.workspace.fs.readFile(resolvedUri);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixing the issue where state.resolvePath can return undefined and make sure we have a better error message when that's the case.

(configOptions.inspect('customREPLHoverSnippets')
.workspaceValue as customREPLCommandSnippet[]) ?? []
configOptions.inspect<customREPLCommandSnippet[]>('customREPLHoverSnippets')?.workspaceValue ??
[]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

since inspect may return undefined here we need the optional ?

@@ -680,15 +680,18 @@ export async function getClojuredocs(symName: string, symNs: string): Promise<an
}

// TODO: This feels a bit brute, what are other ways to wait for the client to initialize?
function getClient(timeout: number): Promise<LanguageClient> | undefined {
function getClient(timeout: number): Promise<LanguageClient> {
const start = Date.now();
return new Promise(waitForClientStarted);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This always returns a promise and so we can remove the undefined return.

if (client) {
resolve(client);
} else if (error) {
reject(new Error('clojure-lsp: ' + error));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Avoid multiple fetches and make the code a little more clear.

export async function isDocumentWritable(
document: vscode.TextDocument
): Promise<boolean | undefined> {
export async function isDocumentWritable(document: vscode.TextDocument): Promise<boolean> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

turns out we're no longer possibly returning undefined here!

@corasaurus-hex corasaurus-hex marked this pull request as ready for review March 20, 2022 06:14
@corasaurus-hex
Copy link
Contributor Author

ping @PEZ @Cyrik @bpringe

@corasaurus-hex corasaurus-hex changed the title WIP yet another strict null checks branch yet another strict null checks branch Mar 20, 2022
@corasaurus-hex
Copy link
Contributor Author

corasaurus-hex commented Mar 20, 2022

Down to 224 errors now, btw, down from 245 on the dev branch. we're asymptotically approaching zero type errors

Copy link
Collaborator

@PEZ PEZ left a comment

Choose a reason for hiding this comment

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

This looks all excellent to me.

@PEZ PEZ merged commit 2e877dd into dev Mar 20, 2022
@PEZ PEZ deleted the cora/yasncb-yet-another-strict-null-checks-branch branch March 20, 2022 09:05
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.

2 participants