• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokucommunity / brighterscript / #13117

01 Oct 2024 08:24AM UTC coverage: 86.842% (-1.4%) from 88.193%
#13117

push

web-flow
Merge abd960cd5 into 3a2dc7282

11537 of 14048 branches covered (82.13%)

Branch coverage included in aggregate %.

6991 of 7582 new or added lines in 100 files covered. (92.21%)

83 existing lines in 18 files now uncovered.

12692 of 13852 relevant lines covered (91.63%)

29478.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.07
/src/bscPlugin/SignatureHelpUtil.ts
1
import { ParameterInformation, SignatureInformation } from 'vscode-languageserver-protocol';
1✔
2
import { isClassStatement, isXmlScope, isFunctionStatement, isMethodStatement } from '../astUtils/reflection';
1✔
3
import { TokenKind } from '../lexer/TokenKind';
1✔
4
import type { Statement } from '../parser/AstNode';
5
import { ParseMode } from '../parser/Parser';
1✔
6
import type { ClassStatement } from '../parser/Statement';
7
import type { SignatureInfoObj } from '../Program';
8
import type { XmlScope } from '../XmlScope';
9
import type { CallExpressionInfo } from './CallExpressionInfo';
10
import { CallExpressionType } from './CallExpressionInfo';
1✔
11
import type { FileLink } from '../interfaces';
12
import { util } from '../util';
1✔
13

