private runAnalysis()

in DevSkim-VSCode-Plugin/server/src/devskimWorker.ts [305:404]


    private runAnalysis(documentContents: string, langID: string, documentURI: string, includeSuppressions : boolean = true): DevSkimProblem[] 
    {
        let problems: DevSkimProblem[] = [];
        let XRegExp = require('xregexp');

        //iterate over all of the rules, and then all of the patterns within a rule looking for a match.
        for (let rule of this.analysisRules)
        {
            const ruleSeverity: DevskimRuleSeverity = DevSkimWorker.MapRuleSeverity(rule.severity);
            //if the rule doesn't apply to whatever language we are analyzing (C++, Java, etc.) or we aren't processing
            //that particular severity skip the rest
            if (this.dswSettings.getSettings().ignoreRulesList.indexOf(rule.id) == -1 &&  /*check to see if this is a rule the user asked to ignore */
                DevSkimWorker.appliesToLangOrFile(langID, rule.applies_to, rule.does_not_apply_to, documentURI) &&
                this.RuleSeverityEnabled(ruleSeverity)) 
            {
                for (let patternIndex = 0; patternIndex < rule.patterns.length; patternIndex++) 
                {
                    let modifiers: string[] = (rule.patterns[patternIndex].modifiers != undefined && rule.patterns[patternIndex].modifiers.length > 0) ?
                        rule.patterns[patternIndex].modifiers.concat(["g"]) : ["g"];

                    const matchPattern: RegExp = DevSkimWorker.MakeRegex(rule.patterns[patternIndex].type, rule.patterns[patternIndex].pattern, modifiers, true);

                    //go through all of the text looking for a match with the given pattern
                    let matchPosition = 0;
                    let match = XRegExp.exec(documentContents, matchPattern, matchPosition);
                    while (match) 
                    {
                        //if the rule doesn't contain any conditions, set it to an empty array to make logic later easier
                        if (!rule.conditions) 
                        {
                            rule.conditions = [];
                        }

                        //check to see if this finding has either been suppressed or reviewed (for manual-review rules)
                        //the suppressionFinding object contains a flag if the finding has been suppressed as well as
                        //range info for the ruleID in the suppression text so that hover text can be added describing
                        //the finding that was suppress
                        let suppressionFinding: DevSkimSuppressionFinding = DevSkimSuppression.isFindingCommented(match.index, documentContents, rule.id,langID, (ruleSeverity == DevskimRuleSeverity.ManualReview));

                        //calculate what line we are on by grabbing the text before the match & counting the newlines in it
                        let lineStart: number = DocumentUtilities.GetLineNumber(documentContents, match.index);
                        let newlineIndex: number = (lineStart == 0) ? -1 : documentContents.substr(0, match.index).lastIndexOf("\n");
                        let columnStart: number = match.index - newlineIndex - 1;

                        //since a match may span lines (someone who broke a long function invocation into multiple lines for example)
                        //it's necessary to see if there are any newlines WITHIN the match so that we get the line the match ends on,
                        //not just the line it starts on.  Also, we use the substring for the match later when making fixes
                        let replacementSource: string = documentContents.substr(match.index, match[0].length);
                        let lineEnd: number = DocumentUtilities.GetLineNumber(replacementSource, replacementSource.length) + lineStart;

                        let columnEnd = (lineStart == lineEnd) ?
                            columnStart + match[0].length :
                            match[0].length - documentContents.substr(match.index).indexOf("\n") - 1;

                        let range: Range = Range.create(lineStart, columnStart, lineEnd, columnEnd);

                        // Is this *not* a suppression finding (a real issue)
                        if (!suppressionFinding.showSuppressionFinding)
                        {
                            if (DocumentUtilities.MatchIsInScope(langID, documentContents.substr(0, match.index), newlineIndex, rule.patterns[patternIndex].scopes))
                            {
                                if (DevSkimWorker.MatchesConditions(rule.conditions, documentContents, range, langID)) 
                                {
                                    let snippet = [];
                                    for (let i=Math.max(0, lineStart - 2); i<=lineEnd + 2; i++)
                                    {
                                        const snippetLine = DocumentUtilities.GetLine(documentContents, i);
                                        snippet.push(snippetLine.substr(0, 80));
                                    }
    
                                    //add in any fixes
                                    let problem: DevSkimProblem = this.MakeProblem(rule, DevSkimWorker.MapRuleSeverity(rule.severity), range, snippet.join('\n'));
                                    problem.fixes = problem.fixes.concat(DevSkimWorker.MakeFixes(rule, replacementSource, range));
                                    problem.fixes = problem.fixes.concat(this.dsSuppressions.createActions(rule.id, documentContents, match.index, lineStart, langID, ruleSeverity));
                                    problem.filePath = documentURI;
                                    problems.push(problem);
                                }
                            }
                        }
                        //throw a pop up if there is a review/suppression comment with the rule id, so that people can figure out what was
                        //suppressed/reviewed
                        else {
                            if (!suppressionFinding.noRange && includeSuppressions && this.RuleSeverityEnabled(DevskimRuleSeverity.WarningInfo)) 
                            {
                                //highlight suppression finding for context
                                //this will look
                                let problem: DevSkimProblem = this.MakeProblem(rule, DevskimRuleSeverity.WarningInfo, suppressionFinding.suppressionRange,"", range);
    
                                problems.push(problem);
                            }
                        }
                        //advance the location we are searching in the line
                        matchPosition = match.index + match[0].length;
                        match = XRegExp.exec(documentContents, matchPattern, matchPosition);
                    }
                }
            }
        }
        return problems;
    }