mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Update qhelp + alert messages
This commit is contained in:
@@ -4,47 +4,49 @@
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Python, unlike statically typed languages such as Java, allows complete freedom when calling methods during object destruction.
|
||||
However, standard object-oriented principles apply to Python classes using deep inheritance hierarchies.
|
||||
Therefore the developer has responsibility for ensuring that objects are properly cleaned up when
|
||||
there are multiple <code>__del__</code> methods that need to be called.
|
||||
<p>
|
||||
Python, unlike some other object-oriented languages such as Java, allows the developer complete freedom in
|
||||
when and how superclass finalizers are called during object finalization.
|
||||
However, the developer has responsibility for ensuring that objects are properly cleaned up, and that all superclass <code>__del__</code>
|
||||
methods are called.
|
||||
</p>
|
||||
<p>
|
||||
If the <code>__del__</code> method of a superclass is not called during object destruction it is likely that
|
||||
Classes with a <code>__del__</code> method (a finalizer) typically hold some resource such as a file handle that needs to be cleaned up.
|
||||
If the <code>__del__</code> method of a superclass is not called during object finalization, it is likely that
|
||||
that resources may be leaked.
|
||||
</p>
|
||||
|
||||
<p>A call to the <code>__del__</code> method of a superclass during object destruction may be omitted:
|
||||
<p>A call to the <code>__init__</code> method of a superclass during object initialization may be unintentionally skipped:
|
||||
</p>
|
||||
<ul>
|
||||
<li>When a subclass calls the <code>__del__</code> method of the wrong class.</li>
|
||||
<li>When a call to the <code>__del__</code> method of one its base classes is omitted.</li>
|
||||
<li>If a subclass calls the <code>__del__</code> method of the wrong class.</li>
|
||||
<li>If a call to the <code>__del__</code> method of one its base classes is omitted.</li>
|
||||
<li>If a call to <code>super().__del__</code> is used, but not all <code>__del__</code> methods in the Method Resolution Order (MRO)
|
||||
chain themselves call <code>super()</code>. This in particular arises more often in cases of multiple inheritance. </li>
|
||||
</ul>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Either be careful to explicitly call the <code>__del__</code> of the correct base class, or
|
||||
use <code>super()</code> throughout the inheritance hierarchy.</p>
|
||||
|
||||
<p>Alternatively refactor one or more of the classes to use composition rather than inheritance.</p>
|
||||
<p>Ensure that all superclass <code>__del__</code> methods are properly called.
|
||||
Either each base class's finalize method should be explicitly called, or <code>super()</code> calls
|
||||
should be consistently used throughout the inheritance hierarchy.</p>
|
||||
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>In this example, explicit calls to <code>__del__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
<p>In the following example, explicit calls to <code>__del__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
<code>Vehicle.__del__</code>. This is fixed in <code>FixedSportsCar</code> by calling <code>Car.__del__</code>.
|
||||
</p>
|
||||
|
||||
<sample src="MissingCallToDel.py" />
|
||||
<sample src="examples/MissingCallToDel.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Python Tutorial: <a href="https://docs.python.org/2/tutorial/classes.html">Classes</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/2/library/functions.html#super">super</a>.</li>
|
||||
<li>Artima Developer: <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to Know About Python Super</a>.</li>
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Composition_over_inheritance">Composition over inheritance</a>.</li>
|
||||
<li>Python Reference: <a href="https://docs.python.org/3/reference/datamodel.html#object.__del__">__del__</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/3/library/functions.html#super">super</a>.</li>
|
||||
<li>Python Glossary: <a href="https://docs.python.org/3/glossary.html#term-method-resolution-order">Method resolution order</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -30,18 +30,18 @@ where
|
||||
not possiblyMissingSuper.isNone() and
|
||||
possibleIssue = possiblyMissingSuper and
|
||||
msg =
|
||||
"This class does not call $@ during destruction. ($@ may be missing a call to super().__del__)"
|
||||
"This class does not call $@ during finalization. ($@ may be missing a call to super().__del__)"
|
||||
or
|
||||
possiblyMissingSuper.isNone() and
|
||||
(
|
||||
possibleIssue.asSome() = getDelMethod(base) and
|
||||
msg =
|
||||
"This class does not call $@ during destruction. ($@ may be missing a call to a base class __del__)"
|
||||
"This class does not call $@ during finalization. ($@ may be missing a call to a base class __del__)"
|
||||
or
|
||||
not exists(getDelMethod(base)) and
|
||||
possibleIssue.isNone() and
|
||||
msg =
|
||||
"This class does not call $@ during destruction. (The class lacks an __del__ method to ensure every base class __del__ is called.)"
|
||||
"This class does not call $@ during finalization. (The class lacks an __del__ method to ensure every base class __del__ is called.)"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -4,49 +4,47 @@
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Python, unlike statically typed languages such as Java, allows complete freedom when calling methods during object initialization.
|
||||
However, standard object-oriented principles apply to Python classes using deep inheritance hierarchies.
|
||||
Therefore the developer has responsibility for ensuring that objects are properly initialized when
|
||||
there are multiple <code>__init__</code> methods that need to be called.
|
||||
<p>Python, unlike some other object-oriented languages such as Java, allows the developer complete freedom in
|
||||
when and how superclass initializers are called during object initialization.
|
||||
However, the developer has responsibility for ensuring that objects are properly initialized, and that all superclass <code>__init__</code>
|
||||
methods are called.
|
||||
</p>
|
||||
<p>
|
||||
If the <code>__init__</code> method of a superclass is not called during object initialization it is likely that
|
||||
that object will end up in an incorrect state.
|
||||
If the <code>__init__</code> method of a superclass is not called during object initialization, this can lead to errors due to
|
||||
the object not being fully initialized, such as having missing attributes.
|
||||
</p>
|
||||
|
||||
<p>A call to the <code>__init__</code> method of a superclass during object initialization may be omitted:
|
||||
<p>A call to the <code>__init__</code> method of a superclass during object initialization may be unintentionally skipped:
|
||||
</p>
|
||||
<ul>
|
||||
<li>When a subclass calls the <code>__init__</code> method of the wrong class.</li>
|
||||
<li>When a call to the <code>__init__</code> method of one its base classes is omitted.</li>
|
||||
<li>When multiple inheritance is used and a class inherits from several base classes,
|
||||
and at least one of those does not use <code>super()</code> in its own <code>__init__</code> method.</li>
|
||||
<li>If a subclass calls the <code>__init__</code> method of the wrong class.</li>
|
||||
<li>If a call to the <code>__init__</code> method of one its base classes is omitted.</li>
|
||||
<li>If a call to <code>super().__init__</code> is used, but not all <code>__init__</code> methods in the Method Resolution Order (MRO)
|
||||
chain themselves call <code>super()</code>. This in particular arises more often in cases of multiple inheritance. </li>
|
||||
</ul>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Either be careful to explicitly call the <code>__init__</code> of the correct base class, or
|
||||
use <code>super()</code> throughout the inheritance hierarchy.</p>
|
||||
|
||||
<p>Alternatively refactor one or more of the classes to use composition rather than inheritance.</p>
|
||||
<p>Ensure that all superclass <code>__init__</code> methods are properly called.
|
||||
Either each base class's initialize method should be explicitly called, or <code>super()</code> calls
|
||||
should be consistently used throughout the inheritance hierarchy.</p>
|
||||
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>In this example, explicit calls to <code>__init__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
<p>In the following example, explicit calls to <code>__init__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
<code>Vehicle.__init__</code>. This is fixed in <code>FixedSportsCar</code> by calling <code>Car.__init__</code>.
|
||||
</p>
|
||||
|
||||
<sample src="MissingCallToInit.py" />
|
||||
<sample src="examples/MissingCallToInit.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Python Tutorial: <a href="https://docs.python.org/2/tutorial/classes.html">Classes</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/2/library/functions.html#super">super</a>.</li>
|
||||
<li>Artima Developer: <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to Know About Python Super</a>.</li>
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Composition_over_inheritance">Composition over inheritance</a>.</li>
|
||||
<li>Python Reference: <a href="https://docs.python.org/3/reference/datamodel.html#object.__init__">__init__</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/3/library/functions.html#super">super</a>.</li>
|
||||
<li>Python Glossary: <a href="https://docs.python.org/3/glossary.html#term-method-resolution-order">Method resolution order</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -4,55 +4,52 @@
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Python, unlike statically typed languages such as Java, allows complete freedom when calling methods during object destruction.
|
||||
However, standard object-oriented principles apply to Python classes using deep inheritance hierarchies.
|
||||
Therefore the developer has responsibility for ensuring that objects are properly cleaned up when
|
||||
there are multiple <code>__del__</code> methods that need to be called.
|
||||
<p>
|
||||
Python, unlike some other object-oriented languages such as Java, allows the developer complete freedom in
|
||||
when and how superclass finalizers are called during object finalization.
|
||||
However, the developer has responsibility for ensuring that objects are properly cleaned up.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Calling a <code>__del__</code> method more than once during object destruction risks resources being released multiple
|
||||
times. The relevant <code>__del__</code> method may not be designed to be called more than once.
|
||||
Objects with a <code>__del__</code> method (a finalizer) often hold resources such as file handles that need to be cleaned up.
|
||||
If a superclass finalizer is called multiple times, this may lead to errors such as closing an already closed file, and lead to objects not being
|
||||
cleaned up properly as expected.
|
||||
</p>
|
||||
|
||||
<p>There are a number of ways that a <code>__del__</code> method may be be called more than once.</p>
|
||||
<ul>
|
||||
<li>There may be more than one explicit call to the method in the hierarchy of <code>__del__</code> methods.</li>
|
||||
<li>A class using multiple inheritance directly calls the <code>__del__</code> methods of its base types.
|
||||
One or more of those base types uses <code>super()</code> to pass down the inheritance chain.</li>
|
||||
<li>In situations involving multiple inheritance, an finalization method may call the finalizers of each of its base types,
|
||||
which themselves both call the finalizer of a shared base type. (This is an example of the Diamond Inheritance problem)</li>
|
||||
<li>Another situation involving multiple inheritance arises when a subclass calls the <code>__del__</code> methods of each of its base classes,
|
||||
one of which calls <code>super().__del__</code>. This super call resolves to the next class in the Method Resolution Order (MRO) of the subclass,
|
||||
which may be another base class that already has its initializer explicitly called.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Either be careful not to explicitly call a <code>__del__</code> method more than once, or
|
||||
use <code>super()</code> throughout the inheritance hierarchy.</p>
|
||||
|
||||
<p>Alternatively refactor one or more of the classes to use composition rather than inheritance.</p>
|
||||
<p>Ensure that each finalizer method is called exactly once during finalization.
|
||||
This can be ensured by calling <code>super().__del__</code> for each finalizer methid in the inheritance chain.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>In the first example, explicit calls to <code>__del__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
both <code>Vehicle.__del__</code> and <code>Car.__del__</code>.
|
||||
This can be fixed by removing the call to <code>Vehicle.__del__</code>, as shown in <code>FixedSportsCar</code>.
|
||||
</p>
|
||||
|
||||
<sample src="SuperclassDelCalledMultipleTimes.py" />
|
||||
|
||||
<p>In the second example, there is a mixture of explicit calls to <code>__del__</code> and calls using <code>super()</code>.
|
||||
To fix this example, <code>super()</code> should be used throughout.
|
||||
<p>In the following example, there is a mixture of explicit calls to <code>__del__</code> and calls using <code>super()</code>, resulting in <code>Vehicle.__del__</code>
|
||||
being called twice.
|
||||
<code>FixedSportsCar.__del__</code> fixes this by using <code>super()</code> consistently with the other delete methods.
|
||||
</p>
|
||||
|
||||
<sample src="SuperclassInitCalledMultipleTimes2.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Python Tutorial: <a href="https://docs.python.org/2/tutorial/classes.html">Classes</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/2/library/functions.html#super">super</a>.</li>
|
||||
<li>Artima Developer: <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to Know About Python Super</a>.</li>
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Composition_over_inheritance">Composition over inheritance</a>.</li>
|
||||
|
||||
|
||||
<li>Python Reference: <a href="https://docs.python.org/3/reference/datamodel.html#object.__del__">__del__</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/3/library/functions.html#super">super</a>.</li>
|
||||
<li>Python Glossary: <a href="https://docs.python.org/3/glossary.html#term-method-resolution-order">Method resolution order</a>.</li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem">The Diamond Problem</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -36,12 +36,12 @@ where
|
||||
(
|
||||
target1 != target2 and
|
||||
msg =
|
||||
"This deletion method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively."
|
||||
"This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively."
|
||||
or
|
||||
target1 = target2 and
|
||||
// The targets themselves are called multiple times (either is calledMulti, or something earlier in the MRO)
|
||||
// Mentioning them again would be redundant.
|
||||
msg = "This deletion method calls $@ multiple times, via $@ and $@."
|
||||
msg = "This finalization method calls $@ multiple times, via $@ and $@."
|
||||
)
|
||||
select meth, msg, calledMulti, calledMulti.getQualifiedName(), call1, "this call", call2,
|
||||
"this call", target1, target1.getQualifiedName(), target2, target2.getQualifiedName()
|
||||
|
||||
@@ -4,54 +4,70 @@
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Python, unlike statically typed languages such as Java, allows complete freedom when calling methods during object initialization.
|
||||
However, standard object-oriented principles apply to Python classes using deep inheritance hierarchies.
|
||||
Therefore the developer has responsibility for ensuring that objects are properly initialized when
|
||||
there are multiple <code>__init__</code> methods that need to be called.
|
||||
<p>Python, unlike some other object-oriented languages such as Java, allows the developer complete freedom in
|
||||
when and how superclass initializers are called during object initialization.
|
||||
However, the developer has responsibility for ensuring that objects are properly initialized.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Calling an <code>__init__</code> method more than once during object initialization risks the object being incorrectly initialized.
|
||||
It is unlikely that the relevant <code>__init__</code> method is designed to be called more than once.
|
||||
Calling an <code>__init__</code> method more than once during object initialization risks the object being incorrectly
|
||||
initialized, as the method and the rest of the inheritance chain may not have been written with the expectation
|
||||
that it could be called multiple times. For example, it may set attributes to a default value in a way that unexpectedly overwrites
|
||||
values setting those attributes in a subclass.
|
||||
</p>
|
||||
|
||||
<p>There are a number of ways that an <code>__init__</code> method may be be called more than once.</p>
|
||||
<ul>
|
||||
<li>There may be more than one explicit call to the method in the hierarchy of <code>__init__</code> methods.</li>
|
||||
<li>A class using multiple inheritance directly calls the <code>__init__</code> methods of its base types.
|
||||
One or more of those base types uses <code>super()</code> to pass down the inheritance chain.</li>
|
||||
<li>In situations involving multiple inheritance, an initialization method may call the initializers of each of its base types,
|
||||
which themselves both call the initializer of a shared base type. (This is an example of the Diamond Inheritance problem)</li>
|
||||
<li>Another situation involving multiple inheritance arises when a subclass calls the <code>__init__</code> methods of each of its base classes,
|
||||
one of which calls <code>super().__init__</code>. This super call resolves to the next class in the Method Resolution Order (MRO) of the subclass,
|
||||
which may be another base class that already has its initializer explicitly called.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Either be careful not to explicitly call an <code>__init__</code> method more than once, or
|
||||
use <code>super()</code> throughout the inheritance hierarchy.</p>
|
||||
<p>
|
||||
Take care whenever possible not to call an an initializer multiple times. If each <code>__init__</code> method in the hierarchy
|
||||
calls <code>super().__init__()</code>, then each initializer will be called exactly once according to the MRO of the subclass.
|
||||
|
||||
When explicitly calling base class initializers (such as to pass different arguments to different initializers),
|
||||
ensure this is done consistently throughout, rather than using <code>super()</code> calls in the base classes.
|
||||
</p>
|
||||
<p>
|
||||
In some cases, it may not be possible to avoid calling a base initializer multiple times without significant refactoring.
|
||||
In this case, carefully check that the initializer does not interfere with subclass initializers
|
||||
when called multiple times (such as by overwriting attributes), and ensure this behavior is documented.
|
||||
</p>
|
||||
|
||||
<p>Alternatively refactor one or more of the classes to use composition rather than inheritance.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>In the first example, explicit calls to <code>__init__</code> are used, but <code>SportsCar</code> erroneously calls
|
||||
both <code>Vehicle.__init__</code> and <code>Car.__init__</code>.
|
||||
This can be fixed by removing the call to <code>Vehicle.__init__</code>, as shown in <code>FixedSportsCar</code>.
|
||||
<p>In the following (BAD) example, the class <code>D</code> calls <code>B.__init__</code> and <code>C.__init__</code>,
|
||||
which each call <code>A.__init__</code>. This results in <code>self.state</code> being set to <code>None</code> as
|
||||
<code>A.__init__</code> is called again after <code>B.__init__</code> had finished. This may lead to unexpected results.
|
||||
</p>
|
||||
|
||||
<sample src="SuperclassInitCalledMultipleTimes.py" />
|
||||
<sample src="examples/SuperclassInitCalledMultipleTimesBad1.py" />
|
||||
|
||||
<p>In the second example, there is a mixture of explicit calls to <code>__init__</code> and calls using <code>super()</code>.
|
||||
To fix this example, <code>super()</code> should be used throughout.
|
||||
<p>In the following (GOOD) example, a call to <code>super().__init__</code> is made in each class
|
||||
in the inheritance hierarchy, ensuring each initializer is called exactly once.
|
||||
</p>
|
||||
|
||||
<sample src="SuperclassInitCalledMultipleTimes2.py" />
|
||||
<sample src="examples/SuperclassInitCalledMultipleTimesGood2.py" />
|
||||
|
||||
<p>In the following (BAD) example, explicit base class calls are mixed with <code>super()</code> calls, and <code>C.__init__</code> is called twice.</p>
|
||||
|
||||
<sample src="examples/SuperclassInitCalledMultipleTimesBad3.py" />
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Python Tutorial: <a href="https://docs.python.org/2/tutorial/classes.html">Classes</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/2/library/functions.html#super">super</a>.</li>
|
||||
<li>Artima Developer: <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=236275">Things to Know About Python Super</a>.</li>
|
||||
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Composition_over_inheritance">Composition over inheritance</a>.</li>
|
||||
<li>Python Reference: <a href="https://docs.python.org/3/reference/datamodel.html#object.__init__">__init__</a>.</li>
|
||||
<li>Python Standard Library: <a href="https://docs.python.org/3/library/functions.html#super">super</a>.</li>
|
||||
<li>Python Glossary: <a href="https://docs.python.org/3/glossary.html#term-method-resolution-order">Method resolution order</a>.</li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem">The Diamond Problem</a>.</li>
|
||||
|
||||
|
||||
</references>
|
||||
|
||||
@@ -10,14 +10,14 @@ class Car(Vehicle):
|
||||
recycle(self.car_parts)
|
||||
Vehicle.__del__(self)
|
||||
|
||||
#Car.__del__ is missed out.
|
||||
#BAD: Car.__del__ is not called.
|
||||
class SportsCar(Car, Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.sports_car_parts)
|
||||
Vehicle.__del__(self)
|
||||
|
||||
#Fix SportsCar by calling Car.__del__
|
||||
#GOOD: Car.__del__ is called correctly.
|
||||
class FixedSportsCar(Car, Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
#Calling a method multiple times by using explicit calls when a base inherits from other base
|
||||
|
||||
#Calling a method multiple times by using explicit calls when a base uses super()
|
||||
class Vehicle(object):
|
||||
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.base_parts)
|
||||
|
||||
super(Vehicle, self).__del__()
|
||||
|
||||
class Car(Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.car_parts)
|
||||
Vehicle.__del__(self)
|
||||
|
||||
|
||||
super(Car, self).__del__()
|
||||
|
||||
|
||||
class SportsCar(Car, Vehicle):
|
||||
|
||||
# Vehicle.__del__ will get called twice
|
||||
# BAD: Vehicle.__del__ will get called twice
|
||||
def __del__(self):
|
||||
recycle(self.sports_car_parts)
|
||||
Car.__del__(self)
|
||||
Vehicle.__del__(self)
|
||||
|
||||
|
||||
#Fix SportsCar by only calling Car.__del__
|
||||
# GOOD: super() is used ensuring each del method is called once.
|
||||
class FixedSportsCar(Car, Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.sports_car_parts)
|
||||
Car.__del__(self)
|
||||
super(SportsCar, self).__del__()
|
||||
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
#Calling a method multiple times by using explicit calls when a base uses super()
|
||||
class Vehicle(object):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.base_parts)
|
||||
super(Vehicle, self).__del__()
|
||||
|
||||
class Car(Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.car_parts)
|
||||
super(Car, self).__del__()
|
||||
|
||||
|
||||
class SportsCar(Car, Vehicle):
|
||||
|
||||
# Vehicle.__del__ will get called twice
|
||||
def __del__(self):
|
||||
recycle(self.sports_car_parts)
|
||||
Car.__del__(self)
|
||||
Vehicle.__del__(self)
|
||||
|
||||
|
||||
#Fix SportsCar by using super()
|
||||
class FixedSportsCar(Car, Vehicle):
|
||||
|
||||
def __del__(self):
|
||||
recycle(self.sports_car_parts)
|
||||
super(SportsCar, self).__del__()
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#Calling a method multiple times by using explicit calls when a base inherits from other base
|
||||
class Vehicle(object):
|
||||
|
||||
def __init__(self):
|
||||
self.mobile = True
|
||||
|
||||
class Car(Vehicle):
|
||||
|
||||
def __init__(self):
|
||||
Vehicle.__init__(self)
|
||||
self.car_init()
|
||||
|
||||
def car_init(self):
|
||||
pass
|
||||
|
||||
class SportsCar(Car, Vehicle):
|
||||
|
||||
# Vehicle.__init__ will get called twice
|
||||
def __init__(self):
|
||||
Vehicle.__init__(self)
|
||||
Car.__init__(self)
|
||||
self.sports_car_init()
|
||||
|
||||
def sports_car_init(self):
|
||||
pass
|
||||
|
||||
#Fix SportsCar by only calling Car.__init__
|
||||
class FixedSportsCar(Car, Vehicle):
|
||||
|
||||
def __init__(self):
|
||||
Car.__init__(self)
|
||||
self.sports_car_init()
|
||||
|
||||
def sports_car_init(self):
|
||||
pass
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
|
||||
#Calling a method multiple times by using explicit calls when a base uses super()
|
||||
class Vehicle(object):
|
||||
|
||||
def __init__(self):
|
||||
super(Vehicle, self).__init__()
|
||||
self.mobile = True
|
||||
|
||||
class Car(Vehicle):
|
||||
|
||||
def __init__(self):
|
||||
super(Car, self).__init__()
|
||||
self.car_init()
|
||||
|
||||
def car_init(self):
|
||||
pass
|
||||
|
||||
class SportsCar(Car, Vehicle):
|
||||
|
||||
# Vehicle.__init__ will get called twice
|
||||
def __init__(self):
|
||||
Vehicle.__init__(self)
|
||||
Car.__init__(self)
|
||||
self.sports_car_init()
|
||||
|
||||
def sports_car_init(self):
|
||||
pass
|
||||
|
||||
#Fix SportsCar by using super()
|
||||
class FixedSportsCar(Car, Vehicle):
|
||||
|
||||
def __init__(self):
|
||||
super(SportsCar, self).__init__()
|
||||
self.sports_car_init()
|
||||
|
||||
def sports_car_init(self):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.state = None
|
||||
|
||||
class B(A):
|
||||
def __init__(self):
|
||||
A.__init__(self)
|
||||
self.state = "B"
|
||||
self.b = 3
|
||||
|
||||
class C(A):
|
||||
def __init__(self):
|
||||
A.__init__(self)
|
||||
self.c = 2
|
||||
|
||||
class D(B,C):
|
||||
def __init__(self):
|
||||
B.__init__(self)
|
||||
C.__init__(self) # BAD: This calls A.__init__ a second time, setting self.state to None.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
class A:
|
||||
def __init__(self):
|
||||
print("A")
|
||||
self.state = None
|
||||
|
||||
class B(A):
|
||||
def __init__(self):
|
||||
print("B")
|
||||
super().__init__() # When called from D, this calls C.__init__
|
||||
self.state = "B"
|
||||
self.b = 3
|
||||
|
||||
class C(A):
|
||||
def __init__(self):
|
||||
print("C")
|
||||
super().__init__()
|
||||
self.c = 2
|
||||
|
||||
class D(B,C):
|
||||
def __init__(self):
|
||||
B.__init__(self)
|
||||
C.__init__(self) # BAD: C.__init__ is called a second time
|
||||
@@ -0,0 +1,22 @@
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.state = None
|
||||
|
||||
class B(A):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.state = "B"
|
||||
self.b = 3
|
||||
|
||||
class C(A):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.c = 2
|
||||
|
||||
class D(B,C):
|
||||
def __init__(self): # GOOD: Each method calls super, so each init method runs once. self.stat =e will be set to "B".
|
||||
super().__init__()
|
||||
self.d = 1
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
| missing_del.py:13:1:13:13 | Class X3 | This class does not call $@ during destruction. ($@ may be missing a call to a base class __del__) | missing_del.py:9:5:9:22 | Function __del__ | X2.__del__ | missing_del.py:15:5:15:22 | Function __del__ | X3.__del__ |
|
||||
| missing_del.py:13:1:13:13 | Class X3 | This class does not call $@ during finalization. ($@ may be missing a call to a base class __del__) | missing_del.py:9:5:9:22 | Function __del__ | X2.__del__ | missing_del.py:15:5:15:22 | Function __del__ | X3.__del__ |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| multiple_del.py:21:5:21:22 | Function __del__ | This deletion method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:23:9:23:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:24:9:24:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:15:5:15:22 | Function __del__ | Y2.__del__ |
|
||||
| multiple_del.py:43:5:43:22 | Function __del__ | This deletion method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:45:9:45:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:46:9:46:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:37:5:37:22 | Function __del__ | Z2.__del__ |
|
||||
| multiple_del.py:21:5:21:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:23:9:23:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:24:9:24:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:9:5:9:22 | Function __del__ | Y1.__del__ | multiple_del.py:15:5:15:22 | Function __del__ | Y2.__del__ |
|
||||
| multiple_del.py:43:5:43:22 | Function __del__ | This finalization method calls $@ multiple times, via $@ and $@, resolving to $@ and $@ respectively. | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:45:9:45:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:46:9:46:24 | ControlFlowNode for Attribute() | this call | multiple_del.py:32:5:32:22 | Function __del__ | Z1.__del__ | multiple_del.py:37:5:37:22 | Function __del__ | Z2.__del__ |
|
||||
|
||||
Reference in New Issue
Block a user