Example #1
0
 public function store()
 {
     if (!Database::isEnabled()) {
         return;
     }
     $this->storeClassMap();
     $this->storeMethodMap();
     $this->storeConstantMap();
     $this->storePropertyMap();
     $this->storeFileMap();
 }
Example #2
0
 /**
  * Analyze the parameters and arguments for a call
  * to the given method or function
  *
  * @param CodeBase $code_base
  * @param Method $method
  * @param Node $node
  *
  * @return null
  */
 private function analyzeCallToMethod(CodeBase $code_base, Method $method, Node $node)
 {
     if (Database::isEnabled()) {
         // Store the call to the method so we can track
         // dependencies later
         (new CalledBy((string) $method->getFQSEN(), $this->context))->write(Database::get());
     }
     // Create variables for any pass-by-reference
     // parameters
     $argument_list = $node->children['args'];
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter) {
             continue;
         }
         // If pass-by-reference, make sure the variable exists
         // or create it if it doesn't.
         if ($parameter->isPassByReference()) {
             if ($argument->kind == \ast\AST_VAR) {
                 // We don't do anything with it; just create it
                 // if it doesn't exist
                 $variable = AST::getOrCreateVariableFromNodeInContext($argument, $this->context, $this->code_base);
             } else {
                 if ($argument->kind == \ast\AST_STATIC_PROP || $argument->kind == \ast\AST_PROP) {
                     $property_name = $argument->children['prop'];
                     if (is_string($property_name)) {
                         // We don't do anything with it; just create it
                         // if it doesn't exist
                         try {
                             $property = AST::getOrCreatePropertyFromNodeInContext($argument->children['prop'], $argument, $this->context, $this->code_base);
                         } catch (CodeBaseException $exception) {
                             Log::err(Log::EUNDEF, $exception->getMessage(), $this->context->getFile(), $node->lineno);
                         } catch (NodeException $exception) {
                             // If we can't figure out what kind of a call
                             // this is, don't worry about it
                         }
                     } else {
                         // This is stuff like `Class->$foo`. I'm ignoring
                         // it.
                     }
                 }
             }
         }
     }
     // Confirm the argument types are clean
     ArgumentType::analyze($method, $node, $this->context, $this->code_base);
     // Take another pass over pass-by-reference parameters
     // and assign types to passed in variables
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter) {
             continue;
         }
         // If the parameter is pass-by-reference and we're
         // passing a variable in, see if we should pass
         // the parameter and variable types to eachother
         $variable = null;
         if ($parameter->isPassByReference()) {
             if ($argument->kind == \ast\AST_VAR) {
                 $variable = AST::getOrCreateVariableFromNodeInContext($argument, $this->context, $this->code_base);
             } else {
                 if ($argument->kind == \ast\AST_STATIC_PROP || $argument->kind == \ast\AST_PROP) {
                     $property_name = $argument->children['prop'];
                     if (is_string($property_name)) {
                         // We don't do anything with it; just create it
                         // if it doesn't exist
                         try {
                             $variable = AST::getOrCreatePropertyFromNodeInContext($argument->children['prop'], $argument, $this->context, $this->code_base);
                         } catch (CodeBaseException $exception) {
                             Log::err(Log::EUNDEF, $exception->getMessage(), $this->context->getFile(), $node->lineno);
                         } catch (NodeException $exception) {
                             // If we can't figure out what kind of a call
                             // this is, don't worry about it
                         }
                     } else {
                         // This is stuff like `Class->$foo`. I'm ignoring
                         // it.
                     }
                 }
             }
             if ($variable) {
                 $variable->getUnionType()->addUnionType($parameter->getUnionType());
             }
         }
     }
     // If we're in quick mode, don't retest methods based on
     // parameter types passed in
     if (Config::get()->quick_mode) {
         return;
     }
     // We're going to hunt to see if any of the arguments
     // have a mismatch with the parameters. If so, we'll
     // re-check the method to see how the parameters impact
     // its return type
     $has_argument_parameter_mismatch = false;
     // Now that we've made sure the arguments are sufficient
     // for definitions on the method, we iterate over the
     // arguments again and add their types to the parameter
     // types so we can test the method again
     $argument_list = $node->children['args'];
     // We create a copy of the parameter list so we can switch
     // back to it after
     $original_parameter_list = $method->getParameterList();
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter) {
             continue;
         }
         // If the parameter has no type, pass the
         // argument's type to it
         if ($parameter->getUnionType()->isEmpty()) {
             $has_argument_parameter_mismatch = true;
             $argument_type = UnionType::fromNode($this->context, $this->code_base, $argument);
             // If this isn't an internal function or method
             // and it has no type, add the argument's type
             // to it so we can compare it to subsequent
             // calls
             if (!$parameter->getContext()->isInternal()) {
                 // Clone the parameter in the original
                 // parameter list so we can reset it
                 // later
                 $original_parameter_list[$i] = clone $parameter;
                 // Then set the new type on that parameter based
                 // on the argument's type. We'll use this to
                 // retest the method with the passed in types
                 $parameter->getUnionType()->addUnionType($argument_type);
             }
         }
     }
     // Now that we know something about the parameters used
     // to call the method, we can reanalyze the method with
     // the types of the parameter, making sure we don't get
     // into an infinite loop of checking calls to the current
     // method in scope
     if ($has_argument_parameter_mismatch && !$method->getContext()->isInternal() && (!$this->context->isMethodScope() || $method->getFQSEN() !== $this->context->getMethodFQSEN())) {
         $method->analyze($method->getContext(), $code_base);
     }
     // Reset to the original parameter list after having
     // tested the parameters with the types passed in
     $method->setParameterList($original_parameter_list);
 }
