/** * 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. * * @param CodeBase $code_base * The CodeBase represents state across the entire * code base. This is a mutable object which is * populated as we parse files * * @param string $file_path * The full path to a file we'd like to parse * * @return 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 $node = \ast\parse_file($file_path, Config::get()->ast_version); if (Config::get()->dump_ast) { echo $file_path . "\n" . str_repeat("¯", strlen($file_path)) . "\n"; Debug::printNode($node); return $context; } if (empty($node)) { Issue::emit(Issue::EmptyFile, $file_path, 0, $file_path); return $context; } return self::parseNodeInContext($code_base, $context, $node); }
/** * 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. * * @param CodeBase $code_base * The CodeBase represents state across the entire * code base. This is a mutable object which is * populated as we parse files * * @param string $file_path * The full path to a file we'd like to parse * * @return 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); }
/** * Accepts a visitor that differentiates on the kind value * of the AST node. */ public function acceptKindVisitor(KindVisitor $visitor) { switch ($this->node->kind) { case \ast\AST_ARG_LIST: return $visitor->visitArgList($this->node); case \ast\AST_ARRAY: return $visitor->visitArray($this->node); case \ast\AST_ARRAY_ELEM: return $visitor->visitArrayElem($this->node); case \ast\AST_ASSIGN: return $visitor->visitAssign($this->node); case \ast\AST_ASSIGN_OP: return $visitor->visitAssignOp($this->node); case \ast\AST_ASSIGN_REF: return $visitor->visitAssignRef($this->node); case \ast\AST_BINARY_OP: return $visitor->visitBinaryOp($this->node); case \ast\AST_BREAK: return $visitor->visitBreak($this->node); case \ast\AST_CALL: return $visitor->visitCall($this->node); case \ast\AST_CAST: return $visitor->visitCast($this->node); case \ast\AST_CATCH: return $visitor->visitCatch($this->node); case \ast\AST_CLASS: $decl = $this->node; assert($decl instanceof Decl); return $visitor->visitClass($decl); case \ast\AST_CLASS_CONST: return $visitor->visitClassConst($this->node); case \ast\AST_CLASS_CONST_DECL: return $visitor->visitClassConstDecl($this->node); case \ast\AST_CLOSURE: $decl = $this->node; assert($decl instanceof Decl); return $visitor->visitClosure($decl); case \ast\AST_CLOSURE_USES: return $visitor->visitClosureUses($this->node); case \ast\AST_CLOSURE_VAR: return $visitor->visitClosureVar($this->node); case \ast\AST_COALESCE: return $visitor->visitCoalesce($this->node); case \ast\AST_CONST: return $visitor->visitConst($this->node); case \ast\AST_CONST_DECL: return $visitor->visitConstDecl($this->node); case \ast\AST_CONST_ELEM: return $visitor->visitConstElem($this->node); case \ast\AST_DECLARE: return $visitor->visitDeclare($this->node); case \ast\AST_DIM: return $visitor->visitDim($this->node); case \ast\AST_DO_WHILE: return $visitor->visitDoWhile($this->node); case \ast\AST_ECHO: return $visitor->visitEcho($this->node); case \ast\AST_EMPTY: return $visitor->visitEmpty($this->node); case \ast\AST_ENCAPS_LIST: return $visitor->visitEncapsList($this->node); case \ast\AST_EXIT: return $visitor->visitExit($this->node); case \ast\AST_EXPR_LIST: return $visitor->visitExprList($this->node); case \ast\AST_FOREACH: return $visitor->visitForeach($this->node); case \ast\AST_FUNC_DECL: $decl = $this->node; assert($decl instanceof Decl); return $visitor->visitFuncDecl($decl); case \ast\AST_ISSET: return $visitor->visitIsset($this->node); case \ast\AST_GLOBAL: return $visitor->visitGlobal($this->node); case \ast\AST_GREATER: return $visitor->visitGreater($this->node); case \ast\AST_GREATER_EQUAL: return $visitor->visitGreaterEqual($this->node); case \ast\AST_GROUP_USE: return $visitor->visitGroupUse($this->node); case \ast\AST_IF: return $visitor->visitIf($this->node); case \ast\AST_IF_ELEM: return $visitor->visitIfElem($this->node); case \ast\AST_INSTANCEOF: return $visitor->visitInstanceof($this->node); case \ast\AST_LIST: return $visitor->visitList($this->node); case \ast\AST_MAGIC_CONST: return $visitor->visitMagicConst($this->node); case \ast\AST_METHOD: $decl = $this->node; assert($decl instanceof Decl); return $visitor->visitMethod($decl); case \ast\AST_METHOD_CALL: return $visitor->visitMethodCall($this->node); case \ast\AST_NAME: return $visitor->visitName($this->node); case \ast\AST_NAMESPACE: return $visitor->visitNamespace($this->node); case \ast\AST_NEW: return $visitor->visitNew($this->node); case \ast\AST_PARAM: return $visitor->visitParam($this->node); case \ast\AST_PARAM_LIST: return $visitor->visitParamList($this->node); case \ast\AST_PRE_INC: return $visitor->visitPreInc($this->node); case \ast\AST_PRINT: return $visitor->visitPrint($this->node); case \ast\AST_PROP: return $visitor->visitProp($this->node); case \ast\AST_PROP_DECL: return $visitor->visitPropDecl($this->node); case \ast\AST_PROP_ELEM: return $visitor->visitPropElem($this->node); case \ast\AST_RETURN: return $visitor->visitReturn($this->node); case \ast\AST_STATIC: return $visitor->visitStatic($this->node); case \ast\AST_STATIC_CALL: return $visitor->visitStaticCall($this->node); case \ast\AST_STATIC_PROP: return $visitor->visitStaticProp($this->node); case \ast\AST_STMT_LIST: return $visitor->visitStmtList($this->node); case \ast\AST_SWITCH: return $visitor->visitSwitch($this->node); case \ast\AST_SWITCH_CASE: return $visitor->visitSwitchCase($this->node); case \ast\AST_SWITCH_LIST: return $visitor->visitSwitchList($this->node); case \ast\AST_TYPE: return $visitor->visitType($this->node); case \ast\AST_UNARY_MINUS: return $visitor->visitUnaryMinus($this->node); case \ast\AST_UNARY_OP: return $visitor->visitUnaryOp($this->node); case \ast\AST_USE: return $visitor->visitUse($this->node); case \ast\AST_USE_ELEM: return $visitor->visitUseElem($this->node); case \ast\AST_USE_TRAIT: return $visitor->visitUseTrait($this->node); case \ast\AST_VAR: return $visitor->visitVar($this->node); case \ast\AST_WHILE: return $visitor->visitWhile($this->node); case \ast\AST_AND: return $visitor->visitAnd($this->node); case \ast\AST_CATCH_LIST: return $visitor->visitCatchList($this->node); case \ast\AST_CLONE: return $visitor->visitClone($this->node); case \ast\AST_CONDITIONAL: return $visitor->visitConditional($this->node); case \ast\AST_CONTINUE: return $visitor->visitContinue($this->node); case \ast\AST_FOR: return $visitor->visitFor($this->node); case \ast\AST_GOTO: return $visitor->visitGoto($this->node); case \ast\AST_HALT_COMPILER: return $visitor->visitHaltCompiler($this->node); case \ast\AST_INCLUDE_OR_EVAL: return $visitor->visitIncludeOrEval($this->node); case \ast\AST_LABEL: return $visitor->visitLabel($this->node); case \ast\AST_METHOD_REFERENCE: return $visitor->visitMethodReference($this->node); case \ast\AST_NAME_LIST: return $visitor->visitNameList($this->node); case \ast\AST_OR: return $visitor->visitOr($this->node); case \ast\AST_POST_DEC: return $visitor->visitPostDec($this->node); case \ast\AST_POST_INC: return $visitor->visitPostInc($this->node); case \ast\AST_PRE_DEC: return $visitor->visitPreDec($this->node); case \ast\AST_REF: return $visitor->visitRef($this->node); case \ast\AST_SHELL_EXEC: return $visitor->visitShellExec($this->node); case \ast\AST_SILENCE: return $visitor->visitSilence($this->node); case \ast\AST_THROW: return $visitor->visitThrow($this->node); case \ast\AST_TRAIT_ADAPTATIONS: return $visitor->visitTraitAdaptations($this->node); case \ast\AST_TRAIT_ALIAS: return $visitor->visitTraitAlias($this->node); case \ast\AST_TRAIT_PRECEDENCE: return $visitor->visitTraitPrecedence($this->node); case \ast\AST_TRY: return $visitor->visitTry($this->node); case \ast\AST_UNARY_PLUS: return $visitor->visitUnaryPlus($this->node); case \ast\AST_UNPACK: return $visitor->visitUnpack($this->node); case \ast\AST_UNSET: return $visitor->visitUnset($this->node); case \ast\AST_YIELD: return $visitor->visitYield($this->node); case \ast\AST_YIELD_FROM: return $visitor->visitYieldFrom($this->node); default: Debug::printNode($this->node); assert(false, 'All node kinds must match'); break; } }
/** * 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. * * @param CodeBase $code_base * The CodeBase represents state across the entire * code base. This is a mutable object which is * populated as we parse files * * @param string $file_path * The full path to a file we'd like to parse */ public function parseFile(CodeBase $code_base, string $file_path) : Context { // Convert the file to an Abstract Syntax Tree // before passing it on to the recursive version // of this method $node = \ast\parse_file($file_path, Config::get()->ast_version); $context = (new Context())->withFile($file_path); if (Config::get()->dump_ast) { echo $file_path . "\n" . str_repeat("¯", strlen($file_path)) . "\n"; Debug::printNode($node); return $context; } if (empty($node)) { Log::err(Log::EUNDEF, "Empty or missing file {$file_path}", $file_path, 0); return $context; } return $this->parseNodeInContext($code_base, $context, $node); }