Merge pull request #1174 from calumgrant/cs/extractor-diagnostics

C#: Log compiler and extractor diagnostics
This commit is contained in:
Tom Hvitved
2019-05-13 12:53:12 +02:00
committed by GitHub
53 changed files with 7653 additions and 145 deletions

View File

@@ -3,6 +3,7 @@ using System.Globalization;
using System.Collections.Generic;
using Semmle.Util.Logging;
using System;
using Semmle.Extraction.Entities;
namespace Semmle.Extraction.CIL.Entities
{
@@ -70,12 +71,7 @@ namespace Semmle.Extraction.CIL.Entities
}
catch (InternalError e)
{
cx.cx.Extractor.Message(new Message
{
exception = e,
message = "Error processing type definition",
severity = Semmle.Util.Logging.Severity.Error
});
cx.cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(cx.cx), e.StackTrace);
}
// Limitation of C#: Cannot yield return inside a try-catch.
@@ -92,12 +88,7 @@ namespace Semmle.Extraction.CIL.Entities
}
catch (InternalError e)
{
cx.cx.Extractor.Message(new Message
{
exception = e,
message = "Error processing bytecode",
severity = Semmle.Util.Logging.Severity.Error
});
cx.cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(cx.cx), e.StackTrace);
}
if (product != null)
@@ -139,7 +130,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile = trapWriter.TrapFile;
if (nocache || !System.IO.File.Exists(trapFile))
{
var cx = new Extraction.Context(extractor, null, trapWriter, null);
var cx = extractor.CreateContext(null, trapWriter, null);
ExtractCIL(cx, assemblyPath, extractPdbs);
extracted = true;
}

View File

@@ -409,7 +409,7 @@ namespace Semmle.Extraction.CIL.Entities
}
else
{
throw new InternalError("Unable to create payload type {0} for opcode {1}", PayloadType, OpCode);
throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}");
}
break;
case Payload.Arg8:
@@ -430,7 +430,7 @@ namespace Semmle.Extraction.CIL.Entities
// Some of these are handled by JumpContents().
break;
default:
throw new InternalError("Unhandled payload type {0}", PayloadType);
throw new InternalError($"Unhandled payload type {PayloadType}");
}
}
}
@@ -479,7 +479,7 @@ namespace Semmle.Extraction.CIL.Entities
// TODO: Find a solution to this.
// For now, just log the error
cx.cx.Extractor.Message(new Message { message = "A CIL instruction jumps outside the current method", severity = Util.Logging.Severity.Warning });
cx.cx.ExtractionError("A CIL instruction jumps outside the current method", "", Extraction.Entities.GeneratedLocation.Create(cx.cx), "", Util.Logging.Severity.Warning);
}
}
}

View File

@@ -497,7 +497,7 @@ namespace Semmle.Extraction.CIL.Entities
constructedTypeSignature = md.DecodeSignature(cx.TypeSignatureDecoder, this);
break;
default:
throw new InternalError("Unexpected constructed method handle kind {0}", ms.Method.Kind);
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
}
PopulateParameters(constructedTypeSignature.ParameterTypes);

View File

@@ -197,7 +197,7 @@ namespace Semmle.Extraction.CIL
case PrimitiveTypeCode.UIntPtr: return uintptrId;
case PrimitiveTypeCode.Void: return voidId;
case PrimitiveTypeCode.TypedReference: return typedReferenceId;
default: throw new InternalError("Unhandled type code {0}", typeCode);
default: throw new InternalError($"Unhandled type code {typeCode}");
}
}
}

View File

@@ -99,12 +99,7 @@ namespace Semmle.Extraction.CSharp
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message
{
exception = ex,
message = string.Format("Exception reading reference file {0}: {1}",
reference.FilePath, ex)
});
extractor.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace));
}
}
}
@@ -215,6 +210,38 @@ namespace Semmle.Extraction.CSharp
return options.Cache && FileIsUpToDate(src, dest);
}
/// <summary>
/// Extracts compilation-wide entities, such as compilations and compiler diagnostics.
/// </summary>
public void AnalyseCompilation(string cwd, string[] args)
{
extractionTasks.Add(() => DoAnalyseCompilation(cwd, args));
}
Entities.Compilation compilationEntity;
IDisposable compilationTrapFile;
void DoAnalyseCompilation(string cwd, string[] args)
{
try
{
var assemblyPath = extractor.OutputPath;
var assembly = compilation.Assembly;
var projectLayout = layout.LookupProjectOrDefault(assemblyPath);
var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true);
compilationTrapFile = trapWriter; // Dispose later
var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath, true));
compilationEntity = new Entities.Compilation(cx, cwd, args);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
Logger.Log(Severity.Error, " Unhandled exception analyzing {0}: {1}", "compilation", ex);
}
}
public void LogPerformance(Entities.PerformanceMetrics p) => compilationEntity.PopulatePerformance(p);
/// <summary>
/// Extract an assembly to a new trap file.
/// If the trap file exists, skip extraction to avoid duplicating
@@ -258,7 +285,7 @@ namespace Semmle.Extraction.CSharp
if (assembly != null)
{
var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath));
var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false));
foreach (var module in assembly.Modules)
{
@@ -344,7 +371,7 @@ namespace Semmle.Extraction.CSharp
if (!upToDate)
{
Context cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree));
Context cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree));
Populators.CompilationUnit.Extract(cx, tree.GetRoot());
cx.PopulateAll();
cx.ExtractComments(cx.CommentGenerator);
@@ -356,7 +383,7 @@ namespace Semmle.Extraction.CSharp
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message { exception = ex, message = string.Format("Unhandled exception processing {0}: {1}", tree.FilePath, ex), severity = Severity.Error });
extractor.Message(new Message("Unhandled exception processing syntax tree", tree.FilePath, null, ex.StackTrace));
}
}
@@ -373,6 +400,8 @@ namespace Semmle.Extraction.CSharp
public void Dispose()
{
compilationTrapFile?.Dispose();
stopWatch.Stop();
Logger.Log(Severity.Info, " Peak working set = {0} MB", Process.GetCurrentProcess().PeakWorkingSet64 / (1024 * 1024));

View File

@@ -105,7 +105,7 @@ namespace Semmle.Extraction.CSharp.Entities
break;
// Strangely, these are reported as SingleLineCommentTrivia.
case SyntaxKind.DocumentationCommentExteriorTrivia:
cx.ModelError("Unhandled comment type {0} for {1}", trivia.Kind(), trivia);
cx.ModelError($"Unhandled comment type {trivia.Kind()} for {trivia}");
break;
}
}

