Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 85.6% 279 / 0 / 326
Functions: -% 0 / 1 / 1
Branches: 60.0% 60 / 0 / 100

OMCompiler/Compiler/FrontEnd/NFSCodeDependency.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package NFSCodeDependency
37 " file: NFSCodeDependency.mo
38 package: NFSCodeDependency
39 description: SCode dependency analysis.
40
41
42 Dependency analysis for SCode.
43 "
44
45 public import Absyn;
46 public import AbsynUtil;
47 public import SCode;
48 public import NFInstPrefix;
49 public import NFSCodeEnv;
50
51 public type Env = NFSCodeEnv.Env;
52
53 protected import Config;
54 protected import Debug;
55 protected import Error;
56 protected import ErrorTypes;
57 protected import Flags;
58 protected import List;
59 protected import Mutable;
60 protected import NFSCodeCheck;
61 protected import NFSCodeFlattenRedeclare;
62 protected import NFSCodeLookup;
63 protected import SCodeDump;
64 import SCodeUtil;
65 protected import System;
66 protected import Util;
67
68 protected type Item = NFSCodeEnv.Item;
69 protected type Extends = NFSCodeEnv.Extends;
70 protected type FrameType = NFSCodeEnv.FrameType;
71 protected type Import = Absyn.Import;
72 protected import NFSCodeEnv.EnvTree;
73
74 public function analyse
75 "This is the entry point of the dependency analysis. The dependency analysis
76 is done in three steps: first it analyses the program and marks each element in
77 the program that's used. The it goes through the used classes and checks if
78 they contain any class extends, and if so it checks of those class extends are
79 used or not. Finally it collects the used elements and builds a new program
80 and environment that only contains those elements."
81 input Absyn.Path inClassName;
82 input Env inEnv;
83 input SCode.Program inProgram;
84 output SCode.Program outProgram;
85 output Env outEnv;
86 algorithm
87 1101 analyseClass(inClassName, inEnv, Absyn.dummyInfo);
88 1088 analyseClassExtends(inEnv);
89 1088 (outEnv, outProgram) :=
90 collectUsedProgram(inEnv, inProgram, inClassName);
91 end analyse;
92
93 protected function analyseClass
94 "Analyses a class by looking up the class, marking it as used and recursively
95 analysing it's contents."
96 input Absyn.Path inClassName;
97 input Env inEnv;
98 input SourceInfo inInfo;
99 algorithm
100 () := matchcontinue inInfo
101 local
102 Item item;
103 Env env;
104
105 case _
106 algorithm
107 63557 (item, env) := lookupClass(inClassName, inEnv, true, inInfo,
108 SOME(Error.LOOKUP_ERROR));
109 63555 checkItemIsClass(item);
110 63553 analyseItem(item, env);
111 then
112 ();
113
114 else
115 algorithm
116
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 true := Flags.isSet(Flags.FAILTRACE);
117 ✗ Debug.traceln("- NFSCodeDependency.analyseClass failed for " +
118 AbsynUtil.pathString(inClassName) + " in " +
119 NFSCodeEnv.getEnvName(inEnv));
120 ✗ then
121 fail();
122
123 end matchcontinue;
124 end analyseClass;
125
126 protected function lookupClass
127 "Lookup a class in the environment. The reason why SCodeLookup is not used
128 directly is because we need to look up each part of the class path and mark
129 them as used."
130 input Absyn.Path inPath;
131 input Env inEnv;
132 input Boolean inBuiltinPossible "True if the path can be a builtin, otherwise false.";
133 input SourceInfo inInfo;
134 input Option<ErrorTypes.Message> inErrorType;
135 output Item outItem;
136 output Env outEnv;
137 algorithm
138 (outItem, outEnv) := matchcontinue inErrorType
139 local
140 Item item;
141 Env env;
142 String name_str, env_str;
143 ErrorTypes.Message error_id;
144
145 case _
146 algorithm
147 586814 (item, env) := lookupClass2(inPath, inEnv, inBuiltinPossible, inInfo, inErrorType);
148 584951 (item, env, _) := NFSCodeEnv.resolveRedeclaredItem(item, env);
149
1/2
✓ Branch 0 taken 584951 times.
✗ Branch 1 not taken.
584951 then
150 (item, env);
151
152 case SOME(error_id)
153 algorithm
154 2 name_str := AbsynUtil.pathString(inPath);
155 2 env_str := NFSCodeEnv.getEnvName(inEnv);
156 2 Error.addSourceMessage(error_id, {name_str, env_str}, inInfo);
157 2 then
158 fail();
159 end matchcontinue;
160 end lookupClass;
161
162 protected function lookupClass2
163 "Help function to lookupClass, does the actual look up."
164 input Absyn.Path inPath;
165 input Env inEnv;
166 input Boolean inBuiltinPossible;
167 input SourceInfo inInfo;
168 input Option<ErrorTypes.Message> inErrorType;
169 output Item outItem;
170 output Env outEnv;
171 algorithm
172 (outItem, outEnv) := match(inPath, inEnv, inBuiltinPossible)
173 local
174 Item item;
175 Env env;
176 String id;
177 Absyn.Path rest_path;
178
179 case (Absyn.IDENT(), _, true)
180 algorithm
181 219325 (item, _, env) :=
182 NFSCodeLookup.lookupNameSilent(inPath, inEnv, inInfo);
183 218266 then
184 (item, env);
185
186 case (Absyn.IDENT(), _, false)
187 algorithm
188 136312 (item, _, env) :=
189 NFSCodeLookup.lookupNameSilentNoBuiltin(inPath, inEnv, inInfo);
190 135969 then
191 (item, env);
192
193 // Special case for the baseclass of a class extends. Should be looked up
194 // among the inherited elements of the enclosing class.
195 case (Absyn.QUALIFIED(name = "$ce", path = Absyn.IDENT(name = id)), _ :: env, _)
196 algorithm
197 563 (item, env) := NFSCodeLookup.lookupInheritedName(id, env);
198 then
199 (item, env);
200
201 case (Absyn.QUALIFIED(name = id, path = rest_path), _, _)
202 algorithm
203 230614 (item, _, env) :=
204 NFSCodeLookup.lookupNameSilent(Absyn.IDENT(id), inEnv, inInfo);
205 230496 (item, env, _) := NFSCodeEnv.resolveRedeclaredItem(item, env);
206 230496 analyseItem(item, env);
207 230496 (item, env) := lookupNameInItem(rest_path, item, env, inErrorType);
208 then
209 (item, env);
210
211 case (Absyn.FULLYQUALIFIED(path = rest_path), _, _)
212 algorithm
213 10446 env := NFSCodeEnv.getEnvTopScope(inEnv);
214 10446 (item, env) := lookupClass2(rest_path, env, false, inInfo, inErrorType);
215 then
216 (item, env);
217
218 end match;
219 end lookupClass2;
220
221 protected function lookupNameInItem
222 input Absyn.Path inName;
223 input Item inItem;
224 input Env inEnv;
225 input Option<ErrorTypes.Message> inErrorType;
226 output Item outItem;
227 output Env outEnv;
228 algorithm
229 (outItem, outEnv) := match(inItem, inEnv)
230 local
231 Absyn.Path type_path;
232 SCode.Mod mods;
233 SourceInfo info;
234 Env env, type_env;
235 NFSCodeEnv.Frame class_env;
236 list<NFSCodeEnv.Redeclaration> redeclares;
237 Item item;
238
239 511 case (_, {}) then (inItem, inEnv);
240
241 case (NFSCodeEnv.VAR(var = SCode.COMPONENT(typeSpec =
242 Absyn.TPATH(path = type_path), modifications = mods, info = info)), _)
243 algorithm
244 43484 (item, type_env) := lookupClass(type_path, inEnv, true, info, inErrorType);
245
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43484 times.
43484 true := NFSCodeEnv.isClassItem(item);
246 43484 redeclares := NFSCodeFlattenRedeclare.extractRedeclaresFromModifier(mods);
247 43484 (item, type_env, _) := NFSCodeFlattenRedeclare.replaceRedeclaredElementsInEnv(
248 redeclares, item, type_env, inEnv, NFInstPrefix.emptyPrefix);
249 43484 (item, env) := lookupNameInItem(inName, item, type_env, inErrorType);
250 then
251 (item, env);
252
253 case (NFSCodeEnv.CLASS(cls = SCode.CLASS(info = info), env = {class_env}), _)
254 algorithm
255 229985 env := NFSCodeEnv.enterFrame(class_env, inEnv);
256 229985 (item, env) := lookupClass(inName, env, false, info, inErrorType);
257 then
258 (item, env);
259
260 end match;
261 end lookupNameInItem;
262
263 protected function checkItemIsClass
264 "Checks that the found item really is a class, otherwise prints an error
265 message."
266 input Item inItem;
267 algorithm
268 () := match inItem
269 local
270 String name;
271 SourceInfo info;
272
273 case NFSCodeEnv.CLASS() then ();
274
275 // We found a component instead, which might happen if the user tries to use
276 // a variable name as a type.
277 case NFSCodeEnv.VAR(var = SCode.COMPONENT(name = name, info = info))
278 algorithm
279 2 Error.addSourceMessage(Error.LOOKUP_TYPE_FOUND_COMP, {name}, info);
280 2 then
281 fail();
282 end match;
283 end checkItemIsClass;
284
285 protected function analyseItem
286 "Analyses an item."
287 input Item inItem;
288 input Env inEnv;
289 algorithm
290 // Check if the item is already marked as used, then we can stop here.
291
2/2
✓ Branch 1 taken 484760 times.
✓ Branch 2 taken 105908 times.
590668 if NFSCodeEnv.isItemUsed(inItem) then
292 484760 return;
293 end if;
294 () := match(inItem, inEnv)
295 local
296 SCode.ClassDef cdef;
297 NFSCodeEnv.Frame cls_env;
298 Env env;
299 SourceInfo info;
300 SCode.Restriction res;
301 SCode.Element cls;
302 SCode.Comment cmt;
303
304 // A component, mark it and it's environment as used.
305 case (NFSCodeEnv.VAR(), env)
306 algorithm
307 55384 markItemAsUsed(inItem, env);
308 then
309 ();
310
311 // A basic type, nothing to be done.
312 case (NFSCodeEnv.CLASS(classType = NFSCodeEnv.BASIC_TYPE()), _) then ();
313
314 // A normal class, mark it and it's environment as used, and recursively
315 // analyse its contents.
316 case (NFSCodeEnv.CLASS(cls = cls as SCode.CLASS(classDef = cdef,
317 restriction = res, info = info, cmt = cmt), env = {cls_env}), env)
318 algorithm
319 20660 markItemAsUsed(inItem, env);
320 20660 env := NFSCodeEnv.enterFrame(cls_env, env);
321
4/4
✓ Branch 0 taken 980 times.
✓ Branch 1 taken 19680 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 946 times.
20660 if (if cls.name=="cardinality" then match inEnv case {NFSCodeEnv.FRAME(name=NONE())} then true; else false; end match else false) then
322 34 System.setUsesCardinality(true);
323 end if;
324 20660 analyseClassDef(cdef, res, env, false, info);
325 20647 analyseMetaType(res, env, info);
326 20647 analyseComment(cmt, env, info);
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20647 times.
20647 _ :: env := env;
328 20647 analyseRedeclaredClass(cls, env);
329 then
330 ();
331
332 else
333 algorithm
334 ✗ true := Flags.isSet(Flags.FAILTRACE);
335 ✗ Debug.traceln("- NFSCodeDependency.analyseItem failed on " +
336 NFSCodeEnv.getItemName(inItem) + " in " +
337 NFSCodeEnv.getEnvName(inEnv));
338 ✗ then
339 fail();
340
341 end match;
342 end analyseItem;
343
344 protected function analyseItemIfRedeclares
345 "Analyses an item again if there were some redeclares applied to the environment"
346 input NFSCodeFlattenRedeclare.Replacements inRepls;
347 input Item inItem;
348 input Env inEnv;
349 algorithm
350 () := match inRepls
351 local
352 Env env;
353 // no replacements happened on the environemnt! do nothing
354 case {} then ();
355 case _
356 algorithm
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 _::env := inEnv;
358 //i = NFSCodeEnv.setItemEnv(inItem, {cls_frm});
359 6 analyseItemNoStopOnUsed(inItem, env);
360 then ();
361 end match;
362 end analyseItemIfRedeclares;
363
364 protected function analyseItemNoStopOnUsed
365 "Analyses an item."
366 input Item inItem;
367 input Env inEnv;
368 algorithm
369 () := matchcontinue(inItem, inEnv)
370 local
371 SCode.ClassDef cdef;
372 NFSCodeEnv.Frame cls_env;
373 Env env;
374 SourceInfo info;
375 SCode.Restriction res;
376 SCode.Element cls;
377 SCode.Comment cmt;
378
379 // A component, mark it and it's environment as used.
380 case (NFSCodeEnv.VAR(), env)
381 algorithm
382 ✗ markItemAsUsed(inItem, env);
383 then
384 ();
385
386 // A basic type, nothing to be done.
387 case (NFSCodeEnv.CLASS(classType = NFSCodeEnv.BASIC_TYPE()), _) then ();
388
389 // A normal class, mark it and it's environment as used, and recursively
390 // analyse it's contents.
391 case (NFSCodeEnv.CLASS(cls = cls as SCode.CLASS(classDef = cdef,
392 restriction = res, info = info, cmt = cmt), env = {cls_env}), env)
393 algorithm
394 6 markItemAsUsed(inItem, env);
395 6 env := NFSCodeEnv.enterFrame(cls_env, env);
396 6 analyseClassDef(cdef, res, env, false, info);
397 6 analyseMetaType(res, env, info);
398 6 analyseComment(cmt, env, info);
399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 _ :: env := env;
400 6 analyseRedeclaredClass(cls, env);
401 then
402 ();
403
404 else
405 algorithm
406 ✗ true := Flags.isSet(Flags.FAILTRACE);
407 ✗ Debug.traceln("- NFSCodeDependency.analyseItemNoStopOnUsed failed on " +
408 NFSCodeEnv.getItemName(inItem) + " in " +
409 NFSCodeEnv.getEnvName(inEnv));
410 ✗ then
411 fail();
412
413 end matchcontinue;
414 end analyseItemNoStopOnUsed;
415
416 protected function markItemAsUsed
417 "Marks an item and it's environment as used."
418 input Item inItem;
419 input Env inEnv;
420 algorithm
421 () := match inItem
422 local
423 NFSCodeEnv.Frame cls_env;
424 Mutable<Boolean> is_used;
425
426 case NFSCodeEnv.VAR(isUsed = SOME(is_used))
427 algorithm
428 42717 Mutable.update(is_used, true);
429 42717 markEnvAsUsed(inEnv);
430 then
431 ();
432
433 case NFSCodeEnv.VAR(isUsed = NONE()) then ();
434
435 case NFSCodeEnv.CLASS(env = {cls_env}, cls = SCode.CLASS())
436 algorithm
437 20666 markFrameAsUsed(cls_env);
438 20666 markEnvAsUsed(inEnv);
439 then
440 ();
441 end match;
442 end markItemAsUsed;
443
444 protected function markFrameAsUsed
445 "Marks a single frame as used."
446 input NFSCodeEnv.Frame inFrame;
447 algorithm
448 () := match inFrame
449 local
450 Mutable<Boolean> is_used;
451
452 case NFSCodeEnv.FRAME(isUsed = SOME(is_used))
453 algorithm
454 20666 Mutable.update(is_used, true);
455 then
456 ();
457
458 else ();
459 end match;
460 end markFrameAsUsed;
461
462 protected function markEnvAsUsed
463 "Marks an environment as used. This is done by marking each frame as used, and
464 for each frame we also analyse the class it represents to make sure we don't
465 miss anything in the enclosing scopes of an item."
466 input Env inEnv;
467 algorithm
468 () := matchcontinue inEnv
469 local
470 Mutable<Boolean> is_used;
471 Env rest_env;
472 NFSCodeEnv.Frame f;
473
474 case (f as NFSCodeEnv.FRAME(isUsed = SOME(is_used))) :: rest_env
475 algorithm
476
2/2
✓ Branch 1 taken 59088 times.
✓ Branch 2 taken 5265 times.
64353 false := Mutable.access(is_used);
477 5265 markEnvAsUsed2(f, rest_env);
478 970 Mutable.update(is_used, true);
479 970 markEnvAsUsed(rest_env);
480 then
481 ();
482
483 else ();
484 end matchcontinue;
485 end markEnvAsUsed;
486
487 protected function markEnvAsUsed2
488 "Helper function to markEnvAsUsed. Checks if the given frame belongs to a
489 class, and if that's the case calls analyseClass on that class."
490 input NFSCodeEnv.Frame inFrame;
491 input NFSCodeEnv.Env inEnv;
492 algorithm
493 () := match inFrame
494 local
495 String name;
496
497 case NFSCodeEnv.FRAME(frameType = NFSCodeEnv.IMPLICIT_SCOPE()) then ();
498
499 case NFSCodeEnv.FRAME(name = SOME(name))
500 algorithm
501 209 analyseClass(Absyn.IDENT(name), inEnv, Absyn.dummyInfo);
502 then
503 ();
504 end match;
505 end markEnvAsUsed2;
506
507 protected function analyseClassDef
508 "Analyses the contents of a class definition."
509 input SCode.ClassDef inClassDef;
510 input SCode.Restriction inRestriction;
511 input Env inEnv;
512 input Boolean inInModifierScope;
513 input SourceInfo inInfo;
514 algorithm
515 () := matchcontinue(inClassDef, inEnv)
516 local
517 list<SCode.Element> el;
518 SCode.Mod mods;
519 Absyn.TypeSpec ty;
520 list<SCode.Equation> nel, iel;
521 list<SCode.AlgorithmSection> nal, ial;
522 Option<SCode.ExternalDecl> ext_decl;
523 Env ty_env, env, nore_env;
524 Item ty_item;
525 list<Absyn.Path> paths;
526 list<NFSCodeEnv.Redeclaration> redecls;
527 NFSCodeFlattenRedeclare.Replacements repls;
528
529 // A class made of parts, analyse elements, equation, algorithms, etc.
530 case (SCode.PARTS(elementLst = el, normalEquationLst = nel,
531 initialEquationLst = iel, normalAlgorithmLst = nal,
532 initialAlgorithmLst = ial, externalDecl = ext_decl), _)
533 algorithm
534 17166 analyseElements(el, inEnv, inRestriction);
535 17131 List.map1_0(nel, analyseEquation, inEnv);
536 17131 List.map1_0(iel, analyseEquation, inEnv);
537 17131 List.map1_0(nal, analyseAlgorithm, inEnv);
538 17131 List.map1_0(ial, analyseAlgorithm, inEnv);
539 17131 analyseExternalDecl(ext_decl, inEnv, inInfo);
540 then
541 ();
542
543 // The previous case failed, which might happen for an external object.
544 // Check if the class definition is an external object and analyse it if
545 // that's the case.
546 case (SCode.PARTS(elementLst = el), _)
547 algorithm
548 35 isExternalObject(el, inEnv, inInfo);
549 23 analyseClass(Absyn.IDENT("constructor"), inEnv, inInfo);
550 23 analyseClass(Absyn.IDENT("destructor"), inEnv, inInfo);
551 then
552 ();
553
554 // A class extends.
555 case (SCode.CLASS_EXTENDS(), _)
556 algorithm
557 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR,
558 {"NFSCodeDependency.analyseClassDef failed on CLASS_EXTENDS"}, inInfo);
559 ✗ then
560 fail();
561
562 // A derived class definition.
563 case (SCode.DERIVED(typeSpec = ty, modifications = mods), _ :: env)
564 algorithm
565
2/2
✓ Branch 0 taken 3166 times.
✓ Branch 1 taken 152 times.
3318 env := if inInModifierScope then inEnv else env;
566 3318 nore_env := NFSCodeEnv.removeRedeclaresFromLocalScope(env);
567 3318 analyseTypeSpec(ty, nore_env, inInfo);
568 3318 (ty_item, _, ty_env) := NFSCodeLookup.lookupTypeSpec(ty, env, inInfo);
569 3318 (ty_item, ty_env, _) := NFSCodeEnv.resolveRedeclaredItem(ty_item, ty_env);
570 3318 ty_env := NFSCodeEnv.mergeItemEnv(ty_item, ty_env);
571 3318 redecls := NFSCodeFlattenRedeclare.extractRedeclaresFromModifier(mods);
572 3318 (ty_item, ty_env, repls) :=
573 NFSCodeFlattenRedeclare.replaceRedeclaredElementsInEnv(redecls, ty_item, ty_env, inEnv, NFInstPrefix.emptyPrefix);
574 3317 analyseItemIfRedeclares(repls, ty_item, ty_env);
575 3317 analyseModifier(mods, inEnv, ty_env, inInfo);
576 then
577 ();
578
579 // Other cases which doesn't need to be analysed.
580 case (SCode.ENUMERATION(), _) then ();
581 case (SCode.OVERLOAD(pathLst = paths), _)
582 algorithm
583
4/6
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 109 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
113 if not Config.synchronousFeaturesAllowed() and AbsynUtil.pathFirstIdent(listHead(paths)) == "OMC_NO_CLOCK" then
584 ✗ List.map2_0({listHead(paths)},analyseClass,inEnv,inInfo);
585 else
586 113 List.map2_0(paths,analyseClass,inEnv,inInfo);
587 end if;
588 then ();
589 case (SCode.PDER(), _) then ();
590
591 end matchcontinue;
592 end analyseClassDef;
593
594 protected function isExternalObject
595 "Checks if a class definition is an external object."
596 input list<SCode.Element> inElements;
597 input Env inEnv;
598 input SourceInfo inInfo;
599 protected
600 list<SCode.Element> el;
601 list<String> el_names;
602 algorithm
603 // Remove all 'extends ExternalObject'.
604 35 el := List.filterOnTrue(inElements, isNotExternalObject);
605 // Check if length of the new list is different to the old, i.e. if we
606 // actually found and removed any 'extends ExternalObject'.
607
2/2
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 23 times.
35 false := (listLength(el) == listLength(inElements));
608 // Ok, we have an external object, check that it's valid.
609 23 el_names := List.filterMap(el, elementName);
610 23 checkExternalObject(el_names, inEnv, inInfo);
611 end isExternalObject;
612
613 protected function elementName
614 input SCode.Element inElement;
615 output String outString;
616 algorithm
617 outString := match inElement
618 local
619 String name;
620 Absyn.Path bc;
621
622 case SCode.COMPONENT(name = name) then name;
623 case SCode.CLASS(name = name) then name;
624 case SCode.DEFINEUNIT(name = name) then name;
625
626 case SCode.EXTENDS(baseClassPath = bc)
627 algorithm
628 ✗ name := AbsynUtil.pathString(bc);
629 ✗ name := "extends " + name;
630 then
631 name;
632
633 end match;
634 end elementName;
635
636 protected function isNotExternalObject
637 "False on 'extends ExternalObject', otherwise true."
638 input SCode.Element inElement;
639 output Boolean b;
640 algorithm
641 b := match inElement
642 case SCode.EXTENDS(baseClassPath = Absyn.IDENT("ExternalObject")) then false;
643 else true;
644 end match;
645 end isNotExternalObject;
646
647 protected function checkExternalObject
648 "Checks that an external object is valid, i.e. has exactly one constructor and
649 one destructor."
650 input list<String> inElements;
651 input Env inEnv;
652 input SourceInfo inInfo;
653 algorithm
654 () := match inElements
655 local
656 String env_str;
657 Boolean has_con, has_des;
658
659 // Ok, we have both a constructor and a destructor.
660 case {"constructor", "destructor"} then ();
661 case {"destructor", "constructor"} then ();
662
663 // Otherwise it's not valid, so print an error message.
664 else
665 algorithm
666 ✗ has_con := List.isMemberOnTrue(
667 "constructor", inElements, stringEqual);
668 ✗ has_des := List.isMemberOnTrue(
669 "destructor", inElements, stringEqual);
670 ✗ env_str := NFSCodeEnv.getEnvName(inEnv);
671 ✗ checkExternalObject2(inElements, has_con, has_des, env_str, inInfo);
672 ✗ then
673 fail();
674
675 end match;
676 end checkExternalObject;
677
678 protected function checkExternalObject2
679 "Helper function to checkExternalObject. Prints an error message depending on
680 what the external object contained."
681 input list<String> inElements;
682 input Boolean inHasConstructor;
683 input Boolean inHasDestructor;
684 input String inObjectName;
685 input SourceInfo inInfo;
686 algorithm
687 () := match(inElements, inHasConstructor, inHasDestructor)
688 local
689 list<String> el;
690 String el_str;
691
692 // The external object contains both a constructor and a destructor, so it
693 // has to also contain some invalid elements.
694 case (el, true, true)
695 algorithm
696 // Remove the constructor and destructor from the list of elements.
697 ✗ (el, _) := List.deleteMemberOnTrue("constructor", el, stringEqual);
698 ✗ (el, _) := List.deleteMemberOnTrue("destructor", el, stringEqual);
699 // Print an error message with the rest of the elements.
700 ✗ el_str := stringDelimitList(el, ", ");
701 ✗ el_str := "contains invalid elements: " + el_str;
702 ✗ Error.addSourceMessage(Error.INVALID_EXTERNAL_OBJECT,
703 {inObjectName, el_str}, inInfo);
704 then
705 ();
706
707 // The external object is missing a constructor.
708 case (_, false, true)
709 algorithm
710 ✗ Error.addSourceMessage(Error.INVALID_EXTERNAL_OBJECT,
711 {inObjectName, "missing constructor"}, inInfo);
712 then
713 ();
714
715 // The external object is missing a destructor.
716 case (_, true, false)
717 algorithm
718 ✗ Error.addSourceMessage(Error.INVALID_EXTERNAL_OBJECT,
719 {inObjectName, "missing destructor"}, inInfo);
720 then
721 ();
722
723 // The external object is missing both a constructor and a destructor.
724 case (_, false, false)
725 algorithm
726 ✗ Error.addSourceMessage(Error.INVALID_EXTERNAL_OBJECT,
727 {inObjectName, "missing both constructor and destructor"}, inInfo);
728 then
729 ();
730 end match;
731 end checkExternalObject2;
732
733 protected function analyseMetaType
734 "If a metarecord is analysed we need to also analyse it's parent uniontype."
735 input SCode.Restriction inRestriction;
736 input Env inEnv;
737 input SourceInfo inInfo;
738 algorithm
739 () := match inRestriction
740 local
741 Absyn.Path union_name;
742
743 case SCode.R_METARECORD(name = union_name)
744 algorithm
745 3 analyseClass(union_name, inEnv, inInfo);
746 then
747 ();
748
749 else ();
750 end match;
751 end analyseMetaType;
752
753 protected function analyseRedeclaredClass
754 "If a class is a redeclaration of an inherited class we need to also analyse
755 the inherited class."
756 input SCode.Element inClass;
757 input Env inEnv;
758 algorithm
759 () := matchcontinue inClass
760 local
761 Item item;
762
763 case SCode.CLASS()
764 algorithm
765
2/2
✓ Branch 1 taken 813 times.
✓ Branch 2 taken 19840 times.
20653 false := SCodeUtil.isElementRedeclare(inClass);
766 then ();
767
768 case SCode.CLASS()
769 algorithm
770 813 item := NFSCodeEnv.CLASS(inClass, NFSCodeEnv.emptyEnv, NFSCodeEnv.USERDEFINED());
771 813 analyseRedeclaredClass2(item, inEnv);
772 then
773 ();
774
775 end matchcontinue;
776 end analyseRedeclaredClass;
777
778 protected function analyseRedeclaredClass2
779 input Item inItem;
780 input Env inEnv;
781 algorithm
782 () := matchcontinue inItem
783 local
784 Item item;
785 Env env;
786 SCode.Element cls;
787 SourceInfo info;
788
789 case NFSCodeEnv.CLASS(cls=SCode.CLASS( info = info))
790 algorithm
791 813 (item, env) := NFSCodeLookup.lookupRedeclaredClassByItem(inItem, inEnv, info);
792 813 analyseItem(item, env);
793 then
794 ();
795
796 else
797 algorithm
798 ✗ true := Flags.isSet(Flags.FAILTRACE);
799 ✗ Debug.traceln("- NFSCodeDependency.analyseRedeclaredClass2 failed for " +
800 NFSCodeEnv.getItemName(inItem) + " in " +
801 NFSCodeEnv.getEnvName(inEnv));
802 ✗ then
803 fail();
804
805 end matchcontinue;
806 end analyseRedeclaredClass2;
807
808 protected function analyseElements
809 input list<SCode.Element> inElements;
810 input Env inEnv;
811 input SCode.Restriction inClassRestriction;
812 protected
813 list<Extends> exts;
814 algorithm
815 17166 exts := NFSCodeEnv.getEnvExtendsFromTable(inEnv);
816 17166 analyseElements2(inElements, inEnv, exts, inClassRestriction);
817 end analyseElements;
818
819 protected function analyseElements2
820 input list<SCode.Element> inElements;
821 input Env inEnv;
822 input list<Extends> inExtends;
823 input SCode.Restriction inClassRestriction;
824 algorithm
825 () := match inElements
826 local
827 SCode.Element el;
828 list<SCode.Element> rest_el;
829 list<Extends> exts;
830
831 case el :: rest_el
832 algorithm
833 156259 exts := analyseElement(el, inEnv, inExtends, inClassRestriction);
834 156224 analyseElements2(rest_el, inEnv, exts, inClassRestriction);
835 then
836 ();
837
838 case {} then ();
839
840 end match;
841 end analyseElements2;
842
843 protected function analyseElement
844 "Analyses an element."
845 input SCode.Element inElement;
846 input Env inEnv;
847 input list<Extends> inExtends;
848 input SCode.Restriction inClassRestriction;
849 output list<Extends> outExtends;
850 algorithm
851 outExtends := match(inElement, inExtends, inClassRestriction)
852 local
853 Absyn.Path bc;
854 SCode.Mod mods;
855 Absyn.TypeSpec ty;
856 SourceInfo info;
857 SCode.Attributes attr;
858 Option<Absyn.Exp> cond_exp;
859 Item ty_item;
860 Env ty_env;
861 SCode.Ident name;
862 SCode.Prefixes prefixes;
863 SCode.Restriction res;
864 String str;
865 list<Extends> exts;
866 list<NFSCodeEnv.Redeclaration> redecls;
867
868 // Fail on 'extends ExternalObject' so we can handle it as a special case in
869 // analyseClassDef.
870 case (SCode.EXTENDS(baseClassPath = Absyn.IDENT("ExternalObject")), _, _)
871 23 then fail();
872
873 // An extends-clause.
874 case (SCode.EXTENDS(modifications = mods, info = info), NFSCodeEnv.EXTENDS(baseClass = bc) :: exts, _)
875 algorithm
876 //print("bc = " + AbsynUtil.pathString(bc) + "\n");
877 //print("bc2 = " + AbsynUtil.pathString(bc2) + "\n");
878 9779 (ty_item, _, ty_env) :=
879 NFSCodeLookup.lookupBaseClassName(bc, inEnv, info);
880 9777 analyseExtends(bc, inEnv, info);
881 9777 ty_env := NFSCodeEnv.mergeItemEnv(ty_item, ty_env);
882 9777 analyseModifier(mods, inEnv, ty_env, info);
883 then
884 exts;
885
886 // A component.
887 case (SCode.COMPONENT(name = name, attributes = attr, typeSpec = ty,
888 modifications = mods, condition = cond_exp, prefixes = prefixes, info = info), _, _)
889 algorithm
890 // *always* keep constants and parameters!
891 // markAsUsedOnConstant(name, attr, inEnv, info);
892 57253 markAsUsedOnRestriction(name, inClassRestriction, inEnv, info);
893 57253 analyseAttributes(attr, inEnv, info);
894 57253 analyseTypeSpec(ty, inEnv, info);
895 57249 (ty_item, _, ty_env) := NFSCodeLookup.lookupTypeSpec(ty, inEnv, info);
896 57247 (ty_item, ty_env, _) := NFSCodeEnv.resolveRedeclaredItem(ty_item, ty_env);
897 57247 ty_env := NFSCodeEnv.mergeItemEnv(ty_item, ty_env);
898 57247 NFSCodeCheck.checkRecursiveComponentDeclaration(name, info, ty_env, ty_item, inEnv);
899 57246 redecls := NFSCodeFlattenRedeclare.extractRedeclaresFromModifier(mods);
900 57246 (ty_item, ty_env,_) :=
901 NFSCodeFlattenRedeclare.replaceRedeclaredElementsInEnv(redecls, ty_item, ty_env, inEnv, NFInstPrefix.emptyPrefix);
902 // analyseItemIfRedeclares(repls, ty_item, ty_env);
903 57246 analyseModifier(mods, inEnv, ty_env, info);
904 57246 analyseOptExp(cond_exp, inEnv, info);
905 57246 analyseConstrainClass(SCodeUtil.replaceableOptConstraint(SCodeUtil.prefixesReplaceable(prefixes)), inEnv, info);
906 then
907 inExtends;
908
909 //operators in operator record might be used later.
910 case (SCode.CLASS(name = name, restriction=SCode.R_OPERATOR(), info = info), _, SCode.R_RECORD(true))
911 algorithm
912 16 analyseClass(Absyn.IDENT(name), inEnv, info);
913 then
914 inExtends;
915
916
917 //operators in any other class type are error.
918 case (SCode.CLASS(name = name, restriction=SCode.R_OPERATOR(), info = info), _, _)
919 algorithm
920 ✗ str := SCodeDump.restrString(inClassRestriction);
921 ✗ Error.addSourceMessage(Error.OPERATOR_FUNCTION_NOT_EXPECTED, {name, str}, info);
922 ✗ then fail();
923
924 //operator functions in operator record might be used later.
925 case (SCode.CLASS(name = name, restriction=SCode.R_FUNCTION(SCode.FR_OPERATOR_FUNCTION()), info = info), _, SCode.R_RECORD(true))
926 algorithm
927 28 analyseClass(Absyn.IDENT(name), inEnv, info);
928 then
929 inExtends;
930
931 //operators functions in any other class type are error.
932 case (SCode.CLASS(name = name, restriction=SCode.R_FUNCTION(SCode.FR_OPERATOR_FUNCTION()), info = info), _, _)
933 algorithm
934 ✗ str := SCodeDump.restrString(inClassRestriction);
935 ✗ Error.addSourceMessage(Error.OPERATOR_FUNCTION_NOT_EXPECTED, {name, str}, info);
936 ✗ then
937 fail();
938
939 //functions in operator might be used later.
940 case (SCode.CLASS(name = name, restriction=res, info = info), _, SCode.R_OPERATOR())
941 algorithm
942 // Allowing external functions to be used operator functions
943
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 true := SCodeUtil.isFunctionOrExtFunctionRestriction(res);
944 28 analyseClass(Absyn.IDENT(name), inEnv, info);
945 then
946 inExtends;
947
948 //operators should only contain function definitions
949 case (SCode.CLASS(name = name, restriction = res, info = info), _, SCode.R_OPERATOR())
950 algorithm
951 ✗ false := SCodeUtil.isFunctionOrExtFunctionRestriction(res);
952 ✗ str := SCodeDump.restrString(res);
953 ✗ Error.addSourceMessage(Error.OPERATOR_FUNCTION_EXPECTED, {name, str}, info);
954 ✗ then
955 fail();
956
957 // equalityConstraints may not be explicitly used but might be needed anyway
958 // (if the record is used in a connect for example), so always mark it as used.
959 case (SCode.CLASS(name = name as "equalityConstraint", info = info), _, _)
960 algorithm
961 60 analyseClass(Absyn.IDENT(name), inEnv, info);
962 then
963 inExtends;
964
965 case (SCode.CLASS(name = name, info = info, classDef=SCode.CLASS_EXTENDS()), _, _)
966 algorithm
967 563 analyseClass(Absyn.IDENT(name), inEnv, info);
968 then
969 inExtends;
970
971 // inner/innerouter classes may not be explicitly used but might be needed anyway
972 case (SCode.CLASS(name = name, prefixes = SCode.PREFIXES(innerOuter = Absyn.INNER()), info = info), _, _)
973 algorithm
974 ✗ analyseClass(Absyn.IDENT(name), inEnv, info);
975 then
976 inExtends;
977
978 // inner/innerouter classes may not be explicitly used but might be needed anyway
979 case (SCode.CLASS(name = name, prefixes = SCode.PREFIXES(innerOuter = Absyn.INNER_OUTER()), info = info), _, _)
980 algorithm
981 ✗ analyseClass(Absyn.IDENT(name), inEnv, info);
982 then
983 inExtends;
984
985 else inExtends;
986 end match;
987 end analyseElement;
988
989 protected function markAsUsedOnConstant
990 input SCode.Ident inName;
991 input SCode.Attributes inAttr;
992 input Env inEnv;
993 input SourceInfo inInfo;
994 algorithm
995 () := matchcontinue(inAttr, inEnv)
996 local
997 EnvTree.Tree cls_and_vars;
998 Mutable<Boolean> is_used;
999 SCode.Variability var;
1000
1001 case (SCode.ATTR(variability = var), NFSCodeEnv.FRAME(clsAndVars = cls_and_vars) :: _)
1002 algorithm
1003 ✗ true := SCodeUtil.isParameterOrConst(var);
1004 ✗ NFSCodeEnv.VAR(isUsed = SOME(is_used)) :=
1005 EnvTree.get(cls_and_vars, inName);
1006 ✗ Mutable.update(is_used, true);
1007 then
1008 ();
1009
1010 else ();
1011 end matchcontinue;
1012 end markAsUsedOnConstant;
1013
1014 protected function markAsUsedOnRestriction
1015 input SCode.Ident inName;
1016 input SCode.Restriction inRestriction;
1017 input Env inEnv;
1018 input SourceInfo inInfo;
1019 algorithm
1020 () := matchcontinue inEnv
1021 local
1022 EnvTree.Tree cls_and_vars;
1023 Mutable<Boolean> is_used;
1024
1025 case NFSCodeEnv.FRAME(clsAndVars = cls_and_vars) :: _
1026 algorithm
1027
2/2
✓ Branch 1 taken 52783 times.
✓ Branch 2 taken 4470 times.
57253 true := markAsUsedOnRestriction2(inRestriction);
1028
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 4470 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4470 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4470 times.
4470 NFSCodeEnv.VAR(isUsed = SOME(is_used)) :=
1029 EnvTree.get(cls_and_vars, inName);
1030 4470 Mutable.update(is_used, true);
1031 then
1032 ();
1033
1034 else ();
1035 end matchcontinue;
1036 end markAsUsedOnRestriction;
1037
1038 protected function markAsUsedOnRestriction2
1039 input SCode.Restriction inRestriction;
1040 output Boolean isRestricted;
1041 algorithm
1042 isRestricted := match inRestriction
1043 case SCode.R_CONNECTOR() then true;
1044 case SCode.R_RECORD(_) then true;
1045 else false;
1046 end match;
1047 end markAsUsedOnRestriction2;
1048
1049 protected function analyseExtends
1050 "Analyses an extends-clause."
1051 input Absyn.Path inClassName;
1052 input Env inEnv;
1053 input SourceInfo inInfo;
1054 protected
1055 Item item;
1056 Env env;
1057 algorithm
1058 9777 (item, env) := lookupClass(inClassName, inEnv, true, inInfo, NONE());
1059 9777 analyseItem(item, env);
1060 end analyseExtends;
1061
1062 protected function analyseAttributes
1063 "Analyses a components attributes (actually only the array dimensions)."
1064 input SCode.Attributes inAttributes;
1065 input Env inEnv;
1066 input SourceInfo inInfo;
1067 protected
1068 Absyn.ArrayDim ad;
1069 algorithm
1070 57253 SCode.ATTR(arrayDims = ad) := inAttributes;
1071 57253 List.map2_0(ad, analyseSubscript, inEnv, inInfo);
1072 end analyseAttributes;
1073
1074 protected function analyseModifier
1075 "Analyses a modifier."
1076 input SCode.Mod inModifier;
1077 input Env inEnv;
1078 input Env inTypeEnv;
1079 input SourceInfo inInfo;
1080 algorithm
1081 () := match inModifier
1082 local
1083 SCode.Element el;
1084 list<SCode.SubMod> sub_mods;
1085 Option<Absyn.Exp> bind_exp;
1086
1087 // No modifier.
1088 case SCode.NOMOD() then ();
1089
1090 // A normal modifier, analyse it's submodifiers and optional binding.
1091 case SCode.MOD(subModLst = sub_mods, binding = bind_exp)
1092 algorithm
1093 76887 List.map2_0(sub_mods, analyseSubMod, (inEnv, inTypeEnv), inInfo);
1094 76883 analyseModBinding(bind_exp, inEnv, inInfo);
1095 then
1096 ();
1097
1098 // A redeclaration modifier, analyse the redeclaration.
1099 case SCode.REDECL(element = el)
1100 algorithm
1101 197 analyseRedeclareModifier(el, inEnv, inTypeEnv);
1102 then
1103 ();
1104 end match;
1105 end analyseModifier;
1106
1107 protected function analyseRedeclareModifier
1108 "Analyses a redeclaration modifier element."
1109 input SCode.Element inElement;
1110 input Env inEnv;
1111 input Env inTypeEnv;
1112 algorithm
1113 () := matchcontinue inElement
1114 local
1115 SCode.ClassDef cdef;
1116 SourceInfo info;
1117 SCode.Restriction restr;
1118 SCode.Prefixes prefixes;
1119
1120 // call analyseClassDef
1121 case SCode.CLASS(prefixes = prefixes, classDef = cdef,
1122 restriction = restr, info = info)
1123 algorithm
1124 153 analyseClassDef(cdef, restr, inEnv, true, info);
1125 153 analyseConstrainClass(SCodeUtil.replaceableOptConstraint(SCodeUtil.prefixesReplaceable(prefixes)), inEnv, info);
1126 then
1127 ();
1128
1129 // Otherwise we can just use analyseElements.
1130 else
1131 algorithm
1132 44 analyseElement(inElement, inEnv, {}, SCode.R_CLASS());
1133 then
1134 ();
1135 end matchcontinue;
1136 end analyseRedeclareModifier;
1137
1138 protected function analyseConstrainClass
1139 "Analyses a constrain class, i.e. given by constrainedby."
1140 input Option<SCode.ConstrainClass> inCC;
1141 input Env inEnv;
1142 input SourceInfo inInfo;
1143 algorithm
1144 () := match inCC
1145 local
1146 Absyn.Path path;
1147 SCode.Mod mod;
1148 Env env;
1149
1150 case SOME(SCode.CONSTRAINCLASS(constrainingClass = path, modifier = mod))
1151 algorithm
1152 6 analyseClass(path, inEnv, inInfo);
1153 6 (_, env) := lookupClass(path, inEnv, true, inInfo, SOME(Error.LOOKUP_ERROR));
1154 6 analyseModifier(mod, inEnv, env, inInfo);
1155 then
1156 ();
1157
1158 else ();
1159 end match;
1160 end analyseConstrainClass;
1161
1162 protected function analyseSubMod
1163 "Analyses a submodifier."
1164 input SCode.SubMod inSubMod;
1165 input tuple<Env, Env> inEnv;
1166 input SourceInfo inInfo;
1167 algorithm
1168 () := match(inSubMod, inEnv)
1169 local
1170 SCode.Ident ident;
1171 SCode.Mod m;
1172 Env env, ty_env;
1173
1174 case (SCode.NAMEMOD(ident = ident, mod = m), (env, ty_env))
1175 algorithm
1176 48296 analyseNameMod(ident, env, ty_env, m, inInfo);
1177 then
1178 ();
1179
1180 end match;
1181 end analyseSubMod;
1182
1183 protected function analyseNameMod
1184 input SCode.Ident inIdent;
1185 input Env inEnv;
1186 input Env inTypeEnv;
1187 input SCode.Mod inMod;
1188 input SourceInfo inInfo;
1189 protected
1190 Option<Item> item;
1191 Option<Env> env;
1192 algorithm
1193 48296 (item, env) := lookupNameMod(Absyn.IDENT(inIdent), inTypeEnv, inInfo);
1194 48296 analyseNameMod2(inIdent, item, env, inEnv, inTypeEnv, inMod, inInfo);
1195 end analyseNameMod;
1196
1197 protected function analyseNameMod2
1198 input SCode.Ident inIdent;
1199 input Option<Item> inItem;
1200 input Option<Env> inItemEnv;
1201 input Env inEnv;
1202 input Env inTypeEnv;
1203 input SCode.Mod inModifier;
1204 input SourceInfo inInfo;
1205 algorithm
1206 () := match(inItem, inItemEnv)
1207 local
1208 Item item;
1209 Env env;
1210
1211 case (SOME(item), SOME(env))
1212 algorithm
1213 47533 NFSCodeCheck.checkModifierIfRedeclare(item, inModifier, inInfo);
1214 47530 analyseItem(item, env);
1215 47530 env := NFSCodeEnv.mergeItemEnv(item, env);
1216 47530 analyseModifier(inModifier, inEnv, env, inInfo);
1217 then
1218 ();
1219
1220 else
1221 algorithm
1222 763 analyseModifier(inModifier, inEnv, inTypeEnv, inInfo);
1223 then
1224 ();
1225 end match;
1226 end analyseNameMod2;
1227
1228 protected function lookupNameMod
1229 input Absyn.Path inPath;
1230 input Env inEnv;
1231 input SourceInfo inInfo;
1232 output Option<Item> outItem;
1233 output Option<Env> outEnv;
1234 algorithm
1235 (outItem, outEnv) := matchcontinue inInfo
1236 local
1237 Item item;
1238 Env env;
1239
1240 case _
1241 algorithm
1242 48296 (item, _, env) := NFSCodeLookup.lookupNameSilent(inPath, inEnv, inInfo);
1243 47533 (item, env, _) := NFSCodeEnv.resolveRedeclaredItem(item, env);
1244 47533 then
1245 (SOME(item), SOME(env));
1246
1247 else (NONE(), NONE());
1248 end matchcontinue;
1249 end lookupNameMod;
1250
1251 protected function analyseSubscript
1252 "Analyses a subscript."
1253 input SCode.Subscript inSubscript;
1254 input Env inEnv;
1255 input SourceInfo inInfo;
1256 algorithm
1257 () := match inSubscript
1258 local
1259 Absyn.Exp sub_exp;
1260
1261 case Absyn.NOSUB() then ();
1262
1263 case Absyn.SUBSCRIPT(sub_exp)
1264 algorithm
1265 5600 analyseExp(sub_exp, inEnv, inInfo);
1266 then
1267 ();
1268 end match;
1269 end analyseSubscript;
1270
1271 protected function analyseModBinding
1272 "Analyses an optional modifier binding."
1273 input Option<Absyn.Exp> inBinding;
1274 input Env inEnv;
1275 input SourceInfo inInfo;
1276 algorithm
1277 () := match inBinding
1278 local
1279 Absyn.Exp bind_exp;
1280
1281 case NONE() then ();
1282
1283 case SOME(bind_exp)
1284 algorithm
1285 64668 analyseExp(bind_exp, inEnv, inInfo);
1286 then
1287 ();
1288 end match;
1289 end analyseModBinding;
1290
1291 protected function analyseTypeSpec
1292 "Analyses a type specificer."
1293 input Absyn.TypeSpec inTypeSpec;
1294 input Env inEnv;
1295 input SourceInfo inInfo;
1296 algorithm
1297 () := match inTypeSpec
1298 local
1299 Absyn.Path type_path;
1300 list<Absyn.TypeSpec> tys;
1301 Option<Absyn.ArrayDim> ad;
1302
1303 // A normal type.
1304 case Absyn.TPATH(path = type_path, arrayDim = ad)
1305 algorithm
1306 60515 analyseClass(type_path, inEnv, inInfo);
1307 60511 analyseTypeSpecDims(ad, inEnv, inInfo);
1308 then
1309 ();
1310
1311 // A polymorphic type, i.e. replaceable type Type subtypeof Any.
1312 case Absyn.TCOMPLEX(path = Absyn.IDENT("polymorphic"))
1313 then ();
1314
1315 // A MetaModelica type such as list or tuple.
1316 case Absyn.TCOMPLEX(typeSpecs = tys)
1317 algorithm
1318 11 List.map2_0(tys, analyseTypeSpec, inEnv, inInfo);
1319 then
1320 ();
1321
1322 end match;
1323 end analyseTypeSpec;
1324
1325 protected function analyseTypeSpecDims
1326 input Option<Absyn.ArrayDim> inDims;
1327 input Env inEnv;
1328 input SourceInfo inInfo;
1329 algorithm
1330 () := match inDims
1331 local
1332 Absyn.ArrayDim dims;
1333
1334 case SOME(dims)
1335 algorithm
1336 132 List.map2_0(dims, analyseTypeSpecDim, inEnv, inInfo);
1337 then
1338 ();
1339
1340 else ();
1341 end match;
1342 end analyseTypeSpecDims;
1343
1344 protected function analyseTypeSpecDim
1345 input Absyn.Subscript inDim;
1346 input Env inEnv;
1347 input SourceInfo inInfo;
1348 algorithm
1349 () := match inDim
1350 local
1351 Absyn.Exp dim;
1352
1353 case Absyn.NOSUB() then ();
1354
1355 case Absyn.SUBSCRIPT(subscript = dim)
1356 algorithm
1357 153 analyseExp(dim, inEnv, inInfo);
1358 then
1359 ();
1360
1361 end match;
1362 end analyseTypeSpecDim;
1363
1364 protected function analyseExternalDecl
1365 "Analyses an external declaration."
1366 input Option<SCode.ExternalDecl> inExtDecl;
1367 input Env inEnv;
1368 input SourceInfo inInfo;
1369 algorithm
1370 () := match inExtDecl
1371 local
1372 SCode.Annotation ann;
1373 list<Absyn.Exp> args;
1374
1375 // An external declaration might have arguments that we need to analyse.
1376 case SOME(SCode.EXTERNALDECL(args = args, annotation_ = NONE()))
1377 algorithm
1378 2501 List.map2_0(args, analyseExp, inEnv, inInfo);
1379 then
1380 ();
1381
1382 // An external declaration might have arguments and an annotation that we need to analyse.
1383 case SOME(SCode.EXTERNALDECL(args = args, annotation_ = SOME(ann)))
1384 algorithm
1385 312 List.map2_0(args, analyseExp, inEnv, inInfo);
1386 312 analyseAnnotation(ann, inEnv, inInfo);
1387 then
1388 ();
1389
1390 else ();
1391 end match;
1392 end analyseExternalDecl;
1393
1394 protected function analyseComment
1395 "Analyses an optional comment."
1396 input SCode.Comment inComment;
1397 input Env inEnv;
1398 input SourceInfo inInfo;
1399 algorithm
1400 () := match inComment
1401 local
1402 SCode.Annotation ann;
1403
1404 // A comment might have an annotation that we need to analyse.
1405 case SCode.COMMENT(annotation_ = SOME(ann))
1406 algorithm
1407 13537 analyseAnnotation(ann, inEnv, inInfo);
1408 then
1409 ();
1410
1411 else ();
1412 end match;
1413 end analyseComment;
1414
1415 protected function analyseAnnotation
1416 "Analyses an annotation."
1417 input SCode.Annotation inAnnotation;
1418 input Env inEnv;
1419 input SourceInfo inInfo;
1420 algorithm
1421 () := match inAnnotation
1422 local
1423 list<SCode.SubMod> sub_mods;
1424
1425 case SCode.ANNOTATION(modification = SCode.MOD(subModLst = sub_mods))
1426 algorithm
1427 13849 List.map2_0(sub_mods, analyseAnnotationMod, inEnv, inInfo);
1428 then
1429 ();
1430
1431 end match;
1432 end analyseAnnotation;
1433
1434 protected function analyseAnnotationMod
1435 "Analyses an annotation modifier."
1436 input SCode.SubMod inMod;
1437 input Env inEnv;
1438 input SourceInfo inInfo;
1439 algorithm
1440 () := matchcontinue inMod
1441 local
1442 SCode.Mod mods;
1443 String id;
1444
1445 // derivative is a bit special since it's not a builtin function, so just
1446 // analyse it's modifier to make sure that we get the derivation function.
1447 case SCode.NAMEMOD(ident = "derivative", mod = mods)
1448 algorithm
1449 239 analyseModifier(mods, inEnv, NFSCodeEnv.emptyEnv, inInfo);
1450 then
1451 ();
1452
1453 case SCode.NAMEMOD(ident = "inverse", mod = mods)
1454 algorithm
1455 29 analyseModifier(mods, inEnv, NFSCodeEnv.emptyEnv, inInfo);
1456 then
1457 ();
1458
1459 // Otherwise, try to analyse the modifier name, and if that succeeds also
1460 // try and analyse the rest of the modification. This is needed for example
1461 // for the graphical annotations such as Icon.
1462 case SCode.NAMEMOD(ident = id, mod = mods)
1463 algorithm
1464 24010 analyseAnnotationName(id, inEnv, inInfo);
1465 12 analyseModifier(mods, inEnv, NFSCodeEnv.emptyEnv, inInfo);
1466 then
1467 ();
1468
1469 else ();
1470 end matchcontinue;
1471 end analyseAnnotationMod;
1472
1473 protected function analyseAnnotationName
1474 "Analyses an annotation name, such as Icon or Line."
1475 input SCode.Ident inName;
1476 input Env inEnv;
1477 input SourceInfo inInfo;
1478 protected
1479 Item item;
1480 Env env;
1481 algorithm
1482 24010 (item, _, env) :=
1483 NFSCodeLookup.lookupNameSilent(Absyn.IDENT(inName), inEnv, inInfo);
1484 12 (item, env, _) := NFSCodeEnv.resolveRedeclaredItem(item, env);
1485 12 analyseItem(item, env);
1486 end analyseAnnotationName;
1487
1488 protected function analyseExp
1489 "Recursively analyses an expression."
1490 input Absyn.Exp inExp;
1491 input Env inEnv;
1492 input SourceInfo inInfo;
1493 algorithm
1494 72371 AbsynUtil.traverseExpBidir(inExp, analyseExpTraverserEnter, analyseExpTraverserExit, (inEnv, inInfo));
1495 end analyseExp;
1496
1497 protected function analyseOptExp
1498 "Recursively analyses an optional expression."
1499 input Option<Absyn.Exp> inExp;
1500 input Env inEnv;
1501 input SourceInfo inInfo;
1502 algorithm
1503 () := match inExp
1504 local
1505 Absyn.Exp exp;
1506
1507 case SOME(exp)
1508 algorithm
1509 552 analyseExp(exp, inEnv, inInfo);
1510 then
1511 ();
1512
1513 else ();
1514 end match;
1515 end analyseOptExp;
1516
1517 protected function analyseExpTraverserEnter
1518 "Traversal enter function for use in analyseExp."
1519 input Absyn.Exp inExp;
1520 input tuple<Env, SourceInfo> inTuple;
1521 output Absyn.Exp outExp;
1522 output tuple<Env, SourceInfo> outTuple;
1523 protected
1524 Env env;
1525 SourceInfo info;
1526 algorithm
1527 728763 (env, info) := inTuple;
1528 728763 env := analyseExp2(inExp, env, info);
1529 outExp := inExp;
1530 728763 outTuple := (env, info);
1531 end analyseExpTraverserEnter;
1532
1533 protected function analyseExp2
1534 "Helper function to analyseExp, does the actual work."
1535 input Absyn.Exp inExp;
1536 input Env inEnv;
1537 input SourceInfo inInfo;
1538 output Env outEnv;
1539 algorithm
1540 outEnv := match inExp
1541 local
1542 Absyn.ComponentRef cref;
1543 Absyn.ForIterators iters;
1544 Env env;
1545
1546 case Absyn.CREF(componentRef = cref)
1547 algorithm
1548 220440 analyseCref(cref, inEnv, inInfo);
1549 then
1550 inEnv;
1551
1552 case Absyn.CALL(function_ = cref, functionArgs = Absyn.FOR_ITER_FARG(iterators = iters))
1553 algorithm
1554 391 analyseCref(cref, inEnv, inInfo); // For user-defined reductions
1555 391 env := NFSCodeEnv.extendEnvWithIterators(iters, System.tmpTickIndex(NFSCodeEnv.tmpTickIndex), inEnv);
1556 then
1557 env;
1558
1559 case Absyn.CALL(function_ = cref)
1560 algorithm
1561 19160 analyseCref(cref, inEnv, inInfo);
1562 then
1563 inEnv;
1564
1565 case Absyn.PARTEVALFUNCTION(function_ = cref)
1566 algorithm
1567 12 analyseCref(cref, inEnv, inInfo);
1568 then
1569 inEnv;
1570
1571 case Absyn.MATCHEXP()
1572 algorithm
1573 10 env := NFSCodeEnv.extendEnvWithMatch(inExp, System.tmpTickIndex(NFSCodeEnv.tmpTickIndex), inEnv);
1574 then
1575 env;
1576
1577 else inEnv;
1578 end match;
1579 end analyseExp2;
1580
1581 protected function analyseCref
1582 "Analyses a component reference."
1583 input Absyn.ComponentRef inCref;
1584 input Env inEnv;
1585 input SourceInfo inInfo;
1586 algorithm
1587 () := matchcontinue inCref
1588 local
1589 Absyn.Path path;
1590 Item item;
1591 Env env;
1592
1593 case Absyn.WILD() then ();
1594
1595 case _
1596 algorithm
1597 // We want to use lookupClass since we need the item and environment, and
1598 // we don't care about any subscripts, so convert the cref to a path.
1599 240005 path := AbsynUtil.crefToPathIgnoreSubs(inCref);
1600 240005 (item, env) := lookupClass(path, inEnv, true, inInfo, NONE());
1601 238487 analyseItem(item, env);
1602 then
1603 ();
1604
1605 else ();
1606
1607 end matchcontinue;
1608 end analyseCref;
1609
1610 protected function analyseExpTraverserExit
1611 "Traversal exit function for use in analyseExp."
1612 input Absyn.Exp inExp;
1613 input tuple<Env, SourceInfo> inTuple;
1614 output Absyn.Exp outExp;
1615 output tuple<Env, SourceInfo> outTuple;
1616 algorithm
1617 (outExp,outTuple) := match(inExp,inTuple)
1618 local
1619 Env env;
1620 SourceInfo info;
1621
1622 // Remove any scopes added by the enter function.
1623
1624 case (Absyn.CALL(functionArgs = Absyn.FOR_ITER_FARG()),(NFSCodeEnv.FRAME(frameType = NFSCodeEnv.IMPLICIT_SCOPE()) :: env, info))
1625 391 then
1626 (inExp, (env, info));
1627
1628 case (Absyn.MATCHEXP(),(NFSCodeEnv.FRAME(frameType = NFSCodeEnv.IMPLICIT_SCOPE()) :: env, info))
1629 10 then
1630 (inExp, (env, info));
1631
1632 else (inExp, inTuple);
1633 end match;
1634 end analyseExpTraverserExit;
1635
1636 protected function analyseEquation
1637 "Analyses an equation."
1638 input SCode.Equation inEquation;
1639 input Env inEnv;
1640 algorithm
1641 8315 SCodeUtil.mapFoldEquations(inEquation, analyseEquationTraverser, inEnv);
1642 end analyseEquation;
1643
1644 protected function analyseEquationTraverser
1645 "Traversal function for use in analyseEquation."
1646 input output SCode.Equation eq;
1647 input output Env env;
1648 algorithm
1649 (eq, env) := match eq
1650 local
1651 SCode.Ident iter_name;
1652 SourceInfo info;
1653 Absyn.ComponentRef cref1;
1654
1655 case SCode.EQ_FOR(index = iter_name, info = info)
1656 algorithm
1657 370 env := NFSCodeEnv.extendEnvWithIterators({Absyn.ITERATOR(iter_name, NONE(), NONE())}, System.tmpTickIndex(NFSCodeEnv.tmpTickIndex), env);
1658 185 (eq, _) := SCodeUtil.mapFoldEquationExps(eq, traverseExp, (env, info));
1659 then
1660 (eq, env);
1661
1662 case SCode.EQ_REINIT(cref = Absyn.CREF(componentRef = cref1), info = info)
1663 algorithm
1664 15 analyseCref(cref1, env, info);
1665 15 (eq, _) := SCodeUtil.mapFoldEquationExps(eq, traverseExp, (env, info));
1666 then
1667 (eq, env);
1668
1669 else
1670 algorithm
1671 10449 info := SCodeUtil.getEquationInfo(eq);
1672 10449 (eq, _) := SCodeUtil.mapFoldEquationExps(eq, traverseExp, (env, info));
1673 then
1674 (eq, env);
1675
1676 end match;
1677 end analyseEquationTraverser;
1678
1679 protected function traverseExp
1680 "Traversal function used by analyseEquationTraverser and
1681 analyseStatementTraverser."
1682 input Absyn.Exp inExp;
1683 input tuple<Env, SourceInfo> inTuple;
1684 output Absyn.Exp outExp;
1685 output tuple<Env, SourceInfo> outTuple;
1686 algorithm
1687 77569 (outExp, outTuple) := AbsynUtil.traverseExpBidir(inExp, analyseExpTraverserEnter, analyseExpTraverserExit, inTuple);
1688 end traverseExp;
1689
1690 protected function analyseAlgorithm
1691 "Analyses an algorithm."
1692 input SCode.AlgorithmSection inAlgorithm;
1693 input Env inEnv;
1694 protected
1695 list<SCode.Statement> stmts;
1696 algorithm
1697 4712 SCode.ALGORITHM(stmts) := inAlgorithm;
1698 4712 List.map1_0(stmts, analyseStatement, inEnv);
1699 end analyseAlgorithm;
1700
1701 protected function analyseStatement
1702 "Analyses a statement in an algorithm."
1703 input SCode.Statement inStatement;
1704 input Env inEnv;
1705 algorithm
1706 19326 SCodeUtil.mapFoldStatements(inStatement, analyseStatementTraverser, inEnv);
1707 end analyseStatement;
1708
1709 protected function analyseStatementTraverser
1710 "Traversal function used by analyseStatement."
1711 input output SCode.Statement stmt;
1712 input output Env env;
1713 algorithm
1714 (stmt, env) := match stmt
1715 local
1716 SourceInfo info;
1717 String iter_name;
1718
1719 case SCode.ALG_FOR(index = iter_name, info = info)
1720 algorithm
1721 392 env := NFSCodeEnv.extendEnvWithIterators({Absyn.ITERATOR(iter_name, NONE(), NONE())}, System.tmpTickIndex(NFSCodeEnv.tmpTickIndex), env);
1722 196 SCodeUtil.mapFoldStatementExps(stmt, traverseExp, (env, info));
1723 then
1724 (stmt, env);
1725
1726 case SCode.ALG_PARFOR(index = iter_name, info = info)
1727 algorithm
1728 ✗ env := NFSCodeEnv.extendEnvWithIterators({Absyn.ITERATOR(iter_name, NONE(), NONE())}, System.tmpTickIndex(NFSCodeEnv.tmpTickIndex), env);
1729 ✗ SCodeUtil.mapFoldStatementExps(stmt, traverseExp, (env, info));
1730 then
1731 (stmt, env);
1732
1733 else
1734 algorithm
1735 30417 info := SCodeUtil.getStatementInfo(stmt);
1736 30417 SCodeUtil.mapFoldStatementExps(stmt, traverseExp, (env, info));
1737 then
1738 (stmt, env);
1739
1740 end match;
1741 end analyseStatementTraverser;
1742
1743 protected function analyseClassExtends
1744 "Goes through the environment and checks if class extends are used or not.
1745 This is done since class extends are sometimes implicitly used (see for
1746 example the test case mofiles/ClassExtends3.mo), so only going through the
1747 first phase of the dependency analysis is not enough to find all class extends
1748 that are used. Adding all class extends would also be problematic, since we
1749 would have to make sure that any class extend and it's dependencies are marked
1750 as used.
1751
1752 This phase goes through all used classes, and if it finds a class extends in
1753 one of them it sets the use flag to the same as the base class. This is not a
1754 perfect solution since it means that all class extends that extend a certain
1755 base class will be marked as used, even if only one of them actually use the
1756 base class. So we might get some extra dependencies that are actually not
1757 used, but it's still better then marking all class extends in the program as
1758 used."
1759 input Env inEnv;
1760 protected
1761 EnvTree.Tree tree;
1762 algorithm
1763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185522 times.
185522 NFSCodeEnv.FRAME(clsAndVars = tree) :: _ := inEnv;
1764 185522 EnvTree.foldCond(tree, analyseAvlValue, inEnv);
1765 end analyseClassExtends;
1766
1767 protected function analyseAvlValue
1768 "Helper function to analyseClassExtends. Analyses a value in the EnvTree."
1769 input String key;
1770 input Item value;
1771 input output Env env;
1772 output Boolean cont;
1773 algorithm
1774 cont := matchcontinue(value, env)
1775 local
1776 NFSCodeEnv.Frame cls_env;
1777 Env env2;
1778 SCode.Element cls;
1779 NFSCodeEnv.ClassType cls_ty;
1780 Mutable<Boolean> is_used;
1781
1782 // Check if the current environment is not used, we can quit here if that's
1783 // the case.
1784 case (_, NFSCodeEnv.FRAME(name = SOME(_), isUsed = SOME(is_used)) :: _)
1785 algorithm
1786
2/2
✓ Branch 1 taken 146649 times.
✓ Branch 2 taken 82447 times.
229096 false := Mutable.access(is_used);
1787 then
1788 false;
1789
1790 case (NFSCodeEnv.CLASS(cls = cls, env = {cls_env}, classType = cls_ty), _)
1791 algorithm
1792 184434 env2 := NFSCodeEnv.enterFrame(cls_env, env);
1793 184434 analyseClassExtendsDef(cls, cls_ty, env2);
1794 // Check all classes inside of this class too.
1795 184434 analyseClassExtends(env2);
1796 then
1797 true;
1798
1799 else true;
1800 end matchcontinue;
1801 end analyseAvlValue;
1802
1803 protected function analyseClassExtendsDef
1804 "Analyses a class extends definition."
1805 input SCode.Element inClass;
1806 input NFSCodeEnv.ClassType inClassType;
1807 input Env inEnv;
1808 algorithm
1809 () := matchcontinue(inClass, inClassType)
1810 local
1811 Item item;
1812 SourceInfo info;
1813 Absyn.Path bc;
1814 String cls_name;
1815 Env env;
1816
1817 case (SCode.CLASS(name = cls_name, classDef =
1818 SCode.PARTS(elementLst = SCode.EXTENDS(baseClassPath = bc) :: _),
1819 info = info), NFSCodeEnv.CLASS_EXTENDS())
1820 algorithm
1821 // Look up the base class of the class extends, and check if it's used.
1822 563 (item, _, env) := NFSCodeLookup.lookupBaseClassName(bc, inEnv, info);
1823
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 563 times.
563 true := NFSCodeEnv.isItemUsed(item);
1824 // Ok, the base is used, analyse the class extends to mark it and it's
1825 // dependencies as used.
1826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 563 times.
563 _ :: env := inEnv;
1827 563 analyseClass(Absyn.IDENT(cls_name), env, info);
1828 then
1829 ();
1830
1831 case (SCode.CLASS(name = cls_name, info = info), NFSCodeEnv.USERDEFINED())
1832 algorithm
1833
2/2
✓ Branch 1 taken 105288 times.
✓ Branch 2 taken 245 times.
105533 true := SCodeUtil.isElementRedeclare(inClass);
1834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 _ :: env := inEnv;
1835 245 item := NFSCodeEnv.CLASS(inClass, NFSCodeEnv.emptyEnv, inClassType);
1836 245 (item, _) := NFSCodeLookup.lookupRedeclaredClassByItem(item, env, info);
1837
2/2
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 193 times.
245 true := NFSCodeEnv.isItemUsed(item);
1838 193 analyseClass(Absyn.IDENT(cls_name), env, info);
1839 then
1840 ();
1841
1842 else ();
1843
1844 end matchcontinue;
1845 end analyseClassExtendsDef;
1846
1847 protected function collectUsedProgram
1848 "Entry point for the second phase in the dependency analysis. Goes through the
1849 environment and collects the used elements in a new program and environment.
1850 Also returns a list of all global constants."
1851 input Env inEnv;
1852 input SCode.Program inProgram;
1853 input Absyn.Path inClassName;
1854 output Env outEnv;
1855 output SCode.Program outProgram;
1856 protected
1857 Env env;
1858 EnvTree.Tree cls_and_vars;
1859 algorithm
1860 1088 env := NFSCodeEnv.buildInitialEnv();
1861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1088 times.
1088 NFSCodeEnv.FRAME(clsAndVars = cls_and_vars) :: _ := inEnv;
1862 1088 (outProgram, outEnv) :=
1863 collectUsedProgram2(cls_and_vars, inEnv, inProgram, inClassName, env);
1864 end collectUsedProgram;
1865
1866 protected function collectUsedProgram2
1867 "Helper function to collectUsedProgram2. Goes through each top-level class in
1868 the program and collects them if they are used. This is to preserve the order
1869 of the classes in the new program. Another alternative would have been to just
1870 traverse the environment and collect the used classes, which would have been a
1871 bit faster but would not have preserved the order of the program."
1872 input EnvTree.Tree clsAndVars;
1873 input Env inEnv;
1874 input SCode.Program inProgram;
1875 input Absyn.Path inClassName;
1876 input Env inAccumEnv;
1877 output SCode.Program outProgram;
1878 output Env outAccumEnv;
1879 algorithm
1880 (outProgram, outAccumEnv) :=
1881 matchcontinue(inProgram, inAccumEnv)
1882 local
1883 SCode.Element cls_el;
1884 SCode.Element cls;
1885 SCode.Program rest_prog;
1886 String name;
1887 Env env;
1888
1889 // We're done!
1890 1088 case ({}, _) then (inProgram, inAccumEnv);
1891
1892 // Try to collect the first class in the list.
1893 case ((cls as SCode.CLASS(name = name)) :: rest_prog, env)
1894 algorithm
1895
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1746 times.
2114 (cls_el as SCode.CLASS(), env) := collectUsedClass(cls, inEnv, clsAndVars,
1896 inClassName, env, Absyn.IDENT(name));
1897 1746 (rest_prog, env) :=
1898 collectUsedProgram2(clsAndVars, inEnv, rest_prog, inClassName, env);
1899 1746 then
1900 (cls_el :: rest_prog, env);
1901
1902 // Could not collect the class (i.e. it's not used), continue with the rest.
1903 case ((SCode.CLASS()) :: rest_prog, env)
1904 algorithm
1905 368 (rest_prog, env) :=
1906 collectUsedProgram2(clsAndVars, inEnv, rest_prog, inClassName, env);
1907 then
1908 (rest_prog, env);
1909
1910 end matchcontinue;
1911 end collectUsedProgram2;
1912
1913 protected function collectUsedClass
1914 "Checks if the given class is used in the program, and if that's the case it
1915 adds the class to the accumulated environment. Otherwise it just fails."
1916 input SCode.Element inClass;
1917 input Env inEnv;
1918 input EnvTree.Tree inClsAndVars;
1919 input Absyn.Path inClassName;
1920 input Env inAccumEnv;
1921 input Absyn.Path inAccumPath;
1922 output SCode.Element outClass;
1923 output Env outAccumEnv;
1924 algorithm
1925 (outClass, outAccumEnv) :=
1926 match inClass
1927 local
1928 SCode.Ident name, basename;
1929 SCode.Prefixes prefixes;
1930 SCode.Restriction res;
1931 SCode.ClassDef cdef;
1932 SCode.Encapsulated ep;
1933 SCode.Partial pp;
1934 SourceInfo info;
1935 Item item, resolved_item;
1936 NFSCodeEnv.Frame class_frame;
1937 Env class_env, env, enclosing_env;
1938 SCode.Element cls;
1939 SCode.Comment cmt;
1940
1941 case SCode.CLASS(name, prefixes as SCode.PREFIXES(replaceablePrefix =
1942 SCode.REPLACEABLE(_)), ep, pp, res, cdef, cmt, info)
1943 algorithm
1944 /*********************************************************************/
1945 // TODO: Fix the usage of alias items in this case.
1946 /*********************************************************************/
1947 // Check if the class is used.
1948 1234 item := EnvTree.get(inClsAndVars, name);
1949 1234 (resolved_item, _) := NFSCodeLookup.resolveAlias(item, inEnv);
1950
2/2
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 1006 times.
1234 true := checkClassUsed(resolved_item, cdef);
1951 // The class is used, recursively collect its contents.
1952
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1006 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1006 times.
1006 {class_frame} := NFSCodeEnv.getItemEnv(resolved_item);
1953 1006 enclosing_env := NFSCodeEnv.enterScope(inEnv, name);
1954 1006 (cdef, class_env) :=
1955 collectUsedClassDef(cdef, enclosing_env, class_frame, inClassName, inAccumPath);
1956
1957 1006 cls := SCode.CLASS(name, prefixes, ep, pp, res, cdef, cmt, info);
1958 1006 resolved_item := updateItemEnv(resolved_item, cls, class_env);
1959 1006 basename := name + NFSCodeEnv.BASE_CLASS_SUFFIX;
1960 1006 env := NFSCodeEnv.extendEnvWithItem(resolved_item, inAccumEnv, basename);
1961 1006 env := NFSCodeEnv.extendEnvWithItem(item, env, name);
1962 then
1963 (cls, env);
1964
1965 case SCode.CLASS(name, prefixes, ep, pp, res, cdef, cmt, info)
1966 algorithm
1967 // TODO! FIXME! add cc to the used classes!
1968 83825 SCodeUtil.replaceableOptConstraint(SCodeUtil.prefixesReplaceable(prefixes));
1969 // Check if the class is used.
1970 83825 item := EnvTree.get(inClsAndVars, name);
1971
2/2
✓ Branch 1 taken 67514 times.
✓ Branch 2 taken 16311 times.
83825 true := checkClassUsed(item, cdef);
1972 // The class is used, recursively collect it's contents.
1973
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 16311 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16311 times.
16311 {class_frame} := NFSCodeEnv.getItemEnv(item);
1974 16311 enclosing_env := NFSCodeEnv.enterScope(inEnv, name);
1975 16311 (cdef, class_env) :=
1976 collectUsedClassDef(cdef, enclosing_env, class_frame, inClassName, inAccumPath);
1977 // Add the class to the new environment.
1978 16311 cls := SCode.CLASS(name, prefixes, ep, pp, res, cdef, cmt, info);
1979 16311 item := updateItemEnv(item, cls, class_env);
1980 16311 env := NFSCodeEnv.extendEnvWithItem(item, inAccumEnv, name);
1981 then
1982 (cls, env);
1983
1984 end match;
1985 end collectUsedClass;
1986
1987 protected function checkClassUsed
1988 "Given the environment item and definition for a class, returns whether the
1989 class is used or not."
1990 input Item inItem;
1991 input SCode.ClassDef inClassDef;
1992 output Boolean isUsed;
1993 algorithm
1994 isUsed := match inItem
1995 // GraphicalAnnotationsProgram____ is a special case, since it's not used by
1996 // anything, but needed during instantiation.
1997 case NFSCodeEnv.CLASS(cls = SCode.CLASS(name = "GraphicalAnnotationsProgram____"))
1998 then true;
1999 // Otherwise, use the environment item to determine if the class is used or
2000 // not.
2001 85059 else NFSCodeEnv.isItemUsed(inItem);
2002 end match;
2003 end checkClassUsed;
2004
2005 protected function updateItemEnv
2006 "Replaces the class and environment in an environment item, preserving the
2007 item's type."
2008 input Item inItem;
2009 input SCode.Element inClass;
2010 input Env inEnv;
2011 output Item outItem;
2012 algorithm
2013 outItem := match inItem
2014 local
2015 NFSCodeEnv.ClassType cls_ty;
2016
2017 case NFSCodeEnv.CLASS(classType = cls_ty)
2018 17317 then NFSCodeEnv.CLASS(inClass, inEnv, cls_ty);
2019
2020 end match;
2021 end updateItemEnv;
2022
2023 protected function collectUsedClassDef
2024 "Collects the contents of a class definition."
2025 input output SCode.ClassDef classDef;
2026 input output Env env;
2027 input NFSCodeEnv.Frame inClassEnv;
2028 input Absyn.Path inClassName;
2029 input Absyn.Path inAccumPath;
2030 algorithm
2031 () := match classDef
2032 local
2033 list<SCode.Element> el;
2034 SCode.ClassDef cdef;
2035
2036 case SCode.PARTS(elementLst = el)
2037 algorithm
2038 14142 (el, env) := collectUsedElements(el, env, inClassEnv, inClassName, inAccumPath);
2039 14142 classDef.elementLst := el;
2040 then
2041 ();
2042
2043 case SCode.CLASS_EXTENDS(composition = cdef)
2044 algorithm
2045 563 (cdef, env) := collectUsedClassDef(cdef, env, inClassEnv, inClassName, inAccumPath);
2046 563 classDef.composition := cdef;
2047 then
2048 ();
2049
2050 else
2051 algorithm
2052 3175 env := {inClassEnv};
2053 then
2054 ();
2055
2056 end match;
2057 end collectUsedClassDef;
2058
2059 protected function collectUsedElements
2060 "Collects a class definition's elements."
2061 input list<SCode.Element> inElements;
2062 input Env inEnv;
2063 input NFSCodeEnv.Frame inClassEnv;
2064 input Absyn.Path inClassName;
2065 input Absyn.Path inAccumPath;
2066 output list<SCode.Element> outUsedElements;
2067 output Env outNewEnv;
2068 protected
2069 NFSCodeEnv.Frame empty_class_env;
2070 EnvTree.Tree cls_and_vars;
2071 Boolean collect_constants;
2072 algorithm
2073 // Create a new class environment that preserves the imports and extends.
2074 14142 (empty_class_env, cls_and_vars) :=
2075 NFSCodeEnv.removeClsAndVarsFromFrame(inClassEnv);
2076 // Collect all constants in the top class, even if they're not used.
2077 // This makes it easier to write test cases.
2078 14142 collect_constants := AbsynUtil.pathEqual(inClassName, inAccumPath);
2079 14142 (outUsedElements, outNewEnv) :=
2080 collectUsedElements2(inElements, inEnv, cls_and_vars, {}, {empty_class_env},
2081 inClassName, inAccumPath, collect_constants);
2082 14142 outNewEnv := removeUnusedRedeclares(outNewEnv, inEnv);
2083 end collectUsedElements;
2084
2085 protected function collectUsedElements2
2086 "Helper function to collectUsedElements2. Goes through the given list of
2087 elements and tries to collect them."
2088 input list<SCode.Element> inElements;
2089 input Env inEnclosingEnv;
2090 input EnvTree.Tree inClsAndVars;
2091 input list<SCode.Element> inAccumElements;
2092 input Env inAccumEnv;
2093 input Absyn.Path inClassName;
2094 input Absyn.Path inAccumPath;
2095 input Boolean inCollectConstants;
2096 output list<SCode.Element> outAccumElements = {};
2097 output Env accum_env = inAccumEnv;
2098 protected
2099 SCode.Element accum_el;
2100 algorithm
2101
2/2
✓ Branch 0 taken 147270 times.
✓ Branch 1 taken 14142 times.
161412 for el in inElements loop
2102 try
2103 147270 (accum_el, accum_env) := collectUsedElement(el, inEnclosingEnv, inClsAndVars, accum_env, inClassName, inAccumPath, inCollectConstants);
2104 outAccumElements := accum_el::outAccumElements;
2105 else
2106 // Skip this element
2107 end try;
2108 end for;
2109 14142 outAccumElements := listReverse(outAccumElements);
2110 end collectUsedElements2;
2111
2112 protected function collectUsedElement
2113 "Collects a class element."
2114 input SCode.Element inElement;
2115 input Env inEnclosingEnv;
2116 input EnvTree.Tree inClsAndVars;
2117 input Env inAccumEnv;
2118 input Absyn.Path inClassName;
2119 input Absyn.Path inAccumPath;
2120 input Boolean inCollectConstants;
2121 output SCode.Element outElement;
2122 output Env outAccumEnv;
2123 algorithm
2124 (outElement, outAccumEnv) :=
2125 match(inElement, inAccumEnv)
2126 local
2127 SCode.Ident name;
2128 SCode.Element cls;
2129 Env env;
2130 Item item;
2131 Absyn.Path cls_path;
2132
2133 // A class definition, just use collectUsedClass.
2134 case (SCode.CLASS(name = name), env)
2135 algorithm
2136 82945 cls_path := AbsynUtil.joinPaths(inAccumPath, Absyn.IDENT(name));
2137 82945 (cls, env) :=
2138 collectUsedClass(inElement, inEnclosingEnv, inClsAndVars,
2139 inClassName,env, cls_path);
2140 then
2141 (cls, env);
2142
2143 // A constant.
2144 case (SCode.COMPONENT(name = name,
2145 attributes = SCode.ATTR(variability = SCode.CONST())), _)
2146 algorithm
2147 9885 item := EnvTree.get(inClsAndVars, name);
2148
4/4
✓ Branch 0 taken 9561 times.
✓ Branch 1 taken 324 times.
✓ Branch 3 taken 6353 times.
✓ Branch 4 taken 3208 times.
9885 true := inCollectConstants or NFSCodeEnv.isItemUsed(item);
2149 6677 env := NFSCodeEnv.extendEnvWithItem(item, inAccumEnv, name);
2150 6677 then
2151 (inElement, env);
2152
2153 // Class components are always collected, regardless of whether they are
2154 // used or not.
2155 case (SCode.COMPONENT(name = name), _)
2156 algorithm
2157 43558 item := NFSCodeEnv.newVarItem(inElement, true);
2158 43558 env := NFSCodeEnv.extendEnvWithItem(item, inAccumEnv, name);
2159 43558 then
2160 (inElement, env);
2161
2162 10882 else (inElement, inAccumEnv);
2163
2164 end match;
2165 end collectUsedElement;
2166
2167 protected function removeUnusedRedeclares
2168 "An unused element might be redeclared, but it's still not actually used. This
2169 function removes such redeclares from extends clauses, so that it's safe to
2170 remove those elements."
2171 input Env inEnv;
2172 input Env inTotalEnv;
2173 output Env outEnv;
2174 protected
2175 Option<String> name;
2176 NFSCodeEnv.FrameType ty;
2177 EnvTree.Tree cls_and_vars;
2178 list<NFSCodeEnv.Extends> bcl;
2179 list<SCode.Element> re;
2180 Option<SCode.Element> cei;
2181 NFSCodeEnv.ImportTable imps;
2182 Option<Mutable<Boolean>> is_used;
2183 Env env;
2184 algorithm
2185
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14142 times.
14142 {NFSCodeEnv.FRAME(name, ty, cls_and_vars, NFSCodeEnv.EXTENDS_TABLE(bcl, re, cei),
2186 imps, is_used)} := inEnv;
2187 14142 env := NFSCodeEnv.removeRedeclaresFromLocalScope(inTotalEnv);
2188 14142 bcl := List.map1(bcl, removeUnusedRedeclares2, env);
2189 14142 outEnv := {NFSCodeEnv.FRAME(name, ty, cls_and_vars,
2190 NFSCodeEnv.EXTENDS_TABLE(bcl, re, cei), imps, is_used)};
2191 end removeUnusedRedeclares;
2192
2193 protected function removeUnusedRedeclares2
2194 input NFSCodeEnv.Extends inExtends;
2195 input Env inEnv;
2196 output NFSCodeEnv.Extends outExtends;
2197 protected
2198 Absyn.Path bc;
2199 list<NFSCodeEnv.Redeclaration> redeclares;
2200 Integer index;
2201 SourceInfo info;
2202 algorithm
2203 9791 NFSCodeEnv.EXTENDS(bc, redeclares, index, info) := inExtends;
2204 9791 redeclares := List.filter1(redeclares, removeUnusedRedeclares3, inEnv);
2205 9791 outExtends := NFSCodeEnv.EXTENDS(bc, redeclares, index, info);
2206 end removeUnusedRedeclares2;
2207
2208 protected function removeUnusedRedeclares3
2209 input NFSCodeEnv.Redeclaration inRedeclare;
2210 input Env inEnv;
2211 protected
2212 String name;
2213 Item item;
2214 algorithm
2215 860 (name, _) := NFSCodeEnv.getRedeclarationNameInfo(inRedeclare);
2216 860 (item, _, _) := NFSCodeLookup.lookupSimpleName(name, inEnv);
2217
2/2
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 807 times.
860 true := NFSCodeEnv.isItemUsed(item);
2218 end removeUnusedRedeclares3;
2219
2220 annotation(__OpenModelica_Interface="frontend");
2221 end NFSCodeDependency;
2222