Repository: sqlfluff/sqlfluff

Issue:
2.0.3 [LT02] - ValueError: max() arg is an empty sequence
### Search before asking

- [X] I searched the [issues](https://github.com/sqlfluff/sqlfluff/issues) and found no similar issues.


### What Happened

Linting a model that had no errors previous to the 2.0.0 upgrade (before rules were grouped and all had L0XX names) now throws an unexpected ValueError exception. 

```python
CRITICAL   [LT02] Applying rule LT02 to 'path/code_snippet.sql' threw an Exception: max() arg is an empty sequence 
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/sqlfluff/core/rules/base.py", line 796, in crawl
    res = self._eval(context=context)
  File "/usr/local/lib/python3.9/site-packages/sqlfluff/rules/layout/LT02.py", line 62, in _eval
    ReflowSequence.from_root(context.segment, context.config)
  File "/usr/local/lib/python3.9/site-packages/sqlfluff/utils/reflow/sequence.py", line 578, in reindent
    elements, indent_results = lint_indent_points(
  File "/usr/local/lib/python3.9/site-packages/sqlfluff/utils/reflow/reindent.py", line 1379, in lint_indent_points
    _revise_templated_lines(lines, elements)
  File "/usr/local/lib/python3.9/site-packages/sqlfluff/utils/reflow/reindent.py", line 498, in _revise_templated_lines
    best_indent = max(overlap)
ValueError: max() arg is an empty sequence
```

### Expected Behaviour

There shouldn't be any critical error.

### Observed Behaviour

Linting the .sql file with jinja code throws the exception. However, compiling the model and linting the compiled version throws no critical issue at all.

### How to reproduce

This snipped of abstract code should replicate the error:

```sql
with data as (
    select
        'A' as company_name,
        'B' as company_location,
),

{% for variable_array in [{"time_aggregation": "X", "cte_order": 1},{"time_aggregation": "Y", "cte_order": 2},{"time_aggregation": "Z", "cte_order": 3}] %}{% for evaluation_metric in ['C', 'D', 'E'] %}

{{ evaluation_metric }}_fill_{{ variable_array.cte_order }} as (
    select
        company_name,
        company_location,
        '{{ evaluation_metric }}' as evaluation_metric,
        '{{ variable_array.time_aggregation }}' as time_aggregation,
        {{ variable_array.cte_order }} as cte_order,
        null as evaluation_value,
    from data
),
{% endfor %}{% endfor %}

union_all_data as (
    {% for variable_array in [{"time_aggregation": "X", "cte_order": 1},{"time_aggregation": "Y", "cte_order": 2},{"time_aggregation": "Z", "cte_order": 3}] %}{% for evaluation_metric in ['C', 'D', 'E'] %}
    select *, from {{ evaluation_metric }}_fill_{{ variable_array.cte_order }}
    {% if not loop.last %}union all{% endif %}{% endfor %}{% if not loop.last %}union all{% endif %}{% endfor %}
)

select *, from union_all_data
```

If you `dbt compile -m code_snippet` it will throw out no exceptions (although it will fail due to a minor LT01 violation)

### Dialect
`
dbt-bigquery
`
### Version
```
sqlfluff = "==2.0.3"
sqlfluff-templater-dbt = "==2.0.3"
```

### Configuration
```
[sqlfluff]
dialect = bigquery
exclude_rules = LT05,RF01,AL07,ST07,ST06,AM06
ignore_templated_areas = True
templater = dbt
large_file_skip_byte_limit = 0

[sqlfluff:rules:capitalisation.keywords]
capitalisation_policy = lower

[sqlfluff:rules:capitalisation.identifiers]
unquoted_identifiers_policy = column_aliases
extended_capitalisation_policy = lower

[sqlfluff:rules:capitalisation.functions]
capitalisation_policy = lower

[sqlfluff:rules:capitalisation.literals]
capitalisation_policy = lower

[sqlfluff:rules:layout.long_lines]
max_line_length = 150

[sqlfluff:rules:convention.select_trailing_comma]
select_clause_trailing_comma = require
```

### Are you willing to work on and submit a PR to address the issue?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/sqlfluff/sqlfluff/blob/main/CODE_OF_CONDUCT.md)


Discussion:
alanmcruickshank: Hold off reviewing this - This solution results in an oscillation 🤦 
coveralls: ## Pull Request Test Coverage Report for [Build 4704783286](https://coveralls.io/builds/58929655)

* **12** of **12**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/58929655/badge)](https://coveralls.io/builds/58929655) |
| :-- | --: |
| Change from base [Build 4704009708](https://coveralls.io/builds/58927123): |  0.0% |
| Covered Lines: | 17845 |
| Relevant Lines: | 17845 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/README.md b/README.md
index 43d641a0b..fd73689c8 100644
--- a/README.md
+++ b/README.md
@@ -101,7 +101,7 @@ L:   1 | P:  14 | LT01 | Expected only single space before naked identifier.
 L:   1 | P:  27 | LT01 | Unnecessary trailing whitespace at end of file.
                        | [layout.spacing]
 L:   1 | P:  27 | LT12 | Files must end with a single trailing newline.
-                       | [layout.end-of-file]
+                       | [layout.end_of_file]
 All Finished 📜 🎉!
 ```
 
diff --git a/docs/generate-rule-docs.py b/docs/generate-rule-docs.py
index 109d1a4b4..8551e190d 100644
--- a/docs/generate-rule-docs.py
+++ b/docs/generate-rule-docs.py
@@ -41,8 +41,9 @@ with open(base_path / "source/partials/rule_table.rst", "w", encoding="utf8") as
         # Set the bundle name to the ref.
         _bundle_name = f":ref:`bundle_{bundle}`"
         for idx, rule in enumerate(rule_bundles[bundle]):
-            aliases = ", ".join(rule.aliases[:3]) + (
-                "," if len(rule.aliases) > 3 else ""
+            step = 1  # The number of aliases per line.
+            aliases = ", ".join(rule.aliases[:step]) + (
+                "," if len(rule.aliases) > step else ""
             )
             name_ref = f":sqlfluff:ref:`{rule.name}`"
             code_ref = f":sqlfluff:ref:`{rule.code}`"
@@ -51,15 +52,16 @@ with open(base_path / "source/partials/rule_table.rst", "w", encoding="utf8") as
                 f"| {code_ref : <28} | {aliases : <18} |\n"
             )
 
-            j = 3
+            j = 1
+
             while True:
                 if not rule.aliases[j:]:
                     break
-                aliases = ", ".join(rule.aliases[j : j + 3]) + (
-                    "," if len(rule.aliases[j:]) > 3 else ""
+                aliases = ", ".join(rule.aliases[j : j + step]) + (
+                    "," if len(rule.aliases[j:]) > step else ""
                 )
                 f.write(f"|{' ' * 42}|{' ' * 50}|{' ' * 30}| {aliases : <18} |\n")
-                j += 3
+                j += step
 
             if idx + 1 < len(rule_bundles[bundle]):
                 f.write(f"|{' ' * 42}+{'-' * 50}+{'-' * 30}+{'-' * 20}+\n")
diff --git a/docs/source/index.rst b/docs/source/index.rst
index fc486e242..6fee6331b 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -46,7 +46,7 @@ have python or pip already installed see :ref:`gettingstartedref`.
     L:   1 | P:  27 | LT01 | Unnecessary trailing whitespace at end of file.
                            | [layout.spacing]
     L:   1 | P:  27 | LT12 | Files must end with a single trailing newline.
-                           | [layout.end-of-file]
+                           | [layout.end_of_file]
     All Finished 📜 🎉!
 
 Contents
diff --git a/src/sqlfluff/rules/layout/LT12.py b/src/sqlfluff/rules/layout/LT12.py
index 7f1f570e6..49cccf7a5 100644
--- a/src/sqlfluff/rules/layout/LT12.py
+++ b/src/sqlfluff/rules/layout/LT12.py
@@ -102,8 +102,10 @@ class Rule_LT12(BaseRule):
 
     """
 
-    name = "layout.end-of-file"
-    aliases = ("L009",)
+    name = "layout.end_of_file"
+    # Between 2.0.0 and 2.0.4 we supported had a kebab-case name for this rule
+    # so the old name remains here as an alias to enable backward compatibility.
+    aliases = ("L009", "layout.end-of-file")
     groups = ("all", "core", "layout")
 
     targets_templated = True
diff --git a/src/sqlfluff/utils/reflow/reindent.py b/src/sqlfluff/utils/reflow/reindent.py
index f5ae4a03f..243e1cf54 100644
--- a/src/sqlfluff/utils/reflow/reindent.py
+++ b/src/sqlfluff/utils/reflow/reindent.py
@@ -272,24 +272,25 @@ def _revise_templated_lines(lines: List[_IndentLine], elements: ReflowSequenceTy
     for idx, line in enumerate(lines):
         if line.is_all_templates(elements):
             # We can't assume they're all a single block.
-            # But if they _start_ with a block, we should
-            # respect the indent of that block.
-            segment = cast(
-                MetaSegment, elements[line.indent_points[-1].idx - 1].segments[0]
-            )
-            assert segment.is_type("placeholder", "template_loop")
-            # If it's not got a block uuid, it's not a block, so it
-            # should just be indented as usual. No need to revise.
-            # e.g. comments or variables
-            if segment.block_uuid:
-                grouped[segment.block_uuid].append(idx)
-                depths[segment.block_uuid].append(line.initial_indent_balance)
-                reflow_logger.debug(
-                    "  UUID: %s @ %s = %r",
-                    segment.block_uuid,
-                    idx,
-                    segment.pos_marker.source_str(),
-                )
+            # So handle all blocks on the line.
+            for i in range(line.indent_points[0].idx, line.indent_points[-1].idx):
+                if isinstance(elements[i], ReflowPoint):
+                    continue
+                # We already checked that it's all templates.
+                segment = cast(MetaSegment, elements[i].segments[0])
+                assert segment.is_type("placeholder", "template_loop")
+                # If it's not got a block uuid, it's not a block, so it
+                # should just be indented as usual. No need to revise.
+                # e.g. comments or variables
+                if segment.block_uuid:
+                    grouped[segment.block_uuid].append(idx)
+                    depths[segment.block_uuid].append(line.initial_indent_balance)
+                    reflow_logger.debug(
+                        "  UUID: %s @ %s = %r",
+                        segment.block_uuid,
+                        idx,
+                        segment.pos_marker.source_str(),
+                    )
 
     # Sort through the lines, so we do to *most* indented first.
     sorted_group_indices = sorted(
@@ -492,17 +493,16 @@ def _revise_templated_lines(lines: List[_IndentLine], elements: ReflowSequenceTy
         # Evaluate options.
         # NOTE: We don't use the _last_ option, because it tends to be trailing
         # and have strange effects.
+        reflow_logger.debug("    Options: %s", options)
         overlap = set.intersection(*options[:-1])
         reflow_logger.debug("    Simple Overlap: %s", overlap)
         # Remove any options above the limit option.
         # We minus one from the limit, because if it comes into effect
         # we'll effectively remove the effects of the indents between the elements.
 
-        best_indent = max(overlap)
-
         # Is there a mutually agreeable option?
         reflow_logger.debug("    Balance Trough: %s", balance_trough)
-        if balance_trough is not None and balance_trough <= 0:
+        if not overlap or (balance_trough is not None and balance_trough <= 0):
             # Set the indent to the minimum of the existing ones.
             best_indent = min(lines[idx].initial_indent_balance for idx in group_lines)
             reflow_logger.debug(
@@ -515,6 +515,7 @@ def _revise_templated_lines(lines: List[_IndentLine], elements: ReflowSequenceTy
                 # MUTATION
                 lines[idx].initial_indent_balance -= 1
         else:
+            best_indent = max(overlap)
             reflow_logger.debug(
                 "    Case 2: Best: %s, Overlap: %s", best_indent, overlap
             )
diff --git a/src/sqlfluff/utils/reflow/respace.py b/src/sqlfluff/utils/reflow/respace.py
index 6316a9ed6..bee949184 100644
--- a/src/sqlfluff/utils/reflow/respace.py
+++ b/src/sqlfluff/utils/reflow/respace.py
@@ -120,6 +120,11 @@ def process_spacing(
         # If it's a newline, react accordingly.
         # NOTE: This should only trigger on literal newlines.
         elif seg.is_type("newline", "end_of_file"):
+            if seg.pos_marker and not seg.pos_marker.is_literal():
+                last_whitespace = []
+                reflow_logger.debug("    Skipping templated newline: %s", seg)
+                continue
+
             # Are we stripping newlines?
             if strip_newlines and seg.is_type("newline"):
                 reflow_logger.debug("    Stripping newline: %s", seg)


Test patch:
diff --git a/test/api/simple_test.py b/test/api/simple_test.py
index e83adfe20..cc99435ab 100644
--- a/test/api/simple_test.py
+++ b/test/api/simple_test.py
@@ -95,7 +95,7 @@ lint_result = [
         "line_no": 1,
         "line_pos": 41,
         "description": "Files must end with a single trailing newline.",
-        "name": "layout.end-of-file",
+        "name": "layout.end_of_file",
     },
 ]
 
diff --git a/test/fixtures/rules/std_rule_cases/LT01-trailing.yml b/test/fixtures/rules/std_rule_cases/LT01-trailing.yml
index 510a40212..68f47fb7b 100644
--- a/test/fixtures/rules/std_rule_cases/LT01-trailing.yml
+++ b/test/fixtures/rules/std_rule_cases/LT01-trailing.yml
@@ -21,3 +21,20 @@ test_pass_trailing_whitespace_before_template_code:
 test_fail_trailing_whitespace_and_whitespace_control:
   fail_str: "{%- set temp = 'temp' -%}\n\nSELECT\n    1, \n    2,\n"
   fix_str: "{%- set temp = 'temp' -%}\n\nSELECT\n    1,\n    2,\n"
+
+test_pass_macro_trailing:
+  pass_str: |
+    {% macro foo(bar) %}
+        {{bar}}
+    {% endmacro %}
+
+    with base as (
+        select
+            a,
+            b,
+            {{ foo(1) }} as c
+        from tblb
+    )
+
+    select *
+    from tbl
diff --git a/test/fixtures/rules/std_rule_cases/LT02-indent.yml b/test/fixtures/rules/std_rule_cases/LT02-indent.yml
index b1253cdbe..9f56de54a 100644
--- a/test/fixtures/rules/std_rule_cases/LT02-indent.yml
+++ b/test/fixtures/rules/std_rule_cases/LT02-indent.yml
@@ -1941,3 +1941,27 @@ test_fail_issue_4680:
         {% else %}
         col1 > 0
       {% endif %}
+
+test_fail_issue_4745:
+  fail_str: |
+    with
+    {% for a in [1, 2, 3] %}{% for b in ['C'] %}
+
+    {{ b }}_fill_{{ a }} as (
+        select *
+        from data
+    ),
+    {% endfor %}{% endfor %}
+
+    select 1
+  fix_str: |
+    with
+    {% for a in [1, 2, 3] %}{% for b in ['C'] %}
+
+        {{ b }}_fill_{{ a }} as (
+            select *
+            from data
+        ),
+    {% endfor %}{% endfor %}
+
+    select 1