View File

@@ -0,0 +1,101 @@
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Semmle.Extraction.CSharp.Entities
{
class Compilation : FreshEntity
{
public Compilation(Context cx, string cwd, string[] args) : base(cx)
{
Extraction.Entities.Assembly.CreateOutputAssembly(cx);
cx.Emit(Tuples.compilations(this, Extraction.Entities.File.PathAsDatabaseString(cwd)));
// Arguments
int index = 0;
foreach(var arg in args)
{
cx.Emit(Tuples.compilation_args(this, index++, arg));
}
// Files
index = 0;
foreach(var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath)))
{
cx.Emit(Tuples.compilation_compiling_files(this, index++, file));
}
// References
index = 0;
foreach(var file in cx.Compilation.References.OfType<PortableExecutableReference>().Select(r => Extraction.Entities.File.Create(cx, r.FilePath)))
{
cx.Emit(Tuples.compilation_referencing_files(this, index++, file));
}
// Diagnostics
index = 0;
foreach(var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d)))
{
cx.Emit(Tuples.diagnostic_for(diag, this, 0, index++));
}
}
public void PopulatePerformance(PerformanceMetrics p)
{
int index = 0;
foreach(float metric in p.Metrics)
{
cx.Emit(Tuples.compilation_time(this, -1, index++, metric));
}
cx.Emit(Tuples.compilation_finished(this, (float)p.Total.Cpu.TotalSeconds, (float)p.Total.Elapsed.TotalSeconds));
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
class Diagnostic : FreshEntity
{
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx)
{
cx.Emit(Tuples.diagnostics(this, (int)diag.Severity, diag.Id, diag.Descriptor.Title.ToString(),
diag.GetMessage(), Extraction.Entities.Location.Create(cx, diag.Location)));
}
}
public struct Timings
{
public TimeSpan Elapsed, Cpu, User;
}
/// <summary>
/// The various performance metrics to log.
/// </summary>
public struct PerformanceMetrics
{
public Timings Frontend, Extractor, Total;
public long PeakWorkingSet;
/// <summary>
/// These are in database order (0 indexed)
/// </summary>
public IEnumerable<float> Metrics
{
get
{
yield return (float)Frontend.Cpu.TotalSeconds;
yield return (float)Frontend.Elapsed.TotalSeconds;
yield return (float)Extractor.Cpu.TotalSeconds;
yield return (float)Extractor.Elapsed.TotalSeconds;
yield return (float)Frontend.User.TotalSeconds;
yield return (float)Extractor.User.TotalSeconds;
yield return PeakWorkingSet / 1024.0f / 1024.0f;
}
}
}
}

View File

@@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.PARAMETER_ACCESS;
default:
cx.ModelError(symbol, "Unhandled access kind '{0}'", symbol.Kind);
cx.ModelError(symbol, $"Unhandled access kind '{symbol.Kind}'");
return ExprKind.UNKNOWN;
}
}

View File

@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.QuestionQuestionToken: return ExprKind.NULL_COALESCING;
// !! And the rest
default:
cx.ModelError("Unhandled operator type {0}", kind);
cx.ModelError($"Unhandled operator type {kind}");
return ExprKind.UNKNOWN;
}
}

View File

@@ -233,7 +233,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return IsPattern.Create(info);
default:
info.Context.ModelError(info.Node, "Unhandled expression '{0}' of kind '{1}'", info.Node, info.Node.Kind());
info.Context.ModelError(info.Node, $"Unhandled expression '{info.Node}' of kind '{info.Node.Kind()}'");
return new Unknown(info);
}
}

View File

@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
new Expression(new ExpressionInfo(cx, Type, cx.Create(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text));
break;
default:
throw new InternalError(c, "Unhandled interpolation kind {0}", c.Kind());
throw new InternalError(c, $"Unhandled interpolation kind {c.Kind()}");
}
}
}

View File

@@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return Access.Create(info, target, false, Parameter.GetAlreadyCreated(info.Context, (IParameterSymbol)target));
default:
throw new InternalError(info.Node, "Unhandled identifier kind '{0}'", target.Kind);
throw new InternalError(info.Node, $"Unhandled identifier kind '{target.Kind}'");
}
}
}

View File

@@ -243,7 +243,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
break;
default:
throw new InternalError(qc, "Unhandled query clause of kind {0}", qc.Kind());
throw new InternalError(qc, $"Unhandled query clause of kind {qc.Kind()}");
}
}

View File

@@ -291,7 +291,7 @@ namespace Semmle.Extraction.CSharp.Entities
case MethodKind.LocalFunction:
return LocalFunction.Create(cx, methodDecl);
default:
throw new InternalError(methodDecl, "Unhandled method '{0}' of kind '{1}'", methodDecl, methodDecl.MethodKind);
throw new InternalError(methodDecl, $"Unhandled method '{methodDecl}' of kind '{methodDecl.MethodKind}'");
}
}

View File

@@ -79,7 +79,7 @@ namespace Semmle.Extraction.CSharp.Entities
HasModifier(cx, type, "private");
break;
default:
throw new InternalError("Unhandled Microsoft.CodeAnalysis.Accessibility value: {0}", access);
throw new InternalError($"Unhandled Microsoft.CodeAnalysis.Accessibility value: {access}");
}
}

View File

@@ -66,7 +66,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
case SyntaxKind.ForEachVariableStatement:
return ForEachVariable.Create(cx, (ForEachVariableStatementSyntax)node, parent, child);
default:
throw new InternalError(node, "Unhandled statement of kind '{0}'", node.Kind());
throw new InternalError(node, $"Unhandled statement of kind '{node.Kind()}'");
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
case SyntaxKind.None: return StmtKind.GOTO;
case SyntaxKind.DefaultKeyword: return StmtKind.GOTO_DEFAULT;
case SyntaxKind.CaseKeyword: return StmtKind.GOTO_CASE;
default: throw new InternalError(node, "Unhandled goto statement kind {0}", node.CaseOrDefaultKeyword.Kind());
default: throw new InternalError(node, $"Unhandled goto statement kind {node.CaseOrDefaultKeyword.Kind()}");
}
}

