Inheritance: extends AddressableElement, use trait Phan\Memoize
Example #1
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeParentConstructorCalled(CodeBase $code_base, Clazz $clazz)
 {
     // Only look at classes configured to require a call
     // to its parent constructor
     if (!in_array($clazz->getName(), Config::get()->parent_constructor_required)) {
         return;
     }
     // Don't worry about internal classes
     if ($clazz->isInternal()) {
         return;
     }
     // Don't worry if there's no parent class
     if (!$clazz->hasParentClassFQSEN()) {
         return;
     }
     if (!$code_base->hasClassWithFQSEN($clazz->getParentClassFQSEN())) {
         // This is an error, but its caught elsewhere. We'll
         // just roll through looking for other errors
         return;
     }
     $parent_clazz = $code_base->getClassByFQSEN($clazz->getParentClassFQSEN());
     if (!$parent_clazz->isAbstract() && !$clazz->getIsParentConstructorCalled()) {
         Issue::emit(Issue::TypeParentConstructorCalled, $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart(), (string) $clazz->getFQSEN(), (string) $parent_clazz->getFQSEN());
     }
 }
Example #2
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzePropertyTypes(CodeBase $code_base, Clazz $clazz)
 {
     foreach ($clazz->getPropertyList($code_base) as $property) {
         try {
             $union_type = $property->getUnionType();
         } catch (IssueException $exception) {
             Issue::maybeEmitInstance($code_base, $property->getContext(), $exception->getIssueInstance());
             continue;
         }
         // Look at each type in the parameter's Union Type
         foreach ($union_type->getTypeSet() as $type) {
             // If its a native type or a reference to
             // self, its OK
             if ($type->isNativeType() || $type->isSelfType()) {
                 continue;
             }
             if ($type instanceof TemplateType) {
                 if ($property->isStatic()) {
                     Issue::maybeEmit($code_base, $property->getContext(), Issue::TemplateTypeStaticProperty, $property->getFileRef()->getLineNumberStart(), (string) $property->getFQSEN());
                 }
             } else {
                 // Make sure the class exists
                 $type_fqsen = $type->asFQSEN();
                 if (!$code_base->hasClassWithFQSEN($type_fqsen) && !$type instanceof TemplateType && (!$property->hasDefiningFQSEN() || $property->getDefiningFQSEN() == $property->getFQSEN())) {
                     Issue::maybeEmit($code_base, $property->getContext(), Issue::UndeclaredTypeProperty, $property->getFileRef()->getLineNumberStart(), (string) $property->getFQSEN(), (string) $type_fqsen);
                 }
             }
         }
     }
 }
Example #3
0
 /**
  * @return bool
  * True if the FQSEN exists. If not, a log line is emitted
  */
 private static function fqsenExistsForClass(FQSEN $fqsen, CodeBase $code_base, Clazz $clazz, string $message_template) : bool
 {
     if (!$code_base->hasClassWithFQSEN($fqsen)) {
         Log::err(Log::EUNDEF, sprintf($message_template, $fqsen), $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart());
         return false;
     }
     return true;
 }
Example #4
0
 /**
  * @return bool
  * True if the FQSEN exists. If not, a log line is emitted
  */
 private static function fqsenExistsForClass(FQSEN $fqsen, CodeBase $code_base, Clazz $clazz) : bool
 {
     if (!$code_base->hasClassWithFQSEN($fqsen)) {
         Log::err(Log::EUNDEF, "Trying to inherit from unknown class {$fqsen}", $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart());
         return false;
     }
     return true;
 }
Example #5
0
 /**
  * @return bool
  * True if the FQSEN exists. If not, a log line is emitted
  */
 private static function fqsenExistsForClass(FQSEN $fqsen, CodeBase $code_base, Clazz $clazz, string $issue_type) : bool
 {
     if (!$code_base->hasClassWithFQSEN($fqsen)) {
         Issue::maybeEmit($code_base, $clazz->getContext(), $issue_type, $clazz->getFileRef()->getLineNumberStart(), (string) $fqsen);
         return false;
     }
     return true;
 }
