@@ -110,8 +110,16 @@ private void TryReplaceMember(IVariable v, IPythonType sourceType, IPythonType s
110
110
}
111
111
break ;
112
112
113
- case PythonClassType sourceClass :
114
- MergeClass ( v , sourceClass , stubType , cancellationToken ) ;
113
+ case IPythonClassType sourceClass :
114
+ MergeMembers ( v , sourceClass , stubType , cancellationToken ) ;
115
+ break ;
116
+
117
+ case PythonFunctionType sourceFunction :
118
+ MergeMembers ( v , sourceFunction , stubType , cancellationToken ) ;
119
+ break ;
120
+
121
+ case PythonPropertyType sourceProperty :
122
+ MergeMembers ( v , sourceProperty , stubType , cancellationToken ) ;
115
123
break ;
116
124
117
125
case IPythonModule _:
@@ -137,28 +145,38 @@ private void TryReplaceMember(IVariable v, IPythonType sourceType, IPythonType s
137
145
}
138
146
}
139
147
140
- private void MergeClass ( IVariable v , IPythonClassType sourceClass , IPythonType stubType , CancellationToken cancellationToken ) {
148
+ private void MergeMembers ( IVariable v , IPythonType sourceType , IPythonType stubType , CancellationToken cancellationToken ) {
141
149
// Transfer documentation first so we get class documentation
142
150
// that comes from the class definition win over one that may
143
151
// come from __init__ during the member merge below.
144
- TransferDocumentationAndLocation ( sourceClass , stubType ) ;
152
+ TransferDocumentationAndLocation ( sourceType . GetPythonType ( ) , stubType ) ;
145
153
146
154
// Replace the class entirely since stub members may use generic types
147
155
// and the class definition is important. We transfer missing members
148
156
// from the original class to the stub.
149
- _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
157
+ //
158
+ // In case module is compiled, it is already a stub and has no locations
159
+ // for code navigation.. In this case we replace the entire variable by one
160
+ // from the stub rather than just the value since stub variable has location
161
+ // and its own root definition/reference chain.
162
+ if ( sourceType . DeclaringModule . ModuleType == ModuleType . Compiled ||
163
+ sourceType . DeclaringModule . ModuleType == ModuleType . CompiledBuiltin ) {
164
+ _eval . ReplaceVariable ( v ) ;
165
+ } else {
166
+ _eval . DeclareVariable ( v . Name , v . Value , v . Source ) ;
167
+ }
150
168
151
169
// First pass: go through source class members and pick those
152
170
// that are not present in the stub class.
153
- foreach ( var name in sourceClass . GetMemberNames ( ) . ToArray ( ) ) {
171
+ foreach ( var name in sourceType . GetMemberNames ( ) . ToArray ( ) ) {
154
172
cancellationToken . ThrowIfCancellationRequested ( ) ;
155
173
156
- var sourceMember = sourceClass . GetMember ( name ) ;
174
+ var sourceMember = sourceType . GetMember ( name ) ;
157
175
if ( sourceMember . IsUnknown ( ) ) {
158
176
continue ; // Do not add unknowns to the stub.
159
177
}
160
178
var sourceMemberType = sourceMember ? . GetPythonType ( ) ;
161
- if ( sourceMemberType is IPythonClassMember cm && cm . DeclaringType != sourceClass ) {
179
+ if ( sourceMemberType is IPythonClassMember cm && ! cm . DeclaringModule . Equals ( sourceType . DeclaringModule ) ) {
162
180
continue ; // Only take members from this class and not from bases.
163
181
}
164
182
if ( ! IsFromThisModuleOrSubmodules ( sourceMemberType ) ) {
@@ -196,7 +214,7 @@ private void MergeClass(IVariable v, IPythonClassType sourceClass, IPythonType s
196
214
continue ; // Only take members from this class and not from bases.
197
215
}
198
216
199
- var sourceMember = sourceClass . GetMember ( name ) ;
217
+ var sourceMember = sourceType . GetMember ( name ) ;
200
218
if ( sourceMember . IsUnknown ( ) ) {
201
219
continue ;
202
220
}
@@ -305,7 +323,13 @@ private bool IsFromThisModuleOrSubmodules(IPythonType type) {
305
323
var thisModule = _eval . Module ;
306
324
var typeModule = type . DeclaringModule ;
307
325
var typeMainModuleName = typeModule . Name . Split ( '.' ) . FirstOrDefault ( ) ;
308
- return typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ;
326
+ if ( typeModule . Equals ( thisModule ) || typeMainModuleName == thisModule . Name ) {
327
+ return true ;
328
+ }
329
+ // Check if module is explicitly imported by the current one. For example, 'os'
330
+ // imports 'nt' and os.pyi specifies functions from 'nt' such as mkdir and so on.
331
+ var imported = thisModule . GlobalScope . Variables [ typeModule . Name ] ;
332
+ return imported ? . Value != null && imported . Source == VariableSource . Import ;
309
333
}
310
334
}
311
335
}
0 commit comments