Skip to content
Merged
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
4 changes: 3 additions & 1 deletion checker/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ cc_library(
hdrs = ["type_check_issue.h"],
deps = [
"//common:source",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/strings:string_view",
],
Expand All @@ -45,6 +44,7 @@ cc_test(

cc_library(
name = "validation_result",
srcs = ["validation_result.cc"],
hdrs = ["validation_result.h"],
deps = [
":type_check_issue",
Expand All @@ -53,6 +53,7 @@ cc_library(
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
],
)
Expand All @@ -64,6 +65,7 @@ cc_test(
":type_check_issue",
":validation_result",
"//base/ast_internal:ast_impl",
"//common:source",
"//internal:testing",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
Expand Down
17 changes: 10 additions & 7 deletions checker/type_check_issue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

#include <string>

#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "common/source.h"
Expand All @@ -42,15 +41,19 @@ absl::string_view SeverityString(TypeCheckIssue::Severity severity) {

} // namespace

std::string TypeCheckIssue::ToDisplayString(const Source& source) const {
std::string TypeCheckIssue::ToDisplayString(const Source* source) const {
int column = location_.column;
// convert to 1-based if it's in range.
int display_column = column >= 0 ? column + 1 : column;
return absl::StrCat(
absl::StrFormat("%s: %s:%d:%d: %s", SeverityString(severity_),
source.description(), location_.line, display_column,
message_),
source.DisplayErrorLocation(location_));
if (source) {
return absl::StrFormat("%s: %s:%d:%d: %s%s", SeverityString(severity_),
source->description(), location_.line,
display_column, message_,
source->DisplayErrorLocation(location_));
}

return absl::StrFormat("%s: :%d:%d: %s", SeverityString(severity_),
location_.line, display_column, message_);
}

} // namespace cel
6 changes: 5 additions & 1 deletion checker/type_check_issue.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class TypeCheckIssue {
}

// Format the issue highlighting the source position.
std::string ToDisplayString(const Source& source) const;
std::string ToDisplayString(const Source* source) const;

std::string ToDisplayString(const Source& source) const {
return ToDisplayString(&source);
}

absl::string_view message() const { return message_; }
Severity severity() const { return severity_; }
Expand Down
32 changes: 32 additions & 0 deletions checker/validation_result.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "checker/validation_result.h"

#include <string>

#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "checker/type_check_issue.h"

namespace cel {

std::string ValidationResult::FormatError() const {
return absl::StrJoin(
issues_, "\n", [this](std::string* out, const TypeCheckIssue& issue) {
absl::StrAppend(out, issue.ToDisplayString(source_.get()));
});
}

} // namespace cel
17 changes: 17 additions & 0 deletions checker/validation_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define THIRD_PARTY_CEL_CPP_CHECKER_VALIDATION_RESULT_H_

#include <memory>
#include <string>
#include <utility>
#include <vector>

Expand Down Expand Up @@ -68,6 +69,22 @@ class ValidationResult {
return std::move(source_);
}

// Returns a string representation of the issues in the result suitable for
// display.
//
// The result is empty if no issues are present.
//
// The result is formatted similarly to CEL-Java and CEL-Go, but we do not
// give strong guarantees on the format or stability.
//
// Example:
//
// ERROR: <source description>:1:3: Issue1
// | source.cel
// | ..^
// INFORMATION: <source description>:-1:-1: Issue2
std::string FormatError() const;

private:
absl::Nullable<std::unique_ptr<Ast>> ast_;
std::vector<TypeCheckIssue> issues_;
Expand Down
21 changes: 21 additions & 0 deletions checker/validation_result_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
#include "checker/validation_result.h"

#include <memory>
#include <utility>

#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "base/ast_internal/ast_impl.h"
#include "checker/type_check_issue.h"
#include "common/source.h"
#include "internal/testing.h"

namespace cel {
Expand Down Expand Up @@ -65,5 +67,24 @@ TEST(ValidationResultTest, GetIssues) {
EXPECT_THAT(result.GetIssues()[1].severity(), Severity::kInformation);
}

TEST(ValidationResultTest, FormatError) {
ValidationResult result(
{TypeCheckIssue::CreateError({1, 2}, "Issue1"),
TypeCheckIssue(Severity::kInformation, {-1, -1}, "Issue2")});
EXPECT_FALSE(result.IsValid());

ASSERT_OK_AND_ASSIGN(std::unique_ptr<Source> source,
NewSource("source.cel", "<description>"));
result.SetSource(std::move(source));

ASSERT_THAT(result.GetIssues(), SizeIs(2));

EXPECT_THAT(result.FormatError(),
"ERROR: <description>:1:3: Issue1\n"
" | source.cel\n"
" | ..^\n"
"INFORMATION: <description>:-1:-1: Issue2");
}

} // namespace
} // namespace cel