/** * Analyze the given set of files and emit any issues * found to STDOUT. * * @param CodeBase $code_base * A code base needs to be passed in because we require * it to be initialized before any classes or files are * loaded. * * @param string[] $file_path_list * A list of files to scan * * @return null * We emit messages to STDOUT. Nothing is returned. * * @see \Phan\CodeBase */ public function analyzeFileList(CodeBase $code_base, array $file_path_list) { $file_count = count($file_path_list); // We'll construct a set of files that we'll // want to run an analysis on $analyze_file_path_list = []; // This first pass parses code and populates the // global state we'll need for doing a second // analysis after. foreach ($file_path_list as $i => $file_path) { CLI::progress('parse', ($i + 1) / $file_count); // Check to see if we need to re-parse this file if (Config::get()->reanalyze_file_list || !$code_base->isParseUpToDateForFile($file_path)) { // Save this to the set of files to analyze $analyze_file_path_list[] = $file_path; // Kick out anything we read from the former version // of this file $code_base->flushDependenciesForFile($file_path); // Parse the file $this->parseFile($code_base, $file_path); // Update the timestamp on when it was last // parsed $code_base->setParseUpToDateForFile($file_path); } } // Don't continue on to analysis if the user has // chosen to just dump the AST if (Config::get()->dump_ast) { exit; } // Take a pass over all classes verifying various // states now that we have the whole state in // memory $this->analyzeClasses($code_base); // Take a pass over all functions verifying // various states now that we have the whole // state in memory $this->analyzeFunctions($code_base); // We can only save classes, methods, properties and // constants after we've merged parent classes in. $code_base->store(); // Once we know what the universe looks like we // can scan for more complicated issues. $file_count = count($analyze_file_path_list); foreach ($analyze_file_path_list as $i => $file_path) { CLI::progress('analyze', ($i + 1) / $file_count); // We skip anything defined as 3rd party code // to save a lil' time if (self::isExcludedAnalysisFile($file_path)) { continue; } // Analyze the file $this->analyzeFile($code_base, $file_path); } // Scan through all globally accessible elements // in the code base and emit errors for dead // code. $this->analyzeDeadCode($code_base); // Emit all log messages Log::display(); }