in src/Caching/Impl/Models/ModuleModel.cs [59:152]
public static ModuleModel FromAnalysis(IDocumentAnalysis analysis, IServiceContainer services, AnalysisCachingLevel options) {
var uniqueId = analysis.Document.GetUniqueId(services, options);
if (uniqueId == null) {
// Caching level setting does not permit this module to be persisted.
return null;
}
var variables = new Dictionary<string, VariableModel>();
var functions = new Dictionary<string, FunctionModel>();
var classes = new Dictionary<string, ClassModel>();
var typeVars = new Dictionary<string, TypeVarModel>();
var namedTuples = new Dictionary<string, NamedTupleModel>();
// Go directly through variables which names are listed in GetMemberNames
// as well as variables that are declarations.
var exportedNames = new HashSet<string>(analysis.Document.GetMemberNames());
foreach (var v in analysis.GlobalScope.Variables
.Where(v => exportedNames.Contains(v.Name) ||
v.Source == VariableSource.Declaration ||
v.Source == VariableSource.Builtin ||
v.Source == VariableSource.Generic)) {
if (v.Value is IGenericTypeParameter && !typeVars.ContainsKey(v.Name)) {
typeVars[v.Name] = TypeVarModel.FromGeneric(v);
continue;
}
switch (v.Value) {
case ITypingNamedTupleType nt:
namedTuples[nt.Name] = new NamedTupleModel(nt);
continue;
case IPythonFunctionType ft when ft.IsLambda():
// No need to persist lambdas.
continue;
case IPythonFunctionType ft when v.Name != ft.Name:
// Variable assigned to type info of the function like
// def func(): ...
// x = type(func)
break;
case IPythonFunctionType ft:
var fm = GetFunctionModel(analysis, v, ft);
if (fm != null && !functions.ContainsKey(ft.Name)) {
functions[ft.Name] = fm;
continue;
}
break;
case IPythonClassType cls when v.Name != cls.Name:
// Variable assigned to type info of the class.
break;
case IPythonClassType cls
when cls.DeclaringModule.Equals(analysis.Document) || cls.DeclaringModule.Equals(analysis.Document.Stub):
if (!classes.ContainsKey(cls.Name)) {
classes[cls.Name] = new ClassModel(cls);
continue;
}
break;
}
// Do not re-declare classes and functions as variables in the model.
if (!variables.ContainsKey(v.Name)) {
variables[v.Name] = VariableModel.FromVariable(v);
}
}
// Take dependencies from imports. If module has stub we should also take
// dependencies from there since persistent state is based on types that
// are combination of stub and the module. Sometimes stub may import more
// and we must make sure dependencies are restored before the module.
var primaryDependencyWalker = new DependencyWalker(analysis.Ast);
var stubDependencyWalker = analysis.Document.Stub != null ? new DependencyWalker(analysis.Document.Stub.Analysis.Ast) : null;
var stubImports = stubDependencyWalker?.Imports ?? Enumerable.Empty<ImportModel>();
var stubFromImports = stubDependencyWalker?.FromImports ?? Enumerable.Empty<FromImportModel>();
return new ModuleModel {
Id = uniqueId.GetStableHash(),
UniqueId = uniqueId,
Name = analysis.Document.Name,
QualifiedName = analysis.Document.QualifiedName,
Documentation = analysis.Document.Documentation,
Functions = functions.Values.ToArray(),
Variables = variables.Values.ToArray(),
Classes = classes.Values.ToArray(),
TypeVars = typeVars.Values.ToArray(),
NamedTuples = namedTuples.Values.ToArray(),
NewLines = analysis.Ast.NewLineLocations.Select(l => new NewLineModel {
EndIndex = l.EndIndex,
Kind = l.Kind
}).ToArray(),
FileSize = analysis.Ast.EndIndex,
Imports = primaryDependencyWalker.Imports.ToArray(),
FromImports = primaryDependencyWalker.FromImports.ToArray(),
StubImports = stubImports.ToArray(),
StubFromImports = stubFromImports.ToArray()
};
}