View File

@@ -56,7 +56,7 @@ namespace Semmle.Extraction.CSharp.Entities
case TypeKind.Delegate: return Kinds.TypeKind.DELEGATE;
case TypeKind.Pointer: return Kinds.TypeKind.POINTER;
default:
cx.ModelError(t, "Unhandled type kind '{0}'", t.TypeKind);
cx.ModelError(t, $"Unhandled type kind '{t.TypeKind}'");
return Kinds.TypeKind.UNKNOWN;
}
}

View File

@@ -94,7 +94,7 @@ namespace Semmle.Extraction.CSharp.Entities
case VarianceKind.Out: return Variance.Out;
case VarianceKind.In: return Variance.In;
default:
throw new InternalError("Unexpected VarianceKind {0}", symbol.Variance);
throw new InternalError($"Unexpected VarianceKind {symbol.Variance}");
}
}
}
@@ -116,7 +116,7 @@ namespace Semmle.Extraction.CSharp.Entities
containingEntity = Create(Context, symbol.ContainingType);
break;
default:
throw new InternalError(symbol, "Unhandled type parameter kind {0}", symbol.TypeParameterKind);
throw new InternalError(symbol, $"Unhandled type parameter kind {symbol.TypeParameterKind}");
}
return new Key(containingEntity, "_", symbol.Ordinal, ";", kind);
}

View File

@@ -191,7 +191,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
string result;
if (!OperatorSymbol(methodName, out result))
cx.ModelError("Unhandled operator name in OperatorSymbol(): '{0}'", methodName);
cx.ModelError($"Unhandled operator name in OperatorSymbol(): '{methodName}'");
return result;
}

View File

@@ -62,6 +62,8 @@ namespace Semmle.Extraction.CSharp
/// <returns><see cref="ExitCode"/></returns>
public static ExitCode Run(string[] args)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var commandLineArguments = Options.CreateWithEnvironment(args);
var fileLogger = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath());
var logger = commandLineArguments.Console
@@ -118,8 +120,8 @@ namespace Semmle.Extraction.CSharp
compilerArguments.Encoding,
syntaxTrees);
var sw = new Stopwatch();
sw.Start();
var sw1 = new Stopwatch();
sw1.Start();
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = commandLineArguments.Threads },
@@ -148,6 +150,7 @@ namespace Semmle.Extraction.CSharp
);
analyser.Initialize(compilerArguments, compilation, commandLineArguments, compilerVersion.ArgsWithResponse);
analyser.AnalyseCompilation(cwd, args);
analyser.AnalyseReferences();
foreach (var tree in compilation.SyntaxTrees)
@@ -155,13 +158,29 @@ namespace Semmle.Extraction.CSharp
analyser.AnalyseTree(tree);
}
sw.Stop();
logger.Log(Severity.Info, " Models constructed in {0}", sw.Elapsed);
var currentProcess = Process.GetCurrentProcess();
var cpuTime1 = currentProcess.TotalProcessorTime;
var userTime1 = currentProcess.UserProcessorTime;
sw1.Stop();
logger.Log(Severity.Info, " Models constructed in {0}", sw1.Elapsed);
sw.Restart();
var sw2 = new Stopwatch();
sw2.Start();
analyser.PerformExtraction(commandLineArguments.Threads);
sw.Stop();
logger.Log(Severity.Info, " Extraction took {0}", sw.Elapsed);
sw2.Stop();
var cpuTime2 = currentProcess.TotalProcessorTime;
var userTime2 = currentProcess.UserProcessorTime;
var performance = new Entities.PerformanceMetrics()
{
Frontend = new Entities.Timings() { Elapsed = sw1.Elapsed, Cpu = cpuTime1, User = userTime1 },
Extractor = new Entities.Timings() { Elapsed = sw2.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1 },
Total = new Entities.Timings() { Elapsed = stopwatch.Elapsed, Cpu=cpuTime2, User = userTime2 },
PeakWorkingSet = currentProcess.PeakWorkingSet64
};
analyser.LogPerformance(performance);
logger.Log(Severity.Info, " Extraction took {0}", sw2.Elapsed);
return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors;
}

View File

@@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Populators
public override void DefaultVisit(SyntaxNode node)
{
cx.ModelError(node, "Unhandled syntax node {0}", node.Kind());
cx.ModelError(node, $"Unhandled syntax node {node.Kind()}");
}
public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
@@ -56,7 +56,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
catch (System.Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
cx.ModelError(node, "Exception processing syntax node of type {0}: {1}", node.Kind(), ex);
cx.ModelError(node, $"Exception processing syntax node of type {node.Kind()}: {ex.Message}");
}
}
}

View File

@@ -87,7 +87,7 @@ namespace Semmle.Extraction.CSharp.Populators
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" });
cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info);
}
public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit)
@@ -119,6 +119,9 @@ namespace Semmle.Extraction.CSharp.Populators
{
public static void Extract(Context cx, SyntaxNode unit)
{
// Ensure that the file itself is populated in case the source file is totally empty
File.Create(cx, unit.SyntaxTree.FilePath);
((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx));
}
}

View File

@@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Populators
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 DefaultVisit(ISymbol symbol) => throw new InternalError(symbol, $"Unhandled symbol '{symbol}' of kind '{symbol.Kind}'");
public override IEntity VisitArrayType(IArrayTypeSymbol array) => ArrayType.Create(cx, array);
@@ -57,7 +57,7 @@ namespace Semmle.Extraction.CSharp.Populators
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
cx.ModelError(symbol, "Exception processing symbol '{2}' of type '{0}': {1}", symbol.Kind, ex, symbol);
cx.ModelError(symbol, $"Exception processing symbol '{symbol.Kind}' of type '{ex}': {symbol}");
return null;
}
}

View File

@@ -130,7 +130,7 @@ namespace Semmle.Extraction.CSharp
tb.Append("dynamic");
return;
default:
throw new InternalError(type, "Unhandled type kind '{0}'", type.TypeKind);
throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'");
}
}
}
@@ -269,7 +269,7 @@ namespace Semmle.Extraction.CSharp
tb.Append("dynamic");
return;
default:
throw new InternalError(type, "Unhandled type kind '{0}'", type.TypeKind);
throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'");
}
}
}

View File

