* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "ir/verifier/verifier.h"
#include <algorithm>
#include <cstddef>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "core/error.h"
#include "ir/program.h"
namespace pypto {
namespace ir {
IRVerifier::IRVerifier() = default;
void IRVerifier::AddRule(PropertyVerifierPtr rule)
{
if (!rule) {
return;
}
auto it = std::find_if(rules_.begin(), rules_.end(), [&rule](const PropertyVerifierPtr& r) {
return r->GetName() == rule->GetName();
});
if (it == rules_.end()) {
rules_.push_back(rule);
}
}
void IRVerifier::EnableRule(const std::string& name) { disabled_rules_.erase(name); }
void IRVerifier::DisableRule(const std::string& name) { disabled_rules_.insert(name); }
bool IRVerifier::IsRuleEnabled(const std::string& name) const { return disabled_rules_.count(name) == 0; }
std::vector<Diagnostic> IRVerifier::Verify(const ProgramPtr& program) const
{
if (!program) {
return {};
}
std::vector<Diagnostic> all_diagnostics;
for (const auto& rule : rules_) {
if (!rule) {
continue;
}
if (!IsRuleEnabled(rule->GetName())) {
continue;
}
rule->Verify(program, all_diagnostics);
}
return all_diagnostics;
}
void IRVerifier::VerifyOrThrow(const ProgramPtr& program) const
{
auto diagnostics = Verify(program);
bool has_errors = std::any_of(diagnostics.begin(), diagnostics.end(), [](const Diagnostic& d) {
return d.severity == DiagnosticSeverity::ERROR;
});
if (has_errors) {
std::string report = GenerateReport(diagnostics);
throw VerificationError(report, std::move(diagnostics));
}
}
std::string IRVerifier::GenerateReport(const std::vector<Diagnostic>& diagnostics)
{
std::ostringstream oss;
size_t error_count = 0;
size_t warning_count = 0;
for (const auto& d : diagnostics) {
if (d.severity == DiagnosticSeverity::ERROR) {
error_count++;
} else {
warning_count++;
}
}
oss << "IR Verification Report\n";
oss << "======================\n";
oss << "Total diagnostics: " << diagnostics.size() << " (";
oss << error_count << " errors, " << warning_count << " warnings)\n\n";
if (diagnostics.empty()) {
oss << "Status: PASSED\n";
return oss.str();
}
for (size_t i = 0; i < diagnostics.size(); ++i) {
const auto& d = diagnostics[i];
std::string severity_str = (d.severity == DiagnosticSeverity::ERROR) ? "ERROR" : "WARNING";
oss << "[" << (i + 1) << "] " << severity_str << " - " << d.ruleName << "\n";
oss << " Message: " << d.message << "\n";
oss << " Location: " << d.span.Filename() << ":" << d.span.BeginLine() << ":" << d.span.BeginColumn() << "\n";
oss << " Error Code: " << d.errorCode << "\n";
oss << "\n";
}
if (error_count > 0) {
oss << "Status: FAILED (" << error_count << " error(s) found)\n";
} else {
oss << "Status: PASSED with " << warning_count << " warning(s)\n";
}
return oss.str();
}
IRVerifier IRVerifier::CreateDefault()
{
IRVerifier verifier;
verifier.AddRule(CreateSSAPropertyVerifier());
verifier.AddRule(CreateTypeCheckPropertyVerifier());
verifier.AddRule(CreateNoNestedCallPropertyVerifier());
return verifier;
}
}
}