Esempio n. 1
0
        /// <summary>
        /// Visit function and checks that it has write verbose
        /// </summary>
        /// <param name="funcAst"></param>
        /// <returns></returns>
        public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst funcAst)
        {
            if (funcAst == null)
            {
                return(AstVisitAction.SkipChildren);
            }

            var  commandAsts = funcAst.Body.FindAll(testAst => testAst is CommandAst, false);
            bool hasVerbose  = false;

            if (commandAsts != null)
            {
                foreach (CommandAst commandAst in commandAsts)
                {
                    hasVerbose |= String.Equals(commandAst.GetCommandName(), "Write-Verbose", StringComparison.OrdinalIgnoreCase);
                }
            }

            if (!hasVerbose)
            {
                DiagnosticRecords.Add(new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ProvideVerboseMessageErrorFunction, funcAst.Name),
                                                           funcAst.Extent, GetName(), DiagnosticSeverity.Information, fileName));
            }

            return(AstVisitAction.Continue);
        }
        /// <summary>
        /// Visit function and checks that it has write verbose
        /// </summary>
        /// <param name="funcAst"></param>
        /// <returns></returns>
        public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst funcAst)
        {
            if (funcAst == null)
            {
                return(AstVisitAction.SkipChildren);
            }

            //Write-Verbose is not required for non-advanced functions
            if (funcAst.Body == null || funcAst.Body.ParamBlock == null ||
                funcAst.Body.ParamBlock.Attributes == null ||
                funcAst.Body.ParamBlock.Parameters == null ||
                !funcAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(CmdletBindingAttribute)))
            {
                return(AstVisitAction.Continue);
            }

            var  commandAsts = funcAst.Body.FindAll(testAst => testAst is CommandAst, false);
            bool hasVerbose  = false;

            if (commandAsts != null)
            {
                foreach (CommandAst commandAst in commandAsts)
                {
                    hasVerbose |= String.Equals(commandAst.GetCommandName(), "Write-Verbose", StringComparison.OrdinalIgnoreCase);
                }
            }

            if (!hasVerbose)
            {
                DiagnosticRecords.Add(new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ProvideVerboseMessageErrorFunction, funcAst.Name),
                                                           funcAst.Extent, GetName(), DiagnosticSeverity.Information, fileName));
            }

            return(AstVisitAction.Continue);
        }
        /// <summary>
        /// AnalyzeScript: Analyzes the ast to check that cmdlets have help.
        /// </summary>
        /// <param name="ast">The script's ast</param>
        /// <param name="fileName">The name of the script</param>
        /// <returns>A List of diagnostic results of this rule</returns>
        public IEnumerable <DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
        {
            if (ast == null)
            {
                throw new ArgumentNullException(Strings.NullAstErrorMessage);
            }

            DiagnosticRecords.Clear();
            this.fileName     = fileName;
            exportedFunctions = Helper.Instance.GetExportedFunction(ast);

            ast.Visit(this);

            return(DiagnosticRecords);
        }
        /// <summary>
        /// AnalyzeScript: Checks that objects return in a cmdlet have their types declared in OutputType Attribute
        /// </summary>
        /// <param name="ast">The script's ast</param>
        /// <param name="fileName">The name of the script</param>
        /// <returns>A List of diagnostic results of this rule</returns>
        public IEnumerable <DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
        {
            if (ast == null)
            {
                throw new ArgumentNullException(Strings.NullAstErrorMessage);
            }

            DiagnosticRecords.Clear();
            this.fileName = fileName;

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

            ast.Visit(this);

            return(DiagnosticRecords);
        }
        /// <summary>
        /// Visit function and checks that it has comment help
        /// </summary>
        /// <param name="funcAst"></param>
        /// <returns></returns>
        public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst funcAst)
        {
            if (funcAst == null)
            {
                return(AstVisitAction.SkipChildren);
            }

            if (exportedFunctions.Contains(funcAst.Name))
            {
                if (funcAst.GetHelpContent() == null)
                {
                    DiagnosticRecords.Add(
                        new DiagnosticRecord(
                            string.Format(CultureInfo.CurrentCulture, Strings.ProvideCommentHelpError, funcAst.Name),
                            funcAst.Extent, GetName(), DiagnosticSeverity.Information, fileName));
                }
            }

            return(AstVisitAction.Continue);
        }
Esempio n. 6
0
        /// <summary>
        /// AnalyzeScript: Analyzes the ast to check that Write-Verbose is called at least once in every cmdlet or script.
        /// <param name="ast">The script's ast</param>
        /// <param name="fileName">The script's file name</param>
        /// </summary>
        public IEnumerable <DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
        {
            if (ast == null)
            {
                throw new ArgumentNullException(Strings.NullAstErrorMessage);
            }

            ClearList();
            this.AddNames(new List <string>()
            {
                "Configuration", "Workflow"
            });
            DiagnosticRecords.Clear();

            this.fileName = fileName;
            //We only check that advanced functions should have Write-Verbose
            ast.Visit(this);

            return(DiagnosticRecords);
        }