@@ -41,6 +41,18 @@ namespace Semmle.Extraction.CSharp
internal static Tuple commentline_location(CommentLine commentLine, Location location) => new Tuple("commentline_location", commentLine, location);
internal static Tuple compilation_args(Compilation compilation, int index, string arg) => new Tuple("compilation_args", compilation, index, arg);
internal static Tuple compilation_compiling_files(Compilation compilation, int index, File file) => new Tuple("compilation_compiling_files", compilation, index, file);
internal static Tuple compilation_referencing_files(Compilation compilation, int index, File file) => new Tuple("compilation_referencing_files", compilation, index, file);
internal static Tuple compilation_finished(Compilation compilation, float cpuSeconds, float elapsedSeconds) => new Tuple("compilation_finished", compilation, cpuSeconds, elapsedSeconds);
internal static Tuple compilation_time(Compilation compilation, int num, int index, float metric) => new Tuple("compilation_time", compilation, num, index, metric);
internal static Tuple compilations(Compilation compilation, string cwd) => new Tuple("compilations", compilation, cwd);
internal static Tuple compiler_generated(IEntity entity) => new Tuple("compiler_generated", entity);
internal static Tuple conditional_access(Expression access) => new Tuple("conditional_access", access);
@@ -59,6 +71,11 @@ namespace Semmle.Extraction.CSharp
internal static Tuple destructors(Destructor destructor, string name, Type containingType, Destructor original) => new Tuple("destructors", destructor, name, containingType, original);
internal static Tuple diagnostic_for(Diagnostic diag, Compilation comp, int fileNo, int index) => new Tuple("diagnostic_for", diag, comp, fileNo, index);
internal static Tuple diagnostics(Diagnostic diag, int severity, string errorTag, string errorMessage, string fullErrorMessage, Location location) =>
new Tuple("diagnostics", diag, severity, errorTag, errorMessage, fullErrorMessage, location);
internal static Tuple dynamic_member_name(Expression e, string name) => new Tuple("dynamic_member_name", e, name);
internal static Tuple enum_underlying_type(Type @enum, Type type) => new Tuple("enum_underlying_type", @enum, type);

View File

@@ -93,7 +93,7 @@ namespace Semmle.Extraction
{
if (idLabelCache.TryGetValue(id, out var originalEntity))
{
Extractor.Message(new Message { message = "Label collision for " + id, severity = Severity.Warning });
ExtractionError("Label collision for " + id, entity.Label.ToString(), Entities.Location.Create(this, entity.ReportingLocation), "", Severity.Warning);
}
else
{
@@ -218,11 +218,11 @@ namespace Semmle.Extraction
}
catch (InternalError ex)
{
Extractor.Message(ex.ExtractionMessage);
ExtractionError(new Message(ex.Text, ex.EntityText, Entities.Location.Create(this, ex.Location), ex.StackTrace));
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
Extractor.Message(new Message { severity = Severity.Error, exception = ex, message = "Uncaught exception" });
ExtractionError("Uncaught exception", ex.Message, GeneratedLocation.Create(this), ex.StackTrace);
}
}
}
@@ -247,6 +247,8 @@ namespace Semmle.Extraction
TrapWriter = trapWriter;
}
public bool IsGlobalContext => Scope.IsGlobalScope;
public readonly ICommentGenerator CommentGenerator = new CommentProcessor();
readonly IExtractionScope Scope;
@@ -378,7 +380,7 @@ namespace Semmle.Extraction
{
case TrapStackBehaviour.NeedsLabel:
if (!tagStack.Any())
Extractor.Message(new Message { message = "Tagstack unexpectedly empty", symbol = optionalSymbol, severity = Severity.Error });
ExtractionError("TagStack unexpectedly empty", optionalSymbol, entity);
duplicationGuard = false;
deferred = false;
break;
@@ -448,6 +450,52 @@ namespace Semmle.Extraction
var duplicationGuardKey = tagStack.Count > 0 ? tagStack.Peek() : null;
CommentGenerator.RegisterElementLocation(entity.Label, duplicationGuardKey, l);
}
/// <summary>
/// Log an extraction error.
/// </summary>
/// <param name="message">The error message.</param>
/// <param name="entityText">A textual representation of the failed entity.</param>
/// <param name="location">The location of the error.</param>
/// <param name="stackTrace">An optional stack trace of the error, or an empty string.</param>
/// <param name="severity">The severity of the error.</param>
public void ExtractionError(string message, string entityText, Entities.Location location, string stackTrace = "", Severity severity = Severity.Error)
{
var msg = new Message(message, entityText, location, stackTrace, severity);
ExtractionError(msg);
}
/// <summary>
/// Log an extraction error.
/// </summary>
/// <param name="message">The text of the message.</param>
/// <param name="optionalSymbol">The symbol of the error, or null.</param>
/// <param name="optionalEntity">The entity of the error, or null.</param>
public void ExtractionError(string message, ISymbol optionalSymbol, IEntity optionalEntity)
{
if (!(optionalSymbol is null))
{
ExtractionError(message, optionalSymbol.ToDisplayString(), Entities.Location.Create(this, optionalSymbol.Locations.FirstOrDefault()));
}
else if(!(optionalEntity is null))
{
ExtractionError(message, optionalEntity.Label.ToString(), Entities.Location.Create(this, optionalEntity.ReportingLocation));
}
else
{
ExtractionError(message, "", GeneratedLocation.Create(this));
}
}
/// <summary>
/// Log an extraction message.
/// </summary>
/// <param name="msg">The message to log.</param>
public void ExtractionError(Message msg)
{
new Entities.ExtractionMessage(this, msg);
Extractor.Message(msg);
}
}
static public class ContextExtensions
@@ -457,12 +505,11 @@ namespace Semmle.Extraction
/// </summary>
/// <param name="cx">The context.</param>
/// <param name="node">The syntax node causing the failure.</param>
/// <param name="format">A string format.</param>
/// <param name="args">Arguments for the format.</param>
static public void ModelError(this Context cx, SyntaxNode node, string format, params object[] args)
/// <param name="msg">The error message.</param>
static public void ModelError(this Context cx, SyntaxNode node, string msg)
{
if (!cx.Extractor.Standalone)
throw new InternalError(node, format, args);
throw new InternalError(node, msg);
}
/// <summary>
@@ -470,24 +517,22 @@ namespace Semmle.Extraction
/// </summary>
/// <param name="context">The context.</param>
/// <param name="node">Symbol causing the error.</param>
/// <param name="format">Format of message string.</param>
/// <param name="args">Arguments to message string.</param>
static public void ModelError(this Context cx, ISymbol symbol, string format, params object[] args)
/// <param name="msg">The error message.</param>
static public void ModelError(this Context cx, ISymbol symbol, string msg)
{
if (!cx.Extractor.Standalone)
throw new InternalError(symbol, format, args);
throw new InternalError(symbol, msg);
}
/// <summary>
/// Signal an error in the program model.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="format">Format of message string.</param>
/// <param name="args">Arguments to message string.</param>
static public void ModelError(this Context cx, string format, params object[] args)
/// <param name="msg">The error message.</param>
static public void ModelError(this Context cx, string msg)
{
if (!cx.Extractor.Standalone)
throw new InternalError(format, args);
throw new InternalError(msg);
}
/// <summary>
@@ -506,32 +551,21 @@ namespace Semmle.Extraction
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
var internalError = ex as InternalError;
var message = internalError != null
? internalError.ExtractionMessage
: new Message { severity = Severity.Error, exception = ex, message = ex.ToString() };
Message message;
if (node != null)
message.node = node;
message = Message.Create(context, ex.Message, node, ex.StackTrace);
else if (symbol != null)
message = Message.Create(context, ex.Message, symbol, ex.StackTrace);
else if (ex is InternalError ie)
message = new Message(ie.Text, ie.EntityText, Entities.Location.Create(context, ie.Location), ex.StackTrace);
else
message = new Message("Uncaught exception", ex.Message, GeneratedLocation.Create(context), ex.StackTrace);
if (symbol != null)
message.symbol = symbol;
context.Extractor.Message(message);
context.ExtractionError(message);
}
}
/// <summary>
/// Logs the given string.
/// </summary>
/// <param name="cx">The extractor context.</param>
/// <param name="format">The format string.</param>
/// <param name="args">The inserts to the format string.</param>
static public void Log(this Context cx, string format, params object[] args)
{
cx.Extractor.Message(new Message { severity = Severity.Info, message = string.Format(format, args) });
}
/// <summary>
/// Write the given tuple to the trap file.
/// </summary>

