Extract pragma warning directives

This commit is contained in:
Tamas Vajk
2021-01-19 15:52:12 +01:00
parent 40186db768
commit 8b9c6712d1
10 changed files with 157 additions and 1 deletions

View File

@@ -380,6 +380,7 @@ namespace Semmle.Extraction.CSharp
var csNode = (CSharpSyntaxNode)root;
csNode.Accept(new CompilationUnitVisitor(cx));
csNode.Accept(new DirectiveVisitor(cx));
cx.PopulateAll();
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
cx.PopulateAll();

View File

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

View File

@@ -0,0 +1,43 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Entities;
using System.IO;
namespace Semmle.Extraction.CSharp.Entities
{
internal class PragmaWarningDirective : FreshEntity, IPreprocessorDirective
{
private readonly PragmaWarningDirectiveTriviaSyntax trivia;
public PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia)
: base(cx)
{
this.trivia = trivia;
TryPopulate();
}
protected override void Populate(TextWriter trapFile)
{
trapFile.pragma_warnings(this, trivia.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1);
var childIndex = 0;
foreach (var code in trivia.ErrorCodes)
{
trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++);
}
trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation));
if (!cx.Extractor.Standalone)
{
var assembly = Assembly.CreateOutputAssembly(cx);
trapFile.preprocessor_directive_assembly(this, assembly);
}
}
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation();
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Semmle.Extraction.CSharp.Populators
{
internal class DirectiveVisitor : CSharpSyntaxWalker
{
private readonly Context cx;
public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia)
{
this.cx = cx;
}
public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node)
{
new Entities.PragmaWarningDirective(cx, node);
}
}
}

View File

@@ -590,5 +590,25 @@ namespace Semmle.Extraction.CSharp
{
trapFile.WriteTuple("using_static_directives", @using, type);
}
internal static void preprocessor_directive_location(this TextWriter trapFile, IPreprocessorDirective directive, Location location)
{
trapFile.WriteTuple("preprocessor_directive_location", directive, location);
}
internal static void preprocessor_directive_assembly(this TextWriter trapFile, IPreprocessorDirective directive, Assembly assembly)
{
trapFile.WriteTuple("preprocessor_directive_assembly", directive, assembly);
}
internal static void pragma_warnings(this TextWriter trapFile, PragmaWarningDirective pragma, int kind)
{
trapFile.WriteTuple("pragma_warnings", pragma, kind);
}
internal static void pragma_warning_error_codes(this TextWriter trapFile, PragmaWarningDirective pragma, string errorCode, int child)
{
trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child);
}
}
}

View File

@@ -19,6 +19,7 @@ import semmle.code.csharp.Type
import semmle.code.csharp.Using
import semmle.code.csharp.Variable
import semmle.code.csharp.XML
import semmle.code.csharp.Preprocessor
import semmle.code.csharp.exprs.Access
import semmle.code.csharp.exprs.ArithmeticOperation
import semmle.code.csharp.exprs.Assignment

View File

@@ -0,0 +1,30 @@
/**
* Provides all preprocessor directive classes.
*/
import Element
class PreprocessorDirective extends Element, @preprocessor_directive {
override Location getALocation() { preprocessor_directive_location(this, result) }
}
/**
* A `#pragma warning` directive.
*/
class PragmaWarningDirective extends PreprocessorDirective, @pragma_warning {
/** Holds if this is a `#pragma warning restore` directive. */
predicate restore() { pragma_warnings(this, 1) }
/** Holds if this is a `#pragma warning disable` directive. */
predicate disable() { pragma_warnings(this, 0) }
/** Holds if this directive specifies error codes. */
predicate hasErrorCodes() { exists(string s | pragma_warning_error_codes(this, s, _)) }
/** Gets a specified error code from this directive. */
string getAnErrorCode() { pragma_warning_error_codes(this, result, _) }
override string toString() { result = "#pragma warning ..." }
override string getAPrimaryQlClass() { result = "PragmaWarningDirective" }
}

View File

@@ -217,7 +217,7 @@ tokens(
@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
| @using_directive | @type_parameter_constraints | @external_element
| @xmllocatable | @asp_element | @namespace;
| @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
@declaration = @callable | @generic | @assignable | @namespace;
@@ -331,6 +331,26 @@ using_directive_location(
unique int id: @using_directive ref,
int loc: @location ref);
@preprocessor_directive = @pragma_warning;
pragma_warnings(
unique int id: @pragma_warning,
int kind: int ref /* 0 = disable, 1 = restore */);
#keyset[id, index]
pragma_warning_error_codes(
int id: @pragma_warning ref,
string errorCode: string ref,
int index: int ref);
preprocessor_directive_location(
unique int id: @preprocessor_directive ref,
int loc: @location ref);
preprocessor_directive_assembly(
unique int id: @preprocessor_directive ref,
int loc: @assembly ref);
/** TYPES **/
types(

View File

@@ -0,0 +1,7 @@
disable
| trivia.cs:12:1:12:35 | #pragma warning ... |
restore
| trivia.cs:23:1:23:23 | #pragma warning ... |
errorCodes
| trivia.cs:12:1:12:35 | #pragma warning ... | 414 |
| trivia.cs:12:1:12:35 | #pragma warning ... | CS3021 |

View File

@@ -0,0 +1,9 @@
import csharp
query predicate disable(PragmaWarningDirective pragma) { pragma.disable() }
query predicate restore(PragmaWarningDirective pragma) { pragma.restore() }
query predicate errorCodes(PragmaWarningDirective pragma, string code) {
pragma.hasErrorCodes() and code = pragma.getAnErrorCode()
}