Esempio n. 7
0
        /// <summary>
        /// AnalyzeScript: Analyzes the ast to check that cmdlets have help.
        /// </summary>
        /// <param name="ast">The script's ast</param>
        /// <param name="fileName">The name of the script</param>
        /// <returns>A List of diagnostic results of this rule</returns>
        public IEnumerable <DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
        {
            if (ast == null)
            {
                throw new ArgumentNullException(Strings.NullAstErrorMessage);
            }

            DiagnosticRecords.Clear();
            this.fileName     = fileName;
            exportedFunctions = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            List <string> exportFunctionsCmdlet = Helper.Instance.CmdletNameAndAliases("export-modulemember");

            // find functions exported
            IEnumerable <Ast> cmdAsts = ast.FindAll(item => item is CommandAst &&
                                                    exportFunctionsCmdlet.Contains((item as CommandAst).GetCommandName(), StringComparer.OrdinalIgnoreCase), true);

            CommandInfo exportMM = Helper.Instance.GetCommandInfo("export-modulemember", CommandTypes.Cmdlet);

            // switch parameters
            IEnumerable <ParameterMetadata> switchParams = (exportMM != null) ? exportMM.Parameters.Values.Where <ParameterMetadata>(pm => pm.SwitchParameter) : Enumerable.Empty <ParameterMetadata>();

            if (exportMM == null)
            {
                return(DiagnosticRecords);
            }

            foreach (CommandAst cmdAst in cmdAsts)
            {
                if (cmdAst.CommandElements == null || cmdAst.CommandElements.Count < 2)
                {
                    continue;
                }

                int i = 1;

                while (i < cmdAst.CommandElements.Count)
                {
                    CommandElementAst ceAst   = cmdAst.CommandElements[i];
                    ExpressionAst     exprAst = null;

                    if (ceAst is CommandParameterAst)
                    {
                        var paramAst = ceAst as CommandParameterAst;
                        var param    = exportMM.ResolveParameter(paramAst.ParameterName);

                        if (param == null)
                        {
                            i += 1;
                            continue;
                        }

                        if (string.Equals(param.Name, "function", StringComparison.OrdinalIgnoreCase))
                        {
                            // checks for the case of -Function:"verb-nouns"
                            if (paramAst.Argument != null)
                            {
                                exprAst = paramAst.Argument;
                            }
                            // checks for the case of -Function "verb-nouns"
                            else if (i < cmdAst.CommandElements.Count - 1)
                            {
                                i      += 1;
                                exprAst = cmdAst.CommandElements[i] as ExpressionAst;
                            }
                        }
                        // some other parameter. we just checks whether the one after this is positional
                        else if (i < cmdAst.CommandElements.Count - 1)
                        {
                            // the next element is a parameter like -module so just move to that one
                            if (cmdAst.CommandElements[i + 1] is CommandParameterAst)
                            {
                                i += 1;
                                continue;
                            }

                            // not a switch parameter so the next element is definitely the argument to this parameter
                            if (paramAst.Argument == null && !switchParams.Contains(param))
                            {
                                // skips the next element
                                i += 1;
                            }

                            i += 1;
                            continue;
                        }
                    }
                    else if (ceAst is ExpressionAst)
                    {
                        exprAst = ceAst as ExpressionAst;
                    }

                    if (exprAst != null)
                    {
                        // One string so just add this to the list
                        if (exprAst is StringConstantExpressionAst)
                        {
                            exportedFunctions.Add((exprAst as StringConstantExpressionAst).Value);
                        }
                        // Array of the form "v-n", "v-n1"
                        else if (exprAst is ArrayLiteralAst)
                        {
                            exportedFunctions.UnionWith(Helper.Instance.GetStringsFromArrayLiteral(exprAst as ArrayLiteralAst));
                        }
                        // Array of the form @("v-n", "v-n1")
                        else if (exprAst is ArrayExpressionAst)
                        {
                            ArrayExpressionAst arrExAst = exprAst as ArrayExpressionAst;
                            if (arrExAst.SubExpression != null && arrExAst.SubExpression.Statements != null)
                            {
                                foreach (StatementAst stAst in arrExAst.SubExpression.Statements)
                                {
                                    if (stAst is PipelineAst)
                                    {
                                        PipelineAst pipeAst = stAst as PipelineAst;
                                        if (pipeAst.PipelineElements != null)
                                        {
                                            foreach (CommandBaseAst cmdBaseAst in pipeAst.PipelineElements)
                                            {
                                                if (cmdBaseAst is CommandExpressionAst)
                                                {
                                                    exportedFunctions.UnionWith(Helper.Instance.GetStringsFromArrayLiteral((cmdBaseAst as CommandExpressionAst).Expression as ArrayLiteralAst));
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    i += 1;
                }
            }

            ast.Visit(this);

            return(DiagnosticRecords);
        }
Esempio n. 8
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);
        }