prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Feature Request: !Sub equivalent of W1001
  *cfn-lint version: 0.58.2*
  
  I believe that `!Sub` parameters should be checked to see if they depend on conditional resources the same way W1001 checks this for `!Ref` (e.g. `SubCondParam.Value` should produce a warning). I suspect this is possible since E1019 checks for non-existent parameters within a `!Sub`.
  
  ```
  ---
  AWSTemplateFormatVersion: 2010-09-09
  
  Conditions:
    CreateContainerRepository: !Equals ["yes", "no"]
  
  Resources:
    Repository:
      Type: AWS::ECR::Repository
      Condition: CreateContainerRepository
  
    SubCondParam:
      Type: AWS::SSM::Parameter
      Properties:
        Type: String
        Value: !Sub ${Repository}
  
    RefCondParam:
      Type: AWS::SSM::Parameter
      Properties:
        Type: String
        Value: !Ref Repository
  
    SubFakeParam:
      Type: AWS::SSM::Parameter
      Properties:
        Type: String
        Value: !Sub ${Fake}
  
    RefFakeParam:
      Type: AWS::SSM::Parameter
      Properties:
        Type: String
        Value: !Ref Fake
  ```
  
  * SubCondParam.Value shows no error or warning, I believe it should show a warning
  * RefCondParam.Value shows W1001
  * SubFakeParam.Value shows E1019
  * RefFakeParam.Value shows E1012
  
  </issue>
  <code>
  [start of src/cfnlint/rules/functions/RelationshipConditions.py]
  1 """
  2 Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3 SPDX-License-Identifier: MIT-0
  4 """
  5 from cfnlint.helpers import PSEUDOPARAMS
  6 from cfnlint.rules import CloudFormationLintRule, RuleMatch
  7 
  8 
  9 class RelationshipConditions(CloudFormationLintRule):
  10     """Check if Ref/GetAtt values are available via conditions"""
  11 
  12     id = "W1001"
  13     shortdesc = "Ref/GetAtt to resource that is available when conditions are applied"
  14     description = (
  15         "Check the Conditions that affect a Ref/GetAtt to make sure "
  16         "the resource being related to is available when there is a resource "
  17         "condition."
  18     )
  19     source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html"
  20     tags = ["conditions", "resources", "relationships", "ref", "getatt"]
  21 
  22     def match(self, cfn):
  23         """Check CloudFormation Ref/GetAtt for Conditions"""
  24 
  25         matches = []
  26 
  27         # Start with Ref checks
  28         ref_objs = cfn.search_deep_keys(searchText="Ref", includeGlobals=False)
  29         for ref_obj in ref_objs:
  30             value = ref_obj[-1]
  31             if value not in PSEUDOPARAMS:
  32                 scenarios = cfn.is_resource_available(ref_obj, value)
  33                 for scenario in scenarios:
  34                     # pylint: disable=consider-using-f-string
  35                     scenario_text = " and ".join(
  36                         [
  37                             'when condition "%s" is %s' % (k, v)
  38                             for (k, v) in scenario.items()
  39                         ]
  40                     )
  41                     message = (
  42                         'Ref to resource "{0}" that may not be available {1} at {2}'
  43                     )
  44                     matches.append(
  45                         RuleMatch(
  46                             ref_obj[:-1],
  47                             message.format(
  48                                 value, scenario_text, "/".join(map(str, ref_obj[:-1]))
  49                             ),
  50                         )
  51                     )
  52 
  53         # The do GetAtt
  54         getatt_objs = cfn.search_deep_keys(
  55             searchText="Fn::GetAtt", includeGlobals=False
  56         )
  57         for getatt_obj in getatt_objs:
  58             value_obj = getatt_obj[-1]
  59             value = None
  60             if isinstance(value_obj, list):
  61                 value = value_obj[0]
  62             elif isinstance(value_obj, str):
  63                 value = value_obj.split(".")[0]
  64             if value:
  65                 if value not in PSEUDOPARAMS:
  66                     scenarios = cfn.is_resource_available(getatt_obj, value)
  67                     for scenario in scenarios:
  68                         scenario_text = " and ".join(
  69                             [
  70                                 f'when condition "{k}" is {v}'
  71                                 for (k, v) in scenario.items()
  72                             ]
  73                         )
  74                         message = 'GetAtt to resource "{0}" that may not be available {1} at {2}'
  75                         matches.append(
  76                             RuleMatch(
  77                                 getatt_obj[:-1],
  78                                 message.format(
  79                                     value,
  80                                     scenario_text,
  81                                     "/".join(map(str, getatt_obj[:-1])),
  82                                 ),
  83                             )
  84                         )
  85 
  86         return matches
  87
  [end of src/cfnlint/rules/functions/RelationshipConditions.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/cfnlint/rules/functions/RelationshipConditions.py b/src/cfnlint/rules/functions/RelationshipConditions.py
  --- a/src/cfnlint/rules/functions/RelationshipConditions.py
  +++ b/src/cfnlint/rules/functions/RelationshipConditions.py
  @@ -17,7 +17,7 @@
           "condition."
       )
       source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html"
  -    tags = ["conditions", "resources", "relationships", "ref", "getatt"]
  +    tags = ["conditions", "resources", "relationships", "ref", "getatt", "sub"]
   
       def match(self, cfn):
           """Check CloudFormation Ref/GetAtt for Conditions"""
  @@ -83,4 +83,46 @@
                               )
                           )
   
  +        # The do Sub
  +        sub_objs = cfn.search_deep_keys(searchText="Fn::Sub", includeGlobals=False)
  +        for sub_obj in sub_objs:
  +            sub_string = sub_obj[-1]
  +            # Filter out bad types of sub_strings.
  +            # Lists have two be two items and it can be just a string
  +            if not isinstance(sub_string, (list, str)):
  +                continue
  +            if isinstance(sub_string, str):
  +                sub_string = [sub_string, {}]
  +            if len(sub_string) != 2:
  +                continue
  +            sub_params = sub_string[1]
  +            string_params = cfn.get_sub_parameters(sub_string[0])
  +
  +            for string_param in string_params:
  +                if string_param not in sub_params:
  +                    # deal with GetAtts by dropping everything after the .
  +                    string_param = string_param.split(".")[0]
  +                    if string_param in cfn.template.get("Resources", {}):
  +                        scenarios = cfn.is_resource_available(
  +                            sub_obj[:-1], string_param
  +                        )
  +                        for scenario in scenarios:
  +                            scenario_text = " and ".join(
  +                                [
  +                                    f'when condition "{k}" is {v}'
  +                                    for (k, v) in scenario.items()
  +                                ]
  +                            )
  +                            message = 'Fn::Sub to resource "{0}" that may not be available {1} at {2}'
  +                            matches.append(
  +                                RuleMatch(
  +                                    sub_obj[:-1],
  +                                    message.format(
  +                                        string_param,
  +                                        scenario_text,
  +                                        "/".join(map(str, sub_obj[:-1])),
  +                                    ),
  +                                )
  +                            )
  +
           return matches
  
