Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Fix null ref in super() #1739

Merged
merged 16 commits into from
Nov 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static IMember Super(IPythonModule declaringModule, IPythonFunctionOverlo
//Zero argument form only works inside a class definition
foreach (var s in argSet.Eval.CurrentScope.EnumerateTowardsGlobal.Where(s => s.Node is ClassDefinition)) {
var classType = s.Variables["__class__"].GetPythonType<IPythonClassType>();
return PythonSuperType.CreateSuper(classType)?.CreateInstance(argSet);
return PythonSuperType.Create(classType)?.CreateInstance(argSet);
}
return null;
}
Expand All @@ -114,14 +114,14 @@ public static IMember Super(IPythonModule declaringModule, IPythonFunctionOverlo
// second argument optional
bool isUnbound = args.Count == 1;
if (isUnbound) {
return PythonSuperType.CreateSuper(firstCls)?.CreateInstance(argSet);
return PythonSuperType.Create(firstCls)?.CreateInstance(argSet);
}

var secondCls = args[1].GetPythonType<IPythonClassType>();
if (secondCls?.Equals(firstCls) == true ||
secondCls?.IsSubClassOf(firstCls) == true) {
// We walk the mro of the second parameter looking for the first
return PythonSuperType.CreateSuper(secondCls, typeToFind: firstCls)?.CreateInstance(argSet);
return PythonSuperType.Create(secondCls, typeToFind: firstCls)?.CreateInstance(argSet);
}

return null;
Expand Down
6 changes: 5 additions & 1 deletion src/Analysis/Ast/Impl/Types/LocatedMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
using System.Linq;
using Microsoft.Python.Analysis.Modules;
using Microsoft.Python.Core;
using Microsoft.Python.Core.Diagnostics;

namespace Microsoft.Python.Analysis.Types {
internal abstract class LocatedMember : ILocatedMember {
private HashSet<Location> _references;

protected LocatedMember(IPythonModule module) : this(new Location(module)) { }
protected LocatedMember(IPythonModule module) : this(new Location(module)) {
Check.InvalidOperation(module != null || this is IPythonModule,
"Located member can only have null declaring module if it is the module.");
}

protected LocatedMember(Location location) {
Location = location;
Expand Down
4 changes: 1 addition & 3 deletions src/Analysis/Ast/Impl/Types/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

namespace Microsoft.Python.Analysis.Types {
public readonly struct Location {
public Location(IPythonModule module) : this(module, default) { }

public Location(IPythonModule module, IndexSpan indexSpan) {
public Location(IPythonModule module, IndexSpan indexSpan = default) {
Module = module;
IndexSpan = indexSpan;
}
Expand Down
37 changes: 18 additions & 19 deletions src/Analysis/Ast/Impl/Types/PythonSuperType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,37 @@
namespace Microsoft.Python.Analysis.Types {
internal sealed class PythonSuperType : PythonType, IPythonSuperType {
/// <summary>
/// more info at https://docs.python.org/3/library/functions.html#super
/// Implements 'super' specialization type.
/// See also https://docs.python.org/3/library/functions.html#super
/// </summary>
/// <param name="location"></param>
/// <param name="mro">Should be a list of IPythonType</param>
public PythonSuperType(IReadOnlyList<IPythonType> mro)
: base("super", new Location(), string.Empty, BuiltinTypeId.Type) {
/// <param name="mro">The derived class MRO.</param>
/// <param name="builtins">Builtins module.</param>
public PythonSuperType(IReadOnlyList<IPythonType> mro, IBuiltinsPythonModule builtins)
: base("super", new Location(builtins), string.Empty, BuiltinTypeId.Type) {
Mro = mro;
}

public override string QualifiedName => $":SuperType[{string.Join(",", Mro.Select(t => t.QualifiedName))}]";

public IReadOnlyList<IPythonType> Mro { get; }

public override IMember GetMember(string name) => Mro.MaybeEnumerate().Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault();

public override IEnumerable<string> GetMemberNames() => Mro.MaybeEnumerate().SelectMany(cls => cls.GetMemberNames()).Distinct();
public override IMember GetMember(string name)
=> Mro.MaybeEnumerate().Select(c => c.GetMember(name)).ExcludeDefault().FirstOrDefault();

public override IEnumerable<string> GetMemberNames()
=> Mro.MaybeEnumerate().SelectMany(cls => cls.GetMemberNames()).Distinct();

/// <summary>
/// This will return PythonSuperType with a mro list that starts with the next class in line in classType's mro,
/// or it will search classType's mro for typeToFild then build an mro list for the remaining classses after typeToFind.
/// Creates PythonSuperType with a MRO list that starts with the next class in line in classType's MRO,
/// or searches classType's MRO for <see cref="typeToFind"/>, then builds an MRO list for
/// the remaining classes after <see cref="typeToFind"/>.
/// </summary>
/// <param name="classType"></param>
/// <param name="typeToFind"></param>
/// <returns></returns>
internal static PythonSuperType CreateSuper(IPythonClassType classType, IPythonType typeToFind = null) {
internal static PythonSuperType Create(IPythonClassType classType, IPythonType typeToFind = null) {
var mro = classType?.Mro ?? Array.Empty<IPythonType>();
if (mro.Count == 0) {
if (classType == null || mro.Count == 0) {
return null;
}

Expand All @@ -64,13 +67,9 @@ internal static PythonSuperType CreateSuper(IPythonClassType classType, IPythonT
}

var nextClassInLine = mro?.FirstOrDefault();
if (nextClassInLine != null) {
// Skip the first element, super's search starts at the next elemement in the mro for both super() and super(cls, typeToFind)
return new PythonSuperType(mro.Skip(1).ToArray());
}

return null;
var builtins = classType.DeclaringModule.Interpreter.ModuleResolution.BuiltinsModule;
// Skip the first element, super's search starts at the next element in the mro for both super() and super(cls, typeToFind)
return nextClassInLine != null ? new PythonSuperType(mro.Skip(1).ToArray(), builtins) : null;
}
}
}

2 changes: 1 addition & 1 deletion src/Caching/Impl/ModuleFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private IMember GetBuiltinMember(IBuiltinsPythonModule builtins, string memberNa
case "Unknown":
return builtins.Interpreter.UnknownType;
case "SuperType":
return new PythonSuperType(typeArgs);
return new PythonSuperType(typeArgs, builtins);
}
return builtins.GetMember(memberName);
}
Expand Down