Skip to content
Open
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
17 changes: 17 additions & 0 deletions .github/workflows/clang-tidy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,20 @@ jobs:
name: clang-tidy-report
path: build/clang-tidy-report.txt
retention-days: 14

- name: Convert clang-tidy report to Allure JUnit XML
if: always()
run: |
THRESHOLD=$(head -1 clang-tidy-baseline.txt 2>/dev/null | tr -d '[:space:]')
python3 scripts/clang_tidy_to_allure.py \
build/clang-tidy-report.txt \
allure-results \
${THRESHOLD:+--threshold "$THRESHOLD"}

- name: Upload Allure results
uses: actions/upload-artifact@v4
if: always()
with:
name: allure-results-clang-tidy
path: allure-results/
retention-days: 14
2 changes: 1 addition & 1 deletion clang-tidy-baseline.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1783
384
8 changes: 4 additions & 4 deletions include/core/session_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,14 @@ class SessionManager {
*/
size_t get_active_session_count() const;

// Prevent copying
SessionManager(const SessionManager&) = delete;
SessionManager& operator=(const SessionManager&) = delete;

private:
std::unordered_map<uint16_t, std::shared_ptr<Session>> sessions_;
mutable platform::Mutex sessions_mutex_;
uint16_t next_session_id_{1};

// Prevent copying
SessionManager(const SessionManager&) = delete;
SessionManager& operator=(const SessionManager&) = delete;
};

} // namespace someip
Expand Down
5 changes: 3 additions & 2 deletions include/e2e/e2e_profile_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ class E2EProfileRegistry {
*/
E2EProfile* get_default_profile();

E2EProfileRegistry(const E2EProfileRegistry&) = delete;
E2EProfileRegistry& operator=(const E2EProfileRegistry&) = delete;

private:
E2EProfileRegistry() = default;
~E2EProfileRegistry() = default;
E2EProfileRegistry(const E2EProfileRegistry&) = delete;
E2EProfileRegistry& operator=(const E2EProfileRegistry&) = delete;

mutable platform::Mutex mutex_;
std::unordered_map<uint32_t, E2EProfilePtr> profiles_by_id_;
Expand Down
2 changes: 1 addition & 1 deletion include/platform/posix/net_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static inline int someip_set_socket_timeout(someip_socket_t fd, int optname,
int timeout_ms) {
struct timeval tv{};
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
tv.tv_usec = static_cast<long>(timeout_ms % 1000) * 1000L;
return ::setsockopt(fd, SOL_SOCKET, optname, &tv, sizeof(tv));
}

Expand Down
8 changes: 4 additions & 4 deletions include/someip/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ struct MessageId {
MessageId(uint16_t service, uint16_t method) : service_id(service), method_id(method) {}

uint32_t to_uint32() const {
return (static_cast<uint32_t>(service_id) << 16) | static_cast<uint32_t>(method_id);
return (static_cast<uint32_t>(service_id) << 16U) | static_cast<uint32_t>(method_id);
}

static MessageId from_uint32(uint32_t value) {
return MessageId(static_cast<uint16_t>(value >> 16), static_cast<uint16_t>(value & 0xFFFFU));
return MessageId(static_cast<uint16_t>(value >> 16U), static_cast<uint16_t>(value & 0xFFFFU));
}

bool operator==(const MessageId& other) const {
Expand All @@ -103,11 +103,11 @@ struct RequestId {
RequestId(uint16_t client, uint16_t session) : client_id(client), session_id(session) {}

uint32_t to_uint32() const {
return (static_cast<uint32_t>(client_id) << 16) | static_cast<uint32_t>(session_id);
return (static_cast<uint32_t>(client_id) << 16U) | static_cast<uint32_t>(session_id);
}

static RequestId from_uint32(uint32_t value) {
return RequestId(static_cast<uint16_t>(value >> 16), static_cast<uint16_t>(value & 0xFFFFU));
return RequestId(static_cast<uint16_t>(value >> 16U), static_cast<uint16_t>(value & 0xFFFFU));
}

bool operator==(const RequestId& other) const {
Expand Down
8 changes: 4 additions & 4 deletions include/transport/udp_transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ class UdpTransport : public ITransport {
Result join_multicast_group(const std::string& multicast_address);
Result leave_multicast_group(const std::string& multicast_address);

// Disable copy and assignment
UdpTransport(const UdpTransport&) = delete;
UdpTransport& operator=(const UdpTransport&) = delete;

private:
Endpoint local_endpoint_;
UdpTransportConfig config_;
Expand Down Expand Up @@ -110,10 +114,6 @@ class UdpTransport : public ITransport {
sockaddr_in create_sockaddr(const Endpoint& endpoint) const;
Endpoint sockaddr_to_endpoint(const sockaddr_in& addr) const;
bool is_multicast_address(const std::string& address) const;

// Disable copy and assignment
UdpTransport(const UdpTransport&) = delete;
UdpTransport& operator=(const UdpTransport&) = delete;
};

} // namespace someip::transport
Expand Down
120 changes: 120 additions & 0 deletions scripts/clang_tidy_to_allure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Convert a clang-tidy report into Allure-compatible JUnit XML.

Each clang-tidy check becomes a test suite, each unique warning becomes a
failing test case. The quality-gate result (pass/fail + counts) is emitted
as its own top-level test case.

Usage:
python3 clang_tidy_to_allure.py <report.txt> <output-dir> [--threshold N]

The output directory will contain a single JUnit XML file that the Allure
report workflow can ingest.
"""

import argparse
import re
import xml.etree.ElementTree as ET
from collections import defaultdict
from pathlib import Path


def parse_report(report_path: str) -> tuple[list[tuple[str, int, str, str]], dict[str, int]]:
warnings: list[tuple[str, int, str, str]] = []
summary: dict[str, int] = {}

with open(report_path, encoding="utf-8", errors="replace") as f:
for line in f:
m = re.match(r"(.+?):(\d+):\d+: warning: (.+?) \[(.+?)\]", line.strip())
if m:
filepath, lineno, message, check = (
m.group(1),
int(m.group(2)),
m.group(3),
m.group(4),
)
warnings.append((filepath, lineno, message, check))
continue

for key in ("Total Warnings", "Total Errors", "Total Issues", "Files with issues"):
if line.strip().startswith(f"{key}:"):
val = line.strip().split(":")[-1].strip()
if val.isdigit():
summary[key] = int(val)

return warnings, summary


def build_xml(
warnings: list[tuple[str, int, str, str]],
summary: dict[str, int],
threshold: int | None,
) -> ET.Element:
testsuites = ET.Element("testsuites")

by_check: dict[str, list[tuple[str, int, str]]] = defaultdict(list)
for filepath, lineno, message, check in warnings:
by_check[check].append((filepath, lineno, message))

for check, items in sorted(by_check.items()):
unique = sorted(set(items))
suite = ET.SubElement(
testsuites,
"testsuite",
name=f"clang-tidy/{check}",
tests=str(len(unique)),
failures=str(len(unique)),
)
for filepath, lineno, message in unique:
tc = ET.SubElement(
suite,
"testcase",
classname=f"clang-tidy.{check}",
name=f"{filepath}:{lineno}",
)
failure = ET.SubElement(tc, "failure", message=message)
failure.text = f"{filepath}:{lineno}: {message} [{check}]"

total = summary.get("Total Issues", len(warnings))
gate_suite = ET.SubElement(
testsuites,
"testsuite",
name="clang-tidy/quality-gate",
tests="1",
failures="0" if (threshold is None or total <= threshold) else "1",
)
tc = ET.SubElement(
gate_suite,
"testcase",
classname="clang-tidy.quality-gate",
name=f"violations={total}" + (f" threshold={threshold}" if threshold is not None else ""),
)
if threshold is not None and total > threshold:
failure = ET.SubElement(
tc, "failure", message=f"Violation count ({total}) exceeds threshold ({threshold})"
)
failure.text = f"FAILED: {total} > {threshold}"

return testsuites


def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("report", help="Path to clang-tidy-report.txt")
parser.add_argument("output_dir", help="Output directory for JUnit XML")
parser.add_argument("--threshold", type=int, default=None, help="Quality-gate threshold")
args = parser.parse_args()

warnings, summary = parse_report(args.report)
xml_root = build_xml(warnings, summary, args.threshold)

out = Path(args.output_dir)
out.mkdir(parents=True, exist_ok=True)
tree = ET.ElementTree(xml_root)
ET.indent(tree, space=" ")
tree.write(out / "clang-tidy-results.xml", encoding="unicode", xml_declaration=True)
print(f"Wrote {len(warnings)} warnings to {out / 'clang-tidy-results.xml'}")


if __name__ == "__main__":
main()
10 changes: 5 additions & 5 deletions src/e2e/e2e_crc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static constexpr uint8_t SAE_J1850_INIT = 0xFF;
uint8_t calculate_crc8_sae_j1850(const std::vector<uint8_t>& data) {
uint32_t crc_reg = SAE_J1850_INIT;

for (uint8_t byte : data) {
for (const uint8_t byte : data) {
crc_reg ^= static_cast<uint32_t>(byte);
for (int i = 0; i < 8; ++i) {
if ((crc_reg & 0x80U) != 0) {
Expand All @@ -59,7 +59,7 @@ static constexpr uint16_t ITU_X25_INIT = 0xFFFF;
uint16_t calculate_crc16_itu_x25(const std::vector<uint8_t>& data) {
uint32_t crc_reg = ITU_X25_INIT;

for (uint8_t byte : data) {
for (const uint8_t byte : data) {
crc_reg ^= static_cast<uint32_t>(byte) << 8U;
for (int i = 0; i < 8; ++i) {
if ((crc_reg & 0x8000U) != 0) {
Expand Down Expand Up @@ -105,8 +105,8 @@ uint32_t calculate_crc32(const std::vector<uint8_t>& data) {

uint32_t crc = CRC32_INIT;

for (uint8_t byte : data) {
uint32_t index = ((crc >> 24U) ^ static_cast<uint32_t>(byte)) & 0xFFU;
for (const uint8_t byte : data) {
const uint32_t index = ((crc >> 24U) ^ static_cast<uint32_t>(byte)) & 0xFFU;
crc = (crc << 8U) ^ crc32_table[index];
}

Expand All @@ -120,7 +120,7 @@ std::optional<uint32_t> calculate_crc(const std::vector<uint8_t>& data, size_t o
}

auto first = data.begin() + static_cast<std::ptrdiff_t>(offset);
std::vector<uint8_t> slice(first, first + static_cast<std::ptrdiff_t>(length));
const std::vector<uint8_t> slice(first, first + static_cast<std::ptrdiff_t>(length));

switch (crc_type) {
case 0: // SAE-J1850 (8-bit)
Expand Down
1 change: 0 additions & 1 deletion src/e2e/e2e_profile_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#include "e2e/e2e_profile_registry.h"

#include "e2e/e2e_config.h"
#include "platform/thread.h"

#include <cstdint>
Expand Down
4 changes: 2 additions & 2 deletions src/e2e/e2e_profiles/standard_profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ class BasicE2EProfile : public E2EProfile {
// which includes E2E header. However, we need to be careful - the actual length
// in the message will be set by update_length() after we set the E2E header.
// For now, calculate what the length will be:
size_t const e2e_size = E2EHeader::get_header_size();
uint32_t length = 8 + e2e_size + static_cast<uint32_t>(msg.get_payload().size());
size_t const e2e_size = E2EHeader::get_header_size();
const uint32_t length = 8 + e2e_size + static_cast<uint32_t>(msg.get_payload().size());
uint32_t length_be = someip_htonl(length);
crc_data.insert(crc_data.end(), reinterpret_cast<const uint8_t*>(&length_be),
reinterpret_cast<const uint8_t*>(&length_be) + sizeof(uint32_t));
Expand Down
7 changes: 6 additions & 1 deletion src/events/event_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

namespace someip::events {

// NOLINTBEGIN(misc-include-cleaner) - platform::Mutex / platform::this_thread from platform/thread.h (IWYU false positives in impl).

/**
* @brief Event Publisher implementation
* @implements REQ_ARCH_001
Expand Down Expand Up @@ -208,6 +210,7 @@ class EventPublisherImpl : public transport::ITransportListener {
std::vector<uint16_t> get_registered_events() const {
platform::ScopedLock const events_lock(events_mutex_);
std::vector<uint16_t> events;
events.reserve(registered_events_.size());

for (const auto& pair : registered_events_) {
events.push_back(pair.first);
Expand Down Expand Up @@ -295,7 +298,7 @@ class EventPublisherImpl : public transport::ITransportListener {
}
}

for (uint16_t eid : events_to_publish) {
for (const uint16_t eid : events_to_publish) {
publish_event(eid, {});
}
}
Expand Down Expand Up @@ -419,4 +422,6 @@ EventPublisher::Statistics EventPublisher::get_statistics() const {
return impl_->get_statistics();
}

// NOLINTEND(misc-include-cleaner)

} // namespace someip::events
Loading
Loading