Merge pull request #11177 from github/redsun82/swift-decls

Swift: extract `PoundDiagnosticDecl` and `MissingMemberDecl`
This commit is contained in:
Paolo Tranquilli
2022-11-09 14:54:57 +01:00
committed by GitHub
17 changed files with 134 additions and 31 deletions

View File

@@ -0,0 +1,23 @@
#pragma once
#include <swift/AST/DiagnosticConsumer.h>
namespace codeql {
inline int translateDiagnosticsKind(swift::DiagnosticKind kind) {
using Kind = swift::DiagnosticKind;
switch (kind) {
case Kind::Error:
return 1;
case Kind::Warning:
return 2;
case Kind::Note:
return 3;
case Kind::Remark:
return 4;
default:
return 0;
}
}
} // namespace codeql

View File

@@ -1,6 +1,7 @@
#include "swift/extractor/invocation/SwiftDiagnosticsConsumer.h"
#include "swift/extractor/trap/generated/TrapEntries.h"
#include "swift/extractor/trap/TrapDomain.h"
#include "swift/extractor/infra/SwiftDiagnosticKind.h"
#include <swift/AST/DiagnosticEngine.h>
#include <swift/Basic/SourceManager.h>
@@ -10,26 +11,12 @@
using namespace codeql;
static int diagnosticsKind(const swift::DiagnosticInfo& diagInfo) {
switch (diagInfo.Kind) {
case swift::DiagnosticKind::Error:
return 1;
case swift::DiagnosticKind::Warning:
return 2;
case swift::DiagnosticKind::Note:
return 3;
case swift::DiagnosticKind::Remark:
return 4;
}
return 0;
}
void SwiftDiagnosticsConsumer::handleDiagnostic(swift::SourceManager& sourceManager,
const swift::DiagnosticInfo& diagInfo) {
auto message = getDiagMessage(sourceManager, diagInfo);
DiagnosticsTrap diag{};
diag.id = trap.createLabel<DiagnosticsTag>();
diag.kind = diagnosticsKind(diagInfo);
diag.kind = translateDiagnosticsKind(diagInfo.Kind);
diag.text = message;
trap.emit(diag);
locationExtractor.attachLocation(sourceManager, diagInfo.Loc, diagInfo.Loc, diag.id);

View File

@@ -2,6 +2,7 @@
#include <swift/AST/GenericParamList.h>
#include <swift/AST/ParameterList.h>
#include "swift/extractor/infra/SwiftDiagnosticKind.h"
namespace codeql {
namespace {
@@ -401,4 +402,18 @@ std::optional<codeql::OpaqueTypeDecl> DeclTranslator::translateOpaqueTypeDecl(
return std::nullopt;
}
codeql::PoundDiagnosticDecl DeclTranslator::translatePoundDiagnosticDecl(
const swift::PoundDiagnosticDecl& decl) {
auto entry = createEntry(decl);
entry.kind = translateDiagnosticsKind(decl.getKind());
entry.message = dispatcher.fetchLabel(decl.getMessage());
return entry;
}
codeql::MissingMemberDecl DeclTranslator::translateMissingMemberDecl(
const swift::MissingMemberDecl& decl) {
auto entry = createEntry(decl);
entry.name = decl.getName().getBaseName().userFacingName().str();
return entry;
}
} // namespace codeql

View File

@@ -46,6 +46,8 @@ class DeclTranslator : public AstTranslatorBase<DeclTranslator> {
std::optional<codeql::ModuleDecl> translateModuleDecl(const swift::ModuleDecl& decl);
codeql::IfConfigDecl translateIfConfigDecl(const swift::IfConfigDecl& decl);
std::optional<codeql::OpaqueTypeDecl> translateOpaqueTypeDecl(const swift::OpaqueTypeDecl& decl);
codeql::PoundDiagnosticDecl translatePoundDiagnosticDecl(const swift::PoundDiagnosticDecl& decl);
codeql::MissingMemberDecl translateMissingMemberDecl(const swift::MissingMemberDecl& decl);
private:
std::string mangledName(const swift::ValueDecl& decl);

View File

@@ -1,4 +1,5 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.decl.MissingMemberDecl
class MissingMemberDecl extends Generated::MissingMemberDecl { }
class MissingMemberDecl extends Generated::MissingMemberDecl {
override string toString() { result = this.getName() + " (missing)" }
}

View File

@@ -2,6 +2,12 @@ private import codeql.swift.generated.decl.PoundDiagnosticDecl
class PoundDiagnosticDecl extends Generated::PoundDiagnosticDecl {
override string toString() {
result = "#..." // TODO: Once we extract whether this is an error or a warning we can improve this.
this.isError() and result = "#error(...)"
or
this.isWarning() and result = "#warning(...)"
}
predicate isError() { this.getKind() = 1 }
predicate isWarning() { this.getKind() = 2 }
}

View File

@@ -373,14 +373,17 @@ private module Impl {
private Element getImmediateChildOfPoundDiagnosticDecl(
PoundDiagnosticDecl e, int index, string partialPredicateCall
) {
exists(int b, int bDecl, int n |
exists(int b, int bDecl, int n, int nMessage |
b = 0 and
bDecl = b + 1 + max(int i | i = -1 or exists(getImmediateChildOfDecl(e, i, _)) | i) and
n = bDecl and
nMessage = n + 1 and
(
none()
or
result = getImmediateChildOfDecl(e, index - b, partialPredicateCall)
or
index = n and result = e.getImmediateMessage() and partialPredicateCall = "Message()"
)
)
}

View File

@@ -115,6 +115,8 @@ module Raw {
class MissingMemberDecl extends @missing_member_decl, Decl {
override string toString() { result = "MissingMemberDecl" }
string getName() { missing_member_decls(this, result) }
}
class OperatorDecl extends @operator_decl, Decl {
@@ -131,6 +133,10 @@ module Raw {
class PoundDiagnosticDecl extends @pound_diagnostic_decl, Decl {
override string toString() { result = "PoundDiagnosticDecl" }
int getKind() { pound_diagnostic_decls(this, result, _) }
StringLiteralExpr getMessage() { pound_diagnostic_decls(this, _, result) }
}
class PrecedenceGroupDecl extends @precedence_group_decl, Decl {

View File

@@ -4,7 +4,17 @@ private import codeql.swift.generated.Raw
import codeql.swift.elements.decl.Decl
module Generated {
/**
* A placeholder for missing declarations that can arise on object deserialization.
*/
class MissingMemberDecl extends Synth::TMissingMemberDecl, Decl {
override string getAPrimaryQlClass() { result = "MissingMemberDecl" }
/**
* Gets the name of this missing member declaration.
*/
string getName() {
result = Synth::convertMissingMemberDeclToRaw(this).(Raw::MissingMemberDecl).getName()
}
}
}

View File

@@ -2,9 +2,38 @@
private import codeql.swift.generated.Synth
private import codeql.swift.generated.Raw
import codeql.swift.elements.decl.Decl
import codeql.swift.elements.expr.StringLiteralExpr
module Generated {
/**
* A diagnostic directive, which is either `#error` or `#warning`.
*/
class PoundDiagnosticDecl extends Synth::TPoundDiagnosticDecl, Decl {
override string getAPrimaryQlClass() { result = "PoundDiagnosticDecl" }
/**
* Gets the This is 1 for `#error` and 2 for `#warning`.
*/
int getKind() {
result = Synth::convertPoundDiagnosticDeclToRaw(this).(Raw::PoundDiagnosticDecl).getKind()
}
/**
* Gets the message of this pound diagnostic declaration.
*
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
* behavior of both the `Immediate` and non-`Immediate` versions.
*/
StringLiteralExpr getImmediateMessage() {
result =
Synth::convertStringLiteralExprFromRaw(Synth::convertPoundDiagnosticDeclToRaw(this)
.(Raw::PoundDiagnosticDecl)
.getMessage())
}
/**
* Gets the message of this pound diagnostic declaration.
*/
final StringLiteralExpr getMessage() { result = getImmediateMessage().resolve() }
}
}

View File

@@ -254,7 +254,8 @@ import_decl_declarations( //dir=decl
);
missing_member_decls( //dir=decl
unique int id: @missing_member_decl
unique int id: @missing_member_decl,
string name: string ref
);
@operator_decl =
@@ -288,7 +289,9 @@ pattern_binding_decl_patterns( //dir=decl
);
pound_diagnostic_decls( //dir=decl
unique int id: @pound_diagnostic_decl
unique int id: @pound_diagnostic_decl,
int kind: int ref,
int message: @string_literal_expr_or_none ref
);
precedence_group_decls( //dir=decl
@@ -2450,6 +2453,11 @@ variadic_sequence_types( //dir=type
| @unspecified_element
;
@string_literal_expr_or_none =
@string_literal_expr
| @unspecified_element
;
@tap_expr_or_none =
@tap_expr
| @unspecified_element

View File

@@ -1,4 +0,0 @@
// generated by codegen/codegen.py
After a swift source file is added in this directory and codegen/codegen.py is run again, test queries
will appear and this file will be deleted

View File

@@ -1,4 +0,0 @@
// generated by codegen/codegen.py
After a swift source file is added in this directory and codegen/codegen.py is run again, test queries
will appear and this file will be deleted

View File

@@ -0,0 +1,2 @@
| diagnostics.swift:2:1:2:25 | #warning(...) | getModule: | file://:0:0:0:0 | diagnostics | getKind: | 2 | getMessage: | diagnostics.swift:2:10:2:10 | I'm a warning |
| diagnostics.swift:3:1:3:26 | #error(...) | getModule: | file://:0:0:0:0 | diagnostics | getKind: | 1 | getMessage: | diagnostics.swift:3:8:3:8 | And I'm an error |

View File

@@ -0,0 +1,12 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from PoundDiagnosticDecl x, ModuleDecl getModule, int getKind, StringLiteralExpr getMessage
where
toBeTested(x) and
not x.isUnknown() and
getModule = x.getModule() and
getKind = x.getKind() and
getMessage = x.getMessage()
select x, "getModule:", getModule, "getKind:", getKind, "getMessage:", getMessage

View File

@@ -0,0 +1,3 @@
//codeql-extractor-expected-status: 1
#warning("I'm a warning")
#error("And I'm an error")

View File

@@ -112,8 +112,10 @@ class ImportDecl(Decl):
imported_module: optional["ModuleDecl"]
declarations: list["ValueDecl"]
@qltest.skip
class MissingMemberDecl(Decl):
pass
"""A placeholder for missing declarations that can arise on object deserialization."""
name: string
class OperatorDecl(Decl):
name: string
@@ -123,7 +125,9 @@ class PatternBindingDecl(Decl):
patterns: list[Pattern] | child
class PoundDiagnosticDecl(Decl):
pass
""" A diagnostic directive, which is either `#error` or `#warning`."""
kind: int | doc("""This is 1 for `#error` and 2 for `#warning`""")
message: "StringLiteralExpr" | child
class PrecedenceGroupDecl(Decl):
pass