C#: Migrate extractor to this repository.

This commit is contained in:
calum
2018-10-08 12:47:37 +01:00
parent 3e022ad36f
commit 103d140e71
247 changed files with 25866 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Entities;
namespace Semmle.Extraction.CSharp.Populators
{
class Ast : CSharpSyntaxVisitor
{
readonly Context cx;
readonly IExpressionParentEntity parent;
readonly int child;
public Ast(Context cx, IExpressionParentEntity parent, int child)
{
this.cx = cx;
this.parent = parent;
this.child = child;
}
public override void DefaultVisit(SyntaxNode node)
{
cx.ModelError(node, "Unhandled syntax node {0}", node.Kind());
}
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
((Property)parent).VisitDeclaration(cx, node);
}
public override void VisitArgumentList(ArgumentListSyntax node)
{
int c = 0;
foreach (var m in node.Arguments)
{
cx.Extract(m, parent, c++);
}
}
public override void VisitArgument(ArgumentSyntax node)
{
Expression.Create(cx, node.Expression, parent, child);
}
}
public static class AstExtensions
{
public static void Extract(this Context cx, CSharpSyntaxNode node, IExpressionParentEntity parent, int child)
{
using (cx.StackGuard)
{
try
{
node.Accept(new Ast(cx, parent, child));
}
catch (System.Exception e)
{
cx.ModelError(node, "Exception processing syntax node of type {0}: {1}", node.Kind(), e);
}
}
}
public static void Extract(this Context cx, SyntaxNode node, IEntity parent, int child)
{
cx.Extract(((CSharpSyntaxNode)node), parent, child);
}
}
}

View File

@@ -0,0 +1,33 @@
using Semmle.Extraction.CommentProcessing;
using System;
namespace Semmle.Extraction.CSharp.Populators
{
/// <summary>
/// Populators for comments.
/// </summary>
public static class Comments
{
public static void ExtractComments(this Context cx, ICommentGenerator gen)
{
cx.Try(null, null, () =>
{
gen.GenerateBindings((entity, duplicationGuardKey, block, binding) =>
{
var commentBlock = Entities.CommentBlock.Create(cx, block);
Action a = () =>
{
commentBlock.BindTo(entity, binding);
};
// When the duplication guard key exists, it means that the entity is guarded against
// trap duplication (<see cref = "Context.BindComments(IEntity, Location)" />).
// We must therefore also guard comment construction.
if (duplicationGuardKey != null)
cx.WithDuplicationGuard(duplicationGuardKey, a);
else
a();
});
});
}
}
}

View File

@@ -0,0 +1,125 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Entities;
using Semmle.Extraction.Entities;
using Semmle.Util.Logging;
namespace Semmle.Extraction.CSharp.Populators
{
public class TypeContainerVisitor : CSharpSyntaxVisitor
{
protected readonly Context cx;
protected readonly IEntity parent;
public TypeContainerVisitor(Context cx, IEntity parent)
{
this.cx = cx;
this.parent = parent;
}
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.Model(node).GetDeclaredSymbol(node)).ExtractRecursive(parent);
}
public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl)
{
Entities.Type.Create(cx, cx.Model(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(parent);
}
public override void VisitStructDeclaration(StructDeclarationSyntax node)
{
Entities.Type.Create(cx, cx.Model(node).GetDeclaredSymbol(node)).ExtractRecursive(parent);
}
public override void VisitEnumDeclaration(EnumDeclarationSyntax node)
{
Entities.Type.Create(cx, cx.Model(node).GetDeclaredSymbol(node)).ExtractRecursive(parent);
}
public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
{
Entities.Type.Create(cx, cx.Model(node).GetDeclaredSymbol(node)).ExtractRecursive(parent);
}
public override void VisitAttributeList(AttributeListSyntax node)
{
if (cx.Extractor.Standalone) return;
var outputAssembly = Assembly.CreateOutputAssembly(cx);
foreach (var attribute in node.Attributes)
{
var ae = new Attribute(cx, attribute, outputAssembly);
cx.BindComments(ae, attribute.GetLocation());
}
}
}
class TypeOrNamespaceVisitor : TypeContainerVisitor
{
public TypeOrNamespaceVisitor(Context cx, IEntity parent)
: base(cx, 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);
}
}
class CompilationUnitVisitor : TypeOrNamespaceVisitor
{
public CompilationUnitVisitor(Context cx)
: base(cx, null) { }
public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node)
{
// This information is not yet extracted.
cx.Extractor.Message(new Message { severity = Severity.Info, message = "Ignoring extern alias directive" });
}
public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit)
{
foreach (var m in compilationUnit.ChildNodes())
{
cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this));
}
// Gather comments:
foreach (SyntaxTrivia 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)
{
((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx));
}
}
}

