Exemplo n.º 1
0
        private void MergeMembers(IVariable v, IPythonType sourceType, IPythonType stubType, CancellationToken cancellationToken)
        {
            // Transfer documentation first so we get class documentation
            // that comes from the class definition win over one that may
            // come from __init__ during the member merge below.
            TransferDocumentationAndLocation(sourceType.GetPythonType(), stubType);

            // Replace the class entirely since stub members may use generic types
            // and the class definition is important. We transfer missing members
            // from the original class to the stub.
            //
            // In case module is compiled, it is already a stub and has no locations
            // for code navigation.. In this case we replace the entire variable by one
            // from the stub rather than just the value since stub variable has location
            // and its own root definition/reference chain.
            if (sourceType.DeclaringModule.ModuleType == ModuleType.Compiled ||
                sourceType.DeclaringModule.ModuleType == ModuleType.CompiledBuiltin)
            {
                _eval.ReplaceVariable(v);
            }
            else
            {
                _eval.DeclareVariable(v.Name, v.Value, v.Source);
            }

            // First pass: go through source class members and pick those
            // that are not present in the stub class.
            foreach (var name in sourceType.GetMemberNames().ToArray())
            {
                cancellationToken.ThrowIfCancellationRequested();

                var sourceMember = sourceType.GetMember(name);
                if (sourceMember.IsUnknown())
                {
                    continue; // Do not add unknowns to the stub.
                }
                var sourceMemberType = sourceMember?.GetPythonType();
                if (sourceMemberType is IPythonClassMember cm && !cm.DeclaringModule.Equals(sourceType.DeclaringModule))
                {
                    continue; // Only take members from this class and not from bases.
                }
                if (!IsFromThisModuleOrSubmodules(sourceMemberType))
                {
                    continue; // Member does not come from module or its submodules.
                }

                var stubMember     = stubType.GetMember(name);
                var stubMemberType = stubMember.GetPythonType();

                // Get documentation from the current type, if any, since stubs
                // typically do not contain documentation while scraped code does.
                TransferDocumentationAndLocation(sourceMemberType, stubMemberType);

                // If stub says 'Any' but we have better type, use member from the original class.
                if (stubMember != null && !(stubType.DeclaringModule is TypingModule && stubType.Name == "Any"))
                {
                    continue; // Stub already have the member, don't replace.
                }

                (stubType as PythonType)?.AddMember(name, sourceMember, overwrite: true);
            }

            // Second pass: go through stub class members and if they don't have documentation
            // or location, check if source class has same member and fetch it from there.
            // The reason is that in the stub sometimes members are specified all in one
            // class while in source they may come from bases. Example: datetime.
            foreach (var name in stubType.GetMemberNames().ToArray())
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stubMember = stubType.GetMember(name);
                if (stubMember.IsUnknown())
                {
                    continue;
                }
                var stubMemberType = stubMember.GetPythonType();
                if (stubMemberType is IPythonClassMember cm && cm.DeclaringType != stubType)
                {
                    continue; // Only take members from this class and not from bases.
                }

                var sourceMember = sourceType.GetMember(name);
                if (sourceMember.IsUnknown())
                {
                    continue;
                }

                var sourceMemberType = sourceMember.GetPythonType();
                if (sourceMemberType.Location.IsValid && !stubMemberType.Location.IsValid)
                {
                    TransferDocumentationAndLocation(sourceMemberType, stubMemberType);
                }
            }
        }