Example #6
0
 /**
  * @param CodeBase $code_base
  * The code base in which the class exists
  *
  * @param Clazz $class
  * A class being analyzed
  *
  * @return void
  */
 public function analyzeClass(CodeBase $code_base, Clazz $class)
 {
     // As an example, we test to see if the name of
     // the class is `Class`, and emit an issue explain that
     // the name is not allowed.
     if ($class->getName() == 'Class') {
         $this->emitIssue($code_base, $class->getContext(), 'DemoPluginClassName', "Class {$class->getFQSEN()} cannot be called `Class`");
     }
 }
Example #7
0
 /**
  * @param array
  * A map from column name to value
  *
  * @return Model
  * An instance of the model derived from row data
  */
 public static function fromRow(array $row) : Clazz
 {
     $parent_fqsen = $row['parent_class_fqsen'] ? FullyQualifiedClassName::fromFullyQualifiedString($row['parent_class_fqsen']) : null;
     $interface_fqsen_list = array_map(function (string $fqsen_string) {
         return FullyQualifiedClassName::fromFullyQualifiedString($fqsen_string);
     }, array_filter(explode('|', $row['interface_fqsen_list'])));
     $trait_fqsen_list = array_map(function (string $fqsen_string) {
         return FullyQualifiedClassName::fromFullyQualifiedString($fqsen_string);
     }, array_filter(explode('|', $row['trait_fqsen_list'])));
     $clazz = new ClazzElement(unserialize(base64_decode($row['context'])), $row['name'], UnionType::fromFullyQualifiedString($row['type']), (int) $row['flags'], $parent_fqsen, $interface_fqsen_list, $trait_fqsen_list);
     $clazz->setFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($row['fqsen']));
     return new Clazz($clazz);
 }
Example #8
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzePropertyTypes(CodeBase $code_base, Clazz $clazz)
 {
     foreach ($clazz->getPropertyList($code_base) as $property) {
         $union_type = $property->getUnionType();
         // Look at each type in the parameter's Union Type
         foreach ($union_type->getTypeSet() as $type) {
             // If its a native type or a reference to
             // self, its OK
             if ($type->isNativeType() || $type->isSelfType()) {
                 continue;
             }
             // Otherwise, make sure the class exists
             $type_fqsen = $type->asFQSEN();
             if (!$code_base->hasClassWithFQSEN($type_fqsen)) {
                 Issue::emit(Issue::UndeclaredTypeProperty, $property->getContext()->getFile(), $property->getContext()->getLineNumberStart(), (string) $type_fqsen);
             }
         }
     }
 }
Example #9
0
 /**
  * @return Method
  * A default constructor for the given class
  */
 public static function defaultConstructorForClassInContext(Clazz $clazz, Context $context, CodeBase $code_base) : Method
 {
     $method_fqsen = FullyQualifiedMethodName::make($clazz->getFQSEN(), '__construct');
     $method = new Method($context, '__construct', $clazz->getUnionType(), 0, $method_fqsen);
     if ($clazz->hasMethodWithName($code_base, $clazz->getName())) {
         $old_style_constructor = $clazz->getMethodByName($code_base, $clazz->getName());
         $method->setParameterList($old_style_constructor->getParameterList());
         $method->setNumberOfRequiredParameters($old_style_constructor->getNumberOfRequiredParameters());
         $method->setNumberOfOptionalParameters($old_style_constructor->getNumberOfOptionalParameters());
     }
     return $method;
 }
Example #10
0
 /**
  * @return Method
  * A default constructor for the given class
  */
 public static function defaultConstructorForClassInContext(Clazz $clazz, Context $context) : Method
 {
     return new Method($context, '__construct', $clazz->getUnionType(), 0);
 }
Example #11
0
 /**
  * Add properties, constants and methods from the given
  * class to this.
  *
  * @param Clazz $superclazz
  * A class to import from
  *
  * @return null
  */
 public function importAncestorClass(CodeBase $code_base, Clazz $superclazz)
 {
     $this->memoize((string) $superclazz->getFQSEN(), function () use($code_base, $superclazz) {
         // Copy properties
         foreach ($superclazz->getPropertyMap($code_base) as $property) {
             $this->addProperty($code_base, $property);
         }
         // Copy constants
         foreach ($superclazz->getConstantMap($code_base) as $constant) {
             $this->addConstant($code_base, $constant);
         }
         // Copy methods
         foreach ($superclazz->getMethodMap($code_base) as $method) {
             $this->addMethod($code_base, $method);
         }
     });
 }
