Skip to content

Commit

Permalink
Move Result class into independent file
Browse files Browse the repository at this point in the history
We prefer more but shortish and specialized files.
  • Loading branch information
martis42 committed Sep 10, 2023
1 parent a06deb2 commit 11be4fa
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 336 deletions.
1 change: 1 addition & 0 deletions src/analyze_includes/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ py_library(
"evaluate_includes.py",
"parse_config.py",
"parse_source.py",
"result.py",
"std_header.py",
"system_under_inspection.py",
],
Expand Down
72 changes: 2 additions & 70 deletions src/analyze_includes/evaluate_includes.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,15 @@
from collections import defaultdict
from dataclasses import dataclass, field
from json import dumps
from pathlib import Path
from typing import DefaultDict, List
from typing import List

from src.analyze_includes.parse_source import Include
from src.analyze_includes.result import Result
from src.analyze_includes.system_under_inspection import (
CcTarget,
SystemUnderInspection,
UsageStatus,
)


@dataclass
class Result:
target: str
public_includes_without_dep: List[Include] = field(default_factory=list)
private_includes_without_dep: List[Include] = field(default_factory=list)
unused_deps: List[str] = field(default_factory=list)
unused_implementation_deps: List[str] = field(default_factory=list)
deps_which_should_be_private: List[str] = field(default_factory=list)
use_implementation_deps: bool = False

def is_ok(self) -> bool:
return (
len(self.public_includes_without_dep) == 0
and len(self.private_includes_without_dep) == 0
and len(self.unused_deps) == 0
and len(self.unused_implementation_deps) == 0
and len(self.deps_which_should_be_private) == 0
)

def to_str(self) -> str:
msg = f"DWYU analyzing: '{self.target}'\n\n"
if self.is_ok():
msg += "Result: SUCCESS"
return self._framed_msg(msg)

msg += "Result: FAILURE\n"
if self.public_includes_without_dep or self.private_includes_without_dep:
msg += "\nIncludes which are not available from the direct dependencies:\n"
msg += "\n".join(f" {inc}" for inc in self.public_includes_without_dep + self.private_includes_without_dep)
if self.unused_deps:
msg += "\nUnused dependencies in 'deps' (none of their headers are referenced):\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.unused_deps)
if self.unused_implementation_deps:
msg += "\nUnused dependencies in 'implementation_deps' (none of their headers are referenced):\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.unused_implementation_deps)
if self.deps_which_should_be_private:
msg += "\nPublic dependencies which are used only in private code:\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.deps_which_should_be_private)
return self._framed_msg(msg)

def to_json(self) -> str:
content = {
"analyzed_target": self.target,
"public_includes_without_dep": self._make_includes_map(self.public_includes_without_dep),
"private_includes_without_dep": self._make_includes_map(self.private_includes_without_dep),
"unused_deps": self.unused_deps,
"unused_implementation_deps": self.unused_implementation_deps,
"deps_which_should_be_private": self.deps_which_should_be_private,
"use_implementation_deps": self.use_implementation_deps,
}
return dumps(content, indent=2) + "\n"

@staticmethod
def _make_includes_map(includes: List[Include]) -> DefaultDict[str, List[str]]:
includes_mapping = defaultdict(list)
for inc in includes:
includes_mapping[str(inc.file)].append(inc.include)
return includes_mapping

@staticmethod
def _framed_msg(msg: str) -> str:
"""Put a msg vertically between 2 borders"""
border = 80 * "="
return border + "\n" + msg + "\n" + border


def does_include_match_available_files(
include_statement: str, include_paths: List[str], header_files: List[str]
) -> bool:
Expand Down
72 changes: 72 additions & 0 deletions src/analyze_includes/result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from collections import defaultdict
from dataclasses import dataclass, field
from json import dumps
from typing import DefaultDict, List

from src.analyze_includes.parse_source import Include


@dataclass
class Result:
target: str
public_includes_without_dep: List[Include] = field(default_factory=list)
private_includes_without_dep: List[Include] = field(default_factory=list)
unused_deps: List[str] = field(default_factory=list)
unused_implementation_deps: List[str] = field(default_factory=list)
deps_which_should_be_private: List[str] = field(default_factory=list)
use_implementation_deps: bool = False

def is_ok(self) -> bool:
return (
len(self.public_includes_without_dep) == 0
and len(self.private_includes_without_dep) == 0
and len(self.unused_deps) == 0
and len(self.unused_implementation_deps) == 0
and len(self.deps_which_should_be_private) == 0
)

def to_str(self) -> str:
msg = f"DWYU analyzing: '{self.target}'\n\n"
if self.is_ok():
msg += "Result: SUCCESS"
return self._framed_msg(msg)

msg += "Result: FAILURE\n"
if self.public_includes_without_dep or self.private_includes_without_dep:
msg += "\nIncludes which are not available from the direct dependencies:\n"
msg += "\n".join(f" {inc}" for inc in self.public_includes_without_dep + self.private_includes_without_dep)
if self.unused_deps:
msg += "\nUnused dependencies in 'deps' (none of their headers are referenced):\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.unused_deps)
if self.unused_implementation_deps:
msg += "\nUnused dependencies in 'implementation_deps' (none of their headers are referenced):\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.unused_implementation_deps)
if self.deps_which_should_be_private:
msg += "\nPublic dependencies which are used only in private code:\n"
msg += "\n".join(f" Dependency='{dep}'" for dep in self.deps_which_should_be_private)
return self._framed_msg(msg)

def to_json(self) -> str:
content = {
"analyzed_target": self.target,
"public_includes_without_dep": self._make_includes_map(self.public_includes_without_dep),
"private_includes_without_dep": self._make_includes_map(self.private_includes_without_dep),
"unused_deps": self.unused_deps,
"unused_implementation_deps": self.unused_implementation_deps,
"deps_which_should_be_private": self.deps_which_should_be_private,
"use_implementation_deps": self.use_implementation_deps,
}
return dumps(content, indent=2) + "\n"

@staticmethod
def _make_includes_map(includes: List[Include]) -> DefaultDict[str, List[str]]:
includes_mapping = defaultdict(list)
for inc in includes:
includes_mapping[str(inc.file)].append(inc.include)
return includes_mapping

@staticmethod
def _framed_msg(msg: str) -> str:
"""Put a msg vertically between 2 borders"""
border = 80 * "="
return border + "\n" + msg + "\n" + border
6 changes: 6 additions & 0 deletions src/analyze_includes/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ py_test(
deps = ["//src/analyze_includes:lib"],
)

py_test(
name = "result_test",
srcs = ["result_test.py"],
deps = ["//src/analyze_includes:lib"],
)

py_test(
name = "system_under_inspection_test",
srcs = ["system_under_inspection_test.py"],
Expand Down
Loading

0 comments on commit 11be4fa

Please sign in to comment.