Esempio n. 1
0
        /// <summary>
        /// AnalyzeDSCResource: Analyzes given DSC Resource
        /// </summary>
        /// <param name="ast">The script's ast</param>
        /// <param name="fileName">The name of the script file being analyzed</param>
        /// <returns>The results of the analysis</returns>
        public IEnumerable <DiagnosticRecord> AnalyzeDSCResource(Ast ast, string fileName)
        {
            if (ast == null)
            {
                throw new ArgumentNullException(Strings.NullAstErrorMessage);
            }

            // TODO: Add logic for DSC Resources

            IEnumerable <Ast> functionDefinitionAsts = Helper.Instance.DscResourceFunctions(ast);

            IEnumerable <TypeDefinitionAst> classes = ast.FindAll(item =>
                                                                  item is TypeDefinitionAst &&
                                                                  ((item as TypeDefinitionAst).IsClass), true).Cast <TypeDefinitionAst>();

            foreach (FunctionDefinitionAst func in functionDefinitionAsts)
            {
                List <Tuple <string, StatementAst> > outputTypes = FindPipelineOutput.OutputTypes(func, classes);

                if (String.Equals(func.Name, "Set-TargetResource", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (Tuple <string, StatementAst> outputType in outputTypes)
                    {
                        yield return(new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReturnCorrectTypesForSetTargetResourceFunctionsDSCError),
                                                          outputType.Item2.Extent, GetName(), DiagnosticSeverity.Information, fileName));
                    }
                }
                else
                {
                    Dictionary <string, string> returnTypes = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                    returnTypes["Get-TargetResource"]  = typeof(System.Collections.Hashtable).FullName;
                    returnTypes["Test-TargetResource"] = typeof(bool).FullName;

                    foreach (Tuple <string, StatementAst> outputType in outputTypes)
                    {
                        string type = outputType.Item1;

                        if (String.IsNullOrEmpty(type) ||
                            String.Equals(typeof(Unreached).FullName, type, StringComparison.OrdinalIgnoreCase) ||
                            String.Equals(typeof(Undetermined).FullName, type, StringComparison.OrdinalIgnoreCase) ||
                            String.Equals(typeof(object).FullName, type, StringComparison.OrdinalIgnoreCase) ||
                            String.Equals(type, returnTypes[func.Name], StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }
                        else
                        {
                            yield return(new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReturnCorrectTypesForGetTestTargetResourceFunctionsDSCResourceError,
                                                                            func.Name, returnTypes[func.Name], type), outputType.Item2.Extent, GetName(), DiagnosticSeverity.Information, fileName));
                        }
                    }
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Visit function and checks that it is a cmdlet. If yes, then checks that any object returns must have a type declared
        /// in the output type (the only exception is if the type is object)
        /// </summary>
        /// <param name="funcAst"></param>
        /// <returns></returns>
        public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst funcAst)
        {
            if (funcAst == null || funcAst.Body == null || funcAst.Body.ParamBlock == null ||
                funcAst.Body.ParamBlock.Attributes == null || funcAst.Body.ParamBlock.Attributes.Count == 0 ||
                !funcAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(CmdletBindingAttribute)))
            {
                return(AstVisitAction.Continue);
            }

            HashSet <string> outputTypes = new HashSet <string>();

            foreach (AttributeAst attrAst in funcAst.Body.ParamBlock.Attributes)
            {
                if (attrAst.TypeName != null && attrAst.TypeName.GetReflectionType() == typeof(OutputTypeAttribute) &&
                    attrAst.PositionalArguments != null)
                {
                    foreach (ExpressionAst expAst in attrAst.PositionalArguments)
                    {
                        if (expAst is StringConstantExpressionAst)
                        {
                            Type type = Type.GetType((expAst as StringConstantExpressionAst).Value);
                            if (type != null)
                            {
                                outputTypes.Add(type.FullName);
                            }
                        }
                        else
                        {
                            TypeExpressionAst typeAst = expAst as TypeExpressionAst;
                            if (typeAst != null && typeAst.TypeName != null)
                            {
                                if (typeAst.TypeName.GetReflectionType() != null)
                                {
                                    outputTypes.Add(typeAst.TypeName.GetReflectionType().FullName);
                                }
                                else
                                {
                                    outputTypes.Add(typeAst.TypeName.FullName);
                                }
                            }
                        }
                    }
                }
            }

            #if PSV3
            List <Tuple <string, StatementAst> > returnTypes = FindPipelineOutput.OutputTypes(funcAst);
            #else
            List <Tuple <string, StatementAst> > returnTypes = FindPipelineOutput.OutputTypes(funcAst, _classes);
            #endif

            HashSet <string> specialTypes = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            specialTypes.Add(typeof(Unreached).FullName);
            specialTypes.Add(typeof(Undetermined).FullName);
            specialTypes.Add(typeof(object).FullName);
            specialTypes.Add(typeof(void).FullName);
            specialTypes.Add(typeof(PSCustomObject).FullName);
            specialTypes.Add(typeof(PSObject).FullName);

            foreach (Tuple <string, StatementAst> returnType in returnTypes)
            {
                string typeName = returnType.Item1;

                if (String.IsNullOrEmpty(typeName) ||
                    specialTypes.Contains(typeName) ||
                    outputTypes.Contains(typeName, StringComparer.OrdinalIgnoreCase))
                {
                    continue;
                }
                else
                {
                    DiagnosticRecords.Add(new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseOutputTypeCorrectlyError,
                                                                             funcAst.Name, typeName), returnType.Item2.Extent, GetName(), DiagnosticSeverity.Information, fileName));
                }
            }

            return(AstVisitAction.Continue);
        }