From 73ead40ad10f47f32bafd3330486552ddffff7ac Mon Sep 17 00:00:00 2001
From: Frederik Hennig <frederik.hennig@fau.de>
Date: Fri, 7 Feb 2025 15:46:46 +0100
Subject: [PATCH] fix remaining bugs and tests

 - fix source file listing on cli
 - properly sort function and method args again
---
 src/pystencilssfg/config.py                |  5 +++--
 src/pystencilssfg/emission/clang_format.py |  4 ++--
 src/pystencilssfg/generator.py             |  3 ++-
 src/pystencilssfg/ir/analysis.py           |  6 ++++--
 src/pystencilssfg/ir/entities.py           | 16 ++++++++++------
 tests/generator_scripts/index.yaml         |  2 +-
 tests/integration/cmake_project/GenTest.py |  4 +---
 7 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/src/pystencilssfg/config.py b/src/pystencilssfg/config.py
index a94d9ad..3b63f4f 100644
--- a/src/pystencilssfg/config.py
+++ b/src/pystencilssfg/config.py
@@ -65,7 +65,7 @@ class CodeStyle(ConfigBase):
 
     includes_sorting_key: BasicOption[Callable[[HeaderFile], Any]] = BasicOption()
     """Key function that will be used to sort `#include` statements in generated files.
-    
+
     Pystencils-sfg will instruct clang-tidy to forego include sorting if this option is set.
     """
 
@@ -196,7 +196,8 @@ class SfgConfig(ConfigBase):
                 case OutputMode.STANDALONE:
                     impl_ext = "cpp"
 
-        if impl_ext is not None:
+        if output_mode != OutputMode.HEADER_ONLY:
+            assert impl_ext is not None
             output_files.append(output_dir / f"{basename}.{impl_ext}")
 
         return tuple(output_files)
