Swift: Emit diagnostics on assertion/expectation violations.

This commit is contained in:
Alexandre Boulgakov
2023-05-16 18:32:41 +01:00
parent 7ada125299
commit 060a48571a
7 changed files with 104 additions and 22 deletions

View File

@@ -0,0 +1,8 @@
py_library(
name = "integration_tests",
srcs = [
"create_database_utils.py",
"diagnostics_test_utils.py",
],
visibility = ["//swift:__subpackages__"],
)

View File

@@ -10,11 +10,12 @@ import os
import difflib
import sys
def _normalize_actual(test_dir, database_dir):
proc = subprocess.run(['codeql', 'database', 'export-diagnostics', '--format', 'raw', '--', database_dir],
def _get_actual(database_dir):
return subprocess.run(['codeql', 'database', 'export-diagnostics', '--format', 'raw', '--', database_dir],
stdout=subprocess.PIPE, universal_newlines=True, check=True, text=True)
data = proc.stdout.replace(str(test_dir.absolute()), "<test-root-directory>")
def _normalize_actual(test_dir, data):
data = data.replace(str(test_dir.absolute()), "<test-root-directory>")
data = json.loads(data)
data[:] = [e for e in data if not e["source"]["id"].startswith("cli/")]
for e in data:
@@ -49,10 +50,12 @@ def _normalize_json(data):
return "\n".join(entries)
def check_diagnostics(test_dir=".", test_db="db"):
def check_diagnostics(test_dir=".", test_db="db", actual = None):
test_dir = pathlib.Path(test_dir)
test_db = pathlib.Path(test_db)
actual = _normalize_actual(test_dir, test_db)
if actual is None:
actual = _get_actual(test_db).stdout
actual = _normalize_actual(test_dir, actual)
if os.environ.get("CODEQL_INTEGRATION_TEST_LEARN") == "true":
with open(test_dir / "diagnostics.expected", "w") as expected:
expected.write(actual)

View File

@@ -4,26 +4,28 @@
#include "swift/logging/SwiftLogging.h"
// assert CONDITION, which is always evaluated (once) regardless of the build type. If
// CONDITION is not satisfied, emit a critical log optionally using provided format and arguments,
// abort the program
// Assert CONDITION, which is always evaluated (once) regardless of the build type. If
// CONDITION is not satisfied, emit a critical log and diagnostic optionally using provided format
// and arguments, and then abort the program.
#define CODEQL_ASSERT(CONDITION, ...) \
CODEQL_ASSERT_IMPL(CRITICAL, std::abort(), CONDITION, __VA_ARGS__)
CODEQL_ASSERT_IMPL(critical, std::abort(), CONDITION, __VA_ARGS__)
// If CONDITION is not satisfied, emit an error log optionally using provided format and arguments,
// but continue execution
// If CONDITION is not satisfied, emit an error log and diagnostic optionally using provided format
// and arguments, but continue execution
#define CODEQL_EXPECT(CONDITION, ...) CODEQL_EXPECT_OR(void(), CONDITION, __VA_ARGS__)
// If CONDITION is not satisfied, emit an error log optionally using provided format and arguments,
// and execute ACTION (for example return)
// If CONDITION is not satisfied, emit an error log and diagnostic optionally using provided format
// and arguments, and execute ACTION (for example return)
#define CODEQL_EXPECT_OR(ACTION, CONDITION, ...) \
CODEQL_ASSERT_IMPL(ERROR, ACTION, CONDITION, __VA_ARGS__)
CODEQL_ASSERT_IMPL(error, ACTION, CONDITION, __VA_ARGS__)
#define CODEQL_ASSERT_IMPL(LEVEL, ACTION, CONDITION, ...) \
do { \
if (!(CONDITION)) { \
[[unlikely]] LOG_##LEVEL("assertion failed on " #CONDITION ". " __VA_ARGS__); \
codeql::Log::flush(); \
ACTION; \
} \
#define CODEQL_ASSERT_IMPL(LEVEL, ACTION, CONDITION, ...) \
do { \
if (!(CONDITION)) { \
[[unlikely]] DIAGNOSE_WITH_LEVEL(LEVEL, codeql::internalError, \
"CodeQL encountered an unexpected internal error with the " \
"following message:\n> Assertion failed: `" #CONDITION \
"`. " __VA_ARGS__); \
ACTION; \
} \
} while (false)

View File

@@ -0,0 +1,12 @@
#include "swift/logging/SwiftAssert.h"
const std::string_view codeql::programName = "test";
static codeql::Logger& logger() {
static codeql::Logger ret{"main"};
return ret;
}
int main() {
CODEQL_ASSERT(false, "Format the int {} and string {} if this assertion fails", 1234, "myString");
}

View File

@@ -0,0 +1,25 @@
load("//swift:rules.bzl", "swift_cc_binary")
load("//misc/bazel/cmake:cmake.bzl", "generate_cmake")
swift_cc_binary(
name = "assert-false",
srcs = ["AssertFalse.cpp"],
visibility = ["//visibility:private"],
deps = [
"//swift/logging",
],
)
py_test(
name = "test",
size = "small",
srcs = ["test.py"],
deps = ["//swift/integration-tests:integration_tests"],
data = [":assert-false", "diagnostics.expected"],
)
generate_cmake(
name = "cmake",
targets = [":assert-false"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,17 @@
{
"helpLinks": [
""
],
"markdownMessage": "CodeQL encountered an unexpected internal error with the following message:\n> Assertion failed: `false`. Format the int 1234 and string myString if this assertion fails.\n\nSome or all of the Swift analysis may have failed.\n\nIf the error persists, contact support, quoting the error message and describing what happened, or [open an issue in our open source repository][1].\n\n[1]: https://github.com/github/codeql/issues/new?labels=bug&template=ql---general.md",
"severity": "warning",
"source": {
"extractorName": "swift",
"id": "swift/test/internal-error",
"name": "Internal error"
},
"visibility": {
"cliSummaryTable": true,
"statusPage": true,
"telemetry": true
}
}

View File

@@ -0,0 +1,15 @@
import importlib
import os
import subprocess
# We have to use importlib due to the '-' in the path
diagnostics_test_utils = importlib.import_module("swift.integration-tests.diagnostics_test_utils")
test_dir = "swift/logging/tests/assertion-diagnostics"
os.environ["CODEQL_EXTRACTOR_SWIFT_DIAGNOSTIC_DIR"] = "."
subprocess.run(os.path.join(test_dir, "assert-false"))
with open(os.path.join("test", os.listdir("test")[0]), "r") as actual:
diagnostics_test_utils.check_diagnostics(test_dir=test_dir,
# Put the diagnostic in a JSON array
actual='[' + actual.read() + ']')