Skip to content

Commit 3ff9beb

Browse files
l46kokcopybara-github
authored andcommitted
Clean up dangling source information from macro expansion
PiperOrigin-RevId: 629898444
1 parent be5aa9b commit 3ff9beb

7 files changed

Lines changed: 192 additions & 36 deletions

File tree

common/src/main/java/dev/cel/common/CelSource.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public final class CelSource {
4949
private CelSource(Builder builder) {
5050
this.codePoints = checkNotNull(builder.codePoints);
5151
this.description = checkNotNull(builder.description);
52-
this.positions = checkNotNull(builder.positions.buildOrThrow());
52+
this.positions = checkNotNull(ImmutableMap.copyOf(builder.positions));
5353
this.lineOffsets = checkNotNull(ImmutableList.copyOf(builder.lineOffsets));
5454
this.macroCalls = checkNotNull(ImmutableMap.copyOf(builder.macroCalls));
5555
this.extensions = checkNotNull(builder.extensions.build());
@@ -208,7 +208,7 @@ public static final class Builder {
208208

209209
private final CelCodePointArray codePoints;
210210
private final List<Integer> lineOffsets;
211-
private final ImmutableMap.Builder<Long, Integer> positions;
211+
private final Map<Long, Integer> positions;
212212
private final Map<Long, CelExpr> macroCalls;
213213
private final ImmutableSet.Builder<Extension> extensions;
214214

@@ -221,7 +221,7 @@ private Builder() {
221221
private Builder(CelCodePointArray codePoints, List<Integer> lineOffsets) {
222222
this.codePoints = checkNotNull(codePoints);
223223
this.lineOffsets = checkNotNull(lineOffsets);
224-
this.positions = ImmutableMap.builder();
224+
this.positions = new HashMap<>();
225225
this.macroCalls = new HashMap<>();
226226
this.extensions = ImmutableSet.builder();
227227
this.description = "";
@@ -261,6 +261,18 @@ public Builder addPositions(long exprId, int position) {
261261
return this;
262262
}
263263

264+
@CanIgnoreReturnValue
265+
public Builder clearPositions() {
266+
this.positions.clear();
267+
return this;
268+
}
269+
270+
@CanIgnoreReturnValue
271+
public Builder removePositions(long exprId) {
272+
this.positions.remove(exprId);
273+
return this;
274+
}
275+
264276
@CanIgnoreReturnValue
265277
public Builder addMacroCalls(long exprId, CelExpr expr) {
266278
this.macroCalls.put(exprId, expr);
@@ -329,8 +341,8 @@ public Optional<CelSourceLocation> getOffsetLocation(int offset) {
329341
}
330342

331343
@CheckReturnValue
332-
public ImmutableMap<Long, Integer> getPositionsMap() {
333-
return this.positions.buildOrThrow();
344+
public Map<Long, Integer> getPositionsMap() {
345+
return this.positions;
334346
}
335347

336348
@CheckReturnValue

common/src/main/java/dev/cel/common/ast/CelExprFactory.java

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,12 @@
2525
/** Factory for generating expression nodes. */
2626
@Internal
2727
public class CelExprFactory {
28-
29-
private final CelExprIdGeneratorFactory.ExprIdGenerator idGenerator;
28+
private long exprId = 0L;
3029

3130
public static CelExprFactory newInstance() {
3231
return new CelExprFactory();
3332
}
3433

35-
public static CelExprFactory newInstance(
36-
CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) {
37-
return new CelExprFactory(exprIdGenerator);
38-
}
39-
4034
/** Create a new constant expression. */
4135
public final CelExpr newConstant(CelConstant constant) {
4236
return CelExpr.newBuilder().setId(nextExprId()).setConstant(constant).build();
@@ -545,19 +539,15 @@ public final CelExpr newSelect(CelExpr operand, String field, boolean testOnly)
545539

546540
/** Returns the next unique expression ID. */
547541
protected long nextExprId() {
548-
return idGenerator.generate(
549-
/* exprId= */ -1); // Unconditionally generate next unique ID (i.e: no renumbering).
542+
return ++exprId;
550543
}
551544

552-
protected CelExprFactory() {
553-
this(CelExprIdGeneratorFactory.newMonotonicIdGenerator(0));
545+
/** Attempts to decrement the next expr ID if possible. */
546+
protected void maybeDeleteId(long id) {
547+
if (id == exprId - 1) {
548+
exprId--;
549+
}
554550
}
555551

556-
private CelExprFactory(CelExprIdGeneratorFactory.MonotonicIdGenerator idGenerator) {
557-
this((unused) -> idGenerator.nextExprId());
558-
}
559-
560-
private CelExprFactory(CelExprIdGeneratorFactory.ExprIdGenerator exprIdGenerator) {
561-
idGenerator = exprIdGenerator;
562-
}
552+
protected CelExprFactory() {}
563553
}

common/src/test/java/dev/cel/common/ast/CelExprFactoryTest.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import static com.google.common.truth.Truth.assertThat;
1818

19-
import dev.cel.common.ast.CelExprIdGeneratorFactory.StableIdGenerator;
2019
import org.junit.Test;
2120
import org.junit.runner.RunWith;
2221
import org.junit.runners.JUnit4;
@@ -38,15 +37,4 @@ public void nextExprId_startingDefaultIsOne() {
3837
assertThat(exprFactory.nextExprId()).isEqualTo(1L);
3938
assertThat(exprFactory.nextExprId()).isEqualTo(2L);
4039
}
41-
42-
@Test
43-
public void nextExprId_usingStableIdGenerator() {
44-
StableIdGenerator stableIdGenerator = CelExprIdGeneratorFactory.newStableIdGenerator(0);
45-
CelExprFactory exprFactory = CelExprFactory.newInstance(stableIdGenerator::nextExprId);
46-
47-
assertThat(exprFactory.nextExprId()).isEqualTo(1L);
48-
assertThat(exprFactory.nextExprId()).isEqualTo(2L);
49-
assertThat(stableIdGenerator.hasId(-1)).isFalse();
50-
assertThat(stableIdGenerator.hasId(0)).isFalse();
51-
}
5240
}

parser/src/main/java/dev/cel/parser/Parser.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ private Optional<CelExpr> visitMacro(
660660
CelExpr.newBuilder().setCall(callExpr.build()).build());
661661
}
662662

663+
exprFactory.maybeDeleteId(expr.id());
663664
return expandedMacro;
664665
}
665666

@@ -895,6 +896,7 @@ private CelExpr macroOrCall(
895896
ImmutableList<CelExpr> arguments = visitExprListContext(args);
896897
Optional<CelExpr> errorArg = arguments.stream().filter(ERROR::equals).findAny();
897898
if (errorArg.isPresent()) {
899+
sourceInfo.clearPositions();
898900
// Any arguments passed in to the macro may fail parsing.
899901
// Stop the macro expansion in this case as the result of the macro will be a parse failure.
900902
return ERROR;
@@ -1109,6 +1111,12 @@ private long nextExprId(int position) {
11091111
return exprId;
11101112
}
11111113

1114+
@Override
1115+
protected void maybeDeleteId(long id) {
1116+
sourceInfo.removePositions(id);
1117+
super.maybeDeleteId(id);
1118+
}
1119+
11121120
@Override
11131121
public long copyExprId(long id) {
11141122
return nextExprId(getPosition(id));

parser/src/test/java/dev/cel/parser/CelParserParameterizedTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.google.protobuf.Descriptors.FieldDescriptor;
3333
import com.google.protobuf.Descriptors.OneofDescriptor;
3434
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
35+
import dev.cel.common.CelAbstractSyntaxTree;
3536
import dev.cel.common.CelOptions;
3637
import dev.cel.common.CelProtoAbstractSyntaxTree;
3738
import dev.cel.common.CelSource;
@@ -248,6 +249,11 @@ public void parser_errors() {
248249
runTest(parserWithoutOptionalSupport, "[?a, ?b]");
249250
}
250251

252+
@Test
253+
public void source_info() throws Exception {
254+
runSourceInfoTest("[{}, {'field': true}].exists(i, has(i.field))");
255+
}
256+
251257
private void runTest(CelParser parser, String expression) {
252258
runTest(parser, expression, true);
253259
}
@@ -287,6 +293,15 @@ private void runTest(CelParser parser, String expression, boolean validateParseO
287293
testOutput().println();
288294
}
289295

296+
private void runSourceInfoTest(String expression) throws Exception {
297+
CelAbstractSyntaxTree ast = PARSER.parse(expression).getAst();
298+
SourceInfo sourceInfo =
299+
CelProtoAbstractSyntaxTree.fromCelAst(ast).toParsedExpr().getSourceInfo();
300+
testOutput().println("I: " + expression);
301+
testOutput().println("=====>");
302+
testOutput().println("S: " + sourceInfo);
303+
}
304+
290305
private String convertMacroCallsToString(SourceInfo sourceInfo) {
291306
KindAndIdAdorner macroCallsAdorner = new KindAndIdAdorner(sourceInfo);
292307
// Sort in ascending order so that nested macro calls are always in the same order for tests

parser/src/test/resources/parser.baseline

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ L: noop_macro(
15431543
I: get_constant_macro()
15441544
=====>
15451545
P: 10^#1:int64#
1546-
L: 10^#1[1,18]#
1546+
L: 10^#1[NO_POS]#
15471547
M: get_constant_macro()^#0:Expr.Call#
15481548

15491549
I: a.?b[?0] && a[?c]
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
I: [{}, {'field': true}].exists(i, has(i.field))
2+
=====>
3+
S: location: "<input>"
4+
line_offsets: 46
5+
positions {
6+
key: 1
7+
value: 0
8+
}
9+
positions {
10+
key: 2
11+
value: 1
12+
}
13+
positions {
14+
key: 3
15+
value: 5
16+
}
17+
positions {
18+
key: 4
19+
value: 13
20+
}
21+
positions {
22+
key: 5
23+
value: 6
24+
}
25+
positions {
26+
key: 6
27+
value: 15
28+
}
29+
positions {
30+
key: 8
31+
value: 29
32+
}
33+
positions {
34+
key: 10
35+
value: 36
36+
}
37+
positions {
38+
key: 11
39+
value: 37
40+
}
41+
positions {
42+
key: 12
43+
value: 35
44+
}
45+
positions {
46+
key: 13
47+
value: 28
48+
}
49+
positions {
50+
key: 14
51+
value: 28
52+
}
53+
positions {
54+
key: 15
55+
value: 28
56+
}
57+
positions {
58+
key: 16
59+
value: 28
60+
}
61+
positions {
62+
key: 17
63+
value: 28
64+
}
65+
positions {
66+
key: 18
67+
value: 28
68+
}
69+
positions {
70+
key: 19
71+
value: 28
72+
}
73+
positions {
74+
key: 20
75+
value: 28
76+
}
77+
macro_calls {
78+
key: 12
79+
value {
80+
call_expr {
81+
function: "has"
82+
args {
83+
id: 11
84+
select_expr {
85+
operand {
86+
id: 10
87+
ident_expr {
88+
name: "i"
89+
}
90+
}
91+
field: "field"
92+
}
93+
}
94+
}
95+
}
96+
}
97+
macro_calls {
98+
key: 20
99+
value {
100+
call_expr {
101+
target {
102+
id: 1
103+
list_expr {
104+
elements {
105+
id: 2
106+
struct_expr {
107+
}
108+
}
109+
elements {
110+
id: 3
111+
struct_expr {
112+
entries {
113+
id: 4
114+
map_key {
115+
id: 5
116+
const_expr {
117+
string_value: "field"
118+
}
119+
}
120+
value {
121+
id: 6
122+
const_expr {
123+
bool_value: true
124+
}
125+
}
126+
}
127+
}
128+
}
129+
}
130+
}
131+
function: "exists"
132+
args {
133+
id: 8
134+
ident_expr {
135+
name: "i"
136+
}
137+
}
138+
args {
139+
id: 12
140+
}
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)