mirror of
https://github.com/github/codeql.git
synced 2025-12-17 17:23:36 +01:00
151 lines
5.6 KiB
C#
151 lines
5.6 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Semmle.Extraction.CSharp.Entities;
|
|
using Semmle.Extraction.Entities;
|
|
using Semmle.Util;
|
|
using Semmle.Util.Logging;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace Semmle.Extraction.CSharp.Populators
|
|
{
|
|
public class TypeContainerVisitor : CSharpSyntaxVisitor
|
|
{
|
|
protected Context cx { get; }
|
|
protected IEntity parent { get; }
|
|
protected TextWriter trapFile { get; }
|
|
private readonly Lazy<Func<SyntaxNode, AttributeData>> attributeLookup;
|
|
|
|
public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent)
|
|
{
|
|
this.cx = cx;
|
|
this.parent = parent;
|
|
this.trapFile = trapFile;
|
|
attributeLookup = new Lazy<Func<SyntaxNode, AttributeData>>(() =>
|
|
{
|
|
var dict = new Dictionary<SyntaxNode, AttributeData>();
|
|
foreach (var attributeData in cx.Compilation.Assembly.GetAttributes().Concat(cx.Compilation.Assembly.Modules.SelectMany(m => m.GetAttributes())))
|
|
{
|
|
if (attributeData.ApplicationSyntaxReference?.GetSyntax() is SyntaxNode syntax)
|
|
dict.Add(syntax, attributeData);
|
|
}
|
|
return dict.GetValueOrDefault;
|
|
});
|
|
}
|
|
|
|
public override void DefaultVisit(SyntaxNode node)
|
|
{
|
|
throw new InternalError(node, "Unhandled top-level syntax node");
|
|
}
|
|
|
|
public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node)
|
|
{
|
|
Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
|
|
}
|
|
|
|
public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl)
|
|
{
|
|
Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent);
|
|
}
|
|
|
|
public override void VisitStructDeclaration(StructDeclarationSyntax node)
|
|
{
|
|
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
|
|
}
|
|
|
|
public override void VisitEnumDeclaration(EnumDeclarationSyntax node)
|
|
{
|
|
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
|
|
}
|
|
|
|
public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
|
|
{
|
|
Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent);
|
|
}
|
|
|
|
public override void VisitAttributeList(AttributeListSyntax node)
|
|
{
|
|
if (cx.Extractor.Standalone)
|
|
return;
|
|
|
|
var outputAssembly = Assembly.CreateOutputAssembly(cx);
|
|
foreach (var attribute in node.Attributes)
|
|
{
|
|
if (attributeLookup.Value(attribute) is AttributeData attributeData)
|
|
{
|
|
var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(cx, attributeData, outputAssembly);
|
|
cx.BindComments(ae, attribute.GetLocation());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class TypeOrNamespaceVisitor : TypeContainerVisitor
|
|
{
|
|
public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent)
|
|
: base(cx, trapFile, parent) { }
|
|
|
|
public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective)
|
|
{
|
|
// Only deal with "using namespace" not "using X = Y"
|
|
if (usingDirective.Alias == null)
|
|
new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent);
|
|
}
|
|
|
|
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
|
|
{
|
|
NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent);
|
|
}
|
|
}
|
|
|
|
internal class CompilationUnitVisitor : TypeOrNamespaceVisitor
|
|
{
|
|
public CompilationUnitVisitor(Context cx)
|
|
: base(cx, cx.TrapWriter.Writer, null) { }
|
|
|
|
public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node)
|
|
{
|
|
// This information is not yet extracted.
|
|
cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info);
|
|
}
|
|
|
|
public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit)
|
|
{
|
|
foreach (var m in compilationUnit.ChildNodes())
|
|
{
|
|
cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this));
|
|
}
|
|
|
|
// Gather comments:
|
|
foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span))
|
|
{
|
|
CommentLine.Extract(cx, trivia);
|
|
}
|
|
|
|
foreach (var trivia in compilationUnit.GetLeadingTrivia())
|
|
{
|
|
CommentLine.Extract(cx, trivia);
|
|
}
|
|
|
|
foreach (var trivia in compilationUnit.GetTrailingTrivia())
|
|
{
|
|
CommentLine.Extract(cx, trivia);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class CompilationUnit
|
|
{
|
|
public static void Extract(Context cx, SyntaxNode unit)
|
|
{
|
|
// Ensure that the file itself is populated in case the source file is totally empty
|
|
Semmle.Extraction.Entities.File.Create(cx, unit.SyntaxTree.FilePath);
|
|
|
|
((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx));
|
|
}
|
|
}
|
|
}
|