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

rokucommunity / brighterscript / #13125

01 Oct 2024 02:12PM UTC coverage: 86.842% (-1.4%) from 88.193%
#13125

push

web-flow
Merge d4a9e5fff into 3a2dc7282

11554 of 14068 branches covered (82.13%)

Branch coverage included in aggregate %.

7000 of 7592 new or added lines in 100 files covered. (92.2%)

83 existing lines in 18 files now uncovered.

12701 of 13862 relevant lines covered (91.62%)

29529.09 hits per line

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

90.38
/src/bscPlugin/CallExpressionInfo.ts
1
import type { Expression } from '../parser/AstNode';
2
import type { CallExpression, CallfuncExpression, NewExpression, VariableExpression } from '../parser/Expression';
3
import type { ClassStatement } from '../parser/Statement';
4
import { isCallExpression, isCallfuncExpression, isVariableExpression, isDottedGetExpression, isClassStatement, isNewExpression } from '../astUtils/reflection';
1✔
5
import type { BrsFile } from '../files/BrsFile';
6
import type { Position } from 'vscode-languageserver-protocol';
7
import { util } from '../util';
1✔
8
import { ParseMode } from '../parser/Parser';
1✔
9
import type { NamespaceContainer } from '../interfaces';
10

11

12
export enum CallExpressionType {
1✔
13
    namespaceCall = 'namespaceCall',
1✔
14
    call = 'call',
1✔
15
    callFunc = 'callFunc',
1✔
16
    constructorCall = 'constructorCall',
1✔
17
    myClassCall = 'myClassCall',
1✔
18
    otherClassCall = 'otherClassCall',
1✔
19
    unknown = 'unknown'
1✔
20
}
21