View File

@@ -0,0 +1,104 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace Semmle.Extraction.CSharp.Populators
{
public static class LocationExtensions
{
/// <summary>
/// Manually extend a location.
/// </summary>
/// <param name="l1">The location to extend.</param>
/// <param name="n2">The node to extend the location to.</param>
/// <returns>Extended location.</returns>
public static Location ExtendLocation(this Location l1, SyntaxNode n2)
{
if (n2 == null)
{
return l1;
}
else
{
var l2 = n2.FixedLocation();
int start = System.Math.Min(l1.SourceSpan.Start, l2.SourceSpan.Start);
int end = System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End);
return Location.Create(n2.SyntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start));
}
}
/// <summary>
/// Adjust the location of some syntax nodes
/// to make them more suitable for displaying results.
/// Sometimes we do not wish to highlight the whole node,
/// so select a sub-node such as the name.
/// !! Refactor this into each entity.
/// </summary>
/// <param name="node">The syntax node.</param>
/// <returns>The fixed location.</returns>
public static Location FixedLocation(this SyntaxNode node)
{
Location result;
switch (node.Kind())
{
case SyntaxKind.EqualsValueClause:
result = ((EqualsValueClauseSyntax)node).Value.FixedLocation();
break;
case SyntaxKind.OperatorDeclaration:
{
var decl = (OperatorDeclarationSyntax)node;
result = decl.OperatorKeyword.GetLocation().ExtendLocation(decl.ParameterList);
break;
}
case SyntaxKind.ConversionOperatorDeclaration:
{
var decl = (ConversionOperatorDeclarationSyntax)node;
result = decl.OperatorKeyword.GetLocation();
break;
}
case SyntaxKind.DelegateDeclaration:
{
var decl = (DelegateDeclarationSyntax)node;
return decl.Identifier.GetLocation().ExtendLocation(decl.TypeParameterList);
}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.StructDeclaration:
case SyntaxKind.InterfaceDeclaration:
{
var decl = (TypeDeclarationSyntax)node;
return decl.Identifier.GetLocation().ExtendLocation(decl.TypeParameterList);
}
case SyntaxKind.EnumDeclaration:
return ((EnumDeclarationSyntax)node).Identifier.GetLocation();
case SyntaxKind.MethodDeclaration:
{
var decl = (MethodDeclarationSyntax)node;
return decl.Identifier.GetLocation().ExtendLocation(decl.TypeParameterList);
}
case SyntaxKind.ConstructorDeclaration:
{
var decl = (ConstructorDeclarationSyntax)node;
return decl.Identifier.GetLocation();
}
case SyntaxKind.ParenthesizedExpression:
return ((ParenthesizedExpressionSyntax)node).Expression.FixedLocation();
case SyntaxKind.CatchDeclaration:
return ((CatchDeclarationSyntax)node).Identifier.GetLocation();
case SyntaxKind.LabeledStatement:
return ((LabeledStatementSyntax)node).Identifier.GetLocation();
default:
result = node.GetLocation();
break;
}
return result;
}
public static Location GetSymbolLocation(this ISymbol symbol)
{
return symbol.DeclaringSyntaxReferences.Any() ?
symbol.DeclaringSyntaxReferences.First().GetSyntax().FixedLocation() :
symbol.Locations.First();
}
}
}

View File

