Skip to content

Commit 6df1739

Browse files
committed
Ignore sourcing like statements in heredoc and raw strings
1 parent e72c667 commit 6df1739

File tree

3 files changed

+69
-18
lines changed

3 files changed

+69
-18
lines changed

Diff for: server/src/analyser.ts

+1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ export default class Analyzer {
360360
fileContent: contents,
361361
fileUri: uri,
362362
rootPath: this.workspaceFolder,
363+
tree,
363364
})
364365

365366
const problems: LSP.Diagnostic[] = []

Diff for: server/src/util/__tests__/sourcing.test.ts

+43-9
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
1+
import * as fs from 'fs'
12
import * as os from 'os'
3+
import * as Parser from 'web-tree-sitter'
24

5+
import { initializeParser } from '../../parser'
36
import { getSourcedUris } from '../sourcing'
47

58
const fileDirectory = '/Users/bash'
69
const fileUri = `${fileDirectory}/file.sh`
710

8-
// mock fs.existsSync to always return true
9-
jest.mock('fs', () => ({
10-
existsSync: () => true,
11-
}))
11+
let parser: Parser
12+
beforeAll(async () => {
13+
parser = await initializeParser()
14+
})
15+
16+
jest.spyOn(fs, 'existsSync').mockImplementation(() => true)
1217

1318
// mock os.homedir() to return a fixed path
1419
jest.spyOn(os, 'homedir').mockImplementation(() => '/Users/bash-user')
1520

1621
describe('getSourcedUris', () => {
1722
it('returns an empty set if no files were sourced', () => {
18-
const result = getSourcedUris({ fileContent: '', fileUri, rootPath: null })
23+
const fileContent = ''
24+
const result = getSourcedUris({
25+
fileContent,
26+
fileUri,
27+
rootPath: null,
28+
tree: parser.parse(fileContent),
29+
})
1930
expect(result).toEqual(new Set([]))
2031
})
2132

2233
it('returns a set of sourced files', () => {
23-
const result = getSourcedUris({
24-
fileContent: `
25-
34+
const fileContent = `
2635
source file-in-path.sh # does not contain a slash (i.e. is maybe somewhere on the path)
2736
2837
source /bin/extension.inc # absolute path
@@ -41,9 +50,34 @@ describe('getSourcedUris', () => {
4150
4251
# conditional is currently not supported
4352
if [[ -z $__COMPLETION_LIB_LOADED ]]; then source "$LIBPATH" ; fi
44-
`,
53+
54+
show ()
55+
{
56+
about 'Shows SVN proxy settings'
57+
group 'proxy'
58+
59+
echo "SVN Proxy Settings"
60+
echo "=================="
61+
python2 - <<END
62+
import ConfigParser
63+
source ./this-should-be-ignored.sh
64+
END
65+
}
66+
67+
cat $f | python -c '
68+
import sys
69+
source also-ignore.sh
70+
' | sort > $counts_file
71+
fi
72+
done
73+
74+
`
75+
76+
const result = getSourcedUris({
77+
fileContent,
4578
fileUri,
4679
rootPath: null,
80+
tree: parser.parse(fileContent),
4781
})
4882

4983
expect(result).toMatchInlineSnapshot(`

Diff for: server/src/util/sourcing.ts

+25-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import * as Parser from 'web-tree-sitter'
66
import { untildify } from './fs'
77

88
// Until the grammar supports sourcing, we use this little regular expression
9-
const SOURCED_FILES_REG_EXP = /^(?:\t|[ ])*(?:source|[.])\s*(\S*)/gm
9+
const SOURCING_STATEMENTS = /^(?:\t|[ ])*(?:source|[.])\s*(\S*)/
10+
const SOURCING_COMMANDS = ['source', '.']
1011

1112
/**
1213
* Analysis the given file content and returns a set of URIs that are
@@ -16,22 +17,37 @@ export function getSourcedUris({
1617
fileContent,
1718
fileUri,
1819
rootPath,
20+
tree,
1921
}: {
2022
fileContent: string
2123
fileUri: string
2224
rootPath: string | null
25+
tree: Parser.Tree
2326
}): Set<string> {
2427
const uris: Set<string> = new Set([])
25-
let match: RegExpExecArray | null
2628
const rootPaths = [path.dirname(fileUri), rootPath].filter(Boolean) as string[]
2729

28-
while ((match = SOURCED_FILES_REG_EXP.exec(fileContent)) !== null) {
29-
const word = match[1]
30-
const sourcedUri = getSourcedUri({ rootPaths, word })
31-
if (sourcedUri) {
32-
uris.add(sourcedUri)
30+
fileContent.split(/\r?\n/).forEach((line, lineIndex) => {
31+
const match = line.match(SOURCING_STATEMENTS)
32+
if (match) {
33+
const [statement, word] = match
34+
35+
if (tree.rootNode) {
36+
const node = tree.rootNode.descendantForPosition({
37+
row: lineIndex,
38+
column: statement.length - 2,
39+
})
40+
if (['heredoc_body', 'raw_string'].includes(node?.type)) {
41+
return
42+
}
43+
}
44+
45+
const sourcedUri = getSourcedUri({ rootPaths, word })
46+
if (sourcedUri) {
47+
uris.add(sourcedUri)
48+
}
3349
}
34-
}
50+
})
3551

3652
return uris
3753
}
@@ -67,7 +83,7 @@ export function getSourcedLocation({
6783
}
6884

6985
const isSourced = node.previousNamedSibling
70-
? ['.', 'source'].includes(node.previousNamedSibling.text.trim())
86+
? SOURCING_COMMANDS.includes(node.previousNamedSibling.text.trim())
7187
: false
7288

7389
const rootPaths = [path.dirname(uri), rootPath].filter(Boolean) as string[]

0 commit comments

Comments
 (0)