Example #12
0
 /**
  * Visit a node with kind `\ast\AST_CLASS`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitClass(Decl $node) : Context
 {
     if ($node->flags & \ast\flags\CLASS_ANONYMOUS) {
         $class_name = (new ContextNode($this->code_base, $this->context, $node))->getUnqualifiedNameForAnonymousClass();
     } else {
         $class_name = (string) $node->name;
     }
     // This happens now and then and I have no idea
     // why.
     if (empty($class_name)) {
         return $this->context;
     }
     assert(!empty($class_name), "Class must have name in {$this->context}");
     $class_fqsen = FullyQualifiedClassName::fromStringInContext($class_name, $this->context);
     assert($class_fqsen instanceof FullyQualifiedClassName, "The class FQSEN must be a FullyQualifiedClassName");
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
         $class_fqsen = $class_fqsen->withAlternateId(++$alternate_id);
     }
     // Build the class from what we know so far
     $class_context = $this->context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? -1);
     $class = new Clazz($class_context, $class_name, $class_fqsen->asUnionType(), $node->flags ?? 0, $class_fqsen);
     // Set the scope of the class's context to be the
     // internal scope of the class
     $class_context = $class_context->withScope($class->getInternalScope());
     // Get a comment on the class declaration
     $comment = Comment::fromStringInContext($node->docComment ?? '', $this->context);
     // Add any template types parameterizing a generic class
     foreach ($comment->getTemplateTypeList() as $template_type) {
         $class->getInternalScope()->addTemplateType($template_type);
     }
     $class->setIsDeprecated($comment->isDeprecated());
     $class->setSuppressIssueList($comment->getSuppressIssueList());
     // Add the class to the code base as a globally
     // accessible object
     $this->code_base->addClass($class);
     // Look to see if we have a parent class
     if (!empty($node->children['extends'])) {
         $parent_class_name = $node->children['extends']->children['name'];
         // Check to see if the name isn't fully qualified
         if ($node->children['extends']->flags & \ast\flags\NAME_NOT_FQ) {
             if ($this->context->hasNamespaceMapFor(T_CLASS, $parent_class_name)) {
                 // Get a fully-qualified name
                 $parent_class_name = (string) $this->context->getNamespaceMapFor(T_CLASS, $parent_class_name);
             } else {
                 $parent_class_name = $this->context->getNamespace() . '\\' . $parent_class_name;
             }
         }
         // The name is fully qualified. Make sure it looks
         // like it is
         if (0 !== strpos($parent_class_name, '\\')) {
             $parent_class_name = '\\' . $parent_class_name;
         }
         $parent_fqsen = FullyQualifiedClassName::fromStringInContext($parent_class_name, $this->context);
         // Set the parent for the class
         $class->setParentType($parent_fqsen->asType());
     }
     // If the class explicitly sets its overriding extension type,
     // set that on the class
     $inherited_type_option = $comment->getInheritedTypeOption();
     if ($inherited_type_option->isDefined()) {
         $class->setParentType($inherited_type_option->get());
     }
     // Add any implemeneted interfaces
     if (!empty($node->children['implements'])) {
         $interface_list = (new ContextNode($this->code_base, $this->context, $node->children['implements']))->getQualifiedNameList();
         foreach ($interface_list as $name) {
             $class->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($name));
         }
     }
     return $class_context;
 }
Example #13
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeDuplicateClass(CodeBase $code_base, Clazz $clazz)
 {
     // Determine if its a duplicate by looking to see if
     // the FQSEN is suffixed with an alternate ID.
     if (!$clazz->getFQSEN()->isAlternate()) {
         return;
     }
     $original_fqsen = $clazz->getFQSEN()->getCanonicalFQSEN();
     if (!$code_base->hasClassWithFQSEN($original_fqsen)) {
         // If there's a missing class we'll catch that
         // elsewhere
         return;
     }
     // Get the original class
     $original_class = $code_base->getClassByFQSEN($original_fqsen);
     // Check to see if the original definition was from
     // an internal class
     if ($original_class->isInternal()) {
         Log::err(Log::EREDEF, "{$clazz} defined at " . "{$clazz->getContext()->getFile()}:{$clazz->getContext()->getLineNumberStart()} " . "was previously defined as {$original_class} internally", $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart());
         // Otherwise, print the coordinates of the original
         // definition
     } else {
         Log::err(Log::EREDEF, "{$clazz} defined at " . "{$clazz->getContext()->getFile()}:{$clazz->getContext()->getLineNumberStart()} " . "was previously defined as {$original_class} at " . "{$original_class->getContext()->getFile()}:{$original_class->getContext()->getLineNumberStart()}", $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart());
     }
     return;
 }
Example #14
0
 /**
  * Check to see if signatures match
  *
  * @return void
  */
 public static function analyzeComposition(CodeBase $code_base, Clazz $class)
 {
     // Get the Class's FQSEN
     $fqsen = $class->getFQSEN();
     // Get the list of all inherited classes.
     $inherited_class_list = $class->getInheritedClassList($code_base);
     // No chance of failed composition if we don't inherit from
     // lots of stuff.
     if (count($inherited_class_list) < 2) {
         return;
     }
     // For each property, find out every inherited class that defines it
     // and check to see if the types line up.
     foreach ($class->getPropertyList($code_base) as $property) {
         try {
             $property_union_type = $property->getUnionType();
         } catch (IssueException $exception) {
             $property_union_type = new UnionType();
         }
         // Check for that property on each inherited
         // class/trait/interface
         foreach ($inherited_class_list as $inherited_class) {
             // Skip any classes/traits/interfaces not defining that
             // property
             if (!$inherited_class->hasPropertyWithName($code_base, $property->getName())) {
                 continue;
             }
             // We don't call `getProperty` because that will create
             // them in some circumstances.
             $inherited_property_map = $inherited_class->getPropertyMap($code_base);
             if (!isset($inherited_property_map[$property->getName()])) {
                 continue;
             }
             // Get the inherited property
             $inherited_property = $inherited_property_map[$property->getName()];
             // Figure out if this property type can cast to the
             // inherited definition's type.
             $can_cast = $property_union_type->canCastToExpandedUnionType($inherited_property->getUnionType(), $code_base);
             if ($can_cast) {
                 continue;
             }
             // Don't emit an issue if the property suppresses the issue
             if ($property->hasSuppressIssue(Issue::IncompatibleCompositionProp)) {
                 continue;
             }
             Issue::maybeEmit($code_base, $property->getContext(), Issue::IncompatibleCompositionProp, $property->getFileRef()->getLineNumberStart(), (string) $class->getFQSEN(), (string) $inherited_class->getFQSEN(), $property->getName(), (string) $class->getFQSEN(), $class->getFileRef()->getFile(), $class->getFileRef()->getLineNumberStart());
         }
     }
     // TODO: This has too much overlap with PhanParamSignatureMismatch
     //       and we should figure out how to merge it.
     /*
     $method_map =
         $code_base->getMethodMapByFullyQualifiedClassName($fqsen);
     
     // For each method, find out every inherited class that defines it
     // and check to see if the types line up.
     foreach ($method_map as $i => $method) {
     
         $method_union_type = $method->getUnionType();
     
         // We don't need to analyze constructors for signature
         // compatibility
         if ($method->getName() == '__construct') {
             continue;
         }
     
         // Get the method parameter list
     
         // Check for that method on each inherited
         // class/trait/interface
         foreach ($inherited_class_list as $inherited_class) {
     
             // Skip anything that doesn't define this method
             if (!$inherited_class->hasMethodWithName($code_base, $method->getName())) {
                 continue;
             }
     
             $inherited_method =
                 $inherited_class->getMethodByName($code_base, $method->getName());
     
             if ($method == $inherited_method) {
                 continue;
             }
     
             // Figure out if this method return type can cast to the
             // inherited definition's return type.
             $is_compatible =
                 $method_union_type->canCastToExpandedUnionType(
                     $inherited_method->getUnionType(),
                     $code_base
                 );
     
             $inherited_method_parameter_map =
                 $inherited_method->getParameterList();
     
             // Figure out if all of the parameter types line up
             foreach ($method->getParameterList() as $i => $parameter) {
                 $is_compatible = (
                     $is_compatible
                     && isset($inherited_method_parameter_map[$i])
                     && $parameter->getUnionType()->canCastToExpandedUnionType(
                         ($inherited_method_parameter_map[$i])->getUnionType(),
                         $code_base
                     )
                 );
             }
     
             if ($is_compatible) {
                 continue;
             }
     
             // Don't emit an issue if the method suppresses the issue
             if ($method->hasSuppressIssue(Issue::IncompatibleCompositionMethod)) {
                 continue;
             }
     
             Issue::maybeEmit(
                 $code_base,
                 $method->getContext(),
                 Issue::IncompatibleCompositionMethod,
                 $method->getFileRef()->getLineNumberStart(),
                 (string)$method,
                 (string)$inherited_method,
                 $inherited_method->getFileRef()->getFile(),
                 $inherited_method->getFileRef()->getLineNumberStart()
             );
         }
     }
     */
 }