View File

@@ -34,7 +34,8 @@ namespace Semmle.Extraction.Entities
}
}
public override bool NeedsPopulation => true;
public override bool NeedsPopulation =>
assembly != Context.Compilation.Assembly || !Context.IsGlobalContext;
public override int GetHashCode() =>
symbol == null ? 91187354 : symbol.GetHashCode();

View File

@@ -0,0 +1,12 @@
namespace Semmle.Extraction.Entities
{
class ExtractionMessage : FreshEntity
{
public ExtractionMessage(Context cx, Message msg) : base(cx)
{
cx.Emit(Tuples.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location, msg.StackTrace));
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
}
}

View File

@@ -27,7 +27,7 @@ namespace Semmle.Extraction.Entities
// On Windows: System.IO.DirectoryInfo.Name returns "L:\"
string shortName = symbol.Parent == null ? "" : symbol.Name;
Context.Emit(Tuples.folders(this, Semmle.Extraction.Entities.File.PathAsDatabaseString(Path), shortName));
Context.Emit(Tuples.folders(this, File.PathAsDatabaseString(Path), shortName));
if (symbol.Parent != null)
{
Context.Emit(Tuples.containerparent(Create(Context, symbol.Parent), this));

View File

@@ -6,9 +6,9 @@ namespace Semmle.Extraction.Entities
public Location(Context cx, Microsoft.CodeAnalysis.Location init)
: base(cx, init) { }
internal static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) =>
loc == null ? GeneratedLocation.Create(cx)
: loc.IsInSource ? SourceLocation.Create(cx, loc)
public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) =>
loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None ?
GeneratedLocation.Create(cx) : loc.IsInSource ? SourceLocation.Create(cx, loc)
: Assembly.Create(cx, loc);
public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol;

View File

@@ -23,6 +23,8 @@ namespace Semmle.Extraction
/// </summary>
/// <param name="path">The path to populate.</param>
bool InFileScope(string path);
bool IsGlobalScope { get; }
}
/// <summary>
@@ -33,15 +35,18 @@ namespace Semmle.Extraction
readonly IAssemblySymbol assembly;
readonly string filepath;
public AssemblyScope(IAssemblySymbol symbol, string path)
public AssemblyScope(IAssemblySymbol symbol, string path, bool isOutput)
{
assembly = symbol;
filepath = path;
IsGlobalScope = isOutput;
}
public bool IsGlobalScope { get; }
public bool InFileScope(string path) => path == filepath;
public bool InScope(ISymbol symbol) => Equals(symbol.ContainingAssembly, assembly);
public bool InScope(ISymbol symbol) => Equals(symbol.ContainingAssembly, assembly) || Equals(symbol, assembly);
}
/// <summary>
@@ -56,6 +61,8 @@ namespace Semmle.Extraction
sourceTree = tree;
}
public bool IsGlobalScope => false;
public bool InFileScope(string path) => path == sourceTree.FilePath;
public bool InScope(ISymbol symbol) => symbol.Locations.Any(loc => loc.SourceTree == sourceTree);

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Semmle.Util;
using Semmle.Util.Logging;
@@ -82,6 +83,15 @@ namespace Semmle.Extraction
/// The extractor SHA, obtained from the git log.
/// </summary>
string Version { get; }
/// <summary>
/// Creates a new context.
/// </summary>
/// <param name="c">The C# compilation.</param>
/// <param name="trapWriter">The trap writer.</param>
/// <param name="scope">The extraction scope (what to include in this trap file).</param>
/// <returns></returns>
Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope);
}
/// <summary>
@@ -122,7 +132,7 @@ namespace Semmle.Extraction
lock (mutex)
{
if (msg.severity == Severity.Error)
if (msg.Severity == Severity.Error)
{
++Errors;
if (Errors == maxErrors)
@@ -136,24 +146,7 @@ namespace Semmle.Extraction
return;
}
Logger.Log(msg.severity, " {0}", msg.message);
if (msg.node != null)
{
Logger.Log(msg.severity, " Syntax element '{0}' at {1}", msg.node, msg.node.GetLocation().GetLineSpan());
}
if (msg.symbol != null)
{
Logger.Log(msg.severity, " Symbol '{0}'", msg.symbol);
foreach (var l in msg.symbol.Locations)
Logger.Log(msg.severity, " Location: {0}", l.IsInSource ? l.GetLineSpan().ToString() : l.MetadataModule.ToString());
}
if (msg.exception != null)
{
Logger.Log(msg.severity, " Exception: {0}", msg.exception);
}
Logger.Log(msg.Severity, $" {msg.ToLogString()}");
}
}
@@ -191,6 +184,11 @@ namespace Semmle.Extraction
missingNamespaces.Add(fqdn);
}
public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope)
{
return new Context(this, c, trapWriter, scope);
}
public IEnumerable<string> MissingTypes => missingTypes;
public IEnumerable<string> MissingNamespaces => missingNamespaces;