22
//Util Class, for extracting info about an expression, which can be used in the IDE
23
export class CallExpressionInfo {
1✔
24
    //the expression that we asked about
25
    expression?: Expression;
26

27
    //the contextually relevant callExpression, which relates to it
28
    callExpression?: CallExpression | CallfuncExpression;
29
    type: CallExpressionType;
30

31
    file: BrsFile;
32
    myClass: ClassStatement;
33
    namespace?: NamespaceContainer;
34
    dotPart: string;
35
    name: string;
36
    isCallingMethodOnMyClass: boolean;
37
    newExpression: NewExpression;
38

39
    //the index of expression, when considered as a param fo callExpression
40
    parameterIndex: number;
41

42
    private position: Position;
43

44
    constructor(file: BrsFile, position: Position) {
45
        this.expression = file.ast.findChildAtPosition<Expression>(position);
182✔
46
        this.file = file;
182✔
47
        this.position = position;
182✔
48
        this.process();
182✔
49
    }
50

51
    private process() {
52

53
        this.callExpression = this.ascertainCallExpression();
182✔
54
        let callExpression = this.callExpression;
182✔
55
        if (!callExpression) {
182✔
56
            this.type = CallExpressionType.unknown;
10✔
57
            return;
10✔
58
        }
59

60
        if (!this.isPositionBetweenParentheses()) {
172!
61
            return;
×
62
        }
63
        this.isCallingMethodOnMyClass = false;
172✔
64

65
        if (isNewExpression(callExpression.parent)) {
172✔
66
            this.name = callExpression.parent.className.getName(ParseMode.BrighterScript);
61✔
67
            this.newExpression = callExpression.parent;
61✔
68
        }
69
        if (isCallfuncExpression(callExpression)) {
172✔
70
            this.name = callExpression.tokens.methodName.text;
1✔
71
        } else if (isVariableExpression(callExpression.callee)) {
171✔
72
            this.name = callExpression.callee.tokens.name.text;
73✔
73
        } else if (isVariableExpression(callExpression)) {
98!
NEW
74
            this.name = (callExpression as VariableExpression).tokens.name.text;
×
75
        } else if (isDottedGetExpression(callExpression.callee)) {
98!
76
            this.name = callExpression.callee.tokens.name.text;
98✔
77
            if (isDottedGetExpression(callExpression.callee) && isVariableExpression(callExpression.callee.obj)) {
98✔
78
                this.isCallingMethodOnMyClass = callExpression.callee.obj.tokens.name.text === 'm';
75✔
79

80
            } else {
81
                let parts = util.getAllDottedGetParts(callExpression.callee);
23✔
82
                if (parts) {
23!
83
                    parts.splice(parts?.length - 1, 1);
23!
84
                    this.dotPart = parts.map(x => x.text).join('.');
46✔
85
                    this.namespace = this.getNamespace();
23✔
86
                }
87
            }
88
        }
89

90
        this.myClass = this.expression.findAncestor<ClassStatement>(isClassStatement);
172✔
91
        this.type = this.ascertainType();
172✔
92
        this.parameterIndex = this.getParameterIndex();
172✔
93
    }
94

95
    isPositionBetweenParentheses() {
96
        let boundingRange = util.createBoundingRange(this.callExpression.tokens.openingParen?.location, this.callExpression.tokens.closingParen?.location);
172!
97
        return util.rangeContains(boundingRange, this.position);
172✔
98
    }
99

100
    ascertainCallExpression(): CallExpression | CallfuncExpression {
101
        let expression = this.expression;
182✔
102
        function isCallFuncOrCallExpression(expression: Expression) {
103
            return isCallfuncExpression(expression) || isCallExpression(expression);
477✔
104
        }
105

106
        let callExpression = expression?.findAncestor<CallExpression | CallfuncExpression>(isCallFuncOrCallExpression);
182!
107
        if (callExpression && callExpression.callee === expression) {
182✔
108
            //this expression is the NAME of a CallExpression
109
            callExpression = expression.parent.findAncestor<CallExpression | CallfuncExpression>(isCallFuncOrCallExpression);
30✔
110
        } else if (isDottedGetExpression(expression.parent) && expression.parent.parent === callExpression) {
152✔
111
            callExpression = callExpression.findAncestor<CallExpression | CallfuncExpression>(isCallFuncOrCallExpression);
6✔
112
        }
113

114
        if (!callExpression && isCallExpression(expression)) {
182✔
115
            //let's check to see if we are in a space, in the args of a valid CallExpression
116
            let boundingRange = util.createBoundingRange(expression.tokens.openingParen, expression.tokens.closingParen);
39✔
117
            if (util.rangeContains(boundingRange, this.position)) {
39!
118
                callExpression = expression;
39✔
119
            }
120
        }
121

122
        return callExpression;
182✔
123
    }
124

125
    ascertainType(): CallExpressionType {
126
        if (this.name) {
172!
127
            //General case, for function calls
128
            if (this.newExpression) {
172✔
129
                return CallExpressionType.constructorCall;
61✔
130
            } else if (this.isCallingMethodOnMyClass && this.myClass) {
111✔
131
                return CallExpressionType.myClassCall;
71✔
132
            } else if (!this.namespace && isDottedGetExpression(this.callExpression)) {
40!
133
                return CallExpressionType.otherClassCall;
×
134
            } else if (isCallfuncExpression(this.callExpression)) {
40✔
135
                return CallExpressionType.callFunc;
1✔
136

137
            } else if (this.namespace) {
39✔
138
                return CallExpressionType.namespaceCall;
2✔
139
            } else {
140
                return CallExpressionType.call;
37✔
141
            }
142
        }
143

144
        return CallExpressionType.unknown;
×
145

146
    }
147

148
    private getNamespace(): NamespaceContainer {
149
        let scope = this.file.program.getFirstScopeForFile(this.file);
23✔
150
        return scope.namespaceLookup.get(this.dotPart);
23✔
151
    }
152

153
    private getParameterIndex() {
154
        for (let i = this.callExpression.args.length - 1; i > -1; i--) {
172✔
155
            let argExpression = this.callExpression.args[i];
326✔
156
            let comparison = util.comparePositionToRange(this.position, argExpression.location?.range);
326!
157
            if (comparison >= 0) {
326✔
158
                return i + comparison;
168✔
159
            }
160
        }
161

162
        return 0;
4✔
163

164
    }
165

166
}
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