|
5 | 5 | private import OverlayXml |
6 | 6 |
|
7 | 7 | /** |
8 | | - * Holds always for the overlay variant and never for the base variant. |
| 8 | + * A local predicate that always holds for the overlay variant and never for the base variant. |
9 | 9 | * This local predicate is used to define local predicates that behave |
10 | 10 | * differently for the base and overlay variant. |
11 | 11 | */ |
12 | 12 | overlay[local] |
13 | 13 | predicate isOverlay() { databaseMetadata("isOverlay", "true") } |
14 | 14 |
|
15 | | -overlay[local] |
16 | | -private string getLocationFilePath(@location_default loc) { |
17 | | - exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result)) |
18 | | -} |
19 | | - |
20 | | -/** |
21 | | - * Gets the file path for an element with a single location. |
22 | | - */ |
23 | | -overlay[local] |
24 | | -private string getSingleLocationFilePath(@element e) { |
25 | | - exists(@location_default loc | |
26 | | - var_decls(e, _, _, _, loc) |
27 | | - or |
28 | | - fun_decls(e, _, _, _, loc) |
29 | | - or |
30 | | - type_decls(e, _, loc) |
31 | | - or |
32 | | - namespace_decls(e, _, loc, _) |
33 | | - or |
34 | | - macroinvocations(e, _, loc, _) |
35 | | - or |
36 | | - preprocdirects(e, _, loc) |
37 | | - or |
38 | | - diagnostics(e, _, _, _, _, loc) |
39 | | - or |
40 | | - usings(e, _, loc, _) |
41 | | - or |
42 | | - static_asserts(e, _, _, loc, _) |
43 | | - or |
44 | | - derivations(e, _, _, _, loc) |
45 | | - or |
46 | | - frienddecls(e, _, _, loc) |
47 | | - or |
48 | | - comments(e, _, loc) |
49 | | - or |
50 | | - exprs(e, _, loc) |
51 | | - or |
52 | | - stmts(e, _, loc) |
53 | | - or |
54 | | - initialisers(e, _, _, loc) |
55 | | - or |
56 | | - attributes(e, _, _, _, loc) |
57 | | - or |
58 | | - attribute_args(e, _, _, _, loc) |
59 | | - or |
60 | | - namequalifiers(e, _, _, loc) |
61 | | - or |
62 | | - enumconstants(e, _, _, _, _, loc) |
63 | | - or |
64 | | - type_mentions(e, _, loc, _) |
65 | | - or |
66 | | - lambda_capture(e, _, _, _, _, _, loc) |
67 | | - or |
68 | | - concept_templates(e, _, loc) |
69 | | - | |
70 | | - result = getLocationFilePath(loc) |
71 | | - ) |
72 | | -} |
73 | | - |
74 | 15 | /** |
75 | | - * Gets the file path for an element with potentially multiple locations. |
| 16 | + * Holds if the TRAP file or tag `t` is reachable from some source file |
| 17 | + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. |
76 | 18 | */ |
77 | 19 | overlay[local] |
78 | | -private string getMultiLocationFilePath(@element e) { |
79 | | - exists(@location_default loc | |
80 | | - var_decls(_, e, _, _, loc) |
81 | | - or |
82 | | - fun_decls(_, e, _, _, loc) |
83 | | - or |
84 | | - type_decls(_, e, loc) |
85 | | - or |
86 | | - namespace_decls(_, e, loc, _) |
87 | | - | |
88 | | - result = getLocationFilePath(loc) |
| 20 | +private predicate locallyReachableTrapOrTag(boolean isOverlayVariant, string sourceFile, @trap_or_tag t) { |
| 21 | + exists(@source_file sf, @trap trap | |
| 22 | + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and |
| 23 | + source_file_uses_trap(sf, trap) and |
| 24 | + source_file_name(sf, sourceFile) and |
| 25 | + (t = trap or trap_uses_tag(trap, t)) |
89 | 26 | ) |
90 | 27 | } |
91 | 28 |
|
92 | 29 | /** |
93 | | - * A local helper predicate that holds in the base variant and never in the |
94 | | - * overlay variant. |
95 | | - */ |
96 | | -overlay[local] |
97 | | -private predicate isBase() { not isOverlay() } |
98 | | - |
99 | | -/** |
100 | | - * Holds if `path` was extracted in the overlay database. |
| 30 | + * Holds if element `e` is in TRAP file or tag `t` |
| 31 | + * in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant. |
101 | 32 | */ |
102 | 33 | overlay[local] |
103 | | -private predicate overlayHasFile(string path) { |
104 | | - isOverlay() and |
105 | | - files(_, path) and |
106 | | - path != "" |
| 34 | +private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) { |
| 35 | + (if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and |
| 36 | + in_trap_or_tag(e, t) |
107 | 37 | } |
108 | 38 |
|
109 | 39 | /** |
110 | 40 | * Discards an element from the base variant if: |
111 | | - * - It has a single location in a file extracted in the overlay, or |
112 | | - * - All of its locations are in files extracted in the overlay. |
| 41 | + * - We have knowledge about what TRAP file or tag it is in (in the base). |
| 42 | + * - It is not in any overlay TRAP file or tag that is reachable from an overlay source file. |
| 43 | + * - For every base TRAP file or tag that contains it and is reachable from a base source file, |
| 44 | + * either the source file has changed or the overlay has redefined the TRAP file or tag. |
113 | 45 | */ |
114 | 46 | overlay[discard_entity] |
115 | 47 | private predicate discardElement(@element e) { |
116 | | - isBase() and |
117 | | - ( |
118 | | - overlayHasFile(getSingleLocationFilePath(e)) |
119 | | - or |
120 | | - forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path)) |
| 48 | + // If we don't have any knowledge about what TRAP file something |
| 49 | + // is in, then we don't want to discard it, so we only consider |
| 50 | + // entities that are known to be in a base TRAP file or tag. |
| 51 | + locallyInTrapOrTag(false, e, _) and |
| 52 | + // Anything that is reachable from an overlay source file should |
| 53 | + // not be discarded. |
| 54 | + not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) | |
| 55 | + locallyReachableTrapOrTag(true, _, t) |
| 56 | + ) and |
| 57 | + // Finally, we have to make sure that base shouldn't retain it. |
| 58 | + // If it is reachable from a base source file, then that is |
| 59 | + // sufficient unless either the base source file has changed (in |
| 60 | + // particular, been deleted) or the overlay has redefined the TRAP |
| 61 | + // file or tag it is in. |
| 62 | + forall(@trap_or_tag t, string sourceFile | |
| 63 | + locallyInTrapOrTag(false, e, t) and |
| 64 | + locallyReachableTrapOrTag(false, sourceFile, t) |
| 65 | + | |
| 66 | + overlayChangedFiles(sourceFile) or |
| 67 | + locallyReachableTrapOrTag(true, _, t) |
121 | 68 | ) |
122 | 69 | } |
0 commit comments