View File

@@ -1,6 +1,6 @@
using Semmle.Util.Logging;
using Microsoft.CodeAnalysis;
using System;
using System.Linq;
namespace Semmle.Extraction
{
@@ -9,26 +9,31 @@ namespace Semmle.Extraction
/// </summary>
public class InternalError : Exception
{
public InternalError(ISymbol symbol, string msg, params object[] args)
public InternalError(ISymbol symbol, string msg)
{
ExtractionMessage = new Message { exception = this, symbol = symbol, severity = Severity.Error, message = string.Format(msg, args) };
Text = msg;
EntityText = symbol.ToString();
Location = symbol.Locations.FirstOrDefault();
}
public InternalError(SyntaxNode node, string msg, params object[] args)
public InternalError(SyntaxNode node, string msg)
{
ExtractionMessage = new Message { exception = this, node = node, severity = Severity.Error, message = string.Format(msg, args) };
Text = msg;
EntityText = node.ToString();
Location = node.GetLocation();
}
public InternalError(string msg, params object[] args)
public InternalError(string msg)
{
ExtractionMessage = new Message { exception = this, severity = Severity.Error, message = string.Format(msg, args) };
Text = msg;
EntityText = "";
Location = null;
}
public Message ExtractionMessage
{
get; private set;
}
public Location Location { get; }
public string Text;
public string EntityText;
public override string Message => ExtractionMessage.message;
public override string Message => Text;
}
}

View File

@@ -1,20 +1,54 @@
using Microsoft.CodeAnalysis;
using Semmle.Util.Logging;
using System;
using System.Linq;
using System.Text;
namespace Semmle.Extraction
{
/// <summary>
/// Encapsulates information for a log message.
/// </summary>
public struct Message
public class Message
{
public Severity severity;
public string message;
public ISymbol symbol;
public SyntaxNode node;
public Exception exception;
public readonly Severity Severity;
public readonly string Text;
public readonly string StackTrace;
public readonly string EntityText;
public readonly Entities.Location Location;
public override string ToString() => message;
public Message(string text, string entityText, Entities.Location location, string stackTrace="", Severity severity = Severity.Error)
{
Severity = severity;
Text = text;
StackTrace = stackTrace;
EntityText = entityText;
Location = location;
}
public static Message Create(Context cx, string text, ISymbol symbol, string stackTrace= "", Severity severity = Severity.Error)
{
return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity);
}
public static Message Create(Context cx, string text, SyntaxNode node, string stackTrace = "", Severity severity = Severity.Error)
{
return new Message(text, node.ToString(), Entities.Location.Create(cx, node.GetLocation()), stackTrace, severity);
}
public override string ToString() => Text;
public string ToLogString()
{
var sb = new StringBuilder();
sb.Append(Text);
if (!string.IsNullOrEmpty(EntityText))
sb.Append(" in ").Append(EntityText);
if (!(Location is null) && !(Location.UnderlyingObject is null))
sb.Append(" at ").Append(Location.UnderlyingObject.GetLineSpan());
if (!string.IsNullOrEmpty(StackTrace))
sb.Append(" ").Append(StackTrace);
return sb.ToString();
}
}
}

View File

@@ -20,8 +20,4 @@
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Entities\" />
</ItemGroup>
</Project>

View File

@@ -32,6 +32,8 @@ namespace Semmle.Extraction
object ICachedEntity.UnderlyingObject => symbol;
public Initializer UnderlyingObject => symbol;
public abstract IId Id
{
get;

View File

@@ -120,6 +120,9 @@ namespace Semmle.Extraction
case int i:
tb.Append(i);
break;
case float f:
tb.Append(f.ToString("0.#####e0")); // Trap importer won't accept ints
break;
case string[] array:
tb.Append("\"");
if (NeedsTruncation(array))
@@ -138,11 +141,9 @@ namespace Semmle.Extraction
tb.Append("\"");
break;
case null:
throw new InternalError("Attempt to write a null argument tuple {0} at column {1}",
Name, column);
throw new InternalError($"Attempt to write a null argument tuple {Name} at column {column}");
default:
throw new InternalError("Attempt to write an invalid argument type {0} in tuple {1} at column {2}",
a.GetType(), Name, column);
throw new InternalError($"Attempt to write an invalid argument type {a.GetType()} in tuple {Name} at column {column}");
}
++column;

View File

@@ -14,6 +14,9 @@ namespace Semmle.Extraction
internal static Tuple containerparent(Folder parent, IEntity child) =>
new Tuple("containerparent", parent, child);
internal static Tuple extractor_messages(ExtractionMessage error, Semmle.Util.Logging.Severity severity, string origin, string errorMessage, string entityText, Location location, string stackTrace) =>
new Tuple("extractor_messages", error, severity, origin, errorMessage, entityText, location, stackTrace);
internal static Tuple file_extraction_mode(File file, int mode) =>
new Tuple("file_extraction_mode", file, mode);

View File

