From 39186acf9e8d3cb6c0a2866cfc378bbaa1e87900 Mon Sep 17 00:00:00 2001 From: c-git <43485962+c-git@users.noreply.github.com> Date: Thu, 10 Nov 2022 15:44:33 -0500 Subject: [PATCH] Add detection of main under more circumstances The cases that are intended to be added by this commit are: - Code with no comments but ends in a semicolon before the declaration of `main`. No comments was required to prevent `//` being included to comment out the line. This was done by not allowing `/` as part of the code before the `;` While this is more restrictive than necessary, it didn't seem likely that the code before `main` would include `/` so didn't seem worthwhile to take the performance hit to make the check less restrictive. To prevent long regex scans going multiple lines I also disallowed newlines in the code by including `\n` and `\r` as disallowed characters. The whole point is code on the same line as `main` so this seemed fine and would help prevent unnecessarily matching all lines before main when it doesn't matter. - Allow multiline comments within the arguments area of main that both start and end within the brackets. I'm not expecting a substantial performance cost from this one because this case is near the end of the matching. I used the following test cases ```rust fn main() { // Should work println!("Hello, world!"); } //;fn main() { //Shouldn't work println!("Hello, world!"); } use std; fn main(){ println!("Hello, world!"); } // Should work const fn main() { // Should work println!("Hello, world!"); } /* fn main() {} */ // Shouldn't work fn main(/* comment */) { // Should work // snip } ``` Co-authored-by: Jake Goulding --- ui/frontend/selectors/index.spec.ts | 8 ++++++++ ui/frontend/selectors/index.ts | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ui/frontend/selectors/index.spec.ts b/ui/frontend/selectors/index.spec.ts index 8644323db..98d1f51bf 100644 --- a/ui/frontend/selectors/index.spec.ts +++ b/ui/frontend/selectors/index.spec.ts @@ -55,4 +55,12 @@ describe('checking for a main function', () => { test('a function with the substring main does not count', () => { expect(doMainFunctionSelector('fn mainly()')).toBe(false); }); + + test('a main function after other items on the same line', () => { + expect(doMainFunctionSelector('use std; fn main(){ println!("Hello, world!"); }')).toBe(true); + }); + + test('a main function with a block comment in the argument list', () => { + expect(doMainFunctionSelector('fn main(/* comment */) {')).toBe(true); + }); }); diff --git a/ui/frontend/selectors/index.ts b/ui/frontend/selectors/index.ts index 462e1676a..0fcfa92f6 100644 --- a/ui/frontend/selectors/index.ts +++ b/ui/frontend/selectors/index.ts @@ -20,7 +20,15 @@ export const selectionSelector = (state: State) => state.selection; const HAS_TESTS_RE = /^\s*#\s*\[\s*test\s*([^"]*)]/m; export const hasTestsSelector = createSelector(codeSelector, code => !!code.match(HAS_TESTS_RE)); -const HAS_MAIN_FUNCTION_RE = /^\s*(pub\s+)?\s*(const\s+)?\s*(async\s+)?\s*fn\s+main\s*\(\s*\)/m; +// https://stackoverflow.com/a/34755045/155423 +const HAS_MAIN_FUNCTION_RE = new RegExp( + [ + /^([^\n\r\/]*;)?/, + /\s*(pub\s+)?\s*(const\s+)?\s*(async\s+)?\s*/, + /fn\s+main\s*\(\s*(\/\*.*\*\/)?\s*\)/, + ].map((r) => r.source).join(''), + 'm' +); export const hasMainFunctionSelector = createSelector(codeSelector, code => !!code.match(HAS_MAIN_FUNCTION_RE)); const CRATE_TYPE_RE = /^\s*#!\s*\[\s*crate_type\s*=\s*"([^"]*)"\s*]/m;