diff --git a/src/pystencilssfg/emission/clang_format.py b/src/pystencilssfg/emission/clang_format.py
index b73d9da..50c51f1 100644
--- a/src/pystencilssfg/emission/clang_format.py
+++ b/src/pystencilssfg/emission/clang_format.py
@@ -14,7 +14,7 @@ def invoke_clang_format(
     Args:
         code: Code string to format
         options: Options controlling the clang-format invocation
-        sort_includes: Option to be passed on to clang-format's ``--sort-includes`` argument            
+        sort_includes: Option to be passed on to clang-format's ``--sort-includes`` argument
 
     Returns:
         The formatted code, if `clang-format` was run sucessfully.
@@ -33,7 +33,7 @@ def invoke_clang_format(
     force = options.get_option("force")
     style = options.get_option("code_style")
     args = [binary, f"--style={style}"]
-    
+
     if sort_includes is not None:
         args += ["--sort-includes", sort_includes]
 
diff --git a/src/pystencilssfg/generator.py b/src/pystencilssfg/generator.py
index dd9a78c..471e60b 100644
--- a/src/pystencilssfg/generator.py
+++ b/src/pystencilssfg/generator.py
@@ -107,12 +107,13 @@ class SourceFileGenerator:
         self._header_file.elements.append("#define RESTRICT __restrict__")
 
         outer_namespace: str | _GlobalNamespace = config.get_option("outer_namespace")
+
         match (outer_namespace, namespace):
             case [_GlobalNamespace(), None]:
                 namespace = None
             case [_GlobalNamespace(), nspace] if nspace is not None:
                 namespace = nspace
-            case [nspace, None]:
+            case [nspace, None] if not isinstance(nspace, _GlobalNamespace):
                 namespace = nspace
             case [outer, inner]:
                 namespace = f"{outer}::{inner}"
diff --git a/src/pystencilssfg/ir/analysis.py b/src/pystencilssfg/ir/analysis.py
index a2bce07..ff8331f 100644
--- a/src/pystencilssfg/ir/analysis.py
+++ b/src/pystencilssfg/ir/analysis.py
@@ -35,7 +35,9 @@ def collect_includes(file: SfgSourceFile) -> set[HeaderFile]:
                 | SfgMethod(_, _, parameters)
                 | SfgConstructor(_, parameters, _, _)
             ):
-                incls = reduce(set.union, (includes(p) for p in parameters), set())
+                incls: set[HeaderFile] = reduce(
+                    lambda accu, p: accu | includes(p), parameters, set()
+                )
                 if isinstance(entity, (SfgFunction, SfgMethod)):
                     incls |= includes(entity.return_type)
                 return incls
@@ -90,7 +92,7 @@ def collect_includes(file: SfgSourceFile) -> set[HeaderFile]:
             case SfgNamespaceBlock(_, elements) | SfgVisibilityBlock(_, elements):
                 return reduce(
                     lambda accu, elem: accu | walk_syntax(elem), elements, set()
-                )
+                )  # type: ignore
 
             case SfgClassBody(_, vblocks):
                 return reduce(
diff --git a/src/pystencilssfg/ir/entities.py b/src/pystencilssfg/ir/entities.py
index 90205fe..a855155 100644
--- a/src/pystencilssfg/ir/entities.py
+++ b/src/pystencilssfg/ir/entities.py
@@ -235,15 +235,17 @@ class SfgFunction(SfgCodeEntity):
         self._return_type = return_type
         self._inline = inline
 
-        self._parameters: set[SfgVar]
+        self._parameters: tuple[SfgVar, ...]
 
         from .postprocessing import CallTreePostProcessing
 
         param_collector = CallTreePostProcessing()
-        self._parameters = param_collector(self._tree).function_params
+        self._parameters = tuple(
+            sorted(param_collector(self._tree).function_params, key=lambda p: p.name)
+        )
 
     @property
-    def parameters(self) -> set[SfgVar]:
+    def parameters(self) -> tuple[SfgVar, ...]:
         return self._parameters
 
     @property
@@ -356,19 +358,21 @@ class SfgMethod(SfgClassMember):
         self._inline = inline
         self._const = const
 
-        self._parameters: set[SfgVar]
+        self._parameters: tuple[SfgVar, ...]
 
         from .postprocessing import CallTreePostProcessing
 
         param_collector = CallTreePostProcessing()
-        self._parameters = param_collector(self._tree).function_params
+        self._parameters = tuple(
+            sorted(param_collector(self._tree).function_params, key=lambda p: p.name)
+        )
 
     @property
     def name(self) -> str:
         return self._name
 
     @property
-    def parameters(self) -> set[SfgVar]:
+    def parameters(self) -> tuple[SfgVar, ...]:
         return self._parameters
 
     @property
diff --git a/tests/generator_scripts/index.yaml b/tests/generator_scripts/index.yaml
index c78b335..eae4c39 100644
--- a/tests/generator_scripts/index.yaml
+++ b/tests/generator_scripts/index.yaml
@@ -25,7 +25,7 @@ BasicDefinitions:
   expect-code:
     hpp:
       - regex: >-
-          #include\s\"config\.h\"\s*
+          #include\s\"config\.h\"(\s|.)*
           namespace\s+awesome\s+{\s+.+\s+
           #define\sPI\s3\.1415\s+
           using\snamespace\sstd\;\s+
diff --git a/tests/integration/cmake_project/GenTest.py b/tests/integration/cmake_project/GenTest.py
index 8399e70..093374c 100644
--- a/tests/integration/cmake_project/GenTest.py
+++ b/tests/integration/cmake_project/GenTest.py
@@ -1,8 +1,6 @@
 from pystencilssfg import SourceFileGenerator
 
-with SourceFileGenerator() as sfg:
-    sfg.namespace("gen")
-
+with SourceFileGenerator(namespace="gen") as sfg:
     retval = 42 if sfg.context.project_info is None else sfg.context.project_info
 
     sfg.function("getValue", return_type="int")(
-- 
GitLab