Example #15
0
 /**
  * @param Clazz $class
  * A class to add.
  *
  * @return void
  */
 public function addClass(Clazz $class)
 {
     // Map the FQSEN to the class
     $this->fqsen_class_map[$class->getFQSEN()] = $class;
 }
Example #16
0
File: Clazz.php Project: etsy/phan
 /**
  * Add properties, constants and methods from the given
  * class to this.
  *
  * @param CodeBase $code_base
  * A reference to the code base in which the ancestor exists
  *
  * @param Clazz $class
  * A class to import from
  *
  * @param Option<Type>|None $type_option
  * A possibly defined ancestor type used to define template
  * parameter types when importing ancestor properties and
  * methods
  *
  * @return void
  */
 public function importAncestorClass(CodeBase $code_base, Clazz $class, $type_option)
 {
     if (!$this->isFirstExecution(__METHOD__ . ':' . (string) $class->getFQSEN())) {
         return;
     }
     $class->addReference($this->getContext());
     // Make sure that the class imports its parents first
     $class->hydrate($code_base);
     // Copy properties
     foreach ($class->getPropertyMap($code_base) as $property) {
         $this->addProperty($code_base, $property, $type_option);
     }
     // Copy constants
     foreach ($class->getConstantMap($code_base) as $constant) {
         $this->addConstant($code_base, $constant);
     }
     // Copy methods
     foreach ($class->getMethodMap($code_base) as $method) {
         $this->addMethod($code_base, $method, $type_option);
     }
 }
