コード例 #1
0
ファイル: FQSENTest.php プロジェクト: nagyistge/phan
 public function testFullyQualifiedFunctionName()
 {
     $this->assertFQSENEqual(FullyQualifiedFunctionName::make('\\Name\\Space', 'g'), '\\Name\\Space\\g');
     $this->assertFQSENEqual(FullyQualifiedFunctionName::make('', 'g'), '\\g');
     $this->assertFQSENEqual(FullyQualifiedGlobalConstantName::make('', 'g'), '\\g');
     $this->assertFQSENEqual(FullyQualifiedFunctionName::fromFullyQualifiedString('\\g'), '\\g');
     $this->assertFQSENEqual(FullyQualifiedFunctionName::fromStringInContext('g', $this->context), '\\g');
 }
コード例 #2
0
ファイル: FunctionFactory.php プロジェクト: tpunt/phan
 /**
  * @return Func[]
  * One or more (alternate) methods begotten from
  * reflection info and internal method data
  */
 public static function functionListFromReflectionFunction(CodeBase $code_base, \ReflectionFunction $reflection_function) : array
 {
     $context = new Context();
     $parts = explode('\\', $reflection_function->getName());
     $method_name = array_pop($parts);
     $namespace = '\\' . implode('\\', $parts);
     $fqsen = FullyQualifiedFunctionName::make($namespace, $method_name);
     $function = new Func($context, $fqsen->getName(), new UnionType(), 0, $fqsen);
     $function->setNumberOfRequiredParameters($reflection_function->getNumberOfRequiredParameters());
     $function->setNumberOfOptionalParameters($reflection_function->getNumberOfParameters() - $reflection_function->getNumberOfRequiredParameters());
     return self::functionListFromFunction($function, $code_base);
 }
コード例 #3
0
ファイル: CodeBase.php プロジェクト: tmli3b3rm4n/phan
 /**
  * Add any functions from the FunctionSignatureMap that aren't
  * defined in this version of PHP to the code base
  *
  * @return void
  */
 private function addUndefinedFunctionSignatures()
 {
     $function_signature_map = UnionType::internalFunctionSignatureMap();
     foreach ($function_signature_map as $function_name => $signature) {
         $fqsen = FullyQualifiedFunctionName::make('\\', $function_name);
         // If we already loaded the function, skip it
         if ($this->hasMethod($fqsen)) {
             continue;
         }
         // Add each method returned for the signature
         foreach (Method::methodListFromSignature($this, $fqsen, $signature) as $method) {
             $this->addMethod($method);
         }
     }
 }
コード例 #4
0
ファイル: Method.php プロジェクト: themarios/phan
 /**
  * @return Method[]
  * One or more (alternate) methods begotten from
  * reflection info and internal method data
  */
 public static function methodListFromReflectionFunction(CodeBase $code_base, \ReflectionFunction $reflection_function) : array
 {
     $number_of_required_parameters = $reflection_function->getNumberOfRequiredParameters();
     $number_of_optional_parameters = $reflection_function->getNumberOfParameters() - $number_of_required_parameters;
     $context = new Context();
     $parts = explode('\\', $reflection_function->getName());
     $method_name = array_pop($parts);
     $namespace = '\\' . implode('\\', $parts);
     $fqsen = FullyQualifiedFunctionName::make($namespace, $method_name);
     $method = new Method($context, $fqsen->getName(), new UnionType(), 0, $number_of_required_parameters, $number_of_optional_parameters);
     $method->setFQSEN($fqsen);
     return self::methodListFromMethod($method, $code_base);
 }
コード例 #5
0
ファイル: ScopeVisitor.php プロジェクト: hslatman/phan
 /**
  * @return array
  * A map from alias to target
  */
 private function aliasTargetMapFromUseNode(Node $node, string $prefix = '') : array
 {
     assert($node->kind == \ast\AST_USE, 'Method takes AST_USE nodes');
     $map = [];
     foreach ($node->children ?? [] as $child_node) {
         $target = $child_node->children['name'];
         if (empty($child_node->children['alias'])) {
             if (($pos = strrpos($target, '\\')) !== false) {
                 $alias = substr($target, $pos + 1);
             } else {
                 $alias = $target;
             }
         } else {
             $alias = $child_node->children['alias'];
         }
         if ($node->flags == T_FUNCTION) {
             $parts = explode('\\', $target);
             $function_name = array_pop($parts);
             $target = FullyQualifiedFunctionName::make(implode('\\', $parts), $function_name);
         } else {
             $target = FullyQualifiedClassName::fromFullyQualifiedString($prefix . '\\' . $target);
         }
         $map[$alias] = [$child_node->flags, $target];
     }
     return $map;
 }
