Skip to content

Accept C files ending in a backslash-newline #187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 19 additions & 12 deletions codebasin/file_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,17 +460,14 @@ def logical_result(self):
)


def c_file_source(fp, relaxed=False, directives_only=False):
def c_file_source(fp, directives_only=False):
"""
Process file fp in terms of logical (sloc) and physical lines of C code.
Yield blocks of logical lines of code with physical extents.
Return total lines at exit.
Relaxed allows for inconsistent state at the end of parsing, usefule for
special composition cases.
directives_only sets up parser to only process directive lines such that
the output can be fed to another file source (i.e. Fortran).
"""

current_physical_line = one_space_line()
cleaner = c_cleaner(current_physical_line, directives_only)

Expand All @@ -479,6 +476,7 @@ def c_file_source(fp, relaxed=False, directives_only=False):
total_sloc = 0

physical_line_num = 0
continued = False
for physical_line_num, line in enumerate(fp, start=1):
current_physical_line.__init__()
end = len(line)
Expand Down Expand Up @@ -513,22 +511,28 @@ def c_file_source(fp, relaxed=False, directives_only=False):
yield curr_line

total_sloc += curr_line.physical_reset()
if not relaxed and not cleaner.state == ["TOPLEVEL"]:

# Even if code is technically wrong, we should only fail when necessary.
parsing_failed = not cleaner.state == ["TOPLEVEL"]
if continued:
log.warning("backslash-newline at end of file")
parsing_failed = False

if parsing_failed:
raise RuntimeError(
"Parser must end at top level without 'relaxed' mode.",
"Parsing failed. Please open a bug report at: "
"https://github.com/intel/code-base-investigator/issues/new?template=bug_report.yml.", # noqa: E501
)

return (total_sloc, total_physical_lines)


def fortran_file_source(fp, relaxed=False):
def fortran_file_source(fp):
"""
Process file fp in terms of logical (sloc) and physical lines of
fixed-form Fortran code.
Yield blocks of logical lines of code with physical extents.
Return total lines at exit.
Relaxed allows for inconsistent state at the end of parsing, usefule for
special composition cases.
"""

current_physical_line = one_space_line()
Expand Down Expand Up @@ -593,9 +597,12 @@ def fortran_file_source(fp, relaxed=False):
yield curr_line

total_sloc += curr_line.physical_reset()
if not relaxed and not cleaner.state == ["TOPLEVEL"]:

parsing_failed = not cleaner.state == ["TOPLEVEL"]
if parsing_failed:
raise RuntimeError(
"Parser must end at top level without 'relaxed' mode.",
"Parsing failed. Please open a bug report at: "
"https://github.com/intel/code-base-investigator/issues/new?template=bug_report.yml.", # noqa: E501
)

return (total_sloc, total_physical_lines)
Expand Down Expand Up @@ -642,7 +649,7 @@ def process(self, lineiter):
pass


def asm_file_source(fp, relaxed=False):
def asm_file_source(fp):
"""
Process file fp in terms of logical (sloc) and physical lines of ASM code.
Yield blocks of logical lines of code with physical extents.
Expand Down
1 change: 1 addition & 0 deletions codebasin/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def find(
leave=False,
disable=not show_progress,
):
log.debug(f"Parsing {f}")
state.insert_file(f)

# Process each tree, by associating nodes with platforms
Expand Down
2 changes: 2 additions & 0 deletions tests/preprocessor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright (C) 2019 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
42 changes: 42 additions & 0 deletions tests/preprocessor/test_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (C) 2019-2024 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause

import logging
import os
import tempfile
import unittest
from pathlib import Path

from codebasin import file_parser


class TestPreprocessorWarnings(unittest.TestCase):
"""
Test that preprocessor generates warnings for weird corner cases.
"""

def setUp(self):
self.cwd = os.getcwd()

def tearDown(self):
os.chdir(self.cwd)

def test_backslash_eof(self):
"""Check backslash-newline at EOF is only a warning"""
tmp = tempfile.TemporaryDirectory()
path = Path(tmp.name)
os.chdir(tmp.name)

with open(path / "test.hpp", mode="w") as f:
f.write("#define BAD_MACRO \\\n")

parser = file_parser.FileParser(path / "test.hpp")

logging.disable(logging.NOTSET)
logger = logging.getLogger("codebasin")
with self.assertLogs(logger, level="WARNING") as cm:
_ = parser.parse_file()
logging.disable()
self.assertRegex(cm.output[0], "backslash-newline at end of file")

tmp.cleanup()