Skip to content

Commit 060a485

Browse files
committed
Swift: Emit diagnostics on assertion/expectation violations.
1 parent 7ada125 commit 060a485

File tree

7 files changed

+104
-22
lines changed

7 files changed

+104
-22
lines changed

swift/integration-tests/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
py_library(
2+
name = "integration_tests",
3+
srcs = [
4+
"create_database_utils.py",
5+
"diagnostics_test_utils.py",
6+
],
7+
visibility = ["//swift:__subpackages__"],
8+
)

swift/integration-tests/diagnostics_test_utils.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
import difflib
1111
import sys
1212

13-
14-
def _normalize_actual(test_dir, database_dir):
15-
proc = subprocess.run(['codeql', 'database', 'export-diagnostics', '--format', 'raw', '--', database_dir],
13+
def _get_actual(database_dir):
14+
return subprocess.run(['codeql', 'database', 'export-diagnostics', '--format', 'raw', '--', database_dir],
1615
stdout=subprocess.PIPE, universal_newlines=True, check=True, text=True)
17-
data = proc.stdout.replace(str(test_dir.absolute()), "<test-root-directory>")
16+
17+
def _normalize_actual(test_dir, data):
18+
data = data.replace(str(test_dir.absolute()), "<test-root-directory>")
1819
data = json.loads(data)
1920
data[:] = [e for e in data if not e["source"]["id"].startswith("cli/")]
2021
for e in data:
@@ -49,10 +50,12 @@ def _normalize_json(data):
4950
return "\n".join(entries)
5051

5152

52-
def check_diagnostics(test_dir=".", test_db="db"):
53+
def check_diagnostics(test_dir=".", test_db="db", actual = None):
5354
test_dir = pathlib.Path(test_dir)
5455
test_db = pathlib.Path(test_db)
55-
actual = _normalize_actual(test_dir, test_db)
56+
if actual is None:
57+
actual = _get_actual(test_db).stdout
58+
actual = _normalize_actual(test_dir, actual)
5659
if os.environ.get("CODEQL_INTEGRATION_TEST_LEARN") == "true":
5760
with open(test_dir / "diagnostics.expected", "w") as expected:
5861
expected.write(actual)

swift/logging/SwiftAssert.h

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,28 @@
44

55
#include "swift/logging/SwiftLogging.h"
66

7-
// assert CONDITION, which is always evaluated (once) regardless of the build type. If
8-
// CONDITION is not satisfied, emit a critical log optionally using provided format and arguments,
9-
// abort the program
7+
// Assert CONDITION, which is always evaluated (once) regardless of the build type. If
8+
// CONDITION is not satisfied, emit a critical log and diagnostic optionally using provided format
9+
// and arguments, and then abort the program.
1010
#define CODEQL_ASSERT(CONDITION, ...) \
11-
CODEQL_ASSERT_IMPL(CRITICAL, std::abort(), CONDITION, __VA_ARGS__)
11+
CODEQL_ASSERT_IMPL(critical, std::abort(), CONDITION, __VA_ARGS__)
1212

13-
// If CONDITION is not satisfied, emit an error log optionally using provided format and arguments,
14-
// but continue execution
13+
// If CONDITION is not satisfied, emit an error log and diagnostic optionally using provided format
14+
// and arguments, but continue execution
1515
#define CODEQL_EXPECT(CONDITION, ...) CODEQL_EXPECT_OR(void(), CONDITION, __VA_ARGS__)
1616

17-
// If CONDITION is not satisfied, emit an error log optionally using provided format and arguments,
18-
// and execute ACTION (for example return)
17+
// If CONDITION is not satisfied, emit an error log and diagnostic optionally using provided format
18+
// and arguments, and execute ACTION (for example return)
1919
#define CODEQL_EXPECT_OR(ACTION, CONDITION, ...) \
20-
CODEQL_ASSERT_IMPL(ERROR, ACTION, CONDITION, __VA_ARGS__)
20+
CODEQL_ASSERT_IMPL(error, ACTION, CONDITION, __VA_ARGS__)
2121

22-
#define CODEQL_ASSERT_IMPL(LEVEL, ACTION, CONDITION, ...) \
23-
do { \
24-
if (!(CONDITION)) { \
25-
[[unlikely]] LOG_##LEVEL("assertion failed on " #CONDITION ". " __VA_ARGS__); \
26-
codeql::Log::flush(); \
27-
ACTION; \
28-
} \
22+
#define CODEQL_ASSERT_IMPL(LEVEL, ACTION, CONDITION, ...) \
23+
do { \
24+
if (!(CONDITION)) { \
25+
[[unlikely]] DIAGNOSE_WITH_LEVEL(LEVEL, codeql::internalError, \
26+
"CodeQL encountered an unexpected internal error with the " \
27+
"following message:\n> Assertion failed: `" #CONDITION \
28+
"`. " __VA_ARGS__); \
29+
ACTION; \
30+
} \
2931
} while (false)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include "swift/logging/SwiftAssert.h"
2+
3+
const std::string_view codeql::programName = "test";
4+
5+
static codeql::Logger& logger() {
6+
static codeql::Logger ret{"main"};
7+
return ret;
8+
}
9+
10+
int main() {
11+
CODEQL_ASSERT(false, "Format the int {} and string {} if this assertion fails", 1234, "myString");
12+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
load("//swift:rules.bzl", "swift_cc_binary")
2+
load("//misc/bazel/cmake:cmake.bzl", "generate_cmake")
3+
4+
swift_cc_binary(
5+
name = "assert-false",
6+
srcs = ["AssertFalse.cpp"],
7+
visibility = ["//visibility:private"],
8+
deps = [
9+
"//swift/logging",
10+
],
11+
)
12+
13+
py_test(
14+
name = "test",
15+
size = "small",
16+
srcs = ["test.py"],
17+
deps = ["//swift/integration-tests:integration_tests"],
18+
data = [":assert-false", "diagnostics.expected"],
19+
)
20+
21+
generate_cmake(
22+
name = "cmake",
23+
targets = [":assert-false"],
24+
visibility = ["//visibility:public"],
25+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"helpLinks": [
3+
""
4+
],
5+
"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",
6+
"severity": "warning",
7+
"source": {
8+
"extractorName": "swift",
9+
"id": "swift/test/internal-error",
10+
"name": "Internal error"
11+
},
12+
"visibility": {
13+
"cliSummaryTable": true,
14+
"statusPage": true,
15+
"telemetry": true
16+
}
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import importlib
2+
import os
3+
import subprocess
4+
# We have to use importlib due to the '-' in the path
5+
diagnostics_test_utils = importlib.import_module("swift.integration-tests.diagnostics_test_utils")
6+
7+
test_dir = "swift/logging/tests/assertion-diagnostics"
8+
9+
os.environ["CODEQL_EXTRACTOR_SWIFT_DIAGNOSTIC_DIR"] = "."
10+
subprocess.run(os.path.join(test_dir, "assert-false"))
11+
12+
with open(os.path.join("test", os.listdir("test")[0]), "r") as actual:
13+
diagnostics_test_utils.check_diagnostics(test_dir=test_dir,
14+
# Put the diagnostic in a JSON array
15+
actual='[' + actual.read() + ']')

0 commit comments

Comments
 (0)