@@ -0,0 +1,65 @@
import csharp
import Diagnostics
/** An invocation of the C# compiler. */
class Compilation extends @compilation {
/** Gets a textual representation of this compilation. */
string toString() { result = "compilation" }
/** Gets the directory in which this compilation was run, as a string. */
string getDirectoryString() { compilations(this, result) }
/** Gets the folder in which this compilation was run. */
Folder getFolder() { result.getAbsolutePath() = getDirectoryString() }
/** Gets the `i`th command line argument. */
string getArgument(int i) { compilation_args(this, i, result) }
/** Gets the arguments as a concatenated string. */
string getArguments() { result = concat(int i | exists(getArgument(i)) | getArgument(i), " ") }
/** Gets the 'i'th source file in this compilation. */
File getFileCompiled(int i) { compilation_compiling_files(this, i, result) }
/** Gets a source file compiled in this compilation. */
File getAFileCompiled() { result = getFileCompiled(_) }
/** Gets the `i`th reference in this compilation. */
File getReference(int i) { compilation_referencing_files(this, i, result) }
/** Gets a reference in this compilation. */
File getAReference() { result = getReference(_) }
/** Gets a diagnostic associated with this compilation. */
Diagnostic getADiagnostic() { result.getCompilation() = this }
/** Gets a performance metric for this compilation. */
float getMetric(int metric) { compilation_time(this, -1, metric, result) }
/** Gets the CPU time of the compilation. */
float getFrontendCpuSeconds() { result = getMetric(0) }
/** Gets the elapsed time of the compilation. */
float getFrontendElapsedSeconds() { result = getMetric(1) }
/** Gets the CPU time of the extraction. */
float getExtractorCpuSeconds() { result = getMetric(2) }
/** Gets the elapsed time of the extraction. */
float getExtractorElapsedSeconds() { result = getMetric(3) }
/** Gets the user CPU time of the compilation. */
float getFrontendUserCpuSeconds() { result = getMetric(4) }
/** Gets the user CPU time of the extraction. */
float getExtractorUserCpuSeconds() { result = getMetric(5) }
/** Gets the peak working set of the extractor process in MB. */
float getPeakWorkingSetMB() { result = getMetric(6) }
/** Gets the CPU seconds for the entire extractor process. */
float getCpuSeconds() { compilation_finished(this, result, _) }
/** Gets the elapsed seconds for the entire extractor process. */
float getElapsedSeconds() { compilation_finished(this, _, result) }
}

View File

@@ -0,0 +1,115 @@
/** Provides classes relating to compilation and extraction diagnostics. */
import csharp
import Compilation
/** A diagnostic emitted by a compilation, such as a compilation warning or an error. */
class Diagnostic extends @diagnostic {
/** Gets the compilation that generated this diagnostic. */
Compilation getCompilation() { diagnostic_for(this, result, _, _) }
int severity;
string tag;
string message;
string fullMessage;
Location location;
Diagnostic() { diagnostics(this, severity, tag, message, fullMessage, location) }
/**
* Gets the severity of this diagnostic.
* 0 = Hidden
* 1 = Info
* 2 = Warning
* 3 = Error
*/
int getSeverity() { result = severity }
/** Gets the identifier of this diagnostic, for example "CS8019". */
string getTag() { result = tag }
/** Gets the short error message of this diagnostic. */
string getMessage() { result = message }
/** Gets the full error message of this diagnostic. */
string getFullMessage() { result = fullMessage }
/** Gets the location of this diagnostic. */
Location getLocation() { result = location }
/** Gets a textual representation of this diagnostic. */
string toString() { result = this.getTag() + ": " + this.getFullMessage() }
/** Gets the element associated with this diagnostic, if any. */
Element getElement() { this.getLocation() = result.getLocation() }
}
/** A diagnostic that is a compilation error. */
class CompilerError extends Diagnostic {
CompilerError() { this.getSeverity() >= 3 }
}
/** A message from an extractor. */
class ExtractorMessage extends @extractor_message {
int severity;
string origin;
string text;
string element;
string stackTrace;
Location location;
ExtractorMessage() {
extractor_messages(this, severity, origin, text, element, location, stackTrace)
}
/** Gets the severity of this message. */
int getSeverity() { result = severity }
/** Gets the name of the extractor that produced this message, for example, `C# extractor`. */
string getOrigin() { result = origin }
/** Gets the text of this message. */
string getText() { result = text }
/** Gets the textual representation of the entity that triggered this message. */
string getElementText() { result = element }
/** Gets a string containing a stack trace of the extractor, or the empty string if none available. */
string getStackTrace() { result = stackTrace }
/** Gets the location of the element. */
Location getLocation() { result = location }
/** Gets a textual representation of this message. */
string toString() { result = text }
/** Gets a string representation of the severity of this message. */
string getSeverityText() {
severity = 1 and result = "Trace"
or
severity = 2 and result = "Debug"
or
severity = 3 and result = "Info"
or
severity = 4 and result = "Warning"
or
severity = 5 and result = "Error"
}
/** Gets the element associated with this message, if any. */
Element getElement() { this.getLocation() = result.getLocation() }
}
/** An error from an extractor. */
class ExtractorError extends ExtractorMessage {
ExtractorError() { this.getSeverity() >= 5 }
}

View File

