Extract region directives

This commit is contained in:
Tamas Vajk
2021-01-20 11:07:24 +01:00
parent fe0a494bab
commit a5d18f9b68
8 changed files with 133 additions and 1 deletions

View File

@@ -0,0 +1,23 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class EndRegionDirective : PreprocessorDirective<EndRegionDirectiveTriviaSyntax>
{
public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia)
: base(cx, trivia)
{
}
protected override void PopulatePreprocessor(TextWriter trapFile)
{
trapFile.directive_endregions(this);
}
internal static void WriteRegionBlock(Context cx, RegionDirective region, EndRegionDirective endregion)
{
cx.TrapWriter.Writer.regions(region, endregion);
}
}
}

View File

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

View File

@@ -1,3 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -52,5 +54,26 @@ namespace Semmle.Extraction.CSharp.Populators
{
new Entities.LineDirective(cx, node);
}
private readonly Stack<Entities.RegionDirective> regionStarts = new Stack<Entities.RegionDirective>();
public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node)
{
var region = new Entities.RegionDirective(cx, node);
regionStarts.Push(region);
}
public override void VisitEndRegionDirectiveTrivia(EndRegionDirectiveTriviaSyntax node)
{
var endregion = new Entities.EndRegionDirective(cx, node);
if (regionStarts.Count == 0)
{
cx.ExtractionError("Couldn't find start region", null,
Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning);
return;
}
var start = regionStarts.Pop();
Entities.EndRegionDirective.WriteRegionBlock(cx, start, endregion);
}
}
}

View File

@@ -655,5 +655,20 @@ namespace Semmle.Extraction.CSharp
{
trapFile.WriteTuple("directive_line_values", directive, line, file);
}
internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name)
{
trapFile.WriteTuple("directive_regions", directive, name);
}
internal static void directive_endregions(this TextWriter trapFile, EndRegionDirective directive)
{
trapFile.WriteTuple("directive_endregions", directive);
}
internal static void regions(this TextWriter trapFile, RegionDirective start, EndRegionDirective end)
{
trapFile.WriteTuple("regions", start, end);
}
}
}

View File

@@ -209,3 +209,30 @@ class NumericLineDirective extends LineDirective {
override string getAPrimaryQlClass() { result = "NumericLineDirective" }
}
/**
* A `#region` directive.
*/
class RegionDirective extends PreprocessorDirective, @directive_region {
/** Gets the name of this region. */
string getName() { directive_regions(this, result) }
/** Gets the closing `#endregion` directive. */
EndRegionDirective getEnd() { regions(this, result) }
override string toString() { result = "#region ..." }
override string getAPrimaryQlClass() { result = "RegionDirective" }
}
/**
* A `#endregion` directive.
*/
class EndRegionDirective extends PreprocessorDirective, @directive_endregion {
/** Gets the opening `#region` directive. */
RegionDirective getStart() { regions(result, this) }
override string toString() { result = "#endregion" }
override string getAPrimaryQlClass() { result = "EndRegionDirective" }
}

View File

@@ -332,7 +332,19 @@ using_directive_location(
int loc: @location ref);
@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
| @directive_error | @directive_nullable | @directive_line;
| @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion;
directive_regions(
unique int id: @directive_region,
string name: string ref);
directive_endregions(
unique int id: @directive_endregion);
#keyset[start, end]
regions(
unique int start: @directive_region ref,
unique int end: @directive_endregion ref);
directive_lines(
unique int id: @directive_line,

View File

@@ -0,0 +1,6 @@
regionDirectives
| trivia.cs:36:9:36:22 | #region ... | fields | trivia.cs:41:9:41:18 | #endregion |
| trivia.cs:38:9:38:22 | #region ... | nested | trivia.cs:40:9:40:18 | #endregion |
endregions
| trivia.cs:40:9:40:18 | #endregion | trivia.cs:38:9:38:22 | #region ... |
| trivia.cs:41:9:41:18 | #endregion | trivia.cs:36:9:36:22 | #region ... |

View File

@@ -0,0 +1,8 @@
import csharp
query predicate regionDirectives(RegionDirective d, string name, EndRegionDirective end) {
d.getName() = name and
d.getEnd() = end
}
query predicate endregions(EndRegionDirective d, RegionDirective start) { d.getStart() = start }