Repository: aws-cloudformation/cfn-lint

Issue:
Using ImportValue skips List type resource validation
*cfn-lint version: (`cfn-lint --version`)*
cfn-lint 0.40.0

*Description of issue.*
When we use [`Fn::ImportValue`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html) for a resource key that needs type List, it accepts a scalar value and cfn-lint doesn't fail. But when we use scalar value directly it works as expected and fails. 

Following template needs `SubnetIds` and `SecurityGroupIds` as list of Strings (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html), but using ImportValue masks the error and linting does not fail as expected

Template that should fail but succeeds
```yaml               
Resources:
  LambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Runtime: java8
      Code:
        S3Bucket: 'foo-bar'
        S3Key: 'foo-bar'
        S3ObjectVersion: 'foo-bar'
      Handler: 'com.foo.bar::handleRequest'
      Role: 'arn:aws:iam::123456789101:role/foo-bar'
      VpcConfig:
        SubnetIds: !ImportValue foobar1
        SecurityGroupIds: !ImportValue foobar2
```

Template that fails correctly
```yaml
Resources:
  LambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Runtime: java8
      Code:
        S3Bucket: 'foo-bar'
        S3Key: 'foo-bar'
        S3ObjectVersion: 'foo-bar'
      Handler: 'com.foo.bar::handleRequest'
      Role: 'arn:aws:iam::123456789101:role/foo-bar'
      VpcConfig:
        SubnetIds: 'foobar1'
        SecurityGroupIds: 'foobar2'

E3002 Property SubnetIds should be of type List for resource LambdaFunction
lambda-function.yaml:14:9

E3002 Property SecurityGroupIds should be of type List for resource LambdaFunction
lambda-function.yaml:15:9
```


Discussion:

Resolving patch:
diff --git a/src/cfnlint/rules/resources/properties/Properties.py b/src/cfnlint/rules/resources/properties/Properties.py
--- a/src/cfnlint/rules/resources/properties/Properties.py
+++ b/src/cfnlint/rules/resources/properties/Properties.py
@@ -23,6 +23,7 @@ def __init__(self):
         self.resourcetypes = {}
         self.propertytypes = {}
         self.parameternames = {}
+        self.intrinsictypes = {}
 
     def primitivetypecheck(self, value, primtype, proppath):
         """
@@ -238,6 +239,7 @@ def propertycheck(self, text, proptype, parenttype, resourcename, path, root):
         # return objects.  FindInMap cannot directly return an object.
         len_of_text = len(text)
 
+        #pylint: disable=too-many-nested-blocks
         for prop in text:
             proppath = path[:]
             proppath.append(prop)
@@ -315,6 +317,17 @@ def propertycheck(self, text, proptype, parenttype, resourcename, path, root):
                                             RuleMatch(
                                                 proppath,
                                                 message.format(prop, resourcename)))
+                                else:
+                                    if len(text[prop]) == 1:
+                                        for k in text[prop].keys():
+                                            def_intrinsic_type = self.intrinsictypes.get(k, {})
+                                            if def_intrinsic_type:
+                                                if len(def_intrinsic_type.get('ReturnTypes')) == 1 and def_intrinsic_type.get('ReturnTypes')[0] == 'Singular':
+                                                    message = 'Property {0} is using {1} when a List is needed for resource {2}'
+                                                    matches.append(
+                                                        RuleMatch(
+                                                            proppath,
+                                                            message.format(prop, k, resourcename)))
                             else:
                                 message = 'Property {0} should be of type List for resource {1}'
                                 matches.append(
@@ -340,6 +353,7 @@ def match(self, cfn):
         resourcespecs = cfnlint.helpers.RESOURCE_SPECS[cfn.regions[0]]
         self.resourcetypes = resourcespecs['ResourceTypes']
         self.propertytypes = resourcespecs['PropertyTypes']
+        self.intrinsictypes = resourcespecs['IntrinsicTypes']
         self.parameternames = self.cfn.get_parameter_names()
         for resourcename, resourcevalue in cfn.get_resources().items():
             if 'Properties' in resourcevalue and 'Type' in resourcevalue:


Test patch:
diff --git a/test/fixtures/templates/bad/resource_properties.yaml b/test/fixtures/templates/bad/resource_properties.yaml
--- a/test/fixtures/templates/bad/resource_properties.yaml
+++ b/test/fixtures/templates/bad/resource_properties.yaml
@@ -35,3 +35,16 @@ Resources:
       UserData: !Ref AWS::NotificationARNs
       Tags:
       - Key: Test
+  LambdaFunction:
+    Type: 'AWS::Lambda::Function'
+    Properties:
+      Runtime: java8
+      Code:
+        S3Bucket: 'foo-bar'
+        S3Key: 'foo-bar'
+        S3ObjectVersion: 'foo-bar'
+      Handler: 'com.foo.bar::handleRequest'
+      Role: 'arn:aws:iam::123456789101:role/foo-bar'
+      VpcConfig:
+        SubnetIds: !ImportValue foobar1
+        SecurityGroupIds: !ImportValue foobar2
diff --git a/test/unit/rules/resources/properties/test_properties.py b/test/unit/rules/resources/properties/test_properties.py
--- a/test/unit/rules/resources/properties/test_properties.py
+++ b/test/unit/rules/resources/properties/test_properties.py
@@ -35,7 +35,7 @@ def test_file_negative_2(self):
 
     def test_file_negative_3(self):
         """Failure test"""
-        self.helper_file_negative('test/fixtures/templates/bad/resource_properties.yaml', 5)
+        self.helper_file_negative('test/fixtures/templates/bad/resource_properties.yaml', 7)
 
     def test_E3012_in_bad_template(self):
         """Test E3012 in known-bad template"""