コード例 #6
0
ファイル: MethodMap.php プロジェクト: black-silence/phan
 /**
  * @param string $scope
  * The scope of the method or function
  *
  * @param string $name
  * The name of the method (with an optional alternate id)
  *
  * @return bool
  */
 private function hasMethodWithScopeAndName(string $scope, string $name)
 {
     if (!empty($this->method_map[$scope][$name])) {
         return true;
     }
     // For elements in the root namespace, check to see if
     // there's a static method signature for something that
     // hasn't been loaded into memory yet and create a
     // method out of it as its requested
     if ('\\' == $scope) {
         $function_signature_map = UnionType::internalFunctionSignatureMap();
         $fqsen = FullyQualifiedFunctionName::make($scope, $name);
         if (!empty($function_signature_map[$name])) {
             $signature = $function_signature_map[$name];
             // Add each method returned for the signature
             foreach (FunctionFactory::functionListFromSignature($this, $fqsen, $signature) as $method) {
                 $this->addMethod($method);
             }
             return true;
         }
     }
     if (Database::isEnabled()) {
         // Otherwise, check the database
         try {
             MethodModel::read(Database::get(), $scope . '|' . $name);
             return true;
         } catch (NotFoundException $exception) {
             return false;
         }
     } else {
         return false;
     }
 }
コード例 #7
0
ファイル: ScopeVisitor.php プロジェクト: ablyler/phan
 /**
  * @return array
  * A map from alias to target
  */
 private function aliasTargetMapFromUseNode(Node $node, string $prefix = '') : array
 {
     assert($node->kind == \ast\AST_USE, 'Method takes AST_USE nodes');
     $map = [];
     foreach ($node->children ?? [] as $child_node) {
         $target = $child_node->children['name'];
         if (empty($child_node->children['alias'])) {
             if (($pos = strrpos($target, '\\')) !== false) {
                 $alias = substr($target, $pos + 1);
             } else {
                 $alias = $target;
             }
         } else {
             $alias = $child_node->children['alias'];
         }
         // if AST_USE does not have any flags set, then its AST_USE_ELEM
         // children will (this will be for AST_GROUP_USE)
         if ($node->flags !== 0) {
             $target_node = $node;
         } else {
             $target_node = $child_node;
         }
         if ($target_node->flags == T_FUNCTION) {
             $parts = explode('\\', $target);
             $function_name = array_pop($parts);
             $target = FullyQualifiedFunctionName::make($prefix . '\\' . implode('\\', $parts), $function_name);
         } else {
             if ($target_node->flags == T_CONST) {
                 $parts = explode('\\', $target);
                 $name = array_pop($parts);
                 $target = FullyQualifiedGlobalConstantName::make($prefix . '\\' . implode('\\', $parts), $name);
             } else {
                 $target = FullyQualifiedClassName::fromFullyQualifiedString($prefix . '\\' . $target);
             }
         }
         $map[$alias] = [$target_node->flags, $target];
     }
     return $map;
 }
コード例 #8
0
ファイル: ContextNode.php プロジェクト: ablyler/phan
 /**
  * @param string $function_name
  * The name of the function we'd like to look up
  *
  * @param bool $is_function_declaration
  * This must be set to true if we're getting a function
  * that is being declared and false if we're getting a
  * function being called.
  *
  * @return FunctionInterface
  * A method with the given name in the given context
  *
  * @throws IssueException
  * An exception is thrown if we can't find the given
  * function
  */
 public function getFunction(string $function_name, bool $is_function_declaration = false) : FunctionInterface
 {
     if ($is_function_declaration) {
         $function_fqsen = FullyQualifiedFunctionName::make($this->context->getNamespace(), $function_name);
     } else {
         $function_fqsen = FullyQualifiedFunctionName::make($this->context->getNamespace(), $function_name);
         // If it doesn't exist in the local namespace, try it
         // in the global namespace
         if (!$this->code_base->hasFunctionWithFQSEN($function_fqsen)) {
             $function_fqsen = FullyQualifiedFunctionName::fromStringInContext($function_name, $this->context);
         }
     }
     // Make sure the method we're calling actually exists
     if (!$this->code_base->hasFunctionWithFQSEN($function_fqsen)) {
         throw new IssueException(Issue::fromType(Issue::UndeclaredFunction)($this->context->getFile(), $this->node->lineno ?? 0, ["{$function_fqsen}()"]));
     }
     return $this->code_base->getFunctionByFQSEN($function_fqsen);
 }
