buildFromEnvironment static method
IntrospectionResult
buildFromEnvironment(
- Environment environment, {
- bool includeBuiltins = false,
- SCompilationUnit? compilationUnit,
Builds an IntrospectionResult from the given environment. Optionally takes a SCompilationUnit to extract additional metadata.
Implementation
static IntrospectionResult buildFromEnvironment(
Environment environment, {
bool includeBuiltins = false,
SCompilationUnit? compilationUnit,
}) {
final functions = <FunctionInfo>[];
final classes = <ClassInfo>[];
final variables = <VariableInfo>[];
final enums = <EnumInfo>[];
final extensions = <ExtensionInfo>[];
// Build a map of variable type metadata from the AST
final variableTypeMap = <String, String>{};
final processedExtensions = <String>{};
// Cluster INTROSPECT (I-FILE-36/38): when a compilation unit is provided,
// collect the names actually declared in the user's source. The
// environment also contains pre-registered stdlib natives (e.g.
// `identityHashCode`, `Object`, `print`); the legacy `_isBuiltinName`
// blocklist covered the common type names but missed many others
// (`identityHashCode` in particular). Driving the filter from the AST
// is exhaustive — anything not declared by the user is a built-in.
final Set<String>? userDeclaredNames =
compilationUnit == null ? null : <String>{};
if (compilationUnit != null) {
// Extract variable type annotations from AST
for (final declaration in compilationUnit.declarations) {
if (declaration is STopLevelVariableDeclaration) {
final typeAnnotation = declaration.variables?.type;
final typeName = _typeNodeToString(typeAnnotation);
for (final variable in declaration.variables?.variables ?? []) {
final varName = variable.name?.name ?? '';
if (typeName != null) {
variableTypeMap[varName] = typeName;
}
if (varName.isNotEmpty) {
userDeclaredNames!.add(varName);
}
}
} else if (declaration is SExtensionDeclaration) {
// Handle extensions (including unnamed ones) from AST
final extName = declaration.name?.name ?? '';
final onTypeNode = declaration.extendedType;
final onType = _typeNodeToString(onTypeNode) ?? 'unknown';
final methodNames = <String>[];
for (final member in declaration.members) {
if (member is SMethodDeclaration) {
methodNames.add(member.name?.name ?? '');
}
}
if (extName.isEmpty) {
// Unnamed extension - create with generated name
extensions.add(ExtensionInfo(
name: '<unnamed extension on $onType>',
onType: onType,
methods: methodNames,
));
} else {
userDeclaredNames!.add(extName);
}
processedExtensions.add(extName);
} else if (declaration is SNamedDeclaration) {
// SClassDeclaration, SEnumDeclaration, SFunctionDeclaration,
// SMixinDeclaration, SExtensionTypeDeclaration, STypedefDeclaration
// — all mix in SNamedDeclaration with a `name` accessor.
final declName = (declaration as SNamedDeclaration).name?.name;
if (declName != null && declName.isNotEmpty) {
userDeclaredNames!.add(declName);
}
}
}
}
// Process the environment values
for (final entry in environment.values.entries) {
final name = entry.key;
final value = entry.value;
// Filter out anything not declared in the user's source. Two modes:
// 1. With a compilation unit (typical for `analyze()`), use the AST
// whitelist — exhaustive and exact.
// 2. Without a compilation unit, fall back to the legacy
// `_isBuiltinName` blocklist for backward compatibility.
if (!includeBuiltins) {
if (userDeclaredNames != null) {
if (!userDeclaredNames.contains(name)) continue;
} else if (_isBuiltinName(name)) {
continue;
}
}
if (value is InterpretedFunction) {
functions.add(_buildFunctionInfo(name, value));
} else if (value is InterpretedClass) {
classes.add(_buildClassInfo(name, value));
} else if (value is InterpretedEnum) {
enums.add(_buildEnumInfo(name, value));
} else if (value is InterpretedExtension) {
extensions.add(_buildExtensionInfo(name, value));
} else {
// It's a variable - use type metadata if available
final declaredType = variableTypeMap[name];
variables
.add(_buildVariableInfo(name, value, declaredType: declaredType));
}
}
return IntrospectionResult(
functions: functions,
classes: classes,
variables: variables,
enums: enums,
extensions: extensions,
);
}