Example #17
0
 /**
  * @return array
  * Get a map from column name to row values for
  * this instance
  */
 public function toRow() : array
 {
     $parent_class_fqsen = $this->clazz->hasParentClassFQSEN() ? (string) $this->clazz->getParentClassFQSEN() : null;
     $interface_fqsen_list_string = implode('|', array_map(function (FullyQualifiedClassName $fqsen) {
         return (string) $fqsen;
     }, $this->clazz->getInterfaceFQSENList()));
     $trait_fqsen_list_string = implode('|', array_map(function (FullyQualifiedClassName $fqsen) {
         return (string) $fqsen;
     }, $this->clazz->getInterfaceFQSENList()));
     return ['name' => (string) $this->clazz->getName(), 'type' => (string) $this->clazz->getUnionType(), 'flags' => $this->clazz->getFlags(), 'fqsen' => (string) $this->clazz->getFQSEN(), 'context' => base64_encode(serialize($this->clazz->getContext())), 'is_deprecated' => $this->clazz->isDeprecated(), 'parent_class_fqsen' => $parent_class_fqsen, 'interface_fqsen_list' => $interface_fqsen_list_string, 'trait_fqsen_list' => $trait_fqsen_list_string, 'is_parent_constructor_called' => $this->clazz->getIsParentConstructorCalled()];
 }