14
export class SignatureHelpUtil {
1✔
15
    getSignatureHelpItems(callExpressionInfo: CallExpressionInfo): SignatureInfoObj[] {
16
        let signatureHelpItems = [];
182✔
17
        let file = callExpressionInfo.file;
182✔
18
        let dotPart = callExpressionInfo.dotPart;
182✔
19
        let name = callExpressionInfo.name;
182✔
20
        let results = new Map<string, SignatureInfoObj>();
182✔
21

22
        switch (callExpressionInfo.type) {
182✔
23
            case CallExpressionType.namespaceCall:
182!
24
                signatureHelpItems = file.program.getStatementsByName(name, file, dotPart).map((fileLink) => this.getSignatureHelpForStatement(fileLink, dotPart));
2✔
25
                break;
2✔
26

27
            case CallExpressionType.myClassCall:
28
                let statement = file.getClassMethod(callExpressionInfo.myClass, name, true);
71✔
29
                if (statement) {
71!
30
                    signatureHelpItems = [this.getSignatureHelpForStatement({ item: statement, file: file })];
71✔
31
                }
32
                break;
71✔
33

34
            case CallExpressionType.otherClassCall:
35
                signatureHelpItems = file.program.getStatementsByName(name, file).filter((fileLink) => isClassStatement(fileLink.item.parent)).map((fileLink) => this.getSignatureHelpForStatement(fileLink));
×
36
                break;
×
37

38
            case CallExpressionType.callFunc:
39
                // must be from some call func interface method
40
                signatureHelpItems = [];
1✔
41
                for (const scope of file.program.getScopes().filter((s) => isXmlScope(s))) {
3✔
42
                    signatureHelpItems.push(...file.program.getStatementsForXmlFile(scope as XmlScope, name).map((fileLink) => this.getSignatureHelpForStatement(fileLink)));
1✔
43
                }
44
                break;
1✔
45

46
            case CallExpressionType.call:
47
                signatureHelpItems = file.program.getStatementsByName(name, file).map((fileLink) => this.getSignatureHelpForStatement(fileLink));
37✔
48
                break;
37✔
49
            case CallExpressionType.constructorCall:
50
                let classItem = file.getClassFileLink(dotPart ? `${dotPart}.${name}` : name);
61✔
51
                let constructorSignatureHelp = this.getClassSignatureHelp(classItem);
61✔
52
                if (constructorSignatureHelp) {
61!
53
                    signatureHelpItems.push(constructorSignatureHelp);
61✔
54
                }
55
                break;
61✔
56
            default:
57
        }
58

59
        for (let sigHelp of signatureHelpItems) {
182✔
60
            if (!results.has[sigHelp.key]) {
169!
61
                sigHelp.index = callExpressionInfo.parameterIndex;
169✔
62
                results.set(sigHelp.key, sigHelp);
169✔
63
            }
64
        }
65

66
        return [...results.values()];
182✔
67

68
    }
69

70
    public getSignatureHelpForStatement(fileLink: FileLink<Statement>, namespaceName?: string): SignatureInfoObj {
71
        let statement = fileLink.item;
168✔
72
        let file = fileLink.file;
168✔
73

74
        if (!isFunctionStatement(statement) && !isMethodStatement(statement)) {
168!
75
            return undefined;
×
76
        }
77
        const func = statement.func;
168✔
78
        const funcStartPosition = func.location?.range.start;
168!
79

80
        // Get function comments in reverse order
81
        const trivia = util.concatAnnotationLeadingTrivia(func).reverse();
168✔
82
        let functionComments = [] as string[];
168✔
83

84
        for (const currentToken of trivia) {
168✔
85
            if (!currentToken) {
380!
UNCOV
86
                break;
×
87
            }
88
            if (currentToken.location?.range.start.line + 1 < funcStartPosition.line) {
380!
89
                if (functionComments.length === 0) {
46✔
90
                    break;
36✔
91
                }
92
            }
93

94
            const kind = currentToken.kind;
344✔
95
            if (kind === TokenKind.Comment) {
344✔
96
                // Strip off common leading characters to make it easier to read
97
                const commentText = currentToken.text.replace(/^[' *\/]+/, '');
4✔
98
                functionComments.unshift(commentText);
4✔
99
            } else if (kind === TokenKind.Newline) {
340✔
100
                if (functionComments.length === 0) {
168✔
101
                    continue;
164✔
102
                }
103
                // if we already had a new line as the last token then exit out
104
                if (functionComments[0] === currentToken.text) {
4!
105
                    break;
×
106
                }
107
                functionComments.unshift(currentToken.text);
4✔
108
            } else if (kind === TokenKind.Whitespace) {
172!
109
            } else {
UNCOV
110
                break;
×
111
            }
112
        }
113

114
        const documentation = functionComments.join('').trim();
168✔
115

116
        const lines = util.splitIntoLines(file.fileContents);
168✔
117
        let key = statement.tokens.name.text + documentation;
168✔
118
        const params = [] as ParameterInformation[];
168✔
119
        for (const param of func.parameters) {
168✔
120
            params.push(ParameterInformation.create(param.tokens.name.text));
445✔
121
            key += param.tokens.name.text;
445✔
122
        }
123

124
        let label = util.getTextForRange(lines, util.createRangeFromPositions(func.tokens.functionType?.location?.range.start, func.body.location?.range.start)).trim();
168!
125
        if (namespaceName) {
168✔
126
            label = label.replace(/^(sub | function )/gim, `$1${namespaceName}.`);
2✔
127
        }
128
        const signature = SignatureInformation.create(label, documentation, ...params);
168✔
129
        const index = 1;
168✔
130
        return { key: key, signature: signature, index: index };
168✔
131
    }
132

133
    public getClassSignatureHelp(fileLink: FileLink<ClassStatement>): SignatureInfoObj | undefined {
134
        let file = fileLink.file;
61✔
135
        let classStatement = fileLink.item;
61✔
136

137
        const classConstructor = file.getClassMethod(classStatement, 'new');
61✔
138
        let sigHelp = classConstructor ? this.getSignatureHelpForStatement({ item: classConstructor, file: file }) : undefined;
61✔
139
        let className = classStatement.getName(ParseMode.BrighterScript);
61✔
140
        if (sigHelp) {
61✔
141
            sigHelp.key = className;
60✔
142
            sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
60✔
143
        } else {
144
            sigHelp = {
1✔
145
                key: className,
146
                signature: SignatureInformation.create(`${className}()`, ''),
147
                index: 0
148
            };
149
        }
150
        return sigHelp;
61✔
151
    }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc