Extract #if directives

This commit is contained in:
Tamas Vajk
2021-01-20 15:21:36 +01:00
parent a5d18f9b68
commit 41fbce0ad0
21 changed files with 639 additions and 5 deletions

View File

@@ -529,7 +529,17 @@ namespace Semmle.Extraction.CSharp.Entities
get
{
var c = Model.GetConstantValue(Node);
return c.HasValue ? Expression.ValueAsString(c.Value) : null;
if (c.HasValue)
{
return Expression.ValueAsString(c.Value);
}
if (TryGetBoolValueInsideIfDirective(out var val))
{
return Expression.ValueAsString(val);
}
return null;
}
}
@@ -593,5 +603,31 @@ namespace Semmle.Extraction.CSharp.Entities
}
public NullableFlowState FlowState => TypeInfo.Nullability.FlowState;
public bool IsInsideIfDirective()
{
return Node.Ancestors().Any(a => a is ElifDirectiveTriviaSyntax || a is IfDirectiveTriviaSyntax);
}
public bool TryGetBoolValueInsideIfDirective(out bool val)
{
var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression);
var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression);
if (!isTrue && !isFalse)
{
val = false;
return false;
}
if (!IsInsideIfDirective())
{
val = false;
return false;
}
val = isTrue;
return true;
}
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class DefineSymbol : Expression<IdentifierNameSyntax>
{
private DefineSymbol(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DEFINE_SYMBOL)) { }
public static Expression Create(ExpressionNodeInfo info) => new DefineSymbol(info).TryPopulate();
protected override void PopulateExpression(TextWriter trapFile)
{
trapFile.directive_define_symbols(this, Syntax.Identifier.Text);
}
}
}

View File

@@ -25,6 +25,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.NULL_LITERAL;
}
if (info.TryGetBoolValueInsideIfDirective(out var _))
{
return ExprKind.BOOL_LITERAL;
}
var type = info.Type?.Symbol;
return GetExprKind(type, info.Node, info.Context);
}

View File

@@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace Semmle.Extraction.CSharp.Entities.Expressions
@@ -26,8 +27,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (target == null)
{
info.Context.ModelError(info.Node, "Failed to resolve name");
return new Unknown(info);
if (info.IsInsideIfDirective())
{
return DefineSymbol.Create(info);
}
else
{
info.Context.ModelError(info.Node, "Failed to resolve name");
return new Unknown(info);
}
}
// There is a very strange bug in Microsoft.CodeAnalysis whereby

View File

@@ -0,0 +1,22 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class ElifDirective : PreprocessorDirective<ElifDirectiveTriviaSyntax>, IIfSiblingDirective, IExpressionParentEntity
{
public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
public bool IsTopLevelParent => true;
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue);
Expression.Create(cx, trivia.Condition, this, 0);
}
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class ElseDirective : PreprocessorDirective<ElseDirectiveTriviaSyntax>, IIfSiblingDirective
{
public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_elses(this, trivia.BranchTaken);
}
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class EndIfDirective : PreprocessorDirective<EndIfDirectiveTriviaSyntax>
{
public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endifs(this);
}
}
}

View File

@@ -0,0 +1,4 @@
namespace Semmle.Extraction.CSharp.Entities
{
internal interface IIfSiblingDirective { }
}

View File

@@ -0,0 +1,40 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class IfDirective : PreprocessorDirective<IfDirectiveTriviaSyntax>, IExpressionParentEntity
{
private readonly List<IIfSiblingDirective> branches = new List<IIfSiblingDirective>();
public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
public bool IsTopLevelParent => true;
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue);
Expression.Create(cx, trivia.Condition, this, 0);
}
internal void Add(IIfSiblingDirective branch)
{
branches.Add(branch);
}
internal void WriteBranches(EndIfDirective endif)
{
cx.TrapWriter.Writer.directive_if_endif(this, endif);
var siblings = 0;
foreach (var branch in branches)
{
cx.TrapWriter.Writer.directive_if_siblings(this, branch, siblings++);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities

View File

@@ -124,5 +124,7 @@ namespace Semmle.Extraction.Kinds
AND_PATTERN = 127,
OR_PATTERN = 128,
FUNCTION_POINTER_INVOCATION = 129,
DEFINE_SYMBOL = 999
}
}

View File

@@ -75,5 +75,52 @@ namespace Semmle.Extraction.CSharp.Populators
var start = regionStarts.Pop();
Entities.EndRegionDirective.WriteRegionBlock(cx, start, endregion);
}
private readonly Stack<Entities.IfDirective> ifStarts = new Stack<Entities.IfDirective>();
public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node)
{
var ifStart = new Entities.IfDirective(cx, node);
ifStarts.Push(ifStart);
}
public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node)
{
var endif = new Entities.EndIfDirective(cx, node);
if (ifStarts.Count == 0)
{
cx.ExtractionError("Couldn't find start if", null,
Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning);
return;
}
var start = ifStarts.Pop();
start.WriteBranches(endif);
}
public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node)
{
var elif = new Entities.ElifDirective(cx, node);
if (ifStarts.Count == 0)
{
cx.ExtractionError("Couldn't find start if", null,
Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning);
return;
}
var start = ifStarts.Peek();
start.Add(elif);
}
public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node)
{
var elseDirective = new Entities.ElseDirective(cx, node);
if (ifStarts.Count == 0)
{
cx.ExtractionError("Couldn't find start if", null,
Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning);
return;
}
var start = ifStarts.Peek();
start.Add(elseDirective);
}
}
}

View File

@@ -1,6 +1,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CommentProcessing;
using Semmle.Extraction.CSharp.Entities;
using Semmle.Extraction.CSharp.Entities.Expressions;
using Semmle.Extraction.Entities;
using Semmle.Extraction.Kinds;
using Semmle.Util;
@@ -670,5 +671,42 @@ namespace Semmle.Extraction.CSharp
{
trapFile.WriteTuple("regions", start, end);
}
internal static void directive_ifs(this TextWriter trapFile, IfDirective directive, bool branchTaken, bool conditionValue)
{
trapFile.WriteTuple("directive_ifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0);
}
internal static void directive_elifs(this TextWriter trapFile, ElifDirective directive, bool branchTaken, bool conditionValue)
{
trapFile.WriteTuple("directive_elifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0);
}
internal static void directive_elses(this TextWriter trapFile, ElseDirective directive, bool branchTaken)
{
trapFile.WriteTuple("directive_elses", directive, branchTaken ? 1 : 0);
}
internal static void directive_endifs(this TextWriter trapFile, EndIfDirective directive)
{
trapFile.WriteTuple("directive_endifs", directive);
}
internal static void directive_if_endif(this TextWriter trapFile, IfDirective start, EndIfDirective end)
{
trapFile.WriteTuple("directive_if_endif", start, end);
}
internal static void directive_if_siblings(this TextWriter trapFile, IfDirective start, IIfSiblingDirective siblingDirective, int index)
{
trapFile.WriteTuple("directive_if_siblings", start, siblingDirective, index);
}
internal static void directive_define_symbols(this TextWriter trapFile, DefineSymbol symb, string name)
{
trapFile.WriteTuple("directive_define_symbols", symb, name);
}
}
}