Phan\Analysis::parseFile PHP Method

parseFile() public static method

This first pass parses code and looks for the subset of issues that can be found without having to have an understanding of the entire code base.
public static parseFile ( CodeBase $code_base, string $file_path ) : Context
$code_base CodeBase The CodeBase represents state across the entire code base. This is a mutable object which is populated as we parse files
$file_path string The full path to a file we'd like to parse
return Phan\Language\Context
    public static function parseFile(CodeBase $code_base, string $file_path) : Context
    {
        $context = (new Context())->withFile($file_path);
        // Convert the file to an Abstract Syntax Tree
        // before passing it on to the recursive version
        // of this method
        try {
            $node = \ast\parse_file(Config::projectPath($file_path), Config::get()->ast_version);
        } catch (\ParseError $parse_error) {
            Issue::maybeEmit($code_base, $context, Issue::SyntaxError, $parse_error->getLine(), $parse_error->getMessage());
            return $context;
        }
        if (Config::get()->dump_ast) {
            echo $file_path . "\n" . str_repeat("¯", strlen($file_path)) . "\n";
            Debug::printNode($node);
            return $context;
        }
        if (empty($node)) {
            Issue::maybeEmit($code_base, $context, Issue::EmptyFile, 0, $file_path);
            return $context;
        }
        return self::parseNodeInContext($code_base, $context, $node);
    }

Same methods

Analysis::parseFile ( CodeBase $code_base, string $file_path ) : Context

Usage Example

示例#1
0
文件: Phan.php 项目: tpunt/phan
 /**
  * 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 bool
  * We emit messages to the configured printer and return
  * true if issues were found.
  *
  * @see \Phan\CodeBase
  */
 public static function analyzeFileList(CodeBase $code_base, array $file_path_list) : bool
 {
     $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);
         // Kick out anything we read from the former version
         // of this file
         $code_base->flushDependenciesForFile($file_path);
         // If the file is gone, no need to continue
         if (($real = realpath($file_path)) === false || !file_exists($real)) {
             continue;
         }
         try {
             // Parse the file
             Analysis::parseFile($code_base, $file_path);
             // Save this to the set of files to analyze
             $analyze_file_path_list[] = $file_path;
         } catch (\Throwable $throwable) {
             error_log($file_path . ' ' . $throwable->getMessage() . "\n");
         }
     }
     // Don't continue on to analysis if the user has
     // chosen to just dump the AST
     if (Config::get()->dump_ast) {
         exit(EXIT_SUCCESS);
     }
     // With parsing complete, we need to tell the code base to
     // start hydrating any requested elements on their way out.
     // Hydration expands class types, imports parent methods,
     // properties, etc., and does stuff like that.
     //
     // This is an optimization that saves us a significant
     // amount of time on very large code bases. Instead of
     // hydrating all classes, we only hydrate the things we
     // actually need. When running as multiple processes this
     // lets us only need to do hydrate a subset of classes.
     $code_base->setShouldHydrateRequestedElements(true);
     // We used to scan all classes here, but now we do it
     // on demand after hydration.
     // Take a pass over all functions verifying
     // various states now that we have the whole
     // state in memory
     Analysis::analyzeFunctions($code_base);
     // Filter out any files that are to be excluded from
     // analysis
     $analyze_file_path_list = array_filter($analyze_file_path_list, function ($file_path) {
         return !self::isExcludedAnalysisFile($file_path);
     });
     // Get the count of all files we're going to analyze
     $file_count = count($analyze_file_path_list);
     // Prevent an ugly failure if we have no files to
     // analyze.
     if (0 == $file_count) {
         return false;
     }
     // Get a map from process_id to the set of files that
     // the given process should analyze in a stable order
     $process_file_list_map = (new Ordering($code_base))->orderForProcessCount(Config::get()->processes, $analyze_file_path_list);
     // This worker takes a file and analyzes it
     $analysis_worker = function ($i, $file_path) use($file_count, $code_base) {
         CLI::progress('analyze', ($i + 1) / $file_count);
         Analysis::analyzeFile($code_base, $file_path);
     };
     // Determine how many processes we're running on. This may be
     // less than the provided number if the files are bunched up
     // excessively.
     $process_count = count($process_file_list_map);
     assert($process_count > 0 && $process_count <= Config::get()->processes, "The process count must be between 1 and the given number of processes. After mapping files to cores, {$process_count} process were set to be used.");
     // Check to see if we're running as multiple processes
     // or not
     if ($process_count > 1) {
         // Run analysis one file at a time, splitting the set of
         // files up among a given number of child processes.
         $pool = new ForkPool($process_file_list_map, function () {
             // Remove any issues that were collected prior to forking
             // to prevent duplicate issues in the output.
             self::getIssueCollector()->reset();
         }, $analysis_worker, function () {
             // Return the collected issues to be serialized.
             return self::getIssueCollector()->getCollectedIssues();
         });
         // Wait for all tasks to complete and collect the results.
         self::collectSerializedResults($pool->wait());
     } else {
         // Get the task data from the 0th processor
         $analyze_file_path_list = array_values($process_file_list_map)[0];
         // If we're not running as multiple processes, just iterate
         // over the file list and analyze them
         foreach ($analyze_file_path_list as $i => $file_path) {
             $analysis_worker($i, $file_path);
         }
         // Scan through all globally accessible elements
         // in the code base and emit errors for dead
         // code.
         Analysis::analyzeDeadCode($code_base);
     }
     // Get a count of the number of issues that were found
     $is_issue_found = 0 !== count(self::$issueCollector->getCollectedIssues());
     // Collect all issues, blocking
     self::display();
     return $is_issue_found;
 }
All Usage Examples Of Phan\Analysis::parseFile