@@ -1,3 +1,156 @@
/**
* An invocation of the compiler. Note that more than one file may be
* compiled per invocation. For example, this command compiles three
* source files:
*
* csc f1.cs f2.cs f3.cs
*
* The `id` simply identifies the invocation, while `cwd` is the working
* directory from which the compiler was invoked.
*/
compilations(
unique int id : @compilation,
string cwd : string ref
);
/**
* The arguments that were passed to the extractor for a compiler
* invocation. If `id` is for the compiler invocation
*
* csc f1.cs f2.cs f3.cs
*
* then typically there will be rows for
*
* num | arg
* --- | ---
* 0 | --compiler
* 1 | *path to compiler*
* 2 | --cil
* 3 | f1.cs
* 4 | f2.cs
* 5 | f3.cs
*/
#keyset[id, num]
compilation_args(
int id : @compilation ref,
int num : int ref,
string arg : string ref
);
/**
* The source files that are compiled by a compiler invocation.
* If `id` is for the compiler invocation
*
* csc f1.cs f2.cs f3.cs
*
* then there will be rows for
*
* num | arg
* --- | ---
* 0 | f1.cs
* 1 | f2.cs
* 2 | f3.cs
*/
#keyset[id, num]
compilation_compiling_files(
int id : @compilation ref,
int num : int ref,
int file : @file ref
);
/**
* The references used by a compiler invocation.
* If `id` is for the compiler invocation
*
* csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
*
* then there will be rows for
*
* num | arg
* --- | ---
* 0 | ref1.dll
* 1 | ref2.dll
* 2 | ref3.dll
*/
#keyset[id, num]
compilation_referencing_files(
int id : @compilation ref,
int num : int ref,
int file : @file ref
);
/**
* The time taken by the extractor for a compiler invocation.
*
* For each file `num`, there will be rows for
*
* kind | seconds
* ---- | ---
* 1 | CPU seconds used by the extractor frontend
* 2 | Elapsed seconds during the extractor frontend
* 3 | CPU seconds used by the extractor backend
* 4 | Elapsed seconds during the extractor backend
*/
#keyset[id, num, kind]
compilation_time(
int id : @compilation ref,
int num : int ref,
/* kind:
1 = frontend_cpu_seconds
2 = frontend_elapsed_seconds
3 = extractor_cpu_seconds
4 = extractor_elapsed_seconds
*/
int kind : int ref,
float seconds : float ref
);
/**
* An error or warning generated by the extractor.
* The diagnostic message `diagnostic` was generated during compiler
* invocation `compilation`, and is the `file_number_diagnostic_number`th
* message generated while extracting the `file_number`th file of that
* invocation.
*/
#keyset[compilation, file_number, file_number_diagnostic_number]
diagnostic_for(
unique int diagnostic : @diagnostic ref,
int compilation : @compilation ref,
int file_number : int ref,
int file_number_diagnostic_number : int ref
);
diagnostics(
unique int id: @diagnostic,
int severity: int ref,
string error_tag: string ref,
string error_message: string ref,
string full_error_message: string ref,
int location: @location_default ref
);
extractor_messages(
unique int id: @extractor_message,
int severity: int ref,
string origin : string ref,
string text : string ref,
string entity : string ref,
int location: @location_default ref,
string stack_trace : string ref
);
/**
* If extraction was successful, then `cpu_seconds` and
* `elapsed_seconds` are the CPU time and elapsed time (respectively)
* that extraction took for compiler invocation `id`.
*/
compilation_finished(
unique int id : @compilation ref,
float cpu_seconds : float ref,
float elapsed_seconds : float ref
);
/*
* External artifacts
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
diagnostics
| Program.cs:7:13:7:13 | CS0219: The variable 'x' is assigned but its value is never used | CS0219 | 2 | Variable is assigned but its value is never used | The variable 'x' is assigned but its value is never used |
| Program.cs:9:9:9:11 | CS0162: Unreachable code detected | CS0162 | 2 | Unreachable code detected | Unreachable code detected |
| Program.cs:9:13:9:13 | CS0219: The variable 'y' is assigned but its value is never used | CS0219 | 2 | Variable is assigned but its value is never used | The variable 'y' is assigned but its value is never used |
compilationErrors
metricIsZero
compilationArguments
| compilation | 0 | -unsafe |
| compilation | 1 | -target:library |
| compilation | 2 | /noconfig |
| compilation | 3 | /r:System.Private.CoreLib.dll |
| compilation | 4 | /r:System.dll |
| compilation | 5 | /r:System.Core.dll |
| compilation | 6 | /r:System.Runtime.dll |
| compilation | 7 | /r:System.Console.dll |
| compilation | 8 | --console |
| compilation | 9 | --verbosity |
| compilation | 10 | 2 |
| compilation | 11 | Program.cs |
compilationFiles
| compilation | 0 | Program.cs:0:0:0:0 | Program.cs |
compilationFolder
| compilation | compilations |
diagnosticElements
| Program.cs:7:13:7:13 | CS0219: The variable 'x' is assigned but its value is never used | Program.cs:7:13:7:13 | access to local variable x |
| Program.cs:7:13:7:13 | CS0219: The variable 'x' is assigned but its value is never used | Program.cs:7:13:7:13 | x |
| Program.cs:9:13:9:13 | CS0219: The variable 'y' is assigned but its value is never used | Program.cs:9:13:9:13 | access to local variable y |
| Program.cs:9:13:9:13 | CS0219: The variable 'y' is assigned but its value is never used | Program.cs:9:13:9:13 | y |
references
| compilation | System.Console.dll |
| compilation | System.Core.dll |
| compilation | System.Private.CoreLib.dll |
| compilation | System.Runtime.dll |
| compilation | System.dll |
| compilation | mscorlib.dll |
timings
| compilation |

View File

@@ -0,0 +1,41 @@
import csharp
import semmle.code.csharp.commons.Diagnostics
query predicate diagnostics(
Diagnostic d, string tag, int severity, string message, string fullMessage
) {
tag = d.getTag() and
severity = d.getSeverity() and
message = d.getMessage() and
fullMessage = d.getFullMessage()
}
query predicate compilationErrors(CompilerError e) { any() }
query predicate metricIsZero(Compilation compilation, int metric) {
compilation.getMetric(metric) = 0 and
metric != 6 // Peak working set not implemented on Linux
}
query predicate compilationArguments(Compilation compilation, int i, string arg) {
arg = compilation.getArgument(i)
}
query predicate compilationFiles(Compilation compilation, int i, File f) {
f = compilation.getFileCompiled(i)
}
query predicate compilationFolder(Compilation c, string folder) {
folder = c.getFolder().getBaseName()
}
query predicate diagnosticElements(Diagnostic d, Element e) { e = d.getElement() }
query predicate references(Compilation c, string reference) {
reference = c.getAReference().getBaseName()
}
query predicate timings(Compilation c) {
c.getCpuSeconds() > 0 and
c.getElapsedSeconds() > 0
}

View File

@@ -0,0 +1,2 @@
extractorElements
extractorErrors

View File

@@ -0,0 +1,8 @@
import csharp
import semmle.code.csharp.commons.Diagnostics
query predicate extractorElements(ExtractorMessage m, Element e) { e = m.getElement() }
query predicate extractorErrors(ExtractorError e, string origin, string stackTrace) {
origin = e.getOrigin() and stackTrace = e.getStackTrace()
}

View File

@@ -0,0 +1,11 @@
using System; // CS8019
class Class
{
static void Main(string[] args)
{
var x = 2; // CS0219
return;
var y = 3; // CS0219, CS0162
}
}

View File

@@ -0,0 +1,2 @@
compilationMessages
extractorMessages

View File

@@ -0,0 +1,6 @@
import csharp
import semmle.code.csharp.commons.Diagnostics
query predicate compilationMessages(Diagnostic diag) { any() }
query predicate extractorMessages(ExtractorMessage msg) { any() }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Adds information about compilations
compatibility: backwards