@@ -0,0 +1,64 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Util;
namespace Semmle.Extraction.CSharp.Populators
{
public static class MethodExtensions
{
class AstLineCounter : CSharpSyntaxVisitor<LineCounts>
{
public override LineCounts DefaultVisit(SyntaxNode node)
{
string text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString();
return Semmle.Util.LineCounter.ComputeLineCounts(text);
}
public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method)
{
return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody);
}
public LineCounts Visit(SyntaxToken identifier, SyntaxNode body)
{
int start = identifier.GetLocation().SourceSpan.Start;
int end = body.GetLocation().SourceSpan.End - 1;
var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start);
string text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n";
return Semmle.Util.LineCounter.ComputeLineCounts(text);
}
public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method)
{
return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody);
}
public override LineCounts VisitDestructorDeclaration(DestructorDeclarationSyntax method)
{
return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody);
}
public override LineCounts VisitOperatorDeclaration(OperatorDeclarationSyntax node)
{
return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody);
}
}
public static void NumberOfLines(this Context cx, ISymbol symbol, IEntity callable)
{
foreach (var decl in symbol.DeclaringSyntaxReferences)
{
cx.NumberOfLines((CSharpSyntaxNode)decl.GetSyntax(), callable);
}
}
public static void NumberOfLines(this Context cx, CSharpSyntaxNode node, IEntity callable)
{
var lineCounts = node.Accept(new AstLineCounter());
cx.Emit(Tuples.numlines(callable, lineCounts));
}
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Semmle.Extraction.CSharp.Entities;
namespace Semmle.Extraction.CSharp.Populators
{
class Symbols : SymbolVisitor<IEntity>
{
readonly Context cx;
public Symbols(Context cx)
{
this.cx = cx;
}
public override IEntity DefaultVisit(ISymbol symbol) => throw new InternalError(symbol, "Unhandled symbol '{0}' of kind '{1}'", symbol, symbol.Kind);
public override IEntity VisitArrayType(IArrayTypeSymbol array) => ArrayType.Create(cx, array);
public override IEntity VisitMethod(IMethodSymbol methodDecl)
{
return Method.Create(cx, methodDecl);
}
public override IEntity VisitField(IFieldSymbol field) => Field.Create(cx, field);
public override IEntity VisitNamedType(INamedTypeSymbol type) =>
type.IsTupleType ? TupleType.Create(cx, type) : (IEntity)NamedType.Create(cx, type);
public override IEntity VisitNamespace(INamespaceSymbol ns) => Namespace.Create(cx, ns);
public override IEntity VisitParameter(IParameterSymbol param) => Parameter.GetAlreadyCreated(cx, param);
public override IEntity VisitProperty(IPropertySymbol symbol) => Property.Create(cx, symbol);
public override IEntity VisitEvent(IEventSymbol symbol) => Event.Create(cx, symbol);
public override IEntity VisitTypeParameter(ITypeParameterSymbol param) => TypeParameter.Create(cx, param);
public override IEntity VisitPointerType(IPointerTypeSymbol symbol) => PointerType.Create(cx, symbol);
public override IEntity VisitDynamicType(IDynamicTypeSymbol symbol) => DynamicType.Create(cx, symbol);
}
public static class SymbolsExtensions
{
public static IEntity CreateEntity(this Context cx, ISymbol symbol)
{
if (symbol == null) return null;
using (cx.StackGuard)
{
try
{
return symbol.Accept(new Symbols(cx));
}
catch (Exception e)
{
cx.ModelError(symbol, "Exception processing symbol '{2}' of type '{0}': {1}", symbol.Kind, e, symbol);
return null;
}
}
}
/// <summary>
/// Tries to recover from an ErrorType.
/// </summary>
///
/// <param name="cx">Extraction context.</param>
/// <param name="type">The type to disambiguate.</param>
/// <returns></returns>
public static ITypeSymbol DisambiguateType(this Context cx, ITypeSymbol type)
{
/* A type could not be determined.
* Sometimes this happens due to a missing reference,
* or sometimes because the same type is defined in multiple places.
*
* In the case that a symbol is multiply-defined, Roslyn tells you which
* symbols are candidates. It usually resolves to the same DB entity,
* so it's reasonably safe to just pick a candidate.
*
* The conservative option would be to resolve all error types as null.
*/
var errorType = type as IErrorTypeSymbol;
return errorType != null && errorType.CandidateSymbols.Any() ?
errorType.CandidateSymbols.First() as ITypeSymbol :
type;
}
public static TypeInfo GetTypeInfo(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node) =>
cx.Model(node).GetTypeInfo(node);
public static SymbolInfo GetSymbolInfo(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node) =>
cx.Model(node).GetSymbolInfo(node);
/// <summary>
/// Gets the symbol for a particular syntax node.
/// Throws an exception if the symbol is not found.
/// </summary>
///
/// <remarks>
/// This gives a nicer message than a "null pointer exception",
/// and should be used where we require a symbol to be resolved.
/// </remarks>
///
/// <param name="cx">The extraction context.</param>
/// <param name="node">The syntax node.</param>
/// <returns>The resolved symbol.</returns>
public static ISymbol GetSymbol(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node)
{
var info = GetSymbolInfo(cx, node);
if (info.Symbol == null)
{
throw new InternalError(node, "Could not resolve symbol");
}
return info.Symbol;
}
/// <summary>
/// Determines the type of a node, or null
/// if the type could not be determined.
/// </summary>
/// <param name="cx">Extractor context.</param>
/// <param name="node">The node to determine.</param>
/// <returns>The type symbol of the node, or null.</returns>
public static ITypeSymbol GetType(this Context cx, Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode node)
{
var info = GetTypeInfo(cx, node);
return cx.DisambiguateType(info.Type);
}
}
}