verification_info: {"golden_diff": "diff --git a/src/cfnlint/rules/functions/RelationshipConditions.py b/src/cfnlint/rules/functions/RelationshipConditions.py\n--- a/src/cfnlint/rules/functions/RelationshipConditions.py\n+++ b/src/cfnlint/rules/functions/RelationshipConditions.py\n@@ -17,7 +17,7 @@\n         \"condition.\"\n     )\n     source_url = \"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html\"\n-    tags = [\"conditions\", \"resources\", \"relationships\", \"ref\", \"getatt\"]\n+    tags = [\"conditions\", \"resources\", \"relationships\", \"ref\", \"getatt\", \"sub\"]\n \n     def match(self, cfn):\n         \"\"\"Check CloudFormation Ref/GetAtt for Conditions\"\"\"\n@@ -83,4 +83,46 @@\n                             )\n                         )\n \n+        # The do Sub\n+        sub_objs = cfn.search_deep_keys(searchText=\"Fn::Sub\", includeGlobals=False)\n+        for sub_obj in sub_objs:\n+            sub_string = sub_obj[-1]\n+            # Filter out bad types of sub_strings.\n+            # Lists have two be two items and it can be just a string\n+            if not isinstance(sub_string, (list, str)):\n+                continue\n+            if isinstance(sub_string, str):\n+                sub_string = [sub_string, {}]\n+            if len(sub_string) != 2:\n+                continue\n+            sub_params = sub_string[1]\n+            string_params = cfn.get_sub_parameters(sub_string[0])\n+\n+            for string_param in string_params:\n+                if string_param not in sub_params:\n+                    # deal with GetAtts by dropping everything after the .\n+                    string_param = string_param.split(\".\")[0]\n+                    if string_param in cfn.template.get(\"Resources\", {}):\n+                        scenarios = cfn.is_resource_available(\n+                            sub_obj[:-1], string_param\n+                        )\n+                        for scenario in scenarios:\n+                            scenario_text = \" and \".join(\n+                                [\n+                                    f'when condition \"{k}\" is {v}'\n+                                    for (k, v) in scenario.items()\n+                                ]\n+                            )\n+                            message = 'Fn::Sub to resource \"{0}\" that may not be available {1} at {2}'\n+                            matches.append(\n+                                RuleMatch(\n+                                    sub_obj[:-1],\n+                                    message.format(\n+                                        string_param,\n+                                        scenario_text,\n+                                        \"/\".join(map(str, sub_obj[:-1])),\n+                                    ),\n+                                )\n+                            )\n+\n         return matches\n", "issue": "Feature Request: !Sub equivalent of W1001\n*cfn-lint version: 0.58.2*\r\n\r\nI believe that `!Sub` parameters should be checked to see if they depend on conditional resources the same way W1001 checks this for `!Ref` (e.g. `SubCondParam.Value` should produce a warning). I suspect this is possible since E1019 checks for non-existent parameters within a `!Sub`.\r\n\r\n```\r\n---\r\nAWSTemplateFormatVersion: 2010-09-09\r\n\r\nConditions:\r\n  CreateContainerRepository: !Equals [\"yes\", \"no\"]\r\n\r\nResources:\r\n  Repository:\r\n    Type: AWS::ECR::Repository\r\n    Condition: CreateContainerRepository\r\n\r\n  SubCondParam:\r\n    Type: AWS::SSM::Parameter\r\n    Properties:\r\n      Type: String\r\n      Value: !Sub ${Repository}\r\n\r\n  RefCondParam:\r\n    Type: AWS::SSM::Parameter\r\n    Properties:\r\n      Type: String\r\n      Value: !Ref Repository\r\n\r\n  SubFakeParam:\r\n    Type: AWS::SSM::Parameter\r\n    Properties:\r\n      Type: String\r\n      Value: !Sub ${Fake}\r\n\r\n  RefFakeParam:\r\n    Type: AWS::SSM::Parameter\r\n    Properties:\r\n      Type: String\r\n      Value: !Ref Fake\r\n```\r\n\r\n* SubCondParam.Value shows no error or warning, I believe it should show a warning\r\n* RefCondParam.Value shows W1001\r\n* SubFakeParam.Value shows E1019\r\n* RefFakeParam.Value shows E1012\n", "before_files": [{"content": "\"\"\"\nCopyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\nSPDX-License-Identifier: MIT-0\n\"\"\"\nfrom cfnlint.helpers import PSEUDOPARAMS\nfrom cfnlint.rules import CloudFormationLintRule, RuleMatch\n\n\nclass RelationshipConditions(CloudFormationLintRule):\n    \"\"\"Check if Ref/GetAtt values are available via conditions\"\"\"\n\n    id = \"W1001\"\n    shortdesc = \"Ref/GetAtt to resource that is available when conditions are applied\"\n    description = (\n        \"Check the Conditions that affect a Ref/GetAtt to make sure \"\n        \"the resource being related to is available when there is a resource \"\n        \"condition.\"\n    )\n    source_url = \"https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html\"\n    tags = [\"conditions\", \"resources\", \"relationships\", \"ref\", \"getatt\"]\n\n    def match(self, cfn):\n        \"\"\"Check CloudFormation Ref/GetAtt for Conditions\"\"\"\n\n        matches = []\n\n        # Start with Ref checks\n        ref_objs = cfn.search_deep_keys(searchText=\"Ref\", includeGlobals=False)\n        for ref_obj in ref_objs:\n            value = ref_obj[-1]\n            if value not in PSEUDOPARAMS:\n                scenarios = cfn.is_resource_available(ref_obj, value)\n                for scenario in scenarios:\n                    # pylint: disable=consider-using-f-string\n                    scenario_text = \" and \".join(\n                        [\n                            'when condition \"%s\" is %s' % (k, v)\n                            for (k, v) in scenario.items()\n                        ]\n                    )\n                    message = (\n                        'Ref to resource \"{0}\" that may not be available {1} at {2}'\n                    )\n                    matches.append(\n                        RuleMatch(\n                            ref_obj[:-1],\n                            message.format(\n                                value, scenario_text, \"/\".join(map(str, ref_obj[:-1]))\n                            ),\n                        )\n                    )\n\n        # The do GetAtt\n        getatt_objs = cfn.search_deep_keys(\n            searchText=\"Fn::GetAtt\", includeGlobals=False\n        )\n        for getatt_obj in getatt_objs:\n            value_obj = getatt_obj[-1]\n            value = None\n            if isinstance(value_obj, list):\n                value = value_obj[0]\n            elif isinstance(value_obj, str):\n                value = value_obj.split(\".\")[0]\n            if value:\n                if value not in PSEUDOPARAMS:\n                    scenarios = cfn.is_resource_available(getatt_obj, value)\n                    for scenario in scenarios:\n                        scenario_text = \" and \".join(\n                            [\n                                f'when condition \"{k}\" is {v}'\n                                for (k, v) in scenario.items()\n                            ]\n                        )\n                        message = 'GetAtt to resource \"{0}\" that may not be available {1} at {2}'\n                        matches.append(\n                            RuleMatch(\n                                getatt_obj[:-1],\n                                message.format(\n                                    value,\n                                    scenario_text,\n                                    \"/\".join(map(str, getatt_obj[:-1])),\n                                ),\n                            )\n                        )\n\n        return matches\n", "path": "src/cfnlint/rules/functions/RelationshipConditions.py"}]}