コード例 #9
0
ファイル: AST.php プロジェクト: tmli3b3rm4n/phan
 /**
  * @param string $function_name
  * The name of the function we'd like to look up
  *
  * @param Context $context
  * The context in which we found the reference to the
  * given function name
  *
  * @param CodeBase $code_base
  * The global code base holding all state
  *
  * @param bool $is_function_declaration
  * This must be set to true if we're getting a function
  * that is being declared and false if we're getting a
  * function being called.
  *
  * @return Method
  * A method with the given name in the given context
  *
  * @throws CodeBaseExtension
  * An exception is thrown if we can't find the given
  * function
  */
 public static function functionFromNameInContext(string $function_name, Context $context, CodeBase $code_base, bool $is_function_declaration = false) : Method
 {
     if ($is_function_declaration) {
         $function_fqsen = FullyQualifiedFunctionName::make($context->getNamespace(), $function_name);
     } else {
         $function_fqsen = FullyQualifiedFunctionName::make($context->getNamespace(), $function_name);
         // If it doesn't exist in the local namespace, try it
         // in the global namespace
         if (!$code_base->hasMethod($function_fqsen)) {
             $function_fqsen = FullyQualifiedFunctionName::fromStringInContext($function_name, $context);
         }
     }
     // Make sure the method we're calling actually exists
     if (!$code_base->hasMethod($function_fqsen)) {
         throw new CodeBaseException("call to undefined function {$function_fqsen}()");
     }
     $method = $code_base->getMethod($function_fqsen);
     return $method;
 }
コード例 #10
0
ファイル: UnionTypeVisitor.php プロジェクト: themarios/phan
 /**
  * Visit a node with kind `\ast\AST_CALL`
  *
  * @param Node $node
  * A node of the type indicated by the method name that we'd
  * like to figure out the type that it produces.
  *
  * @return UnionType
  * The set of types that are possibly produced by the
  * given node
  */
 public function visitCall(Node $node) : UnionType
 {
     if ($node->children['expr']->kind !== \ast\AST_NAME) {
         // Things like `$func()`
         return new UnionType();
     }
     $function_name = $node->children['expr']->children['name'];
     $function_fqsen = null;
     // If its not fully qualified
     if ($node->children['expr']->flags & \ast\flags\NAME_NOT_FQ) {
         // Check to see if we have a mapped name
         if ($this->context->hasNamespaceMapFor(T_FUNCTION, $function_name)) {
             $function_fqsen = $this->context->getNamespaceMapFor(T_FUNCTION, $function_name);
         } else {
             $function_fqsen = FullyQualifiedFunctionName::fromStringInContext($function_name, $this->context);
         }
         // If the name is fully qualified
     } else {
         $function_fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString($function_name);
     }
     // If the function doesn't exist, check to see if its
     // a call to a builtin method
     if (!$this->code_base->hasMethod($function_fqsen)) {
         $function_fqsen = FullyQualifiedFunctionName::make('', $function_name);
     }
     if (!$this->code_base->hasMethod($function_fqsen)) {
         // Missing internal (bulitin) method.
         return new UnionType();
     }
     $function = $this->code_base->getMethod($function_fqsen);
     // If this is an internal function, see if we can get
     // its types from the static dataset.
     if ($function->getContext()->isInternal() && $function->getUnionType()->isEmpty()) {
         $map = UnionType::internalFunctionSignatureMapForFQSEN($function_fqsen);
         return $map[$function_name] ?? new UnionType();
     }
     return $function->getUnionType();
 }