Example #3
0
File: File.php Project: actank/phan
 /**
  * Mark the file at the given path as up to date so
  * that we know if its changed on subsequent runs
  *
  * @return null
  */
 public function setParseUpToDate()
 {
     $this->modification_time = filemtime(realpath($this->file_path));
     if (Database::isEnabled()) {
         // Write it to disk
         (new FileModel($this))->write(Database::get());
     }
 }
Example #4
0
 /**
  * @return null
  */
 protected function flushMethodWithScopeAndName(string $scope, string $name)
 {
     if (Database::isEnabled()) {
         MethodModel::delete(Database::get(), $scope . '|' . $name);
     }
     unset($this->method_map[$scope][$name]);
 }
Example #5
0
 /**
  * Save all file state
  *
  * @return null
  */
 public function storeFileMap()
 {
     if (!Database::isEnabled()) {
         return;
     }
     foreach ($this->file_map as $file) {
         (new FileModel($file))->write(Database::get());
     }
 }
Example #6
0
 /**
  * @return null
  */
 protected function flushConstantWithScopeAndName(string $scope, string $name)
 {
     // Remove it from the database
     if (Database::isEnabled()) {
         ConstantModel::delete(Database::get(), $scope . '|' . $name);
     }
     // Remove it from memory
     unset($this->constant_map[$scope][$name]);
 }
Example #7
0
 /**
  * @return FileRef[]
  * A list of references to this typed structural element.
  */
 public function getReferenceList() : array
 {
     if (!empty($this->reference_list)) {
         return $this->reference_list;
     }
     // If we have a database, see if we have some callers
     // defined there and save those
     if (Database::isEnabled()) {
         $this->reference_list = array_map(function (CalledBy $called_by) : FileRef {
             return $called_by->getFileRef();
         }, CalledBy::findManyByFQSEN(Database::get(), $this->getFQSEN()));
     }
     return $this->reference_list;
 }
Example #8
0
 /**
  * @return null
  */
 protected function flushClassWithFQSEN(FullyQualifiedClassName $fqsen)
 {
     // Remove it from the database
     if (Database::isEnabled()) {
         ClazzModel::delete(Database::get(), (string) $fqsen);
     }
     // Remove it from memory
     unset($this->class_map[$fqsen]);
 }
Example #9
0
 /**
  * @param FileRef $file_ref
  * A reference to a location in which this typed structural
  * element is referenced.
  *
  * @return void
  */
 public function addReference(FileRef $file_ref)
 {
     $this->reference_list[] = $file_ref;
     // If requested, save the reference to the
     // database
     if (Database::isEnabled()) {
         if ($this instanceof Addressable) {
             (new CalledBy((string) $this->getFQSEN(), $file_ref))->write(Database::get());
         }
     }
 }