in src/dotnet/APIView/APIViewWeb/Languages/CLanguageService.cs [116:383]
private static void BuildNodes(CodeFileTokensBuilder builder, List<NavigationItem> navigation, MemoryStream astStream)
{
Span<byte> ast = astStream.ToArray();
while (ast.Length > 2)
{
Utf8JsonReader reader = new Utf8JsonReader(ast);
var astNode = JsonSerializer.Deserialize<CAstNode>(ref reader);
ast = ast.Slice((int)reader.BytesConsumed);
var queue = new Queue<CAstNode>(astNode.inner);
var types = new HashSet<string>();
foreach (var node in queue)
{
if (node.kind == "TypedefDecl")
{
types.Add(node.name);
}
}
NavigationItem currentFileItem = null;
List<NavigationItem> currentFileMembers = new List<NavigationItem>();
while (queue.TryDequeue(out var node))
{
if (node.isImplicit == true || node.loc?.includedFrom?.file != null ||
node.loc?.spellingLoc?.includedFrom?.file != null)
{
continue;
}
var file = node.loc.file;
if (file != null && currentFileItem == null)
{
currentFileItem = new NavigationItem()
{
NavigationId = file,
Text = file,
Tags = { { "TypeKind", "namespace" } }
};
builder.Append(new CodeFileToken()
{
DefinitionId = file,
Value = "// " + file,
Kind = CodeFileTokenKind.Comment,
});
builder.NewLine();
builder.Space();
builder.NewLine();
}
bool TryDequeTypeDef(out CAstNode typedefNode)
{
if (queue.TryPeek(out typedefNode))
{
if (typedefNode.kind == "TypedefDecl")
{
queue.Dequeue();
return true;
}
}
typedefNode = null;
return false;
}
void BuildDeclaration(string name, string kind)
{
builder.Append(new CodeFileToken()
{
DefinitionId = name,
Kind = CodeFileTokenKind.TypeName,
Value = name,
});
currentFileMembers.Add(new NavigationItem()
{
NavigationId = name,
Text = name,
Tags = { { "TypeKind", kind } }
});
}
void BuildMemberDeclaration(string containerName, string name)
{
builder.Append(new CodeFileToken()
{
DefinitionId = containerName + "." + name,
Kind = CodeFileTokenKind.MemberName,
Value = name,
});
}
switch (node.kind)
{
case "FunctionDecl":
{
var type = node.type.qualType;
var returnType = type.Split(" ")[0];
BuildType(builder, returnType, types);
builder.Space();
BuildDeclaration(node.name, "method");
builder.Punctuation("(");
builder.IncrementIndent();
bool first = true;
foreach (var parameterNode in node.inner)
{
if (parameterNode.kind == "ParmVarDecl")
{
if (first)
{
builder.NewLine();
first = false;
}
builder.WriteIndent();
BuildType(builder, parameterNode.type.qualType, types);
builder.Space();
builder.Text(parameterNode.name);
builder.Punctuation(",");
builder.NewLine();
}
}
builder.DecrementIndent();
builder.Punctuation(");");
builder.NewLine();
break;
}
case "EnumDecl":
{
if (TryDequeTypeDef(out var typeDef))
{
builder.Keyword("typedef");
builder.Space();
}
builder.Keyword("enum");
builder.NewLine();
builder.Punctuation("{");
builder.NewLine();
builder.IncrementIndent();
foreach (var parameterNode in node.inner)
{
if (parameterNode.kind == "EnumConstantDecl")
{
builder.WriteIndent();
BuildMemberDeclaration(typeDef?.name, parameterNode.name);
if (parameterNode.inner?.FirstOrDefault(n => n.kind == "ConstantExpr") is CAstNode
exprNode)
{
builder.Space();
builder.Punctuation("=");
builder.Space();
BuildExpression(builder, exprNode);
}
builder.Punctuation(",");
builder.NewLine();
}
}
builder.DecrementIndent();
builder.Punctuation("}");
if (typeDef != null)
{
builder.Space();
BuildDeclaration(typeDef.name, "enum");
}
builder.Punctuation(";");
builder.NewLine();
break;
}
case "TypedefDecl":
{
builder.Keyword("typedef ");
foreach (var typeDefValueNode in node.inner)
{
var type = typeDefValueNode.type?.qualType;
if (type != null)
{
BuildType(builder, type, types);
}
}
builder.Space();
BuildDeclaration(node.name, "class");
builder.Punctuation(";");
builder.NewLine();
break;
}
case "VarDecl":
{
BuildType(builder, node.type.qualType, types);
builder.Space();
BuildDeclaration(node.name, "unknown");
builder.Punctuation(";");
builder.NewLine();
break;
}
case "RecordDecl":
{
if (TryDequeTypeDef(out var typeDef))
{
builder.Keyword("typedef");
builder.Space();
}
builder.Keyword("struct");
builder.NewLine();
builder.Punctuation("{");
builder.NewLine();
builder.IncrementIndent();
if (node.inner != null)
{
foreach (var parameterNode in node.inner)
{
if (parameterNode.kind == "FieldDecl")
{
builder.WriteIndent();
BuildType(builder, parameterNode.type.qualType, types);
builder.Space();
BuildMemberDeclaration(typeDef?.name, parameterNode.name);
builder.Punctuation(",");
builder.NewLine();
}
}
}
builder.DecrementIndent();
builder.Punctuation("}");
if (typeDef != null)
{
builder.Space();
BuildDeclaration(typeDef.name, "struct");
}
builder.Punctuation(";");
builder.NewLine();
break;
}
default:
builder.Text(node.ToString());
break;
}
builder.Space();
builder.NewLine();
}
if (currentFileItem != null)
{
currentFileItem.ChildItems = currentFileMembers.ToArray();
navigation.Add(currentFileItem);
}
}
}