Coverage Report

Created: 2023-09-25 07:10

/src/jsonnet/core/static_analysis.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
Copyright 2015 Google Inc. All rights reserved.
3
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
    http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
#include <set>
18
19
#include "ast.h"
20
#include "static_analysis.h"
21
#include "static_error.h"
22
23
namespace jsonnet::internal {
24
25
typedef std::set<const Identifier *> IdSet;
26
27
/** Inserts all of s into r. */
28
static void append(IdSet &r, const IdSet &s)
29
616M
{
30
616M
    r.insert(s.begin(), s.end());
31
616M
}
32
33
/** Statically analyse the given ast.
34
 *
35
 * \param ast_ The AST.
36
 * \param in_object Whether or not ast_ is within the lexical scope of an object AST.
37
 * \param vars The variables defined within lexical scope of ast_.
38
 * \returns The free variables in ast_.
39
 */
40
static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars)
41
563M
{
42
563M
    IdSet r;
43
44
563M
    switch (ast_->type) {
45
50.5M
    case AST_APPLY: {
46
50.5M
        assert(dynamic_cast<Apply *>(ast_));
47
0
        auto* ast = static_cast<Apply *>(ast_);
48
50.5M
        append(r, static_analysis(ast->target, in_object, vars));
49
50.5M
        for (const auto &arg : ast->args)
50
83.3M
            append(r, static_analysis(arg.expr, in_object, vars));
51
50.5M
    } break;
52
0
    case AST_APPLY_BRACE: {
53
0
        assert(dynamic_cast<ApplyBrace *>(ast_));
54
        // Nothing to do.
55
0
    } break;
56
11.5M
    case AST_ARRAY: {
57
11.5M
        assert(dynamic_cast<Array *>(ast_));
58
0
        auto* ast = static_cast<Array *>(ast_);
59
11.5M
        for (auto &el : ast->elements)
60
19.1M
            append(r, static_analysis(el.expr, in_object, vars));
61
11.5M
    } break;
62
51.0M
    case AST_BINARY: {
63
51.0M
        assert(dynamic_cast<Binary *>(ast_));
64
0
        auto* ast = static_cast<Binary *>(ast_);
65
51.0M
        append(r, static_analysis(ast->left, in_object, vars));
66
51.0M
        append(r, static_analysis(ast->right, in_object, vars));
67
51.0M
    } break;
68
717k
    case AST_BUILTIN_FUNCTION: {
69
717k
        assert(dynamic_cast<BuiltinFunction *>(ast_));
70
        // Nothing to do.
71
717k
    } break;
72
20.7M
    case AST_CONDITIONAL: {
73
20.7M
        assert(dynamic_cast<Conditional *>(ast_));
74
0
        auto* ast = static_cast<Conditional *>(ast_);
75
20.7M
        append(r, static_analysis(ast->cond, in_object, vars));
76
20.7M
        append(r, static_analysis(ast->branchTrue, in_object, vars));
77
20.7M
        append(r, static_analysis(ast->branchFalse, in_object, vars));
78
20.7M
    } break;
79
10.9M
    case AST_ERROR: {
80
10.9M
        assert(dynamic_cast<Error *>(ast_));
81
0
        auto* ast = static_cast<Error *>(ast_);
82
10.9M
        append(r, static_analysis(ast->expr, in_object, vars));
83
10.9M
    } break;
84
12.7M
    case AST_FUNCTION: {
85
12.7M
        assert(dynamic_cast<Function *>(ast_));
86
0
        auto* ast = static_cast<Function *>(ast_);
87
12.7M
        auto new_vars = vars;
88
12.7M
        IdSet params;
89
23.3M
        for (const auto &p : ast->params) {
90
23.3M
            if (params.find(p.id) != params.end()) {
91
43
                std::string msg = "Duplicate function parameter: " + encode_utf8(p.id->name);
92
43
                throw StaticError(ast_->location, msg);
93
43
            }
94
23.3M
            params.insert(p.id);
95
23.3M
            new_vars.insert(p.id);
96
23.3M
        }
97
98
12.7M
        auto fv = static_analysis(ast->body, in_object, new_vars);
99
23.3M
        for (const auto &p : ast->params) {
100
23.3M
            if (p.expr != nullptr)
101
392k
                append(fv, static_analysis(p.expr, in_object, new_vars));
102
23.3M
        }
103
12.7M
        for (const auto &p : ast->params)
104
23.3M
            fv.erase(p.id);
105
12.7M
        append(r, fv);
106
12.7M
    } break;
107
850
    case AST_IMPORT: {
108
850
        assert(dynamic_cast<Import *>(ast_));
109
        // Nothing to do.
110
850
    } break;
111
650
    case AST_IMPORTSTR: {
112
650
        assert(dynamic_cast<Importstr *>(ast_));
113
        // Nothing to do.
114
650
    } break;
115
559
    case AST_IMPORTBIN: {
116
559
        assert(dynamic_cast<Importbin *>(ast_));
117
        // Nothing to do.
118
559
    } break;
119
204k
    case AST_IN_SUPER: {
120
204k
        assert(dynamic_cast<const InSuper *>(ast_));
121
0
        auto* ast = static_cast<const InSuper *>(ast_);
122
204k
        if (!in_object)
123
15
            throw StaticError(ast_->location, "Can't use super outside of an object.");
124
204k
        append(r, static_analysis(ast->element, in_object, vars));
125
204k
    } break;
126
55.1M
    case AST_INDEX: {
127
55.1M
        assert(dynamic_cast<const Index *>(ast_));
128
0
        auto* ast = static_cast<const Index *>(ast_);
129
55.1M
        append(r, static_analysis(ast->target, in_object, vars));
130
55.1M
        append(r, static_analysis(ast->index, in_object, vars));
131
55.1M
    } break;
132
26.7M
    case AST_LOCAL: {
133
26.7M
        assert(dynamic_cast<const Local *>(ast_));
134
0
        auto* ast = static_cast<const Local *>(ast_);
135
26.7M
        IdSet ast_vars;
136
44.7M
        for (const auto &bind : ast->binds) {
137
44.7M
            ast_vars.insert(bind.var);
138
44.7M
        }
139
26.7M
        auto new_vars = vars;
140
26.7M
        append(new_vars, ast_vars);
141
26.7M
        IdSet fvs;
142
44.6M
        for (const auto &bind : ast->binds) {
143
44.6M
            append(fvs, static_analysis(bind.body, in_object, new_vars));
144
44.6M
        }
145
146
26.7M
        append(fvs, static_analysis(ast->body, in_object, new_vars));
147
148
26.7M
        for (const auto &bind : ast->binds)
149
44.5M
            fvs.erase(bind.var);
150
151
26.7M
        append(r, fvs);
152
26.7M
    } break;
153
1.74M
    case AST_LITERAL_BOOLEAN: {
154
1.74M
        assert(dynamic_cast<const LiteralBoolean *>(ast_));
155
        // Nothing to do.
156
1.74M
    } break;
157
39.1M
    case AST_LITERAL_NUMBER: {
158
39.1M
        assert(dynamic_cast<const LiteralNumber *>(ast_));
159
        // Nothing to do.
160
39.1M
    } break;
161
98.3M
    case AST_LITERAL_STRING: {
162
98.3M
        assert(dynamic_cast<const LiteralString *>(ast_));
163
        // Nothing to do.
164
98.3M
    } break;
165
923k
    case AST_LITERAL_NULL: {
166
923k
        assert(dynamic_cast<const LiteralNull *>(ast_));
167
        // Nothing to do.
168
923k
    } break;
169
3.58M
    case AST_DESUGARED_OBJECT: {
170
3.58M
        assert(dynamic_cast<DesugaredObject *>(ast_));
171
0
        auto* ast = static_cast<DesugaredObject *>(ast_);
172
15.4M
        for (auto &field : ast->fields) {
173
15.4M
            append(r, static_analysis(field.name, in_object, vars));
174
15.4M
            append(r, static_analysis(field.body, true, vars));
175
15.4M
        }
176
3.58M
        for (AST *assert : ast->asserts) {
177
255k
            append(r, static_analysis(assert, true, vars));
178
255k
        }
179
3.58M
    } break;
180
2.15M
    case AST_OBJECT_COMPREHENSION_SIMPLE: {
181
2.15M
        assert(dynamic_cast<ObjectComprehensionSimple *>(ast_));
182
0
        auto* ast = static_cast<ObjectComprehensionSimple *>(ast_);
183
2.15M
        auto new_vars = vars;
184
2.15M
        new_vars.insert(ast->id);
185
2.15M
        append(r, static_analysis(ast->field, false, new_vars));
186
2.15M
        append(r, static_analysis(ast->value, true, new_vars));
187
2.15M
        r.erase(ast->id);
188
2.15M
        append(r, static_analysis(ast->array, in_object, vars));
189
2.15M
    } break;
190
4.50M
    case AST_SELF: {
191
4.50M
        assert(dynamic_cast<const Self *>(ast_));
192
4.50M
        if (!in_object)
193
6
            throw StaticError(ast_->location, "Can't use self outside of an object.");
194
4.50M
    } break;
195
4.50M
    case AST_SUPER_INDEX: {
196
201k
        assert(dynamic_cast<const SuperIndex *>(ast_));
197
0
        auto* ast = static_cast<const SuperIndex *>(ast_);
198
201k
        if (!in_object)
199
26
            throw StaticError(ast_->location, "Can't use super outside of an object.");
200
201k
        append(r, static_analysis(ast->index, in_object, vars));
201
201k
    } break;
202
1.72M
    case AST_UNARY: {
203
1.72M
        assert(dynamic_cast<const Unary *>(ast_));
204
0
        auto* ast = static_cast<const Unary *>(ast_);
205
1.72M
        append(r, static_analysis(ast->expr, in_object, vars));
206
1.72M
    } break;
207
170M
    case AST_VAR: {
208
170M
        assert(dynamic_cast<const Var *>(ast_));
209
0
        auto* ast = static_cast<const Var *>(ast_);
210
170M
        if (vars.find(ast->id) == vars.end()) {
211
1.84k
            throw StaticError(ast->location, "Unknown variable: " + encode_utf8(ast->id->name));
212
1.84k
        }
213
170M
        r.insert(ast->id);
214
170M
    } break;
215
0
    default:
216
0
        std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl;
217
0
        std::abort();
218
0
        break;
219
563M
    }
220
221
562M
    for (auto *id : r)
222
737M
        ast_->freeVariables.push_back(id);
223
224
562M
    return r;
225
563M
}
226
227
void jsonnet_static_analysis(AST *ast)
228
18.3k
{
229
18.3k
    static_analysis(ast, false, IdSet{});
230
18.3k
}
231
232
}  // namespace jsonnet::internal