Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions checker/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ java_library(
exports = ["//checker/src/main/java/dev/cel/checker:type_provider_legacy"],
)

java_library(
name = "type_provider_legacy_impl",
visibility = ["//:internal"],
exports = ["//checker/src/main/java/dev/cel/checker:type_provider_legacy_impl"],
)

java_library(
name = "checker_legacy_environment",
deprecation = "See go/cel-java-migration-guide. Please use CEL-Java Fluent APIs //compiler instead",
Expand Down
19 changes: 1 addition & 18 deletions checker/src/main/java/dev/cel/checker/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ CHECKER_LEGACY_ENV_SOURCES = [
"ExprChecker.java",
"ExprVisitor.java",
"InferenceContext.java",
"LegacyTypeProviderBridge.java",
"TypeFormatter.java",
]

Expand Down Expand Up @@ -129,24 +130,6 @@ java_library(
],
)

java_library(
name = "type_provider_legacy_impl",
srcs = ["TypeProviderLegacyImpl.java"],
tags = [
],
deps = [
":type_provider_legacy",
"//common/annotations",
"//common/types",
"//common/types:cel_proto_types",
"//common/types:type_providers",
"@cel_spec//proto/cel/expr:checked_java_proto",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:org_jspecify_jspecify",
],
)

java_library(
name = "checker_legacy_environment",
srcs = CHECKER_LEGACY_ENV_SOURCES,
Expand Down
163 changes: 133 additions & 30 deletions checker/src/main/java/dev/cel/checker/CelCheckerLegacyImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import dev.cel.expr.Decl;
import dev.cel.expr.Type;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
Expand All @@ -48,10 +48,13 @@
import dev.cel.common.types.CelProtoTypes;
import dev.cel.common.types.CelType;
import dev.cel.common.types.CelTypeProvider;
import dev.cel.common.types.ProtoMessageType;
import dev.cel.common.types.ProtoMessageTypeProvider;
import dev.cel.common.types.StructType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.SortedSet;
import java.util.TreeSet;
import org.jspecify.annotations.Nullable;
Expand All @@ -73,10 +76,28 @@ public final class CelCheckerLegacyImpl implements CelChecker, EnvVisitable {
private final ImmutableSet<CelFunctionDecl> functionDeclarations;
private final Optional<CelType> expectedResultType;

/**
* Preserved exclusively so {@link #toCheckerBuilder()} can round-trip caller-supplied legacy
* {@link TypeProvider} instances. Checker execution itself interacts strictly with {@link
* #celTypeProvider}.
*/
@SuppressWarnings("Immutable")
private final @Nullable TypeProvider typeProvider;
private final @Nullable TypeProvider legacyTypeProvider;

private final CelTypeProvider celTypeProvider;

/**
* The type provider handed to {@link Env}. Identical to {@link #celTypeProvider}, except that a
* caller-supplied legacy {@link TypeProvider} is adapted onto it.
*
* <p>This is deliberately kept separate from {@link #celTypeProvider}: a {@link
* LegacyTypeProviderBridge} resolves types lazily and cannot enumerate them, so it must not
* escape through {@link #getTypeProvider()} into callers that iterate {@code types()} or {@code
* fieldNames()} (for example {@code ConstantFoldingOptimizer}), nor through {@link
* #toCheckerBuilder()}.
*/
private final CelTypeProvider envCelTypeProvider;

private final boolean standardEnvironmentEnabled;

private final CelStandardDeclarations overriddenStandardDeclarations;
Expand Down Expand Up @@ -124,12 +145,10 @@ public CelCheckerBuilder toCheckerBuilder() {
.addFileTypes(fileDescriptors)
.addProtoTypeMasks(protoTypeMasks);

if (typeProvider != null) {
builder.setTypeProvider(typeProvider);
}
expectedResultType.ifPresent(builder::setResultType);

if (expectedResultType.isPresent()) {
builder.setResultType(expectedResultType.get());
if (legacyTypeProvider != null) {
builder.setTypeProvider(legacyTypeProvider);
}

if (overriddenStandardDeclarations != null) {
Expand Down Expand Up @@ -166,13 +185,11 @@ public void accept(EnvVisitor envVisitor) {
private Env getEnv(Errors errors) {
Env env;
if (overriddenStandardDeclarations != null) {
env =
Env.standard(
overriddenStandardDeclarations, errors, celTypeProvider, typeProvider, celOptions);
env = Env.standard(overriddenStandardDeclarations, errors, envCelTypeProvider, celOptions);
} else if (standardEnvironmentEnabled) {
env = Env.standard(errors, celTypeProvider, typeProvider, celOptions);
env = Env.standard(errors, envCelTypeProvider, celOptions);
} else {
env = Env.unconfigured(errors, celTypeProvider, typeProvider, celOptions);
env = Env.unconfigured(errors, envCelTypeProvider, celOptions);
}
identDeclarations.forEach(env::add);
functionDeclarations.forEach(env::add);
Expand Down Expand Up @@ -475,7 +492,7 @@ public CelCheckerLegacyImpl build() {
container,
identDeclarationSet,
functionDeclarations.build(),
Optional.fromNullable(expectedResultType),
Optional.ofNullable(expectedResultType),
customTypeProvider,
messageTypeProvider,
standardEnvironmentEnabled,
Expand All @@ -497,13 +514,30 @@ private Builder() {
}
}

private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
ImmutableList<Errors.Error> errorList = errors.getErrors();
CelIssue.Builder issueBuilder = CelIssue.newBuilder().setSeverity(CelIssue.Severity.ERROR);
return errorList.stream()
.map(
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
}

private CelCheckerLegacyImpl(
CelOptions celOptions,
CelContainer container,
ImmutableSet<CelVarDecl> identDeclarations,
ImmutableSet<CelFunctionDecl> functionDeclarations,
Optional<CelType> expectedResultType,
@Nullable TypeProvider typeProvider,
@Nullable TypeProvider legacyTypeProvider,
CelTypeProvider celTypeProvider,
boolean standardEnvironmentEnabled,
@Nullable CelStandardDeclarations overriddenStandardDeclarations,
Expand All @@ -516,29 +550,98 @@ private CelCheckerLegacyImpl(
this.identDeclarations = identDeclarations;
this.functionDeclarations = functionDeclarations;
this.expectedResultType = expectedResultType;
this.typeProvider = typeProvider;
this.legacyTypeProvider = legacyTypeProvider;
this.celTypeProvider = celTypeProvider;
this.envCelTypeProvider =
legacyTypeProvider == null
? celTypeProvider
: new LegacyBridgeCombinedTypeProvider(
celTypeProvider, new LegacyTypeProviderBridge(legacyTypeProvider));
this.standardEnvironmentEnabled = standardEnvironmentEnabled;
this.overriddenStandardDeclarations = overriddenStandardDeclarations;
this.checkerLibraries = checkerLibraries;
this.fileDescriptors = fileDescriptors;
this.protoTypeMasks = protoTypeMasks;
}

private static ImmutableList<CelIssue> errorsToIssues(Errors errors) {
ImmutableList<Errors.Error> errorList = errors.getErrors();
CelIssue.Builder issueBuilder = CelIssue.newBuilder().setSeverity(CelIssue.Severity.ERROR);
return errorList.stream()
.map(
e -> {
Errors.SourceLocation loc = errors.getPositionLocation(e.position());
CelSourceLocation newLoc = CelSourceLocation.of(loc.line(), loc.column() - 1);
return issueBuilder
.setExprId(e.exprId())
.setMessage(e.rawMessage())
.setSourceLocation(newLoc)
.build();
})
.collect(toImmutableList());
@VisibleForTesting
@Immutable
static final class LegacyBridgeCombinedTypeProvider implements CelTypeProvider {
private final CelTypeProvider modernTypeProvider;
private final LegacyTypeProviderBridge legacyTypeProviderBridge;
private final CelTypeProvider.CombinedCelTypeProvider delegate;

@Override
public ImmutableCollection<CelType> types() {
return delegate.types();
}

@Override
public Optional<CelType> findType(String typeName) {
return resolveType(typeName);
}

private Optional<CelType> resolveType(String typeName) {
Optional<CelType> modernType = modernTypeProvider.findType(typeName);
if (modernType.isPresent()) {
CelType type = modernType.get();
if (type instanceof ProtoMessageType) {
Optional<CelType> legacyType = legacyTypeProviderBridge.findType(typeName);
if (legacyType.isPresent() && legacyType.get() instanceof ProtoMessageType) {
return Optional.of(
combineProtoMessageTypes(
(ProtoMessageType) type, (ProtoMessageType) legacyType.get()));
}
}
return modernType;
}
return legacyTypeProviderBridge.findType(typeName);
}

private static ProtoMessageType combineProtoMessageTypes(
ProtoMessageType modern, ProtoMessageType legacy) {
boolean isEnumerable = true;
ImmutableSet<String> fieldNames;
try {
fieldNames = modern.fieldNames();
} catch (IllegalStateException e) {
isEnumerable = false;
fieldNames = ImmutableSet.of();
}

StructType.FieldResolver combinedExtensionResolver =
extensionName -> {
Optional<CelType> modernExt =
modern.findExtension(extensionName).map(ProtoMessageType.Extension::type);
if (modernExt.isPresent()) {
return modernExt;
}
return legacy.findExtension(extensionName).map(ProtoMessageType.Extension::type);
};

if (!isEnumerable) {
return ProtoMessageType.createWithUnenumerableFields(
modern.name(),
fieldName -> modern.findField(fieldName).map(StructType.Field::type),
combinedExtensionResolver,
modern::isJsonName);
}

return ProtoMessageType.create(
modern.name(),
fieldNames,
fieldName -> modern.findField(fieldName).map(StructType.Field::type),
combinedExtensionResolver,
modern::isJsonName);
}

@VisibleForTesting
LegacyBridgeCombinedTypeProvider(
CelTypeProvider modernTypeProvider, LegacyTypeProviderBridge legacyTypeProviderBridge) {
this.modernTypeProvider = checkNotNull(modernTypeProvider);
this.legacyTypeProviderBridge = checkNotNull(legacyTypeProviderBridge);
this.delegate =
new CelTypeProvider.CombinedCelTypeProvider(modernTypeProvider, legacyTypeProviderBridge);
}
}
}
Loading
Loading