5151#include " common/source.h"
5252#include " common/type.h"
5353#include " common/type_kind.h"
54+ #include " internal/annotations.h"
5455#include " internal/status_macros.h"
5556#include " google/protobuf/arena.h"
5657
@@ -68,6 +69,10 @@ std::string FormatCandidate(absl::Span<const std::string> qualifiers) {
6869 return absl::StrJoin (qualifiers, " ." );
6970}
7071
72+ static const TraversalOptions kTraversalOptions = {
73+ /* .use_comprehension_callbacks=*/ true ,
74+ };
75+
7176SourceLocation ComputeSourceLocation (const AstImpl& ast, int64_t expr_id) {
7277 const auto & source_info = ast.source_info ();
7378 auto iter = source_info.positions ().find (expr_id);
@@ -235,6 +240,8 @@ absl::StatusOr<AstType> FlattenType(const Type& type) {
235240 }
236241}
237242
243+ using AnnotationMap = internal::AnnotationMap;
244+
238245class ResolveVisitor : public AstVisitorBase {
239246 public:
240247 struct FunctionResolution {
@@ -247,13 +254,17 @@ class ResolveVisitor : public AstVisitorBase {
247254 const TypeCheckEnv& env, const AstImpl& ast,
248255 TypeInferenceContext& inference_context,
249256 std::vector<TypeCheckIssue>& issues,
257+ AnnotationMap& annotations,
258+ cel::CheckerAnnotationSupport annotation_support,
250259 absl::Nonnull<google::protobuf::Arena*> arena)
251260 : container_(container),
261+ annotation_support_ (annotation_support),
252262 namespace_generator_(std::move(namespace_generator)),
253263 env_(&env),
254264 inference_context_(&inference_context),
255265 issues_(&issues),
256266 ast_(&ast),
267+ annotations_(&annotations),
257268 root_scope_(env.MakeVariableScope()),
258269 arena_(arena),
259270 current_scope_(&root_scope_) {}
@@ -265,6 +276,43 @@ class ResolveVisitor : public AstVisitorBase {
265276 return ;
266277 }
267278 expr_stack_.pop_back ();
279+ if (!status_.ok ()) {
280+ return ;
281+ }
282+ if (annotation_support_ != CheckerAnnotationSupport::kCheck ) {
283+ return ;
284+ }
285+ auto annotations = annotations_->find (expr.id ());
286+ if (annotations == annotations_->end ()) {
287+ return ;
288+ }
289+ if (annotation_context_.has_value ()) {
290+ issues_->push_back (
291+ TypeCheckIssue::CreateError (ComputeSourceLocation (*ast_, expr.id ()),
292+ " Nested annotations are not supported." ));
293+ return ;
294+ }
295+ auto annotation_scope = current_scope_->MakeNestedScope ();
296+ VariableScope* annotation_scope_ptr = annotation_scope.get ();
297+ // bit of a misuse, but annotation scope is largely the same as for
298+ // comprehensions.
299+ comprehension_vars_.push_back (std::move (annotation_scope));
300+
301+ annotation_context_ = {current_scope_};
302+ current_scope_ = annotation_scope_ptr;
303+ Type annotated_expr_type = GetDeducedType (&expr);
304+ annotation_scope_ptr->InsertVariableIfAbsent (
305+ MakeVariableDecl (" cel.annotated_value" , annotated_expr_type));
306+
307+ // Note: this does not need to happen now during the main traversal, but
308+ // it's a easier to reason about for me. It's equally valid to just record
309+ // the relevant annotations and do a separate check pass later.
310+ for (const auto & annotation : annotations->second ) {
311+ CheckAnnotation (annotation, expr, annotated_expr_type);
312+ }
313+
314+ current_scope_ = annotation_context_->parent ;
315+ annotation_context_.reset ();
268316 }
269317
270318 void PostVisitConst (const Expr& expr, const Constant& constant) override ;
@@ -341,6 +389,10 @@ class ResolveVisitor : public AstVisitorBase {
341389 const FunctionDecl* decl;
342390 };
343391
392+ struct AnnotationContext {
393+ const VariableScope* parent;
394+ };
395+
344396 void ResolveSimpleIdentifier (const Expr& expr, absl::string_view name);
345397
346398 void ResolveQualifiedIdentifier (const Expr& expr,
@@ -459,12 +511,17 @@ class ResolveVisitor : public AstVisitorBase {
459511 return DynType ();
460512 }
461513
514+ void CheckAnnotation (const internal::AnnotationRep& annotation_expr,
515+ const Expr& annotated_expr, const Type& annotated_type);
516+
462517 absl::string_view container_;
518+ CheckerAnnotationSupport annotation_support_;
463519 NamespaceGenerator namespace_generator_;
464520 absl::Nonnull<const TypeCheckEnv*> env_;
465521 absl::Nonnull<TypeInferenceContext*> inference_context_;
466522 absl::Nonnull<std::vector<TypeCheckIssue>*> issues_;
467523 absl::Nonnull<const ast_internal::AstImpl*> ast_;
524+ absl::Nonnull<AnnotationMap*> annotations_;
468525 VariableScope root_scope_;
469526 absl::Nonnull<google::protobuf::Arena*> arena_;
470527
@@ -479,6 +536,7 @@ class ResolveVisitor : public AstVisitorBase {
479536 absl::flat_hash_set<const Expr*> deferred_select_operations_;
480537 std::vector<std::unique_ptr<VariableScope>> comprehension_vars_;
481538 std::vector<ComprehensionScope> comprehension_scopes_;
539+ absl::optional<AnnotationContext> annotation_context_;
482540 absl::Status status_;
483541 int error_count_ = 0 ;
484542
@@ -535,6 +593,64 @@ void ResolveVisitor::PostVisitIdent(const Expr& expr, const IdentExpr& ident) {
535593 }
536594}
537595
596+ void ResolveVisitor::CheckAnnotation (const internal::AnnotationRep& annotation,
597+ const Expr& annotated_expr,
598+ const Type& annotated_type) {
599+ const auto * annotation_decl = env_->LookupAnnotation (annotation.name );
600+ if (annotation_decl == nullptr ) {
601+ ReportIssue (TypeCheckIssue::CreateError (
602+ ComputeSourceLocation (*ast_, annotated_expr.id ()),
603+ absl::StrCat (" undefined annotation '" , annotation.name , " '" )));
604+ return ;
605+ }
606+
607+ // Checking if assignable to Dyn may influence the type inference so skip
608+ // here.
609+ if (!annotation_decl->applicable_type ().IsDyn ()) {
610+ if (!inference_context_->IsAssignable (annotated_type,
611+ annotation_decl->applicable_type ())) {
612+ ReportIssue (TypeCheckIssue::CreateError (
613+ ComputeSourceLocation (*ast_, annotated_expr.id ()),
614+ absl::StrCat (
615+ " annotation '" , annotation.name , " ' is not applicable to type '" ,
616+ inference_context_->FinalizeType (annotated_type).DebugString (),
617+ " '" )));
618+ return ;
619+ }
620+ }
621+
622+ if (annotation.inspect_only ) {
623+ // Nothing to do -- the value expression is not intended to be evaluated.
624+ // Examples are for things like a pointer to another file if the
625+ // subexpression is inlined from somewhere else.
626+ return ;
627+ }
628+
629+ // TODO - re-entrant traversal bypasses the complexity limits.
630+ AstTraverse (*annotation.value_expr , *this , kTraversalOptions );
631+
632+ if (!status_.ok ()) {
633+ return ;
634+ }
635+
636+ Type value_expression_type = GetDeducedType (annotation.value_expr );
637+
638+ if (!annotation_decl->expected_type ().IsDyn ()) {
639+ if (!inference_context_->IsAssignable (value_expression_type,
640+ annotation_decl->expected_type ())) {
641+ ReportIssue (TypeCheckIssue::CreateError (
642+ ComputeSourceLocation (*ast_, annotated_expr.id ()),
643+ absl::StrCat (" annotation '" , annotation.name ,
644+ " ' value expression type '" ,
645+ inference_context_->FinalizeType (value_expression_type)
646+ .DebugString (),
647+ " ' is not assignable to '" ,
648+ annotation_decl->expected_type ().DebugString (), " '" )));
649+ return ;
650+ }
651+ }
652+ }
653+
538654void ResolveVisitor::PostVisitConst (const Expr& expr,
539655 const Constant& constant) {
540656 switch (constant.kind ().index ()) {
@@ -1276,13 +1392,28 @@ absl::StatusOr<ValidationResult> TypeCheckerImpl::Check(
12761392
12771393 TypeInferenceContext type_inference_context (
12781394 &type_arena, options_.enable_legacy_null_assignment );
1395+
1396+ internal::AnnotationMap annotation_exprs;
1397+ Expr* root = &ast_impl.root_expr ();
1398+ if (ast_impl.root_expr ().has_call_expr () &&
1399+ ast_impl.root_expr ().call_expr ().function () == " cel.@annotated" &&
1400+ ast_impl.root_expr ().call_expr ().args ().size () == 2 ) {
1401+ if (options_.annotation_support == CheckerAnnotationSupport::kStrip ) {
1402+ ast_impl.root_expr () =
1403+ std::move (ast_impl.root_expr ().mutable_call_expr ().mutable_args ()[0 ]);
1404+ root = &ast_impl.root_expr ();
1405+ } else {
1406+ annotation_exprs = internal::BuildAnnotationMap (ast_impl);
1407+ root = &ast_impl.root_expr ().mutable_call_expr ().mutable_args ()[0 ];
1408+ }
1409+ }
1410+
12791411 ResolveVisitor visitor (env_.container (), std::move (generator), env_, ast_impl,
1280- type_inference_context, issues, &type_arena);
1412+ type_inference_context, issues, annotation_exprs,
1413+ options_.annotation_support , &type_arena);
12811414
1282- TraversalOptions opts;
1283- opts.use_comprehension_callbacks = true ;
12841415 bool error_limit_reached = false ;
1285- auto traversal = AstTraversal::Create (ast_impl. root_expr (), opts );
1416+ auto traversal = AstTraversal::Create (*root, kTraversalOptions );
12861417
12871418 for (int step = 0 ; step < options_.max_expression_node_count * 2 ; ++step) {
12881419 bool has_next = traversal.Step (visitor);
@@ -1300,7 +1431,7 @@ absl::StatusOr<ValidationResult> TypeCheckerImpl::Check(
13001431
13011432 if (!traversal.IsDone () && !error_limit_reached) {
13021433 return absl::InvalidArgumentError (
1303- absl::StrCat (" Maximum expression node count exceeded: " ,
1434+ absl::StrCat (" maximum expression node count exceeded: " ,
13041435 options_.max_expression_node_count ));
13051436 }
13061437
@@ -1309,7 +1440,7 @@ absl::StatusOr<ValidationResult> TypeCheckerImpl::Check(
13091440 {}, absl::StrCat (" maximum number of ERROR issues exceeded: " ,
13101441 options_.max_error_issues )));
13111442 } else if (env_.expected_type ().has_value ()) {
1312- visitor.AssertExpectedType (ast_impl. root_expr () , *env_.expected_type ());
1443+ visitor.AssertExpectedType (*root , *env_.expected_type ());
13131444 }
13141445
13151446 // If any issues are errors, return without an AST.
@@ -1324,7 +1455,14 @@ absl::StatusOr<ValidationResult> TypeCheckerImpl::Check(
13241455 // been invalidated by other updates.
13251456 ResolveRewriter rewriter (visitor, type_inference_context, options_,
13261457 ast_impl.reference_map (), ast_impl.type_map ());
1327- AstRewrite (ast_impl.root_expr (), rewriter);
1458+ AstRewrite (*root, rewriter);
1459+ if (options_.annotation_support == CheckerAnnotationSupport::kCheck ) {
1460+ for (auto & annotations : annotation_exprs) {
1461+ for (auto & annotation : annotations.second ) {
1462+ AstRewrite (*annotation.value_expr , rewriter);
1463+ }
1464+ }
1465+ }
13281466
13291467 CEL_RETURN_IF_ERROR (rewriter.status ());
13301468
0 commit comments