Example #18
0
 /**
  * Visit a node with kind `\ast\AST_CLASS`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitClass(Decl $node) : Context
 {
     if ($node->flags & \ast\flags\CLASS_ANONYMOUS) {
         $class_name = (new ContextNode($this->code_base, $this->context, $node))->getUnqualifiedNameForAnonymousClass();
     } else {
         $class_name = (string) $node->name;
     }
     // This happens now and then and I have no idea
     // why.
     if (empty($class_name)) {
         return $this->context;
     }
     assert(!empty($class_name), "Class must have name in {$this->context}");
     $class_fqsen = FullyQualifiedClassName::fromStringInContext($class_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
         $class_fqsen = $class_fqsen->withAlternateId(++$alternate_id);
     }
     // Build the class from what we know so far
     $class_context = $this->context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? -1);
     $clazz = new Clazz($class_context, $class_name, UnionType::fromStringInContext($class_name, $this->context), $node->flags ?? 0);
     // Override the FQSEN with the found alternate ID
     $clazz->setFQSEN($class_fqsen);
     // Get a comment on the class declaration
     $comment = Comment::fromStringInContext($node->docComment ?? '', $this->context);
     $clazz->setIsDeprecated($comment->isDeprecated());
     $clazz->setSuppressIssueList($comment->getSuppressIssueList());
     // Add the class to the code base as a globally
     // accessible object
     $this->code_base->addClass($clazz);
     // Look to see if we have a parent class
     if (!empty($node->children['extends'])) {
         $parent_class_name = $node->children['extends']->children['name'];
         // Check to see if the name isn't fully qualified
         if ($node->children['extends']->flags & \ast\flags\NAME_NOT_FQ) {
             if ($this->context->hasNamespaceMapFor(T_CLASS, $parent_class_name)) {
                 // Get a fully-qualified name
                 $parent_class_name = (string) $this->context->getNamespaceMapFor(T_CLASS, $parent_class_name);
             } else {
                 $parent_class_name = $this->context->getNamespace() . '\\' . $parent_class_name;
             }
         }
         // The name is fully qualified. Make sure it looks
         // like it is
         if (0 !== strpos($parent_class_name, '\\')) {
             $parent_class_name = '\\' . $parent_class_name;
         }
         $parent_fqsen = FullyQualifiedClassName::fromStringInContext($parent_class_name, $this->context);
         // Set the parent for the class
         $clazz->setParentClassFQSEN($parent_fqsen);
     }
     // Add any implemeneted interfaces
     if (!empty($node->children['implements'])) {
         $interface_list = (new ContextNode($this->code_base, $this->context, $node->children['implements']))->getQualifiedNameList();
         foreach ($interface_list as $name) {
             $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($name));
         }
     }
     // Update the context to signal that we're now
     // within a class context.
     $context = $class_context->withClassFQSEN($class_fqsen);
     return $context;
 }
Example #19
0
 /**
  * @return Method
  * A default constructor for the given class
  */
 public static function defaultConstructorForClassInContext(Clazz $clazz, Context $context) : Method
 {
     $method = new Method($context, '__construct', $clazz->getUnionType(), 0);
     $method->setFQSEN(FullyQualifiedMethodName::make($clazz->getFQSEN(), '__construct'));
     return $method;
 }
Example #20
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeDuplicateClass(CodeBase $code_base, Clazz $clazz)
 {
     // Determine if its a duplicate by looking to see if
     // the FQSEN is suffixed with an alternate ID.
     if (!$clazz->getFQSEN()->isAlternate()) {
         return;
     }
     $original_fqsen = $clazz->getFQSEN()->getCanonicalFQSEN();
     if (!$code_base->hasClassWithFQSEN($original_fqsen)) {
         // If there's a missing class we'll catch that
         // elsewhere
         return;
     }
     // Get the original class
     $original_class = $code_base->getClassByFQSEN($original_fqsen);
     // Check to see if the original definition was from
     // an internal class
     if ($original_class->isInternal()) {
         Issue::emit(Issue::RedefineClassInternal, $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart(), (string) $clazz, $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart(), (string) $original_class);
         // Otherwise, print the coordinates of the original
         // definition
     } else {
         Issue::emit(Issue::RedefineClass, $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart(), (string) $clazz, $clazz->getContext()->getFile(), $clazz->getContext()->getLineNumberStart(), (string) $original_class, $original_class->getContext()->getFile(), $original_class->getContext()->getLineNumberStart());
     }
     return;
 }
Example #21
0
 /**
  * @param string[] $class_name_list
  * A list of class names to load type information for
  *
  * @return null
  */
 private function addClassesByNames(array $class_name_list)
 {
     foreach ($class_name_list as $i => $class_name) {
         $clazz = Clazz::fromClassName($this, $class_name);
         $this->class_map[$clazz->getFQSEN()] = $clazz;
     }
 }