mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge branch 'main' into rdmarsh2/cpp/input-iterators-1Merge changes to input/output models for functions that return thisand resolve conflicting changes to taint tests.
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
- [yargs](https://www.npmjs.com/package/yargs)
|
||||
- [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server)
|
||||
|
||||
* TypeScript 3.9 is now supported.
|
||||
* TypeScript 4.0 is now supported.
|
||||
|
||||
* TypeScript code embedded in HTML and Vue files is now extracted and analyzed.
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ The following changes in version 1.26 affect C# analysis in all applications.
|
||||
## Changes to code extraction
|
||||
|
||||
* Partial method bodies are extracted. Previously, partial method bodies were skipped completely.
|
||||
* Inferring the lengths of implicitely sized arrays is fixed. Previously, multidimensional arrays were always extracted with the same length for
|
||||
each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted.
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
|
||||
| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. |
|
||||
| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. |
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
22
change-notes/1.26/analysis-python.md
Normal file
22
change-notes/1.26/analysis-python.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Improvements to Python analysis
|
||||
|
||||
The following changes in version 1.26 affect Python analysis in all applications.
|
||||
|
||||
## General improvements
|
||||
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
|
||||
|
||||
## Changes to libraries
|
||||
|
||||
* Added taint tracking support for string formatting through f-strings.
|
||||
@@ -325,6 +325,10 @@
|
||||
"csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
|
||||
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
|
||||
],
|
||||
"Inline Test Expectations": [
|
||||
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
||||
],
|
||||
"XML": [
|
||||
"cpp/ql/src/semmle/code/cpp/XML.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/XML.qll",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
void test(char *arg1, int *arg2) {
|
||||
if (arg1[0] == 'A') {
|
||||
if (arg2 != NULL) { //maybe redundant
|
||||
*arg2 = 42;
|
||||
}
|
||||
}
|
||||
if (arg1[1] == 'B')
|
||||
{
|
||||
*arg2 = 54; //dereferenced without checking first
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's
|
||||
likely either the check is not required and can be removed, or it should be added before the dereference
|
||||
so that a null pointer dereference does not occur.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A check should be added to before the dereference, in a way that prevents a null pointer value from
|
||||
being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src="RedundantNullCheckParam.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://www.owasp.org/index.php/Null_Dereference">
|
||||
Null Dereference
|
||||
</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @name Redundant null check or missing null check of parameter
|
||||
* @description Checking a parameter for nullness in one path,
|
||||
* and not in another is likely to be a sign that either
|
||||
* the check can be removed, or added in the other case.
|
||||
* @kind problem
|
||||
* @id cpp/redundant-null-check-param
|
||||
* @problem.severity recommendation
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-476
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate blockDominates(Block check, Block access) {
|
||||
check.getLocation().getStartLine() <= access.getLocation().getStartLine() and
|
||||
check.getLocation().getEndLine() >= access.getLocation().getEndLine()
|
||||
}
|
||||
|
||||
predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) {
|
||||
checked = any(VariableAccess va | va.getTarget() = unchecked.getTarget()) and
|
||||
//Simple test if the first access in this code path is dereferenced
|
||||
not dereferenced(checked) and
|
||||
blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock())
|
||||
}
|
||||
|
||||
predicate candidateResultUnchecked(VariableAccess unchecked) {
|
||||
not isCheckedInstruction(unchecked, _)
|
||||
}
|
||||
|
||||
predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) {
|
||||
//not dereferenced to check against pointer, not its pointed value
|
||||
not dereferenced(check) and
|
||||
//assert macros are not taken into account
|
||||
not check.isInMacroExpansion() and
|
||||
// is part of a comparison against some constant NULL
|
||||
eqop.getAnOperand() = check and
|
||||
eqop.getAnOperand() instanceof NullValue
|
||||
}
|
||||
|
||||
from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param
|
||||
where
|
||||
// a dereference
|
||||
dereferenced(unchecked) and
|
||||
// for a function parameter
|
||||
unchecked.getTarget() = param and
|
||||
// this function parameter is not overwritten
|
||||
count(param.getAnAssignment()) = 0 and
|
||||
check.getTarget() = param and
|
||||
// which is once checked
|
||||
candidateResultChecked(check, eqop) and
|
||||
// and which has not been checked before in this code path
|
||||
candidateResultUnchecked(unchecked)
|
||||
select check, "This null check is redundant or there is a missing null check before $@ ", unchecked,
|
||||
"where dereferencing happens"
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -484,6 +484,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
// Assignment -> LValue post-update node
|
||||
//
|
||||
// This is used for assignments whose left-hand side is not a variable
|
||||
// assignment or a storeStep but is still modeled by other means. It could be
|
||||
// a call to `operator*` or `operator[]` where taint should flow to the
|
||||
// post-update node of the qualifier.
|
||||
exists(AssignExpr assign |
|
||||
nodeFrom.asExpr() = assign and
|
||||
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() = assign.getLValue()
|
||||
)
|
||||
or
|
||||
// Node -> FlowVar -> VariableAccess
|
||||
exists(FlowVar var |
|
||||
(
|
||||
|
||||
@@ -82,6 +82,19 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
|
||||
or
|
||||
// Reverse taint: taint that flows from the post-update node of a reference
|
||||
// returned by a function call, back into the qualifier of that function.
|
||||
// This allows taint to flow 'in' through references returned by a modeled
|
||||
// function such as `operator[]`.
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
inModel.isReturnValueDeref() and
|
||||
outModel.isQualifierObject() and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = call and
|
||||
nodeTo.asDefiningArgument() = call.getQualifier()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -14,10 +14,7 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
*/
|
||||
class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
StdSequenceContainerConstructor() {
|
||||
this.getDeclaringType().hasQualifiedName("std", "vector") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "deque") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "list") or
|
||||
this.getDeclaringType().hasQualifiedName("std", "forward_list")
|
||||
this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +23,7 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector<T>`
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -36,16 +33,32 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `data`.
|
||||
*/
|
||||
class StdSequenceContainerData extends TaintFunction {
|
||||
StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from container itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends TaintFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.hasQualifiedName("std", "vector", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_back") or
|
||||
this.hasQualifiedName("std", "deque", "push_front") or
|
||||
this.hasQualifiedName("std", "list", "push_back") or
|
||||
this.hasQualifiedName("std", "list", "push_front") or
|
||||
this.hasQualifiedName("std", "deque", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "list", ["push_back", "push_front"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "push_front")
|
||||
}
|
||||
|
||||
@@ -61,14 +74,10 @@ class StdSequenceContainerPush extends TaintFunction {
|
||||
*/
|
||||
class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.hasQualifiedName("std", "array", "front") or
|
||||
this.hasQualifiedName("std", "array", "back") or
|
||||
this.hasQualifiedName("std", "vector", "front") or
|
||||
this.hasQualifiedName("std", "vector", "back") or
|
||||
this.hasQualifiedName("std", "deque", "front") or
|
||||
this.hasQualifiedName("std", "deque", "back") or
|
||||
this.hasQualifiedName("std", "list", "front") or
|
||||
this.hasQualifiedName("std", "list", "back") or
|
||||
this.hasQualifiedName("std", "array", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "vector", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "deque", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "list", ["front", "back"]) or
|
||||
this.hasQualifiedName("std", "forward_list", "front")
|
||||
}
|
||||
|
||||
@@ -79,16 +88,36 @@ class StdSequenceContainerFrontBack extends TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container function `assign`.
|
||||
*/
|
||||
class StdSequenceContainerAssign extends TaintFunction {
|
||||
StdSequenceContainerAssign() {
|
||||
this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a reference to the
|
||||
* value type of the container.
|
||||
*/
|
||||
int getAValueTypeParameterIndex() {
|
||||
getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAValueTypeParameterIndex()) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container `swap` functions.
|
||||
*/
|
||||
class StdSequenceContainerSwap extends TaintFunction {
|
||||
StdSequenceContainerSwap() {
|
||||
this.hasQualifiedName("std", "array", "swap") or
|
||||
this.hasQualifiedName("std", "vector", "swap") or
|
||||
this.hasQualifiedName("std", "deque", "swap") or
|
||||
this.hasQualifiedName("std", "list", "swap") or
|
||||
this.hasQualifiedName("std", "forward_list", "swap")
|
||||
this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "swap")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -100,3 +129,22 @@ class StdSequenceContainerSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends TaintFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"])
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,33 @@ class StdBasicString extends TemplateClass {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `c_str` and `data`.
|
||||
* The `std::string` function `c_str`.
|
||||
*/
|
||||
class StdStringCStr extends TaintFunction {
|
||||
StdStringCStr() {
|
||||
this.hasQualifiedName("std", "basic_string", "c_str") or
|
||||
this.hasQualifiedName("std", "basic_string", "data")
|
||||
}
|
||||
StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `data`.
|
||||
*/
|
||||
class StdStringData extends TaintFunction {
|
||||
StdStringData() { this.hasQualifiedName("std", "basic_string", "data") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string itself (qualifier) to return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// `data`)
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,33 +71,31 @@ class StdStringPlus extends TaintFunction {
|
||||
*/
|
||||
class StdStringAppend extends TaintFunction {
|
||||
StdStringAppend() {
|
||||
this.hasQualifiedName("std", "basic_string", "operator+=") or
|
||||
this.hasQualifiedName("std", "basic_string", "append") or
|
||||
this.hasQualifiedName("std", "basic_string", "insert") or
|
||||
this.hasQualifiedName("std", "basic_string", "replace")
|
||||
this.hasQualifiedName("std", "basic_string", ["operator+=", "append", "insert", "replace"])
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameter() { getParameter(result).getType() instanceof Iterator }
|
||||
int getAnIteratorParameterIndex() { getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(getAStringParameter()) or
|
||||
input.isParameter(getAnIteratorParameter())
|
||||
input.isParameterDeref(getAStringParameterIndex()) or
|
||||
input.isParameter(getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
@@ -101,15 +114,16 @@ class StdStringAssign extends TaintFunction {
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameter() {
|
||||
int getAStringParameterIndex() {
|
||||
getParameter(result).getType() instanceof PointerType or
|
||||
getParameter(result).getType() instanceof ReferenceType or
|
||||
getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT`
|
||||
getParameter(result).getUnspecifiedType() =
|
||||
getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
input.isParameterDeref(getAStringParameter()) and
|
||||
input.isParameterDeref(getAStringParameterIndex()) and
|
||||
(
|
||||
output.isQualifierObject() or
|
||||
output.isReturnValueDeref()
|
||||
@@ -180,3 +194,20 @@ class StdStringSwap extends TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdStringAt extends TaintFunction {
|
||||
StdStringAt() { this.hasQualifiedName("std", "basic_string", ["at", "operator[]"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ private newtype TFunctionInput =
|
||||
TInParameter(ParameterIndex i) or
|
||||
TInParameterDeref(ParameterIndex i) or
|
||||
TInQualifierObject() or
|
||||
TInQualifierAddress()
|
||||
TInQualifierAddress() or
|
||||
TInReturnValueDeref()
|
||||
|
||||
/**
|
||||
* An input to a function. This can be:
|
||||
@@ -106,6 +107,31 @@ class FunctionInput extends TFunctionInput {
|
||||
* (with type `C const *`) on entry to the function.
|
||||
*/
|
||||
predicate isQualifierAddress() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by the return value of a
|
||||
* function, if the function returns a pointer, or the input value referred
|
||||
* to by the return value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `*getPointer()` (with type `char`).
|
||||
* - `isReturnValueDeref()` holds for the `FunctionInput` that represents the
|
||||
* value of `getReference()` (with type `float`).
|
||||
* - There is no `FunctionInput` of `getInt()` for which
|
||||
* `isReturnValueDeref()` holds because the return type of `getInt()` is
|
||||
* neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
predicate isReturnValueDeref() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +225,34 @@ class InQualifierAddress extends FunctionInput, TInQualifierAddress {
|
||||
override predicate isQualifierAddress() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The input value pointed to by the return value of a function, if the
|
||||
* function returns a pointer, or the input value referred to by the return
|
||||
* value of a function, if the function returns a reference.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* char* getPointer();
|
||||
* float& getReference();
|
||||
* int getInt();
|
||||
* ```
|
||||
* - `InReturnValueDeref` represents the value of `*getPointer()` (with type
|
||||
* `char`).
|
||||
* - `InReturnValueDeref` represents the value of `getReference()` (with type
|
||||
* `float`).
|
||||
* - `InReturnValueDeref` does not represent the return value of `getInt()`
|
||||
* because the return type of `getInt()` is neither a pointer nor a reference.
|
||||
*
|
||||
* Note that data flows in through function return values are relatively
|
||||
* rare, but they do occur when a function returns a reference to itself,
|
||||
* part of itself, or one of its other inputs.
|
||||
*/
|
||||
class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
||||
override string toString() { result = "InReturnValueDeref" }
|
||||
|
||||
override predicate isReturnValueDeref() { any() }
|
||||
}
|
||||
|
||||
private newtype TFunctionOutput =
|
||||
TOutParameterDeref(ParameterIndex i) or
|
||||
TOutQualifierObject() or
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
* Provides a library for writing QL tests whose success or failure is based on expected results
|
||||
* embedded in the test source code as comments, rather than a `.expected` file.
|
||||
*
|
||||
* To add this framework to a new language:
|
||||
* - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class
|
||||
* must support a `getContents` method that returns the contents of the given comment, _excluding_
|
||||
* the comment indicator itself. It should also define `toString` and `getLocation` as usual.
|
||||
*
|
||||
* To create a new inline expectations test:
|
||||
* - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the
|
||||
* new class, bind `this` to a unique string (usually the name of the test).
|
||||
@@ -13,7 +18,7 @@
|
||||
* `hasActualResult()`. Often this is just a single tag.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```ql
|
||||
* class ConstantValueTest extends InlineExpectationsTest {
|
||||
* ConstantValueTest() { this = "ConstantValueTest" }
|
||||
*
|
||||
@@ -23,11 +28,11 @@
|
||||
* }
|
||||
*
|
||||
* override predicate hasActualResult(
|
||||
* Location location, string element, string tag, string valuesasas
|
||||
* Location location, string element, string tag, string value
|
||||
* ) {
|
||||
* exists(Expr e |
|
||||
* tag = "const" and // The tag for this test.
|
||||
* valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* value = e.getValue() and // The expected value. Will only hold for constant expressions.
|
||||
* location = e.getLocation() and // The location of the result to be reported.
|
||||
* element = e.toString() // The display text for the result.
|
||||
* )
|
||||
@@ -38,10 +43,10 @@
|
||||
* There is no need to write a `select` clause or query predicate. All of the differences between
|
||||
* expected results and actual results will be reported in the `failures()` query predicate.
|
||||
*
|
||||
* To annotate the test source code with an expected result, place a C++-style (`//`) comment on the
|
||||
* To annotate the test source code with an expected result, place a comment on the
|
||||
* same line as the expected result, with text of the following format as the body of the comment:
|
||||
*
|
||||
* `// $tag=expected-value`
|
||||
* `$tag=expected-value`
|
||||
*
|
||||
* Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is
|
||||
* the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be
|
||||
@@ -53,7 +58,7 @@
|
||||
* "Missing result: tag=expected-value".
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* ```cpp
|
||||
* int i = x + 5; // $const=5
|
||||
* int j = y + (7 - 3) // $const=7 $const=3 $const=4 // The result of the subtraction is a constant.
|
||||
* ```
|
||||
@@ -62,8 +67,8 @@
|
||||
* annotate that a particular expected result is known to be a false positive, or that a particular
|
||||
* missing result is known to be a false negative:
|
||||
*
|
||||
* `// $f+:tag=expected-value` // False positive
|
||||
* `// $f-:tag=expected-value` // False negative
|
||||
* `$f+:tag=expected-value` // False positive
|
||||
* `$f-:tag=expected-value` // False negative
|
||||
*
|
||||
* A false positive expectation is treated as any other expected result, except that if there is no
|
||||
* matching actual result, the message will be of the form "Fixed false positive: tag=value". A
|
||||
@@ -74,14 +79,14 @@
|
||||
* If the same result value is expected for two or more tags on the same line, there is a shorthand
|
||||
* notation available:
|
||||
*
|
||||
* `// $tag1,tag2=expected-value`
|
||||
* `$tag1,tag2=expected-value`
|
||||
*
|
||||
* is equivalent to:
|
||||
*
|
||||
* `// $tag1=expected-value $tag2=expected-value`
|
||||
* `$tag1=expected-value $tag2=expected-value`
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import InlineExpectationsTestPrivate
|
||||
|
||||
/**
|
||||
* Base class for tests with inline expectations. The test extends this class to provide the actual
|
||||
@@ -150,12 +155,12 @@ abstract class InlineExpectationsTest extends string {
|
||||
}
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must be a
|
||||
* C++-style (`//`) comment with `$` as its first non-whitespace character. Any subsequent character
|
||||
* RegEx pattern to match a comment containing one or more expected results. The comment must have
|
||||
* `$` as its first non-whitespace character. Any subsequent character
|
||||
* is treated as part of the expected results, except that the comment may contain a `//` sequence
|
||||
* to treat the remainder of the line as a regular (non-interpreted) comment.
|
||||
*/
|
||||
private string expectationCommentPattern() { result = "//\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
private string expectationCommentPattern() { result = "\\s*(\\$(?:[^/]|/[^/])*)(?://.*)?" }
|
||||
|
||||
/**
|
||||
* RegEx pattern to match a single expected result, not including the leading `$`. It starts with an
|
||||
@@ -166,7 +171,7 @@ private string expectationPattern() {
|
||||
result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?"
|
||||
}
|
||||
|
||||
private string getAnExpectation(CppStyleComment comment) {
|
||||
private string getAnExpectation(LineComment comment) {
|
||||
result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and
|
||||
result != ""
|
||||
}
|
||||
@@ -177,7 +182,7 @@ private newtype TFailureLocatable =
|
||||
) {
|
||||
test.hasActualResult(location, element, tag, value)
|
||||
} or
|
||||
TValidExpectation(CppStyleComment comment, string tag, string value, string knownFailure) {
|
||||
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
|
||||
exists(string expectation |
|
||||
expectation = getAnExpectation(comment) and
|
||||
expectation.regexpMatch(expectationPattern()) and
|
||||
@@ -194,7 +199,7 @@ private newtype TFailureLocatable =
|
||||
)
|
||||
)
|
||||
} or
|
||||
TInvalidExpectation(CppStyleComment comment, string expectation) {
|
||||
TInvalidExpectation(LineComment comment, string expectation) {
|
||||
expectation = getAnExpectation(comment) and
|
||||
not expectation.regexpMatch(expectationPattern())
|
||||
}
|
||||
@@ -232,7 +237,7 @@ class ActualResult extends FailureLocatable, TActualResult {
|
||||
}
|
||||
|
||||
abstract private class Expectation extends FailureLocatable {
|
||||
CppStyleComment comment;
|
||||
LineComment comment;
|
||||
|
||||
override string toString() { result = comment.toString() }
|
||||
|
||||
|
||||
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
23
cpp/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll
Normal file
@@ -0,0 +1,23 @@
|
||||
import cpp
|
||||
|
||||
private newtype TLineComment = MkLineComment(CppStyleComment c)
|
||||
|
||||
/**
|
||||
* Represents a line comment in the CPP style.
|
||||
* Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_
|
||||
* include the preceding comment marker (`//`).
|
||||
*/
|
||||
class LineComment extends TLineComment {
|
||||
CppStyleComment comment;
|
||||
|
||||
LineComment() { this = MkLineComment(comment) }
|
||||
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = comment.getContents().suffix(2) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = comment.toString() }
|
||||
|
||||
/** Gets the location of this comment. */
|
||||
Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
@@ -14,7 +14,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. |
|
||||
| lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -29,5 +29,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
| example.c:17:19:17:22 | {...} | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:2:24:7 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:2:24:30 | ... = ... | example.c:24:9:24:9 | x [post update] |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:24:2:24:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:2:26:7 | coords |
|
||||
| example.c:24:13:24:18 | coords [post update] | example.c:26:19:26:24 | coords |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:2:24:30 | ... = ... |
|
||||
| example.c:24:13:24:30 | ... = ... | example.c:24:20:24:20 | y [post update] |
|
||||
| example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... |
|
||||
| example.c:26:2:26:25 | ... = ... | example.c:26:9:26:9 | x [post update] |
|
||||
| example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords |
|
||||
| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] |
|
||||
|
||||
@@ -16,7 +16,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
| A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -23,5 +23,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
|
||||
int source();
|
||||
void sink(int);
|
||||
void sink(class MyInt);
|
||||
void sink(class MyArray);
|
||||
|
||||
void test_pointer_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int *p2_x = &x;
|
||||
int &r_x = x;
|
||||
|
||||
*p_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p2_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
void test_reference_deref_assignment()
|
||||
{
|
||||
int x = 0;
|
||||
int *p_x = &x;
|
||||
int &r_x = x;
|
||||
int &r2_x = x;
|
||||
|
||||
r_x = source();
|
||||
|
||||
sink(x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(*p_x); // tainted [DETECTED BY IR ONLY]
|
||||
sink(r_x); // tainted
|
||||
sink(r2_x); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
|
||||
class MyInt
|
||||
{
|
||||
public:
|
||||
MyInt() : i(0) {}
|
||||
|
||||
int &get() { return i; }
|
||||
|
||||
MyInt &operator=(const int &other);
|
||||
MyInt &operator=(const MyInt &other);
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
void test_myint_member_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.i = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_method_assignment()
|
||||
{
|
||||
MyInt mi;
|
||||
|
||||
mi.get() = source();
|
||||
|
||||
sink(mi); // tainted [DETECTED BY IR ONLY]
|
||||
sink(mi.get()); // tainted
|
||||
}
|
||||
|
||||
void test_myint_overloaded_assignment()
|
||||
{
|
||||
MyInt mi, mi2;
|
||||
|
||||
mi = source();
|
||||
mi2 = mi;
|
||||
|
||||
sink(mi); // tainted [NOT DETECTED]
|
||||
sink(mi.get()); // tainted [NOT DETECTED]
|
||||
sink(mi2); // tainted [NOT DETECTED]
|
||||
sink(mi2.get()); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
class MyArray
|
||||
{
|
||||
public:
|
||||
MyArray() : values({0}) {}
|
||||
|
||||
int &get(int i) { return values[i]; }
|
||||
|
||||
int &operator[](int i);
|
||||
|
||||
int values[10];
|
||||
};
|
||||
|
||||
void test_myarray_member_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.values[0] = source();
|
||||
|
||||
sink(ma.values[0]); // tainted
|
||||
}
|
||||
|
||||
void test_myarray_method_assignment()
|
||||
{
|
||||
MyArray ma;
|
||||
|
||||
ma.get(0) = source();
|
||||
|
||||
sink(ma.get(0)); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void test_myarray_overloaded_assignment()
|
||||
{
|
||||
MyArray ma, ma2;
|
||||
|
||||
ma[0] = source();
|
||||
ma2 = ma;
|
||||
|
||||
sink(ma[0]); // tainted [NOT DETECTED]
|
||||
sink(ma2[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_array_reference_assignment()
|
||||
{
|
||||
int arr1[10] = {0};
|
||||
int arr2[10] = {0};
|
||||
int arr3[10] = {0};
|
||||
int &ref1 = arr1[5];
|
||||
int *ptr2, *ptr3;
|
||||
|
||||
ref1 = source();
|
||||
sink(ref1); // tainted
|
||||
sink(arr1[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr2 = &(arr2[5]);
|
||||
*ptr2 = source();
|
||||
sink(*ptr2); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr2[5]); // tainted [DETECTED BY IR ONLY]
|
||||
|
||||
ptr3 = arr3;
|
||||
ptr3[5] = source();
|
||||
sink(ptr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
sink(arr3[5]); // tainted [DETECTED BY IR ONLY]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,12 +8,14 @@ namespace std {
|
||||
|
||||
template<class I> struct iterator_traits;
|
||||
|
||||
template <class iterator_category,
|
||||
template <class Category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
typedef Category iterator_category;
|
||||
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
iterator &operator--();
|
||||
@@ -53,6 +55,9 @@ namespace std
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
using value_type = charT;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
typedef typename Allocator::size_type size_type;
|
||||
static const size_type npos = -1;
|
||||
|
||||
@@ -73,6 +78,10 @@ namespace std
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
const_reference operator[](size_type pos) const;
|
||||
reference operator[](size_type pos);
|
||||
const_reference at(size_type n) const;
|
||||
reference at(size_type n);
|
||||
template<class T> basic_string& operator+=(const T& t);
|
||||
basic_string& operator+=(const charT* s);
|
||||
basic_string& append(const basic_string& str);
|
||||
@@ -152,6 +161,10 @@ namespace std {
|
||||
|
||||
vector& operator=(const vector& x);
|
||||
vector& operator=(vector&& x) noexcept/*(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value)*/;
|
||||
template<class InputIterator, class IteratorCategory = typename InputIterator::iterator_category> void assign(InputIterator first, InputIterator last);
|
||||
// use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or
|
||||
// similar that should match a different overload (SFINAE).
|
||||
void assign(size_type n, const T& u);
|
||||
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
|
||||
@@ -322,6 +322,33 @@ void test_string_substr()
|
||||
sink(b.substr(0, b.length())); // tainted
|
||||
}
|
||||
|
||||
void test_string_at()
|
||||
{
|
||||
std::string a("123");
|
||||
std::string b("123");
|
||||
std::string c("123");
|
||||
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c);
|
||||
|
||||
a[0] = ns_char::source();
|
||||
b.at(0) = ns_char::source();
|
||||
c[0] = a[0];
|
||||
|
||||
sink(a); // tainted
|
||||
sink(b); // tainted
|
||||
sink(c); // tainted
|
||||
}
|
||||
|
||||
void test_string_data_more()
|
||||
{
|
||||
std::string str("123");
|
||||
|
||||
str.data()[1] = ns_char::source();
|
||||
sink(str); // tainted
|
||||
sink(str.data()); // tainted
|
||||
}
|
||||
void test_string_iterators() {
|
||||
// string append
|
||||
{
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
| copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source |
|
||||
| copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source |
|
||||
@@ -98,19 +103,24 @@
|
||||
| string.cpp:302:7:302:8 | s3 | string.cpp:290:17:290:22 | call to source |
|
||||
| string.cpp:311:9:311:12 | call to data | string.cpp:308:16:308:21 | call to source |
|
||||
| string.cpp:322:9:322:14 | call to substr | string.cpp:319:16:319:21 | call to source |
|
||||
| string.cpp:334:11:334:16 | call to append | string.cpp:329:18:329:23 | call to source |
|
||||
| string.cpp:335:8:335:9 | s1 | string.cpp:329:18:329:23 | call to source |
|
||||
| string.cpp:353:8:353:8 | call to operator* | string.cpp:345:18:345:23 | call to source |
|
||||
| string.cpp:354:13:354:13 | call to operator[] | string.cpp:345:18:345:23 | call to source |
|
||||
| string.cpp:367:8:367:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:368:8:368:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:370:8:370:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:372:8:372:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:375:8:375:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:378:8:378:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:382:8:382:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:386:8:386:8 | call to operator* | string.cpp:360:18:360:23 | call to source |
|
||||
| string.cpp:339:7:339:7 | a | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:340:7:340:7 | b | string.cpp:336:12:336:26 | call to source |
|
||||
| string.cpp:341:7:341:7 | c | string.cpp:335:9:335:23 | call to source |
|
||||
| string.cpp:349:7:349:9 | str | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:350:11:350:14 | call to data | string.cpp:348:18:348:32 | call to source |
|
||||
| string.cpp:361:11:361:16 | call to append | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:362:8:362:9 | s1 | string.cpp:356:18:356:23 | call to source |
|
||||
| string.cpp:380:8:380:8 | call to operator* | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:381:13:381:13 | call to operator[] | string.cpp:372:18:372:23 | call to source |
|
||||
| string.cpp:394:8:394:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:395:8:395:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:397:8:397:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:399:8:399:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:402:8:402:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:405:8:405:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:407:8:407:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:409:8:409:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| string.cpp:413:8:413:8 | call to operator* | string.cpp:387:18:387:23 | call to source |
|
||||
| structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
| structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source |
|
||||
| structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source |
|
||||
@@ -220,9 +230,27 @@
|
||||
| vector.cpp:20:8:20:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:28:8:28:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:33:8:33:8 | x | vector.cpp:16:43:16:49 | source1 |
|
||||
| vector.cpp:52:7:52:8 | v2 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:53:9:53:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:54:9:54:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:55:9:55:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:58:7:58:8 | v3 | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:59:9:59:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:60:9:60:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:61:9:61:9 | call to operator[] | vector.cpp:51:10:51:15 | call to source |
|
||||
| vector.cpp:64:7:64:8 | v4 | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:65:9:65:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:66:9:66:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:67:9:67:9 | call to operator[] | vector.cpp:63:10:63:15 | call to source |
|
||||
| vector.cpp:70:7:70:8 | v5 | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:71:10:71:14 | call to front | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:72:10:72:13 | call to back | vector.cpp:69:15:69:20 | call to source |
|
||||
| vector.cpp:75:7:75:8 | v6 | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:76:7:76:18 | access to array | vector.cpp:74:17:74:22 | call to source |
|
||||
| vector.cpp:97:7:97:8 | v9 | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:98:10:98:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:99:10:99:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:100:10:100:11 | call to at | vector.cpp:96:13:96:18 | call to source |
|
||||
| vector.cpp:109:7:109:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
| vector.cpp:112:7:112:8 | v4 | vector.cpp:107:15:107:20 | call to source |
|
||||
| vector.cpp:117:7:117:8 | v1 | vector.cpp:106:15:106:20 | call to source |
|
||||
@@ -235,3 +263,17 @@
|
||||
| vector.cpp:139:7:139:8 | v1 | vector.cpp:126:15:126:20 | call to source |
|
||||
| vector.cpp:140:7:140:8 | v2 | vector.cpp:127:15:127:20 | call to source |
|
||||
| vector.cpp:141:7:141:8 | v3 | vector.cpp:128:15:128:20 | call to source |
|
||||
| vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source |
|
||||
| vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source |
|
||||
| vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source |
|
||||
| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source |
|
||||
| vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source |
|
||||
| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source |
|
||||
| vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source |
|
||||
| vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source |
|
||||
| vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source |
|
||||
| vector.cpp:290:7:290:8 | v2 | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:291:10:291:13 | call to data | vector.cpp:289:17:289:30 | call to source |
|
||||
| vector.cpp:292:7:292:18 | access to array | vector.cpp:289:17:289:30 | call to source |
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:17:7:17:10 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only |
|
||||
| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only |
|
||||
| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only |
|
||||
| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only |
|
||||
| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only |
|
||||
| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only |
|
||||
| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only |
|
||||
| arrayassignment.cpp:140:7:140:11 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only |
|
||||
| arrayassignment.cpp:145:7:145:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only |
|
||||
| copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
| copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only |
|
||||
| copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only |
|
||||
@@ -95,19 +113,24 @@
|
||||
| string.cpp:302:7:302:8 | string.cpp:290:17:290:22 | AST only |
|
||||
| string.cpp:311:9:311:12 | string.cpp:308:16:308:21 | AST only |
|
||||
| string.cpp:322:9:322:14 | string.cpp:319:16:319:21 | AST only |
|
||||
| string.cpp:334:11:334:16 | string.cpp:329:18:329:23 | AST only |
|
||||
| string.cpp:335:8:335:9 | string.cpp:329:18:329:23 | AST only |
|
||||
| string.cpp:353:8:353:8 | string.cpp:345:18:345:23 | AST only |
|
||||
| string.cpp:354:13:354:13 | string.cpp:345:18:345:23 | AST only |
|
||||
| string.cpp:367:8:367:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:368:8:368:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:370:8:370:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:372:8:372:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:375:8:375:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:378:8:378:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:382:8:382:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:386:8:386:8 | string.cpp:360:18:360:23 | AST only |
|
||||
| string.cpp:339:7:339:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:340:7:340:7 | string.cpp:336:12:336:26 | AST only |
|
||||
| string.cpp:341:7:341:7 | string.cpp:335:9:335:23 | AST only |
|
||||
| string.cpp:349:7:349:9 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:350:11:350:14 | string.cpp:348:18:348:32 | AST only |
|
||||
| string.cpp:361:11:361:16 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:362:8:362:9 | string.cpp:356:18:356:23 | AST only |
|
||||
| string.cpp:380:8:380:8 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:381:13:381:13 | string.cpp:372:18:372:23 | AST only |
|
||||
| string.cpp:394:8:394:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:395:8:395:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:397:8:397:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:399:8:399:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:402:8:402:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:405:8:405:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:407:8:407:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:409:8:409:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| string.cpp:413:8:413:8 | string.cpp:387:18:387:23 | AST only |
|
||||
| structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
| structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only |
|
||||
| structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only |
|
||||
@@ -155,9 +178,27 @@
|
||||
| vector.cpp:20:8:20:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:28:8:28:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:33:8:33:8 | vector.cpp:16:43:16:49 | AST only |
|
||||
| vector.cpp:52:7:52:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:53:9:53:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:54:9:54:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:55:9:55:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:58:7:58:8 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:59:9:59:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:60:9:60:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:61:9:61:9 | vector.cpp:51:10:51:15 | AST only |
|
||||
| vector.cpp:64:7:64:8 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:65:9:65:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:66:9:66:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:67:9:67:9 | vector.cpp:63:10:63:15 | AST only |
|
||||
| vector.cpp:70:7:70:8 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only |
|
||||
| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only |
|
||||
| vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:100:10:100:11 | vector.cpp:96:13:96:18 | AST only |
|
||||
| vector.cpp:109:7:109:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
| vector.cpp:112:7:112:8 | vector.cpp:107:15:107:20 | AST only |
|
||||
| vector.cpp:117:7:117:8 | vector.cpp:106:15:106:20 | AST only |
|
||||
@@ -170,3 +211,18 @@
|
||||
| vector.cpp:139:7:139:8 | vector.cpp:126:15:126:20 | AST only |
|
||||
| vector.cpp:140:7:140:8 | vector.cpp:127:15:127:20 | AST only |
|
||||
| vector.cpp:141:7:141:8 | vector.cpp:128:15:128:20 | AST only |
|
||||
| vector.cpp:162:8:162:15 | vector.cpp:161:14:161:19 | IR only |
|
||||
| vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only |
|
||||
| vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only |
|
||||
| vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only |
|
||||
| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only |
|
||||
| vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only |
|
||||
| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only |
|
||||
| vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only |
|
||||
| vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only |
|
||||
| vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only |
|
||||
| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only |
|
||||
| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only |
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source |
|
||||
| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source |
|
||||
| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source |
|
||||
| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source |
|
||||
| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source |
|
||||
| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source |
|
||||
| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source |
|
||||
| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source |
|
||||
| format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source |
|
||||
| format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source |
|
||||
@@ -79,3 +98,4 @@
|
||||
| taint.cpp:465:7:465:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:470:7:470:7 | x | taint.cpp:462:6:462:11 | call to source |
|
||||
| taint.cpp:485:7:485:10 | line | taint.cpp:480:26:480:32 | source1 |
|
||||
| vector.cpp:162:8:162:15 | access to array | vector.cpp:161:14:161:19 | call to source |
|
||||
|
||||
@@ -5,9 +5,9 @@ using namespace std;
|
||||
|
||||
int source();
|
||||
|
||||
namespace ns_char
|
||||
namespace ns_int
|
||||
{
|
||||
char source();
|
||||
int source();
|
||||
}
|
||||
|
||||
void sink(int);
|
||||
@@ -49,22 +49,22 @@ void test_element_taint(int x) {
|
||||
sink(v1.back());
|
||||
|
||||
v2[0] = source();
|
||||
sink(v2); // tainted [NOT DETECTED]
|
||||
sink(v2[0]); // tainted [NOT DETECTED]
|
||||
sink(v2[1]);
|
||||
sink(v2); // tainted
|
||||
sink(v2[0]); // tainted
|
||||
sink(v2[1]); // [FALSE POSITIVE]
|
||||
sink(v2[x]); // potentially tainted
|
||||
|
||||
v3 = v2;
|
||||
sink(v3); // tainted [NOT DETECTED]
|
||||
sink(v3[0]); // tainted [NOT DETECTED]
|
||||
sink(v3[1]);
|
||||
sink(v3); // tainted
|
||||
sink(v3[0]); // tainted
|
||||
sink(v3[1]); // [FALSE POSITIVE]
|
||||
sink(v3[x]); // potentially tainted
|
||||
|
||||
v4[x] = source();
|
||||
sink(v4); // tainted [NOT DETECTED]
|
||||
sink(v4); // tainted
|
||||
sink(v4[0]); // potentially tainted
|
||||
sink(v4[1]); // potentially tainted
|
||||
sink(v4[x]); // tainted [NOT DETECTED]
|
||||
sink(v4[x]); // tainted
|
||||
|
||||
v5.push_back(source());
|
||||
sink(v5); // tainted
|
||||
@@ -72,8 +72,8 @@ void test_element_taint(int x) {
|
||||
sink(v5.back()); // tainted
|
||||
|
||||
v6.data()[2] = source();
|
||||
sink(v6); // tainted [NOT DETECTED]
|
||||
sink(v6.data()[2]); // tainted [NOT DETECTED]
|
||||
sink(v6); // tainted
|
||||
sink(v6.data()[2]); // tainted
|
||||
|
||||
{
|
||||
const std::vector<int> &v7c = v7; // (workaround because our iterators don't convert to const_iterator)
|
||||
@@ -87,17 +87,17 @@ void test_element_taint(int x) {
|
||||
{
|
||||
const std::vector<int> &v8c = v8;
|
||||
std::vector<int>::const_iterator it = v8c.begin();
|
||||
v8.insert(it, 10, ns_char::source());
|
||||
v8.insert(it, 10, ns_int::source());
|
||||
}
|
||||
sink(v8); // tainted [NOT DETECTED]
|
||||
sink(v8.front()); // tainted [NOT DETECTED]
|
||||
sink(v8.back());
|
||||
|
||||
v9.at(x) = source();
|
||||
sink(v9); // tainted [NOT DETECTED]
|
||||
sink(v9); // tainted
|
||||
sink(v9.at(0)); // potentially tainted
|
||||
sink(v9.at(1)); // potentially tainted
|
||||
sink(v9.at(x)); // tainted [NOT DETECTED]
|
||||
sink(v9.at(x)); // tainted
|
||||
}
|
||||
|
||||
void test_vector_swap() {
|
||||
@@ -141,3 +141,153 @@ void test_vector_clear() {
|
||||
sink(v3); // [FALSE POSITIVE]
|
||||
sink(v4);
|
||||
}
|
||||
|
||||
struct MyPair
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
struct MyVectorContainer
|
||||
{
|
||||
std::vector<int> vs;
|
||||
};
|
||||
|
||||
void test_nested_vectors()
|
||||
{
|
||||
{
|
||||
int aa[10][20] = {0};
|
||||
|
||||
sink(aa[0][0]);
|
||||
aa[0][0] = source();
|
||||
sink(aa[0][0]); // tainted [IR ONLY]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::vector<int> > bb(30);
|
||||
|
||||
bb[0].push_back(0);
|
||||
sink(bb[0][0]);
|
||||
bb[0][0] = source();
|
||||
sink(bb[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> cc[40];
|
||||
|
||||
cc[0].push_back(0);
|
||||
sink(cc[0][0]);
|
||||
cc[0][0] = source();
|
||||
sink(cc[0][0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyPair> dd;
|
||||
MyPair mp = {0, 0};
|
||||
|
||||
dd.push_back(mp);
|
||||
sink(dd[0].a);
|
||||
sink(dd[0].b);
|
||||
dd[0].a = source();
|
||||
sink(dd[0].a); // tainted [NOT DETECTED]
|
||||
sink(dd[0].b);
|
||||
}
|
||||
|
||||
{
|
||||
MyVectorContainer ee;
|
||||
|
||||
ee.vs.push_back(0);
|
||||
sink(ee.vs[0]);
|
||||
ee.vs[0] = source();
|
||||
sink(ee.vs[0]); // tainted
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<MyVectorContainer> ff;
|
||||
MyVectorContainer mvc;
|
||||
|
||||
mvc.vs.push_back(0);
|
||||
ff.push_back(mvc);
|
||||
sink(ff[0].vs[0]);
|
||||
ff[0].vs[0] = source();
|
||||
sink(ff[0].vs[0]); // tainted [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
void sink(std::vector<int>::iterator &);
|
||||
|
||||
typedef int myInt;
|
||||
typedef float myFloat;
|
||||
|
||||
namespace ns_myFloat
|
||||
{
|
||||
myFloat source();
|
||||
}
|
||||
|
||||
namespace ns_ci_ptr
|
||||
{
|
||||
const int *source();
|
||||
}
|
||||
|
||||
void sink(std::vector<myFloat> &);
|
||||
void sink(std::vector<const int *> &);
|
||||
|
||||
void test_vector_assign() {
|
||||
std::vector<int> v1, v2, v3;
|
||||
|
||||
v1.assign(100, 0);
|
||||
v2.assign(100, ns_int::source());
|
||||
v3.push_back(source());
|
||||
|
||||
sink(v1);
|
||||
sink(v2); // tainted
|
||||
sink(v3); // tainted
|
||||
|
||||
{
|
||||
std::vector<int> v4, v5, v6;
|
||||
std::vector<int>::iterator i1, i2;
|
||||
|
||||
v4.assign(v1.begin(), v1.end());
|
||||
v5.assign(v3.begin(), v3.end());
|
||||
i1 = v3.begin();
|
||||
i1++;
|
||||
i2 = i1;
|
||||
i2++;
|
||||
v6.assign(i1, i2);
|
||||
|
||||
sink(v4);
|
||||
sink(v5); // tainted [NOT DETECTED]
|
||||
sink(i1); // tainted [NOT DETECTED]
|
||||
sink(i2); // tainted [NOT DETECTED]
|
||||
sink(v6); // tainted [NOT DETECTED]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<myInt> v7;
|
||||
std::vector<myFloat> v8;
|
||||
std::vector<const int *> v9;
|
||||
|
||||
v7.assign(100, ns_int::source());
|
||||
v8.assign(100, ns_myFloat::source());
|
||||
v9.assign(100, ns_ci_ptr::source());
|
||||
|
||||
sink(v7); // tainted
|
||||
sink(v8); // tainted
|
||||
sink(v9); // tainted
|
||||
}
|
||||
}
|
||||
|
||||
void sink(int *);
|
||||
|
||||
void test_data_more() {
|
||||
std::vector<int> v1, v2;
|
||||
|
||||
v1.push_back(source());
|
||||
sink(v1); // tainted
|
||||
sink(v1.data()); // tainted
|
||||
sink(v1.data()[2]); // tainted
|
||||
|
||||
*(v2.data()) = ns_int::source();
|
||||
sink(v2); // tainted
|
||||
sink(v2.data()); // tainted
|
||||
sink(v2.data()[2]); // tainted
|
||||
}
|
||||
|
||||
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
10
cpp/ql/test/library-tests/specifiers2/cpp20.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --c++20
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // not const in C++ >= 14
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
} // namespace cpp20
|
||||
@@ -1,5 +1,22 @@
|
||||
| Class | specifiers2pp.cpp:8:7:8:13 | MyClass | MyClass | abstract |
|
||||
| Class | specifiers2pp.cpp:24:7:24:14 | MyClass2 | MyClass2 | abstract |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | extern |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | inline |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | is_constexpr |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:5:7:5:7 | operator= | operator= | public |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:6:19:6:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | cpp20.cpp:7:19:7:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| Function | specifiers2.c:11:6:11:6 | f | f | extern |
|
||||
| Function | specifiers2.c:12:13:12:13 | f | f | extern |
|
||||
| Function | specifiers2.c:13:13:13:13 | f | f | extern |
|
||||
@@ -79,6 +96,24 @@
|
||||
| Function | specifiers2pp.cpp:41:16:41:23 | someFun2 | someFun2 | extern |
|
||||
| Function | specifiers2pp.cpp:43:9:43:16 | someFun3 | someFun3 | extern |
|
||||
| Function | specifiers2pp.cpp:44:16:44:23 | someFun4 | someFun4 | static |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | extern |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | inline |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:62:7:62:7 | operator= | operator= | public |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:63:19:63:34 | member_constexpr | member_constexpr | private |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | const |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | declared_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | inline |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | is_constexpr |
|
||||
| Function | specifiers2pp.cpp:64:19:64:40 | member_const_constexpr | member_const_constexpr | private |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | c_linkage |
|
||||
| FunctionDeclarationEntry | specifiers2.c:11:6:11:6 | declaration of f | f | void_param_list |
|
||||
| FunctionDeclarationEntry | specifiers2.c:12:13:12:13 | declaration of f | f | c_linkage |
|
||||
|
||||
@@ -58,3 +58,8 @@ template<typename T> using Const = const T;
|
||||
using Const_int = Const<int>;
|
||||
|
||||
typedef volatile Const_int volatile_Const_int;
|
||||
|
||||
class TestConstexpr {
|
||||
constexpr int member_constexpr() { return 0; } // const in C++11
|
||||
constexpr int member_const_constexpr() const { return 0; }
|
||||
};
|
||||
|
||||
@@ -60,7 +60,6 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
| builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -1473,5 +1473,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
argHasPostUpdate
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| a.c:4:5:4:6 | definition of is | array of {int} | 1 |
|
||||
| a.h:2:12:2:13 | declaration of is | array of 4 {int} | 1 |
|
||||
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |
|
||||
| file://:0:0:0:0 | definition of reg_save_area | pointer to {void} | 1 |
|
||||
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
5
cpp/ql/test/library-tests/variables/global/vardecl.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from VariableDeclarationEntry vd, Type t
|
||||
where t = vd.getType()
|
||||
select vd, t.explain(), count(Type u | u = vd.getType())
|
||||
@@ -1,5 +1,4 @@
|
||||
| a.c:4:5:4:6 | is | array of 4 {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 2 |
|
||||
| a.c:4:5:4:6 | is | array of {int} | 1 |
|
||||
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |
|
||||
|
||||
213
csharp/.editorconfig
Normal file
213
csharp/.editorconfig
Normal file
@@ -0,0 +1,213 @@
|
||||
# Taken as is from https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2019
|
||||
# Customizations are added at the bottom of the file.
|
||||
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
|
||||
# Field preferences
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
|
||||
#### C# Formatting Rules ####
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
#
|
||||
# Customizations
|
||||
#
|
||||
|
||||
# IDE0055: Fix formatting
|
||||
dotnet_diagnostic.IDE0055.severity = warning
|
||||
|
||||
[extractor/Semmle.Extraction/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CSharp/Tuples.cs,
|
||||
extractor/Semmle.Extraction.CIL/Tuples.cs]
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = none
|
||||
8
csharp/.vscode/settings.json
vendored
8
csharp/.vscode/settings.json
vendored
@@ -3,5 +3,11 @@
|
||||
"dotnet-test-explorer.testProjectPath": "**/*Tests.@(csproj|vbproj|fsproj)",
|
||||
"dotnet-test-explorer.testArguments": "/property:GenerateTargetFrameworkAttribute=false",
|
||||
"csharp.supressBuildAssetsNotification": true,
|
||||
"csharp.suppressDotnetRestoreNotification": true
|
||||
"csharp.suppressDotnetRestoreNotification": true,
|
||||
"[csharp]": {
|
||||
"editor.defaultFormatter": "ms-dotnettools.csharp"
|
||||
},
|
||||
"omnisharp.enableMsBuildLoadProjectsOnDemand": true,
|
||||
"omnisharp.enableEditorConfigSupport": true,
|
||||
"omnisharp.enableRoslynAnalyzers": true,
|
||||
}
|
||||
@@ -450,15 +450,22 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap
|
||||
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)";
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2";
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0";
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2\nC:\\VS3";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0\n16.0";
|
||||
|
||||
var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray();
|
||||
Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path);
|
||||
Assert.Equal(10, candidates[0].ToolsVersion);
|
||||
Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path);
|
||||
Assert.Equal(11, candidates[1].ToolsVersion);
|
||||
Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars32.bat", candidates[2].Path);
|
||||
Assert.Equal(16, candidates[2].ToolsVersion);
|
||||
Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars64.bat", candidates[3].Path);
|
||||
Assert.Equal(16, candidates[3].ToolsVersion);
|
||||
Assert.Equal(@"C:\VS3\Common7\Tools\VsDevCmd.bat", candidates[4].Path);
|
||||
Assert.Equal(16, candidates[4].ToolsVersion);
|
||||
Assert.Equal(5, candidates.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -11,13 +11,11 @@ namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
public readonly int ToolsVersion;
|
||||
public readonly string Path;
|
||||
public readonly string[] Platform;
|
||||
|
||||
public VcVarsBatFile(string path, int version, params string[] platform)
|
||||
public VcVarsBatFile(string path, int version)
|
||||
{
|
||||
Path = path;
|
||||
ToolsVersion = version;
|
||||
Platform = platform;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,12 +49,15 @@ namespace Semmle.Autobuild.Shared
|
||||
{
|
||||
if (majorVersion < 15)
|
||||
{
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion, "x86");
|
||||
// Visual Studio 2015 and below
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion, "x64");
|
||||
// Visual Studio 2017 and above
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion);
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion);
|
||||
yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion);
|
||||
}
|
||||
}
|
||||
// else: Skip installation without a version
|
||||
@@ -66,10 +67,10 @@ namespace Semmle.Autobuild.Shared
|
||||
}
|
||||
|
||||
// vswhere not installed or didn't run correctly - return legacy Visual Studio versions
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10, "x86");
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14);
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12);
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11);
|
||||
yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Semmle.Autobuild.Shared
|
||||
|
||||
if (vsTools == null && builder.Actions.IsWindows())
|
||||
{
|
||||
builder.Log(Severity.Warning, "Could not find a suitable version of vcvarsall.bat");
|
||||
builder.Log(Severity.Warning, "Could not find a suitable version of VsDevCmd.bat/vcvarsall.bat");
|
||||
}
|
||||
|
||||
var nuget =
|
||||
|
||||
@@ -50,6 +50,13 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
return an;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssemblyInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="path">Path of the assembly.</param>
|
||||
/// <exception cref="Semmle.Extraction.CIL.Driver.InvalidAssemblyException">
|
||||
/// Thrown when the input file is not a valid assembly.
|
||||
/// </exception>
|
||||
public AssemblyInfo(string path)
|
||||
{
|
||||
filename = path;
|
||||
@@ -60,13 +67,11 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
try
|
||||
{
|
||||
isAssembly = peReader.HasMetadata;
|
||||
if (!isAssembly) return;
|
||||
if (!peReader.HasMetadata) throw new InvalidAssemblyException();
|
||||
|
||||
var mdReader = peReader.GetMetadataReader();
|
||||
|
||||
isAssembly = mdReader.IsAssembly;
|
||||
if (!mdReader.IsAssembly) return;
|
||||
if (!mdReader.IsAssembly) throw new InvalidAssemblyException();
|
||||
|
||||
// Get our own assembly name
|
||||
name = CreateAssemblyName(mdReader, mdReader.GetAssemblyDefinition());
|
||||
@@ -81,7 +86,7 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
// This failed on one of the Roslyn tests that includes
|
||||
// a deliberately malformed assembly.
|
||||
// In this case, we just skip the extraction of this assembly.
|
||||
isAssembly = false;
|
||||
throw new InvalidAssemblyException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +94,6 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
public readonly AssemblyName name;
|
||||
public readonly string filename;
|
||||
public bool extract;
|
||||
public readonly bool isAssembly;
|
||||
public readonly AssemblyName[] references;
|
||||
}
|
||||
|
||||
@@ -102,11 +106,12 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
class AssemblyNameComparer : IEqualityComparer<AssemblyName>
|
||||
{
|
||||
bool IEqualityComparer<AssemblyName>.Equals(AssemblyName x, AssemblyName y) =>
|
||||
x.Name == y.Name && x.Version == y.Version;
|
||||
bool IEqualityComparer<AssemblyName>.Equals(AssemblyName? x, AssemblyName? y) =>
|
||||
object.ReferenceEquals(x, y) ||
|
||||
x?.Name == y?.Name && x?.Version == y?.Version;
|
||||
|
||||
int IEqualityComparer<AssemblyName>.GetHashCode(AssemblyName obj) =>
|
||||
obj.Name.GetHashCode() + 7 * obj.Version.GetHashCode();
|
||||
(obj.Name, obj.Version).GetHashCode();
|
||||
}
|
||||
|
||||
readonly Dictionary<AssemblyName, AssemblyInfo> assembliesRead = new Dictionary<AssemblyName, AssemblyInfo>(new AssemblyNameComparer());
|
||||
@@ -116,13 +121,15 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
if (!filesAnalyzed.Contains(assemblyPath))
|
||||
{
|
||||
filesAnalyzed.Add(assemblyPath);
|
||||
var info = new AssemblyInfo(assemblyPath);
|
||||
if (info.isAssembly)
|
||||
try
|
||||
{
|
||||
var info = new AssemblyInfo(assemblyPath);
|
||||
info.extract = extractAll;
|
||||
if (!assembliesRead.ContainsKey(info.name))
|
||||
assembliesRead.Add(info.name, info);
|
||||
}
|
||||
catch (InvalidAssemblyException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,8 +144,7 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
while (assembliesToReference.Any())
|
||||
{
|
||||
var item = assembliesToReference.Pop();
|
||||
AssemblyInfo info;
|
||||
if (assembliesRead.TryGetValue(item, out info))
|
||||
if (assembliesRead.TryGetValue(item, out AssemblyInfo? info))
|
||||
{
|
||||
if (!info.extract)
|
||||
{
|
||||
@@ -165,6 +171,21 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
readonly AssemblyList assemblyList = new AssemblyList();
|
||||
|
||||
public ExtractorOptions(string[] args)
|
||||
{
|
||||
Verbosity = Verbosity.Info;
|
||||
Threads = System.Environment.ProcessorCount;
|
||||
PDB = true;
|
||||
TrapCompression = TrapWriter.CompressionMode.Gzip;
|
||||
|
||||
ParseArgs(args);
|
||||
|
||||
AddFrameworkDirectories(false);
|
||||
|
||||
assemblyList.ResolveReferences();
|
||||
AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray();
|
||||
}
|
||||
|
||||
public void AddDirectory(string directory, bool extractAll)
|
||||
{
|
||||
foreach (var file in
|
||||
@@ -192,7 +213,12 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
if (File.Exists(path))
|
||||
{
|
||||
assemblyList.AddFile(path, true);
|
||||
AddDirectory(Path.GetDirectoryName(path), false);
|
||||
string? directory = Path.GetDirectoryName(path);
|
||||
if (directory is null)
|
||||
{
|
||||
throw new InternalError($"Directory of path '{path}' is null");
|
||||
}
|
||||
AddDirectory(directory, false);
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
@@ -200,13 +226,7 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveReferences()
|
||||
{
|
||||
assemblyList.ResolveReferences();
|
||||
AssembliesToExtract = assemblyList.AssembliesToExtract.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract { get; private set; }
|
||||
public IEnumerable<AssemblyInfo> AssembliesToExtract { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assemblies that were referenced but were not available to be
|
||||
@@ -215,55 +235,43 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
/// </summary>
|
||||
public IEnumerable<AssemblyName> MissingReferences => assemblyList.missingReferences;
|
||||
|
||||
public static ExtractorOptions ParseCommandLine(string[] args)
|
||||
private void ParseArgs(string[] args)
|
||||
{
|
||||
var options = new ExtractorOptions();
|
||||
options.Verbosity = Verbosity.Info;
|
||||
options.Threads = System.Environment.ProcessorCount;
|
||||
options.PDB = true;
|
||||
options.TrapCompression = TrapWriter.CompressionMode.Gzip;
|
||||
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (arg == "--verbose")
|
||||
{
|
||||
options.Verbosity = Verbosity.All;
|
||||
Verbosity = Verbosity.All;
|
||||
}
|
||||
else if (arg == "--silent")
|
||||
{
|
||||
options.Verbosity = Verbosity.Off;
|
||||
Verbosity = Verbosity.Off;
|
||||
}
|
||||
else if (arg.StartsWith("--verbosity:"))
|
||||
{
|
||||
options.Verbosity = (Verbosity)int.Parse(arg.Substring(12));
|
||||
Verbosity = (Verbosity)int.Parse(arg.Substring(12));
|
||||
}
|
||||
else if (arg == "--dotnet")
|
||||
{
|
||||
options.AddFrameworkDirectories(true);
|
||||
AddFrameworkDirectories(true);
|
||||
}
|
||||
else if (arg == "--nocache")
|
||||
{
|
||||
options.NoCache = true;
|
||||
NoCache = true;
|
||||
}
|
||||
else if (arg.StartsWith("--threads:"))
|
||||
{
|
||||
options.Threads = int.Parse(arg.Substring(10));
|
||||
Threads = int.Parse(arg.Substring(10));
|
||||
}
|
||||
else if (arg == "--no-pdb")
|
||||
{
|
||||
options.PDB = false;
|
||||
PDB = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.AddFileOrDirectory(arg);
|
||||
AddFileOrDirectory(arg);
|
||||
}
|
||||
}
|
||||
|
||||
options.AddFrameworkDirectories(false);
|
||||
options.ResolveReferences();
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Driver
|
||||
{
|
||||
class InvalidAssemblyException : Exception
|
||||
{ }
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace Semmle.Extraction.CIL.Driver
|
||||
return;
|
||||
}
|
||||
|
||||
var options = ExtractorOptions.ParseCommandLine(args);
|
||||
var options = new ExtractorOptions(args);
|
||||
var layout = new Layout();
|
||||
var logger = new ConsoleLogger(options.Verbosity);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<RootNamespace>Semmle.Extraction.CIL.Driver</RootNamespace>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL
|
||||
/// </summary>
|
||||
/// <typeparam name="SrcType">The type of the source.</typeparam>
|
||||
/// <typeparam name="TargetType">The type of the generated object.</typeparam>
|
||||
public class CachedFunction<SrcType, TargetType>
|
||||
public class CachedFunction<SrcType, TargetType> where SrcType : notnull
|
||||
{
|
||||
readonly Func<SrcType, TargetType> generator;
|
||||
readonly Dictionary<SrcType, TargetType> cache;
|
||||
|
||||
@@ -14,13 +14,19 @@ namespace Semmle.Extraction.CIL
|
||||
/// </summary>
|
||||
partial class Context : IDisposable
|
||||
{
|
||||
public Extraction.Context cx;
|
||||
readonly FileStream stream;
|
||||
public readonly MetadataReader mdReader;
|
||||
public readonly PEReader peReader;
|
||||
public readonly string assemblyPath;
|
||||
public Entities.Assembly assembly;
|
||||
public PDB.IPdb pdb;
|
||||
Entities.Assembly? assemblyNull;
|
||||
|
||||
public Extraction.Context cx { get; }
|
||||
public MetadataReader mdReader { get; }
|
||||
public PEReader peReader { get; }
|
||||
public string assemblyPath { get; }
|
||||
public Entities.Assembly assembly
|
||||
{
|
||||
get { return assemblyNull!; }
|
||||
set { assemblyNull = value; }
|
||||
}
|
||||
public PDB.IPdb? pdb { get; }
|
||||
|
||||
public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs)
|
||||
{
|
||||
@@ -105,7 +111,7 @@ namespace Semmle.Extraction.CIL
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the method.</param>
|
||||
/// <returns>The debugging information, or null if the information could not be located.</returns>
|
||||
public PDB.IMethod GetMethodDebugInformation(MethodDefinitionHandle handle)
|
||||
public PDB.IMethod? GetMethodDebugInformation(MethodDefinitionHandle handle)
|
||||
{
|
||||
return pdb == null ? null : pdb.GetMethod(handle.ToDebugInformationHandle());
|
||||
}
|
||||
@@ -125,7 +131,8 @@ namespace Semmle.Extraction.CIL
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The list of generic type parameters.
|
||||
/// The list of generic type parameters, including type parameters of
|
||||
/// containing types.
|
||||
/// </summary>
|
||||
public abstract IEnumerable<Entities.Type> TypeParameters { get; }
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(cx.assemblyPath.Replace("\\", "/"));
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj.GetType() && Equals(file, ((Assembly)obj).file);
|
||||
return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 7 * file.GetHashCode();
|
||||
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
get
|
||||
{
|
||||
yield return file;
|
||||
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name, assemblyName.Version.ToString());
|
||||
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty);
|
||||
|
||||
if (cx.pdb != null)
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
foreach (var handle in cx.mdReader.TypeDefinitions)
|
||||
{
|
||||
IExtractionProduct product = null;
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = cx.Create(handle);
|
||||
@@ -92,7 +92,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
foreach (var handle in cx.mdReader.MethodDefinitions)
|
||||
{
|
||||
IExtractionProduct product = null;
|
||||
IExtractionProduct? product = null;
|
||||
try
|
||||
{
|
||||
product = cx.Create(handle);
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
this.@object = @object;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Attribute attribute && handle.Equals(attribute.handle);
|
||||
}
|
||||
@@ -58,13 +58,15 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
for (int index = 0; index < decoded.FixedArguments.Length; ++index)
|
||||
{
|
||||
object value = decoded.FixedArguments[index].Value;
|
||||
yield return Tuples.cil_attribute_positional_argument(this, index, value == null ? "null" : value.ToString());
|
||||
var stringValue = value?.ToString();
|
||||
yield return Tuples.cil_attribute_positional_argument(this, index, stringValue ?? "null");
|
||||
}
|
||||
|
||||
foreach (var p in decoded.NamedArguments)
|
||||
{
|
||||
object value = p.Value;
|
||||
yield return Tuples.cil_attribute_named_argument(this, p.Name, value == null ? "null" : value.ToString());
|
||||
var stringValue = value?.ToString();
|
||||
yield return Tuples.cil_attribute_named_argument(this, p.Name, stringValue ?? "null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override string IdSuffix => ";cil-event";
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Event e && handle.Equals(e.handle);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
IInstruction try_start, try_end, handler_start;
|
||||
IInstruction? try_start, try_end, handler_start;
|
||||
|
||||
if (!jump_table.TryGetValue(r.TryOffset, out try_start))
|
||||
throw new InternalError("Failed to retrieve handler");
|
||||
@@ -44,7 +44,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
if (r.FilterOffset != -1)
|
||||
{
|
||||
IInstruction filter_start;
|
||||
IInstruction? filter_start;
|
||||
if (!jump_table.TryGetValue(r.FilterOffset, out filter_start))
|
||||
throw new InternalError("ExceptionRegion filter clause");
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
fd = cx.mdReader.GetFieldDefinition(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionField field && handle.Equals(field.handle);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
declType = (Type)cx.CreateGeneric(gc, mr.Parent);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceField field && Handle.Equals(field.Handle);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return GetType() == obj.GetType() && path == ((File)obj).path;
|
||||
return GetType() == obj?.GetType() && path == ((File)obj).path;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 11 * path.GetHashCode();
|
||||
@@ -36,7 +36,11 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
var parent = cx.CreateFolder(System.IO.Path.GetDirectoryName(path));
|
||||
var directoryName = System.IO.Path.GetDirectoryName(path);
|
||||
if (directoryName is null)
|
||||
throw new InternalError($"Directory name for path '{path}' is null.");
|
||||
|
||||
var parent = cx.CreateFolder(directoryName);
|
||||
yield return parent;
|
||||
yield return Tuples.containerparent(parent, this);
|
||||
yield return Tuples.files(this, path, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetExtension(path).Substring(1));
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Folder folder && path == folder.path;
|
||||
}
|
||||
|
||||
@@ -365,6 +365,11 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
int offset = Offset;
|
||||
|
||||
if (Method.Implementation is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation);
|
||||
|
||||
switch (PayloadType)
|
||||
@@ -414,11 +419,17 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
break;
|
||||
case Payload.Arg8:
|
||||
case Payload.Arg16:
|
||||
yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]);
|
||||
if (Method.Parameters is object)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.Local8:
|
||||
case Payload.Local16:
|
||||
yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]);
|
||||
if (Method.LocalVariables is object)
|
||||
{
|
||||
yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]);
|
||||
}
|
||||
break;
|
||||
case Payload.None:
|
||||
case Payload.Target8:
|
||||
@@ -439,7 +450,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
public IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, IInstruction> jump_table)
|
||||
{
|
||||
int target;
|
||||
IInstruction inst;
|
||||
IInstruction? inst;
|
||||
|
||||
switch (PayloadType)
|
||||
{
|
||||
|
||||
@@ -23,25 +23,29 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
/// </summary>
|
||||
abstract class Method : TypeContainer, IMethod
|
||||
{
|
||||
protected MethodTypeParameter[]? genericParams;
|
||||
protected GenericContext gc;
|
||||
protected MethodSignature<ITypeSignature> signature;
|
||||
|
||||
protected Method(GenericContext gc) : base(gc.cx)
|
||||
{
|
||||
this.gc = gc;
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declaringType.TypeParameters);
|
||||
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
|
||||
|
||||
public override IEnumerable<Type> MethodParameters =>
|
||||
genericParams == null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams);
|
||||
|
||||
public int GenericParameterCount => signature.GenericParameterCount;
|
||||
|
||||
public virtual Method SourceDeclaration => this;
|
||||
public virtual Method? SourceDeclaration => this;
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual IList<LocalVariable> LocalVariables => throw new NotImplementedException();
|
||||
public IList<Parameter> Parameters { get; private set; }
|
||||
public virtual IList<LocalVariable>? LocalVariables => throw new NotImplementedException();
|
||||
public IList<Parameter>? Parameters { get; protected set; }
|
||||
|
||||
public override void WriteId(TextWriter trapFile) => WriteMethodId(trapFile, DeclaringType, NameLabel);
|
||||
|
||||
@@ -70,19 +74,8 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(')');
|
||||
}
|
||||
|
||||
protected MethodTypeParameter[] genericParams;
|
||||
protected Type declaringType;
|
||||
protected GenericContext gc;
|
||||
protected MethodSignature<ITypeSignature> signature;
|
||||
protected string name;
|
||||
|
||||
public override string IdSuffix => ";cil-method";
|
||||
|
||||
protected void PopulateParameters(IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
Parameters = MakeParameters(parameterTypes).ToArray();
|
||||
}
|
||||
|
||||
protected IEnumerable<IExtractionProduct> PopulateFlags
|
||||
{
|
||||
get
|
||||
@@ -94,7 +87,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public abstract bool IsStatic { get; }
|
||||
|
||||
private IEnumerable<Parameter> MakeParameters(IEnumerable<Type> parameterTypes)
|
||||
protected IEnumerable<Parameter> MakeParameters(IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@@ -145,13 +138,15 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
readonly Handle handle;
|
||||
readonly MethodDefinition md;
|
||||
readonly PDB.IMethod methodDebugInformation;
|
||||
readonly PDB.IMethod? methodDebugInformation;
|
||||
readonly Type declaringType;
|
||||
|
||||
LocalVariable[] locals;
|
||||
readonly string name;
|
||||
LocalVariable[]? locals;
|
||||
|
||||
public MethodImplementation Implementation { get; private set; }
|
||||
public MethodImplementation? Implementation { get; private set; }
|
||||
|
||||
public override IList<LocalVariable> LocalVariables => locals;
|
||||
public override IList<LocalVariable>? LocalVariables => locals;
|
||||
|
||||
public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc)
|
||||
{
|
||||
@@ -167,7 +162,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
methodDebugInformation = cx.GetMethodDebugInformation(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is DefinitionMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
@@ -206,7 +201,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
var typeSignature = md.DecodeSignature(cx.TypeSignatureDecoder, this);
|
||||
|
||||
PopulateParameters(typeSignature.ParameterTypes);
|
||||
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
|
||||
|
||||
foreach (var c in Parameters)
|
||||
yield return c;
|
||||
@@ -315,8 +310,8 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
// The sequence point gives the location of each instruction.
|
||||
// The location of an instruction is given by the sequence point *after* the
|
||||
// instruction.
|
||||
IEnumerator<PDB.SequencePoint> nextSequencePoint = null;
|
||||
PdbSourceLocation instructionLocation = null;
|
||||
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
|
||||
PdbSourceLocation? instructionLocation = null;
|
||||
|
||||
if (methodDebugInformation != null)
|
||||
{
|
||||
@@ -401,9 +396,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
readonly MemberReferenceHandle handle;
|
||||
readonly MemberReference mr;
|
||||
readonly Type declType;
|
||||
readonly Type declaringType;
|
||||
readonly GenericContext parent;
|
||||
readonly Method sourceDeclaration;
|
||||
readonly Method? sourceDeclaration;
|
||||
|
||||
public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc)
|
||||
{
|
||||
@@ -416,22 +411,24 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
parent = (GenericContext)cx.CreateGeneric(gc, mr.Parent);
|
||||
|
||||
var parentMethod = parent as Method;
|
||||
nameLabel = cx.GetString(mr.Name);
|
||||
|
||||
declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType;
|
||||
var declType = parentMethod is null ? parent as Type : parentMethod.DeclaringType;
|
||||
|
||||
if (declType is null)
|
||||
throw new InternalError("Parent context of method is not a type");
|
||||
|
||||
var typeSourceDeclaration = declType.SourceDeclaration;
|
||||
sourceDeclaration = typeSourceDeclaration == declType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
|
||||
declaringType = declType;
|
||||
nameLabel = cx.GetString(mr.Name);
|
||||
|
||||
var typeSourceDeclaration = declaringType.SourceDeclaration;
|
||||
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
|
||||
}
|
||||
|
||||
private readonly string nameLabel;
|
||||
|
||||
public override string NameLabel => nameLabel;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
@@ -441,11 +438,11 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override Method SourceDeclaration => sourceDeclaration;
|
||||
public override Method? SourceDeclaration => sourceDeclaration;
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declType;
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => cx.ShortName(mr.Name);
|
||||
|
||||
@@ -464,7 +461,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
var typeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this);
|
||||
|
||||
PopulateParameters(typeSignature.ParameterTypes);
|
||||
Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray();
|
||||
foreach (var p in Parameters) yield return p;
|
||||
|
||||
foreach (var f in PopulateFlags) yield return f;
|
||||
@@ -486,6 +483,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
readonly MethodSpecification ms;
|
||||
readonly Method unboundMethod;
|
||||
readonly ImmutableArray<Type> typeParams;
|
||||
readonly Type declaringType;
|
||||
|
||||
public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc)
|
||||
{
|
||||
@@ -501,7 +499,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
unboundMethod.WriteId(trapFile);
|
||||
trapFile.Write('<');
|
||||
int index = 0;
|
||||
foreach(var param in typeParams)
|
||||
foreach (var param in typeParams)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
trapFile.WriteSubId(param);
|
||||
@@ -511,7 +509,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override string NameLabel => throw new NotImplementedException();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
|
||||
}
|
||||
@@ -547,7 +545,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");
|
||||
}
|
||||
|
||||
PopulateParameters(constructedTypeSignature.ParameterTypes);
|
||||
Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray();
|
||||
foreach (var p in Parameters)
|
||||
yield return p;
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
/// </summary>
|
||||
public sealed class Namespace : TypeContainer, INamespace
|
||||
{
|
||||
public Namespace ParentNamespace;
|
||||
public Namespace? ParentNamespace;
|
||||
public readonly string Name;
|
||||
|
||||
public bool IsGlobalNamespace => ParentNamespace == null;
|
||||
public bool IsGlobalNamespace => ParentNamespace is null;
|
||||
|
||||
public override string IdSuffix => ";namespace";
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(Name);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is Namespace ns && Name == ns.Name)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
return i == -1 ? fqn : fqn.Substring(i + 1);
|
||||
}
|
||||
|
||||
static Namespace createParentNamespace(Context cx, string fqn)
|
||||
static Namespace? createParentNamespace(Context cx, string fqn)
|
||||
{
|
||||
if (fqn == "") return null;
|
||||
var i = fqn.LastIndexOf('.');
|
||||
@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string name, Namespace parent) : base(cx)
|
||||
public Namespace(Context cx, string name, Namespace? parent) : base(cx)
|
||||
{
|
||||
Name = name;
|
||||
ParentNamespace = parent;
|
||||
@@ -85,7 +85,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
get
|
||||
{
|
||||
yield return Tuples.namespaces(this, Name);
|
||||
if (!IsGlobalNamespace)
|
||||
if (ParentNamespace is object)
|
||||
yield return Tuples.parent_namespace(this, ParentNamespace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Parameter param && method.Equals(param.method) && index == param.index;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(cx.GetString(pd.Name));
|
||||
trapFile.Write("(");
|
||||
int index=0;
|
||||
int index = 0;
|
||||
var signature = pd.DecodeSignature(new SignatureDecoder(), gc);
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(")");
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is Property property && Equals(handle, property.handle);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(location.EndColumn);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PdbSourceLocation l && location.Equals(l.location);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Reflection;
|
||||
using Semmle.Util;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
@@ -103,7 +104,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
/// shortcut to comparing the signature bytes since handles are unique.
|
||||
/// </param>
|
||||
/// <returns>The method, or 'null' if not found or not supported.</returns>
|
||||
internal virtual Method LookupMethod(StringHandle methodName, BlobHandle signature)
|
||||
internal virtual Method? LookupMethod(StringHandle methodName, BlobHandle signature)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -160,7 +161,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
get;
|
||||
}
|
||||
|
||||
public virtual TypeContainer Parent => (TypeContainer)ContainingType ?? Namespace;
|
||||
public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? Namespace!;
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
@@ -177,9 +178,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract Namespace Namespace { get; }
|
||||
public abstract Namespace? Namespace { get; }
|
||||
|
||||
public abstract Type ContainingType { get; }
|
||||
public abstract Type? ContainingType { get; }
|
||||
|
||||
public abstract Type Construct(IEnumerable<Type> typeArguments);
|
||||
|
||||
@@ -233,7 +234,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
/// </summary>
|
||||
/// <param name="t">The resulting primitive type, or null.</param>
|
||||
/// <returns>True if this type is a primitive type.</returns>
|
||||
public bool TryGetPrimitiveType(out PrimitiveType t)
|
||||
public bool TryGetPrimitiveType([NotNullWhen(true)] out PrimitiveType? t)
|
||||
{
|
||||
if (TryGetPrimitiveTypeCode(out var code))
|
||||
{
|
||||
@@ -249,7 +250,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
|
||||
{
|
||||
if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name)
|
||||
if (ContainingType == null && Namespace?.Name == cx.SystemNamespace.Name)
|
||||
{
|
||||
switch (Name)
|
||||
{
|
||||
@@ -341,7 +342,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
typeParams = new Lazy<IEnumerable<TypeTypeParameter>>(MakeTypeParameters);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeDefinitionType t && handle.Equals(t.handle);
|
||||
}
|
||||
@@ -390,9 +391,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override Namespace Namespace => cx.Create(td.NamespaceDefinition);
|
||||
|
||||
readonly Type declType;
|
||||
readonly Type? declType;
|
||||
|
||||
public override Type ContainingType => declType;
|
||||
public override Type? ContainingType => declType;
|
||||
|
||||
public override int ThisTypeParameters
|
||||
{
|
||||
@@ -562,18 +563,14 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
readonly TypeReference tr;
|
||||
readonly Lazy<TypeTypeParameter[]> typeParams;
|
||||
|
||||
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : this(cx, handle, cx.mdReader.GetTypeReference(handle))
|
||||
{
|
||||
typeParams = new Lazy<TypeTypeParameter[]>(MakeTypeParameters);
|
||||
}
|
||||
|
||||
public TypeReferenceType(Context cx, TypeReferenceHandle handle, TypeReference tr) : base(cx)
|
||||
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx)
|
||||
{
|
||||
this.typeParams = new Lazy<TypeTypeParameter[]>(MakeTypeParameters);
|
||||
this.handle = handle;
|
||||
this.tr = tr;
|
||||
this.tr = cx.mdReader.GetTypeReference(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeReferenceType t && handle.Equals(t.handle);
|
||||
}
|
||||
@@ -637,7 +634,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override Type ContainingType
|
||||
public override Type? ContainingType
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -654,7 +651,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
switch (tr.ResolutionScope.Kind)
|
||||
{
|
||||
case HandleKind.TypeReference:
|
||||
ContainingType.WriteAssemblyPrefix(trapFile);
|
||||
ContainingType!.WriteAssemblyPrefix(trapFile);
|
||||
break;
|
||||
case HandleKind.AssemblyReference:
|
||||
var assemblyDef = cx.mdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
|
||||
@@ -684,7 +681,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
var ct = ContainingType;
|
||||
if (ct != null)
|
||||
{
|
||||
ContainingType.GetId(trapFile, inContext);
|
||||
ct.GetId(trapFile, inContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -719,9 +716,11 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
public sealed class ConstructedType : Type
|
||||
{
|
||||
readonly Type unboundGenericType;
|
||||
readonly Type[] thisTypeArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments;
|
||||
// Either null or notEmpty
|
||||
readonly Type[]? thisTypeArguments;
|
||||
|
||||
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
|
||||
|
||||
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
|
||||
|
||||
@@ -751,7 +750,6 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
unboundGenericType = unboundType;
|
||||
var thisParams = unboundType.ThisTypeParameters;
|
||||
var parentParams = suppliedArgs - thisParams;
|
||||
|
||||
if (typeArguments.Count() == thisParams)
|
||||
{
|
||||
@@ -760,18 +758,21 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
else if (thisParams == 0)
|
||||
{
|
||||
containingType = unboundType.ContainingType.Construct(typeArguments);
|
||||
// all type arguments belong to containing type
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
containingType = unboundType.ContainingType.Construct(typeArguments.Take(parentParams));
|
||||
// some type arguments belong to containing type
|
||||
var parentParams = suppliedArgs - thisParams;
|
||||
containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams));
|
||||
thisTypeArguments = typeArguments.Skip(parentParams).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if(obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
|
||||
if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
|
||||
{
|
||||
if (thisTypeArguments is null) return t.thisTypeArguments is null;
|
||||
if (!(t.thisTypeArguments is null)) return thisTypeArguments.SequenceEqual(t.thisTypeArguments);
|
||||
@@ -788,12 +789,12 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
return h;
|
||||
}
|
||||
|
||||
readonly Type containingType;
|
||||
public override Type ContainingType => containingType;
|
||||
readonly Type? containingType;
|
||||
public override Type? ContainingType => containingType;
|
||||
|
||||
public override string Name => unboundGenericType.Name;
|
||||
|
||||
public override Namespace Namespace => unboundGenericType.Namespace;
|
||||
public override Namespace Namespace => unboundGenericType.Namespace!;
|
||||
|
||||
public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length;
|
||||
|
||||
@@ -851,7 +852,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
typeCode = tc;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PrimitiveType pt && typeCode == pt.typeCode;
|
||||
}
|
||||
@@ -871,7 +872,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override Namespace Namespace => cx.SystemNamespace;
|
||||
|
||||
public override Type ContainingType => null;
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameters => 0;
|
||||
|
||||
@@ -894,19 +895,17 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
readonly Type elementType;
|
||||
readonly int rank;
|
||||
|
||||
public ArrayType(Context cx, Type element, ArrayShape shape) : base(cx)
|
||||
public ArrayType(Context cx, Type elementType, int rank) : base(cx)
|
||||
{
|
||||
rank = shape.Rank;
|
||||
elementType = element;
|
||||
this.rank = rank;
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public ArrayType(Context cx, Type element) : base(cx)
|
||||
public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1)
|
||||
{
|
||||
rank = 1;
|
||||
elementType = element;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
|
||||
}
|
||||
@@ -929,7 +928,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override Namespace Namespace => cx.SystemNamespace;
|
||||
|
||||
public override Type ContainingType => null;
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameters => elementType.ThisTypeParameters;
|
||||
|
||||
@@ -972,9 +971,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
this.gc = gc;
|
||||
}
|
||||
|
||||
public override Namespace Namespace => null;
|
||||
public override Namespace? Namespace => null;
|
||||
|
||||
public override Type ContainingType => null;
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameters => 0;
|
||||
|
||||
@@ -1034,7 +1033,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index;
|
||||
}
|
||||
@@ -1072,7 +1071,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
type = t;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index;
|
||||
}
|
||||
@@ -1089,7 +1088,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override TypeContainer Parent => type ?? gc as TypeContainer;
|
||||
public override TypeContainer Parent => type;
|
||||
public override string Name => "!" + index;
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => Enumerable.Empty<Type>();
|
||||
@@ -1119,7 +1118,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
this.pointee = pointee;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is PointerType pt && pointee.Equals(pt.pointee);
|
||||
}
|
||||
@@ -1138,9 +1137,9 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override string Name => pointee.Name + "*";
|
||||
|
||||
public override Namespace Namespace => pointee.Namespace;
|
||||
public override Namespace? Namespace => pointee.Namespace;
|
||||
|
||||
public override Type ContainingType => pointee.ContainingType;
|
||||
public override Type? ContainingType => pointee.ContainingType;
|
||||
|
||||
public override TypeContainer Parent => pointee.Parent;
|
||||
|
||||
@@ -1180,7 +1179,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public override Namespace Namespace => cx.GlobalNamespace;
|
||||
|
||||
public override Type ContainingType => null;
|
||||
public override Type? ContainingType => null;
|
||||
|
||||
public override int ThisTypeParameters => 0;
|
||||
|
||||
@@ -1202,13 +1201,20 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
struct Array : ITypeSignature
|
||||
{
|
||||
public ITypeSignature elementType;
|
||||
public ArrayShape shape;
|
||||
private readonly ITypeSignature elementType;
|
||||
private readonly ArrayShape shape;
|
||||
|
||||
public Array(ITypeSignature elementType, ArrayShape shape) : this()
|
||||
{
|
||||
this.elementType = elementType;
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
trapFile.Write('[');
|
||||
for (int i=1; i<shape.Rank; ++i)
|
||||
for (int i = 1; i < shape.Rank; ++i)
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(']');
|
||||
}
|
||||
@@ -1216,7 +1222,12 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
struct ByRef : ITypeSignature
|
||||
{
|
||||
public ITypeSignature elementType;
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public ByRef(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1227,7 +1238,12 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
struct FnPtr : ITypeSignature
|
||||
{
|
||||
public MethodSignature<ITypeSignature> signature;
|
||||
private readonly MethodSignature<ITypeSignature> signature;
|
||||
|
||||
public FnPtr(MethodSignature<ITypeSignature> signature)
|
||||
{
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1236,25 +1252,32 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetArrayType(ITypeSignature elementType, ArrayShape shape) =>
|
||||
new Array { elementType = elementType, shape = shape };
|
||||
new Array(elementType, shape);
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetByReferenceType(ITypeSignature elementType) =>
|
||||
new ByRef { elementType = elementType };
|
||||
new ByRef(elementType);
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetFunctionPointerType(MethodSignature<ITypeSignature> signature) =>
|
||||
new FnPtr { signature = signature };
|
||||
new FnPtr(signature);
|
||||
|
||||
class Instantiation : ITypeSignature
|
||||
{
|
||||
public ITypeSignature genericType;
|
||||
public ImmutableArray<ITypeSignature> typeArguments;
|
||||
private readonly ITypeSignature genericType;
|
||||
private readonly ImmutableArray<ITypeSignature> typeArguments;
|
||||
|
||||
public Instantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments)
|
||||
{
|
||||
this.genericType = genericType;
|
||||
this.typeArguments = typeArguments;
|
||||
}
|
||||
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
genericType.WriteId(trapFile, gc);
|
||||
trapFile.Write('<');
|
||||
int index = 0;
|
||||
foreach(var arg in typeArguments)
|
||||
foreach (var arg in typeArguments)
|
||||
{
|
||||
trapFile.WriteSeparator(",", ref index);
|
||||
arg.WriteId(trapFile, gc);
|
||||
@@ -1264,12 +1287,18 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments) =>
|
||||
new Instantiation { genericType = genericType, typeArguments = typeArguments };
|
||||
new Instantiation(genericType, typeArguments);
|
||||
|
||||
class GenericMethodParameter : ITypeSignature
|
||||
{
|
||||
public object innerGc;
|
||||
public int index;
|
||||
private readonly object innerGc;
|
||||
private readonly int index;
|
||||
|
||||
public GenericMethodParameter(object innerGc, int index)
|
||||
{
|
||||
this.innerGc = innerGc;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext outerGc)
|
||||
{
|
||||
@@ -1284,7 +1313,12 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
class GenericTypeParameter : ITypeSignature
|
||||
{
|
||||
public int index;
|
||||
private readonly int index;
|
||||
|
||||
public GenericTypeParameter(int index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1294,16 +1328,23 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericMethodParameter(object genericContext, int index) =>
|
||||
new GenericMethodParameter { innerGc = genericContext, index = index };
|
||||
new GenericMethodParameter(genericContext, index);
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericTypeParameter(object genericContext, int index) =>
|
||||
new GenericTypeParameter { index = index };
|
||||
new GenericTypeParameter(index);
|
||||
|
||||
class Modified : ITypeSignature
|
||||
{
|
||||
public ITypeSignature modifier;
|
||||
public ITypeSignature unmodifiedType;
|
||||
public bool isRequired;
|
||||
private readonly ITypeSignature modifier;
|
||||
private readonly ITypeSignature unmodifiedType;
|
||||
private readonly bool isRequired;
|
||||
|
||||
public Modified(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
|
||||
{
|
||||
this.modifier = modifier;
|
||||
this.unmodifiedType = unmodifiedType;
|
||||
this.isRequired = isRequired;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1313,12 +1354,17 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
|
||||
{
|
||||
return new Modified { modifier = modifier, unmodifiedType = unmodifiedType, isRequired = isRequired };
|
||||
return new Modified(modifier, unmodifiedType, isRequired);
|
||||
}
|
||||
|
||||
class Pinned : ITypeSignature
|
||||
{
|
||||
public ITypeSignature elementType;
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public Pinned(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1329,12 +1375,17 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetPinnedType(ITypeSignature elementType)
|
||||
{
|
||||
return new Pinned { elementType = elementType };
|
||||
return new Pinned(elementType);
|
||||
}
|
||||
|
||||
class PointerType : ITypeSignature
|
||||
{
|
||||
public ITypeSignature elementType;
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public PointerType(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1345,12 +1396,17 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetPointerType(ITypeSignature elementType)
|
||||
{
|
||||
return new PointerType { elementType = elementType };
|
||||
return new PointerType(elementType);
|
||||
}
|
||||
|
||||
class Primitive : ITypeSignature
|
||||
{
|
||||
public PrimitiveTypeCode typeCode;
|
||||
private readonly PrimitiveTypeCode typeCode;
|
||||
|
||||
public Primitive(PrimitiveTypeCode typeCode)
|
||||
{
|
||||
this.typeCode = typeCode;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
@@ -1360,12 +1416,18 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetPrimitiveType(PrimitiveTypeCode typeCode)
|
||||
{
|
||||
return new Primitive { typeCode = typeCode };
|
||||
return new Primitive(typeCode);
|
||||
}
|
||||
|
||||
class SzArrayType : ITypeSignature
|
||||
{
|
||||
public ITypeSignature elementType;
|
||||
private readonly ITypeSignature elementType;
|
||||
|
||||
public SzArrayType(ITypeSignature elementType)
|
||||
{
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
elementType.WriteId(trapFile, gc);
|
||||
@@ -1375,41 +1437,53 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
ITypeSignature ISZArrayTypeProvider<ITypeSignature>.GetSZArrayType(ITypeSignature elementType)
|
||||
{
|
||||
return new SzArrayType { elementType = elementType };
|
||||
return new SzArrayType(elementType);
|
||||
}
|
||||
|
||||
class TypeDefinition : ITypeSignature
|
||||
{
|
||||
public TypeDefinitionHandle handle;
|
||||
public byte rawTypeKind;
|
||||
Type type;
|
||||
private readonly TypeDefinitionHandle handle;
|
||||
private readonly byte rawTypeKind;
|
||||
|
||||
public TypeDefinition(TypeDefinitionHandle handle, byte rawTypeKind)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.rawTypeKind = rawTypeKind;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
type = (Type)gc.cx.Create(handle);
|
||||
var type = (Type)gc.cx.Create(handle);
|
||||
type.WriteId(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
|
||||
{
|
||||
return new TypeDefinition { handle = handle, rawTypeKind = rawTypeKind };
|
||||
return new TypeDefinition(handle, rawTypeKind);
|
||||
}
|
||||
|
||||
class TypeReference : ITypeSignature
|
||||
{
|
||||
public TypeReferenceHandle handle;
|
||||
public byte rawTypeKind; // struct/class (not used)
|
||||
Type type;
|
||||
private readonly TypeReferenceHandle handle;
|
||||
private readonly byte rawTypeKind; // struct/class (not used)
|
||||
|
||||
public TypeReference(TypeReferenceHandle handle, byte rawTypeKind)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.rawTypeKind = rawTypeKind;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter trapFile, GenericContext gc)
|
||||
{
|
||||
type = (Type)gc.cx.Create(handle);
|
||||
var type = (Type)gc.cx.Create(handle);
|
||||
type.WriteId(trapFile);
|
||||
}
|
||||
}
|
||||
|
||||
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
|
||||
{
|
||||
return new TypeReference { handle = handle, rawTypeKind = rawTypeKind };
|
||||
return new TypeReference(handle, rawTypeKind);
|
||||
}
|
||||
|
||||
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
|
||||
@@ -1433,7 +1507,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
}
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetArrayType(Type elementType, ArrayShape shape) =>
|
||||
cx.Populate(new ArrayType(cx, elementType, shape));
|
||||
cx.Populate(new ArrayType(cx, elementType, shape.Rank));
|
||||
|
||||
Type IConstructedTypeProvider<Type>.GetByReferenceType(Type elementType) =>
|
||||
elementType; // ??
|
||||
@@ -1451,8 +1525,7 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
genericContext.GetGenericTypeParameter(index);
|
||||
|
||||
Type ISignatureTypeProvider<Type, GenericContext>.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) =>
|
||||
// !! Not implemented properly
|
||||
unmodifiedType;
|
||||
unmodifiedType; // !! Not implemented properly
|
||||
|
||||
Type ISignatureTypeProvider<Type, GenericContext>.GetPinnedType(Type elementType) =>
|
||||
cx.Populate(new PointerType(cx, elementType));
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL
|
||||
e.WriteId(writer);
|
||||
var id = writer.ToString();
|
||||
|
||||
if (debugLabels.TryGetValue(id, out IExtractedEntity previousEntity))
|
||||
if (debugLabels.TryGetValue(id, out IExtractedEntity? previousEntity))
|
||||
{
|
||||
cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.PDB
|
||||
|
||||
public string Path { get; private set; }
|
||||
|
||||
public string Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null;
|
||||
public string? Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null;
|
||||
}
|
||||
|
||||
// Turns out to be very important to keep the MetadataReaderProvider live
|
||||
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.PDB
|
||||
|
||||
public IEnumerable<ISourceFile> SourceFiles => reader.Documents.Select(handle => new SourceFile(reader, handle));
|
||||
|
||||
public IMethod GetMethod(MethodDebugInformationHandle handle)
|
||||
public IMethod? GetMethod(MethodDebugInformationHandle handle)
|
||||
{
|
||||
var debugInfo = reader.GetMethodDebugInformation(handle);
|
||||
|
||||
@@ -51,10 +51,10 @@ namespace Semmle.Extraction.PDB
|
||||
Where(p => p.Location.File.Path != null).
|
||||
ToArray();
|
||||
|
||||
return sequencePoints.Any() ? new Method() { SequencePoints = sequencePoints } : null;
|
||||
return sequencePoints.Any() ? new Method(sequencePoints) : null;
|
||||
}
|
||||
|
||||
public static MetadataPdbReader CreateFromAssembly(string assemblyPath, PEReader peReader)
|
||||
public static MetadataPdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader)
|
||||
{
|
||||
foreach (var provider in peReader.
|
||||
ReadDebugDirectory().
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Semmle.Extraction.PDB
|
||||
public Document(ISymUnmanagedDocument doc)
|
||||
{
|
||||
document = doc;
|
||||
contents = new Lazy<string>(() =>
|
||||
contents = new Lazy<string?>(() =>
|
||||
{
|
||||
bool isEmbedded;
|
||||
if (document.HasEmbeddedSource(out isEmbedded) == 0 && isEmbedded)
|
||||
@@ -38,7 +38,7 @@ namespace Semmle.Extraction.PDB
|
||||
});
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
var otherDoc = obj as Document;
|
||||
return otherDoc != null && Path.Equals(otherDoc.Path);
|
||||
@@ -50,14 +50,14 @@ namespace Semmle.Extraction.PDB
|
||||
|
||||
public override string ToString() => Path;
|
||||
|
||||
readonly Lazy<string> contents;
|
||||
readonly Lazy<string?> contents;
|
||||
|
||||
public string Contents => contents.Value;
|
||||
public string? Contents => contents.Value;
|
||||
}
|
||||
|
||||
public IEnumerable<ISourceFile> SourceFiles => reader.GetDocuments().Select(d => new Document(d));
|
||||
|
||||
public IMethod GetMethod(MethodDebugInformationHandle h)
|
||||
public IMethod? GetMethod(MethodDebugInformationHandle h)
|
||||
{
|
||||
int methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle());
|
||||
var method = reader.GetMethod(methodToken);
|
||||
@@ -72,7 +72,7 @@ namespace Semmle.Extraction.PDB
|
||||
Select(sp => new SequencePoint(sp.Offset, new Location(new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn))).
|
||||
ToArray();
|
||||
|
||||
return s.Any() ? new Method { SequencePoints = s } : null;
|
||||
return s.Any() ? new Method(s) : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace Semmle.Extraction.PDB
|
||||
readonly ISymUnmanagedReader5 reader;
|
||||
readonly FileStream pdbStream;
|
||||
|
||||
public static NativePdbReader CreateFromAssembly(string assemblyPath, PEReader peReader)
|
||||
public static NativePdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader)
|
||||
{
|
||||
// The Native PDB reader uses an unmanaged Windows DLL
|
||||
// so only works on Windows.
|
||||
@@ -123,7 +123,7 @@ namespace Semmle.Extraction.PDB
|
||||
{
|
||||
}
|
||||
|
||||
public object GetMetadataImport() => null;
|
||||
public object? GetMetadataImport() => null;
|
||||
|
||||
public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Semmle.Extraction.PDB
|
||||
return string.Format("({0},{1})-({2},{3})", StartLine, StartColumn, EndLine, EndColumn);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
var otherLocation = obj as Location;
|
||||
|
||||
@@ -91,7 +91,12 @@ namespace Semmle.Extraction.PDB
|
||||
|
||||
class Method : IMethod
|
||||
{
|
||||
public IEnumerable<SequencePoint> SequencePoints { get; set; }
|
||||
public IEnumerable<SequencePoint> SequencePoints { get; }
|
||||
|
||||
public Method(IEnumerable<SequencePoint> sequencePoints)
|
||||
{
|
||||
SequencePoints = sequencePoints;
|
||||
}
|
||||
|
||||
public Location Location => SequencePoints.First().Location;
|
||||
}
|
||||
@@ -111,7 +116,7 @@ namespace Semmle.Extraction.PDB
|
||||
/// null if the contents are unavailable.
|
||||
/// E.g. if the PDB file exists but the corresponding source files are missing.
|
||||
/// </summary>
|
||||
string Contents { get; }
|
||||
string? Contents { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -131,7 +136,7 @@ namespace Semmle.Extraction.PDB
|
||||
/// </summary>
|
||||
/// <param name="methodHandle">The handle to query.</param>
|
||||
/// <returns>The method information, or null if the method does not have debug information.</returns>
|
||||
IMethod GetMethod(MethodDebugInformationHandle methodHandle);
|
||||
IMethod? GetMethod(MethodDebugInformationHandle methodHandle);
|
||||
}
|
||||
|
||||
class PdbReader
|
||||
@@ -140,11 +145,11 @@ namespace Semmle.Extraction.PDB
|
||||
/// Returns the PDB information associated with an assembly.
|
||||
/// </summary>
|
||||
/// <param name="assemblyPath">The path to the assembly.</param>
|
||||
/// <param name="peReader">The PE reader for the assembky.</param>
|
||||
/// <param name="peReader">The PE reader for the assembly.</param>
|
||||
/// <returns>A PdbReader, or null if no PDB information is available.</returns>
|
||||
public static IPdb Create(string assemblyPath, PEReader peReader)
|
||||
public static IPdb? Create(string assemblyPath, PEReader peReader)
|
||||
{
|
||||
return (IPdb)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ??
|
||||
return (IPdb?)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ??
|
||||
NativePdbReader.CreateFromAssembly(assemblyPath, peReader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -26,28 +26,28 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
// Arguments
|
||||
int index = 0;
|
||||
foreach(var arg in args)
|
||||
foreach (var arg in args)
|
||||
{
|
||||
trapFile.compilation_args(this, index++, arg);
|
||||
}
|
||||
|
||||
// Files
|
||||
index = 0;
|
||||
foreach(var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath)))
|
||||
foreach (var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath)))
|
||||
{
|
||||
trapFile.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)))
|
||||
foreach (var file in cx.Compilation.References.OfType<PortableExecutableReference>().Select(r => Extraction.Entities.File.Create(cx, r.FilePath)))
|
||||
{
|
||||
trapFile.compilation_referencing_files(this, index++, file);
|
||||
}
|
||||
|
||||
// Diagnostics
|
||||
index = 0;
|
||||
foreach(var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d)))
|
||||
foreach (var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d)))
|
||||
{
|
||||
trapFile.diagnostic_for(diag, this, 0, index++);
|
||||
}
|
||||
@@ -57,7 +57,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
var trapFile = cx.TrapWriter.Writer;
|
||||
int index = 0;
|
||||
foreach(float metric in p.Metrics)
|
||||
foreach (float metric in p.Metrics)
|
||||
{
|
||||
trapFile.compilation_time(this, -1, index++, metric);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
trapFile.type_nullability(this, n);
|
||||
}
|
||||
|
||||
if(Info.FlowState != NullableFlowState.None)
|
||||
if (Info.FlowState != NullableFlowState.None)
|
||||
{
|
||||
trapFile.expr_flowstate(this, (int)Info.FlowState);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
protected Expression(ExpressionNodeInfo info)
|
||||
: base(info)
|
||||
{
|
||||
Syntax = (SyntaxNode)info.Node;
|
||||
Syntax = (SyntaxNode)info.Node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -307,7 +307,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
protected new Expression TryPopulate()
|
||||
{
|
||||
cx.Try(Syntax, null, ()=>PopulateExpression(cx.TrapWriter.Writer));
|
||||
cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
@@ -21,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
var child = 0;
|
||||
|
||||
var explicitlySized = false;
|
||||
|
||||
if (TypeSyntax is null)
|
||||
@@ -29,38 +30,21 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
cx.ModelError(Syntax, "Array has unexpected type syntax");
|
||||
}
|
||||
|
||||
foreach (var rank in TypeSyntax.RankSpecifiers.SelectMany(rs => rs.Sizes))
|
||||
var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList<ExpressionSyntax>();
|
||||
|
||||
if (firstLevelSizes.OfType<ExpressionSyntax>().Any(s => s is OmittedArraySizeExpressionSyntax))
|
||||
{
|
||||
if (rank is OmittedArraySizeExpressionSyntax)
|
||||
{
|
||||
// Create an expression which simulates the explicit size of the array
|
||||
|
||||
if (!(Initializer is null))
|
||||
{
|
||||
// An implicitly-sized array must have an initializer.
|
||||
// Guard it just in case.
|
||||
var size = Initializer.Expressions.Count;
|
||||
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None),
|
||||
Location,
|
||||
ExprKind.INT_LITERAL,
|
||||
this,
|
||||
child,
|
||||
true,
|
||||
size.ToString());
|
||||
|
||||
new Expression(info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Create(cx, rank, this, child);
|
||||
explicitlySized = true;
|
||||
}
|
||||
child++;
|
||||
SetArraySizes(Initializer, firstLevelSizes.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var sizeIndex = 0; sizeIndex < firstLevelSizes.Count; sizeIndex++)
|
||||
{
|
||||
Create(cx, firstLevelSizes[sizeIndex], this, sizeIndex);
|
||||
}
|
||||
explicitlySized = true;
|
||||
}
|
||||
|
||||
if (!(Initializer is null))
|
||||
{
|
||||
ArrayInitializer.Create(new ExpressionNodeInfo(cx, Initializer, this, -1));
|
||||
@@ -69,6 +53,31 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
if (explicitlySized)
|
||||
trapFile.explicitly_sized_array_creation(this);
|
||||
}
|
||||
|
||||
private void SetArraySizes(InitializerExpressionSyntax initializer, int rank)
|
||||
{
|
||||
for (var level = 0; level < rank; level++)
|
||||
{
|
||||
if (initializer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var info = new ExpressionInfo(
|
||||
cx,
|
||||
new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None),
|
||||
Location,
|
||||
ExprKind.INT_LITERAL,
|
||||
this,
|
||||
level,
|
||||
true,
|
||||
initializer.Expressions.Count.ToString());
|
||||
|
||||
new Expression(info);
|
||||
|
||||
initializer = initializer.Expressions.FirstOrDefault() as InitializerExpressionSyntax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NormalArrayCreation : ExplicitArrayCreation<ArrayCreationExpressionSyntax>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
}
|
||||
|
||||
public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method)
|
||||
: base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue) )
|
||||
: base(new ExpressionInfo(info.Context, Entities.Type.Create(info.Context, info.ConvertedType), info.Location, ExprKind.OPERATOR_INVOCATION, info.Parent, info.Child, true, info.ExprValue))
|
||||
{
|
||||
Expr = Factory.Create(info.SetParent(this, 0));
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
public static Lambda Create(ExpressionNodeInfo info, SimpleLambdaExpressionSyntax node) => new Lambda(info, node);
|
||||
|
||||
Lambda(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) :
|
||||
this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList == null ? Enumerable.Empty<ParameterSyntax>() : node.ParameterList.Parameters) { }
|
||||
this(info.SetKind(ExprKind.ANONYMOUS_METHOD), node.Body, node.ParameterList == null ? Enumerable.Empty<ParameterSyntax>() : node.ParameterList.Parameters)
|
||||
{ }
|
||||
|
||||
public static Lambda Create(ExpressionNodeInfo info, AnonymousMethodExpressionSyntax node) => new Lambda(info, node);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
class Literal : Expression<LiteralExpressionSyntax>
|
||||
{
|
||||
Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info)) ) { }
|
||||
Literal(ExpressionNodeInfo info) : base(info.SetKind(GetKind(info))) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new Literal(info).TryPopulate();
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
static ExprKind GetKind(ExpressionNodeInfo info)
|
||||
{
|
||||
switch(info.Node.Kind())
|
||||
switch (info.Node.Kind())
|
||||
{
|
||||
case SyntaxKind.DefaultLiteralExpression:
|
||||
return ExprKind.DEFAULT;
|
||||
|
||||
@@ -27,10 +27,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
}
|
||||
}
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info, ConditionalAccessExpressionSyntax node) =>
|
||||
public static Expression Create(ExpressionNodeInfo info, ConditionalAccessExpressionSyntax node)
|
||||
{
|
||||
// The qualifier is located by walking the syntax tree.
|
||||
// `node.WhenNotNull` will contain a MemberBindingExpressionSyntax, calling the method below.
|
||||
CreateFromNode(new ExpressionNodeInfo(info.Context, node.WhenNotNull, info.Parent, info.Child, info.TypeInfo));
|
||||
return CreateFromNode(new ExpressionNodeInfo(info.Context, node.WhenNotNull, info.Parent, info.Child, info.TypeInfo));
|
||||
}
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info, MemberBindingExpressionSyntax node)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
protected override void Populate(TextWriter trapFile)
|
||||
{
|
||||
var @namespace = (INamespaceSymbol) cx.GetModel(Node).GetSymbolInfo(Node.Name).Symbol;
|
||||
var @namespace = (INamespaceSymbol)cx.GetModel(Node).GetSymbolInfo(Node.Name).Symbol;
|
||||
var ns = Namespace.Create(cx, @namespace);
|
||||
trapFile.namespace_declarations(this, ns);
|
||||
trapFile.namespace_declaration_location(this, cx.Create(Node.Name.GetLocation()));
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Emit(trapFile, Loc ?? Syntax.GetLocation(), Parent, Type);
|
||||
Create(cx, nts.ElementType, this, nt.symbol.IsReferenceType ? nt : nt.TypeArguments[0]);
|
||||
}
|
||||
else if(Type is ArrayType array)
|
||||
else if (Type is ArrayType array)
|
||||
{
|
||||
Create(cx, nts.ElementType, Parent, array);
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
if (symbol.HasConstructorConstraint)
|
||||
trapFile.general_type_parameter_constraints(constraints, 3);
|
||||
|
||||
if(symbol.HasUnmanagedTypeConstraint)
|
||||
if (symbol.HasUnmanagedTypeConstraint)
|
||||
trapFile.general_type_parameter_constraints(constraints, 4);
|
||||
|
||||
ITypeSymbol baseType = symbol.HasValueTypeConstraint ?
|
||||
Context.Compilation.GetTypeByMetadataName(valueTypeName) :
|
||||
Context.Compilation.ObjectType;
|
||||
|
||||
if(symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
|
||||
if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated)
|
||||
trapFile.general_type_parameter_constraints(constraints, 5);
|
||||
|
||||
foreach (var abase in symbol.GetAnnotatedTypeConstraints())
|
||||
|
||||
@@ -140,6 +140,12 @@ namespace Semmle.Extraction.CSharp
|
||||
return ExitCode.Failed;
|
||||
}
|
||||
|
||||
// csc.exe (CSharpCompiler.cs) also provides CompilationOptions
|
||||
// .WithMetadataReferenceResolver(),
|
||||
// .WithXmlReferenceResolver() and
|
||||
// .WithSourceReferenceResolver().
|
||||
// These would be needed if we hadn't explicitly provided the source/references
|
||||
// already.
|
||||
var compilation = CSharpCompilation.Create(
|
||||
compilerArguments.CompilationName,
|
||||
syntaxTrees,
|
||||
@@ -147,11 +153,6 @@ namespace Semmle.Extraction.CSharp
|
||||
compilerArguments.CompilationOptions.
|
||||
WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default).
|
||||
WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths))
|
||||
// csc.exe (CSharpCompiler.cs) also provides WithMetadataReferenceResolver,
|
||||
// WithXmlReferenceResolver and
|
||||
// WithSourceReferenceResolver.
|
||||
// These would be needed if we hadn't explicitly provided the source/references
|
||||
// already.
|
||||
);
|
||||
|
||||
analyser.EndInitialize(compilerArguments, commandLineArguments, compilation);
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Semmle.Extraction.Tests
|
||||
var layout = new Semmle.Extraction.Layout(null, null, null);
|
||||
var project = layout.LookupProjectOrNull("foo.cs");
|
||||
|
||||
Assert.NotNull(project);
|
||||
|
||||
// All files are mapped when there's no layout file.
|
||||
Assert.True(layout.FileInLayout("foo.cs"));
|
||||
|
||||
@@ -28,7 +30,7 @@ namespace Semmle.Extraction.Tests
|
||||
Assert.NotEqual(Directory.GetCurrentDirectory(), tmpDir);
|
||||
return;
|
||||
}
|
||||
var f1 = project.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var f1 = project!.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(Logger, tmpDir, "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE);
|
||||
Assert.Equal(f1, g1);
|
||||
|
||||
@@ -72,7 +74,9 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
// Test the trap file
|
||||
var project = layout.LookupProjectOrNull("bar.cs");
|
||||
var trapwriterFilename = project.GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip);
|
||||
Assert.NotNull(project);
|
||||
|
||||
var trapwriterFilename = project!.GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip);
|
||||
Assert.Equal(TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "bar.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE),
|
||||
trapwriterFilename);
|
||||
|
||||
@@ -90,7 +94,9 @@ namespace Semmle.Extraction.Tests
|
||||
// When you specify both a trap file and a layout, use the trap file.
|
||||
var layout = new Semmle.Extraction.Layout(Path.GetFullPath("snapshot\\trap"), null, "something.txt");
|
||||
Assert.True(layout.FileInLayout("bar.cs"));
|
||||
var f1 = layout.LookupProjectOrNull("foo.cs").GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var subProject = layout.LookupProjectOrNull("foo.cs");
|
||||
Assert.NotNull(subProject);
|
||||
var f1 = subProject!.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap"), "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE);
|
||||
Assert.Equal(f1, g1);
|
||||
}
|
||||
@@ -118,13 +124,17 @@ namespace Semmle.Extraction.Tests
|
||||
|
||||
// Use Section 2
|
||||
Assert.True(layout.FileInLayout("bar.cs"));
|
||||
var f1 = layout.LookupProjectOrNull("bar.cs").GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var subProject = layout.LookupProjectOrNull("bar.cs");
|
||||
Assert.NotNull(subProject);
|
||||
var f1 = subProject!.GetTrapPath(Logger, "bar.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var g1 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap2"), "bar.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE);
|
||||
Assert.Equal(f1, g1);
|
||||
|
||||
// Use Section 1
|
||||
Assert.True(layout.FileInLayout("foo.cs"));
|
||||
var f2 = layout.LookupProjectOrNull("foo.cs").GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
subProject = layout.LookupProjectOrNull("foo.cs");
|
||||
Assert.NotNull(subProject);
|
||||
var f2 = subProject!.GetTrapPath(Logger, "foo.cs", TrapWriter.CompressionMode.Gzip);
|
||||
var g2 = TrapWriter.NestPaths(Logger, Path.GetFullPath("snapshot\\trap1"), "foo.cs.trap.gz", TrapWriter.InnerPathComputation.ABSOLUTE);
|
||||
Assert.Equal(f2, g2);
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace Semmle.Extraction.Tests
|
||||
{
|
||||
public class OptionsTests
|
||||
{
|
||||
CSharp.Options options;
|
||||
CSharp.Standalone.Options standaloneOptions;
|
||||
CSharp.Options? options;
|
||||
CSharp.Standalone.Options? standaloneOptions;
|
||||
|
||||
public OptionsTests()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Semmle.Extraction
|
||||
/// <param name="factory">The entity factory.</param>
|
||||
/// <param name="init">The initializer for the entity.</param>
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity where Type:struct
|
||||
public Entity CreateEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity where Type : struct
|
||||
{
|
||||
return CreateNonNullEntity(factory, init);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ namespace Semmle.Extraction
|
||||
/// <returns>The new/existing entity.</returns>
|
||||
public Entity CreateEntityFromSymbol<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init)
|
||||
where Entity : ICachedEntity
|
||||
where Type: ISymbol
|
||||
where Type : ISymbol
|
||||
{
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
|
||||
}
|
||||
@@ -500,7 +500,7 @@ namespace Semmle.Extraction
|
||||
{
|
||||
ExtractionError(message, optionalSymbol.ToDisplayString(), Entities.Location.Create(this, optionalSymbol.Locations.FirstOrDefault()));
|
||||
}
|
||||
else if(!(optionalEntity is null))
|
||||
else if (!(optionalEntity is null))
|
||||
{
|
||||
ExtractionError(message, optionalEntity.Label.ToString(), Entities.Location.Create(this, optionalEntity.ReportingLocation));
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
protected override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace);
|
||||
trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? GeneratedLocation.Create(cx), msg.StackTrace);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
|
||||
@@ -4,7 +4,8 @@ using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
{
|
||||
public abstract class SourceLocation : Location {
|
||||
public abstract class SourceLocation : Location
|
||||
{
|
||||
protected SourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace Semmle.Extraction
|
||||
{
|
||||
entity.WriteQuotedId(trapFile);
|
||||
}
|
||||
catch(Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
|
||||
{
|
||||
trapFile.WriteLine("\"");
|
||||
extractor.Message(new Message("Unhandled exception generating id", entity.ToString() ?? "", null, ex.StackTrace));
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
/// <param name="srcFile">The source file.</param>
|
||||
/// <returns>A newly created TrapWriter.</returns>
|
||||
public TrapWriter CreateTrapWriter(ILogger logger, string srcFile, bool discardDuplicates, TrapWriter.CompressionMode trapCompression) =>
|
||||
public TrapWriter CreateTrapWriter(ILogger logger, string srcFile, bool discardDuplicates, TrapWriter.CompressionMode trapCompression) =>
|
||||
new TrapWriter(logger, srcFile, TRAP_FOLDER, SOURCE_ARCHIVE, discardDuplicates, trapCompression);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Semmle.Util
|
||||
/// dictionary. If a list does not already exist, a new list is
|
||||
/// created.
|
||||
/// </summary>
|
||||
public static void AddAnother<T1, T2>(this Dictionary<T1, List<T2>> dict, T1 key, T2 element) where T1:notnull
|
||||
public static void AddAnother<T1, T2>(this Dictionary<T1, List<T2>> dict, T1 key, T2 element) where T1 : notnull
|
||||
{
|
||||
if (!dict.TryGetValue(key, out var list))
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Semmle.Util
|
||||
/// </remarks>
|
||||
///
|
||||
/// <typeparam name="T">The value type.</typeparam>
|
||||
public class FuzzyDictionary<T> where T:class
|
||||
public class FuzzyDictionary<T> where T : class
|
||||
{
|
||||
// All data items indexed by the "base string" (stripped of numbers)
|
||||
readonly Dictionary<string, List<KeyValuePair<string, T>>> index = new Dictionary<string, List<KeyValuePair<string, T>>>();
|
||||
@@ -61,7 +61,7 @@ namespace Semmle.Util
|
||||
/// <param name="v1">Vector 1</param>
|
||||
/// <param name="v2">Vector 2</param>
|
||||
/// <returns>The Hamming Distance.</returns>
|
||||
static int HammingDistance<U>(IEnumerable<U> v1, IEnumerable<U> v2) where U: notnull
|
||||
static int HammingDistance<U>(IEnumerable<U> v1, IEnumerable<U> v2) where U : notnull
|
||||
{
|
||||
return v1.Zip(v2, (x, y) => x.Equals(y) ? 0 : 1).Sum();
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Semmle.Util
|
||||
/// Enumerates a possibly null enumerable.
|
||||
/// If the enumerable is null, the list is empty.
|
||||
/// </summary>
|
||||
public static IEnumerable<T> EnumerateNull<T>(this IEnumerable<T> items)
|
||||
public static IEnumerable<T> EnumerateNull<T>(this IEnumerable<T>? items)
|
||||
{
|
||||
if (items == null) yield break;
|
||||
foreach (var item in items) yield return item;
|
||||
@@ -93,7 +93,7 @@ namespace Semmle.Util
|
||||
/// <typeparam name="T">The type of the item.</typeparam>
|
||||
/// <param name="items">The list of items to hash.</param>
|
||||
/// <returns>The hash code.</returns>
|
||||
public static int SequenceHash<T>(this IEnumerable<T> items) where T: notnull
|
||||
public static int SequenceHash<T>(this IEnumerable<T> items) where T : notnull
|
||||
{
|
||||
int h = 0;
|
||||
foreach (var i in items)
|
||||
|
||||
@@ -6,18 +6,32 @@
|
||||
import csharp
|
||||
|
||||
//#################### PREDICATES ####################
|
||||
Stmt firstStmt(ForeachStmt fes) {
|
||||
private Stmt firstStmt(ForeachStmt fes) {
|
||||
if fes.getBody() instanceof BlockStmt
|
||||
then result = fes.getBody().(BlockStmt).getStmt(0)
|
||||
else result = fes.getBody()
|
||||
}
|
||||
|
||||
private int numStmts(ForeachStmt fes) {
|
||||
if fes.getBody() instanceof BlockStmt
|
||||
then result = count(fes.getBody().(BlockStmt).getAStmt())
|
||||
else result = 1
|
||||
}
|
||||
|
||||
/** Holds if the type's qualified name is "System.Linq.Enumerable" */
|
||||
predicate isEnumerableType(ValueOrRefType t) { t.hasQualifiedName("System.Linq.Enumerable") }
|
||||
|
||||
/** Holds if the type's qualified name starts with "System.Collections.Generic.IEnumerable" */
|
||||
predicate isIEnumerableType(ValueOrRefType t) {
|
||||
t.getQualifiedName().matches("System.Collections.Generic.IEnumerable%")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `foreach` statement `fes` could be converted to a `.All()` call.
|
||||
* That is, the `ForeachStmt` contains a single `if` with a condition that
|
||||
* accesses the loop variable and with a body that assigns `false` to a variable
|
||||
* and `break`s out of the `foreach`.
|
||||
*/
|
||||
predicate missedAllOpportunity(ForeachStmt fes) {
|
||||
exists(IfStmt is |
|
||||
// The loop contains an if statement with no else case, and nothing else.
|
||||
@@ -36,6 +50,12 @@ predicate missedAllOpportunity(ForeachStmt fes) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `foreach` statement `fes` could be converted to a `.Cast()` call.
|
||||
* That is, the loop variable is accessed only in the first statement of the
|
||||
* block, and the access is a cast. The first statement needs to be a
|
||||
* `LocalVariableDeclStmt`.
|
||||
*/
|
||||
predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
s = firstStmt(fes) and
|
||||
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
|
||||
@@ -47,6 +67,12 @@ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `foreach` statement `fes` could be converted to an `.OfType()` call.
|
||||
* That is, the loop variable is accessed only in the first statement of the
|
||||
* block, and the access is a cast with the `as` operator. The first statement
|
||||
* needs to be a `LocalVariableDeclStmt`.
|
||||
*/
|
||||
predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
s = firstStmt(fes) and
|
||||
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
|
||||
@@ -58,6 +84,12 @@ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `foreach` statement `fes` could be converted to a `.Select()` call.
|
||||
* That is, the loop variable is accessed only in the first statement of the
|
||||
* block, and the access is not a cast. The first statement needs to be a
|
||||
* `LocalVariableDeclStmt`.
|
||||
*/
|
||||
predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
s = firstStmt(fes) and
|
||||
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
|
||||
@@ -66,6 +98,12 @@ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) {
|
||||
not s.getAVariableDeclExpr().getInitializer() instanceof Cast
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `foreach` statement `fes` could be converted to a `.Where()` call.
|
||||
* That is, first statement of the loop is an `if`, which accesses the loop
|
||||
* variable, and the body of the `if` is either a `continue` or there's nothing
|
||||
* else in the loop than the `if`.
|
||||
*/
|
||||
predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) {
|
||||
// The very first thing the foreach loop does is test its iteration variable.
|
||||
is = firstStmt(fes) and
|
||||
@@ -82,12 +120,6 @@ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) {
|
||||
)
|
||||
}
|
||||
|
||||
int numStmts(ForeachStmt fes) {
|
||||
if fes.getBody() instanceof BlockStmt
|
||||
then result = count(fes.getBody().(BlockStmt).getAStmt())
|
||||
else result = 1
|
||||
}
|
||||
|
||||
//#################### CLASSES ####################
|
||||
/** A LINQ Any(...) call. */
|
||||
class AnyCall extends MethodCall {
|
||||
|
||||
25
csharp/ql/src/external/CodeDuplication.qll
vendored
25
csharp/ql/src/external/CodeDuplication.qll
vendored
@@ -66,9 +66,9 @@ class SimilarBlock extends Copy, @similarity {
|
||||
}
|
||||
}
|
||||
|
||||
Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) }
|
||||
private Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) }
|
||||
|
||||
int numberOfSourceMethods(Class c) {
|
||||
private int numberOfSourceMethods(Class c) {
|
||||
result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c)
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `duplicate` number of statements are duplicated in the methods. */
|
||||
predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) {
|
||||
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
|
||||
total = strictcount(statementInMethod(m1))
|
||||
@@ -109,7 +110,7 @@ predicate duplicateMethod(Method m, Method other) {
|
||||
exists(int total | duplicateStatements(m, other, total, total))
|
||||
}
|
||||
|
||||
predicate similarLines(File f, int line) {
|
||||
private predicate similarLines(File f, int line) {
|
||||
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
|
||||
}
|
||||
|
||||
@@ -148,7 +149,7 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile)
|
||||
)
|
||||
}
|
||||
|
||||
predicate duplicateLines(File f, int line) {
|
||||
private predicate duplicateLines(File f, int line) {
|
||||
exists(DuplicateBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
@@ -189,6 +190,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the two files are not duplicated but have more than 80% similar lines. */
|
||||
predicate similarFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
similarLinesCovered(f, covered, other) and
|
||||
@@ -199,6 +201,7 @@ predicate similarFiles(File f, File other, int percent) {
|
||||
not duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/** Holds if the two files have more than 70% duplicated lines. */
|
||||
predicate duplicateFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
duplicateLinesCovered(f, covered, other) and
|
||||
@@ -209,7 +212,7 @@ predicate duplicateFiles(File f, File other, int percent) {
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
|
||||
private predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
|
||||
exists(int numDup |
|
||||
numDup =
|
||||
strictcount(Method m1 |
|
||||
@@ -248,6 +251,7 @@ private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int
|
||||
not other instanceof AnonymousClass
|
||||
}
|
||||
|
||||
/** Holds if the methods in the two classes are more than 80% duplicated. */
|
||||
predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
exists(int numDup, int total |
|
||||
mostlyDuplicateClassBase(c, other, numDup, total) and
|
||||
@@ -272,19 +276,28 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the two files are similar or duplicated. */
|
||||
predicate fileLevelDuplication(File f, File other) {
|
||||
similarFiles(f, other, _) or duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the two classes are duplicated anonymous classes or more than 80% of
|
||||
* their methods are duplicated.
|
||||
*/
|
||||
predicate classLevelDuplication(Class c, Class other) {
|
||||
duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _)
|
||||
}
|
||||
|
||||
Element whitelistedDuplicateElement() {
|
||||
private Element whitelistedDuplicateElement() {
|
||||
result instanceof UsingNamespaceDirective or
|
||||
result instanceof UsingStaticDirective
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `line` in the `file` contains an element, such as a `using`
|
||||
* directive, that is not considered for code duplication.
|
||||
*/
|
||||
predicate whitelistedLineForDuplication(File file, int line) {
|
||||
exists(Location loc | loc = whitelistedDuplicateElement().getLocation() |
|
||||
line = loc.getStartLine() and file = loc.getFile()
|
||||
|
||||
@@ -31,6 +31,7 @@ class ReadRefAccess extends ReadAccess, ReadRef { }
|
||||
|
||||
/** An instruction that writes a variable. */
|
||||
class WriteAccess extends VariableAccess, @cil_write_access {
|
||||
/** Gets the expression whose value is used in this variable write. */
|
||||
Expr getExpr() { none() }
|
||||
}
|
||||
|
||||
|
||||
@@ -437,6 +437,9 @@ class Operator extends Callable, Member, Attributable, @operator {
|
||||
|
||||
override string getName() { operators(this, _, result, _, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
||||
*/
|
||||
string getFunctionName() { none() }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
|
||||
|
||||
@@ -514,6 +514,11 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fromType` is `NullType`, and `toType` is a type that can represent
|
||||
* the `null` value, such as a reference type, `Nullable<T>` or a type parameter
|
||||
* with contraints that restrict it to a reference type.
|
||||
*/
|
||||
// This is a deliberate, small Cartesian product, so we have manually lifted it to force the
|
||||
// evaluator to evaluate it in its entirety, rather than trying to optimize it in context.
|
||||
pragma[noinline]
|
||||
|
||||
@@ -212,7 +212,12 @@ module AbstractValues {
|
||||
c.isValidFor(cfe) and
|
||||
foreachEmptiness(fs, cfe) and
|
||||
e = fs.getIterableExpr()
|
||||
)
|
||||
) and
|
||||
// Only when taking the non-empty successor do we know that the original iterator
|
||||
// expression was non-empty. When taking the empty successor, we may have already
|
||||
// iterated through the `foreach` loop zero or more times, hence the iterator
|
||||
// expression can be both empty and non-empty
|
||||
this.isNonEmpty()
|
||||
}
|
||||
|
||||
override EmptyCollectionValue getDualValue() {
|
||||
|
||||
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -26,6 +26,7 @@ class RuntimeMethod extends RuntimeCallable {
|
||||
this instanceof CIL::Method
|
||||
}
|
||||
|
||||
/** Holds if the method is `static`. */
|
||||
predicate isStatic() { this.(Method).isStatic() or this.(CIL::Method).isStatic() }
|
||||
}
|
||||
|
||||
|
||||
@@ -1011,6 +1011,7 @@ class RangeExpr extends Expr, @range_expr {
|
||||
|
||||
/** An index expression, for example `^1` meaning "1 from the end". */
|
||||
class IndexExpr extends Expr, @index_expr {
|
||||
/** Gets the sub expression of this index expression. */
|
||||
Expr getExpr() { result.getParent() = this }
|
||||
|
||||
override string toString() { result = "^..." }
|
||||
|
||||
@@ -8,7 +8,12 @@ private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
private import semmle.code.csharp.frameworks.Sql
|
||||
private import semmle.code.csharp.dataflow.LibraryTypeDataFlow
|
||||
|
||||
/**
|
||||
* Definitions relating to the `System.ComponentModel.DataAnnotations`
|
||||
* namespace.
|
||||
*/
|
||||
module DataAnnotations {
|
||||
/** Class for `NotMappedAttribute`. */
|
||||
class NotMappedAttribute extends Attribute {
|
||||
NotMappedAttribute() {
|
||||
this
|
||||
@@ -18,6 +23,10 @@ module DataAnnotations {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Definitions relating to the `Microsoft.EntityFrameworkCore` or
|
||||
* `System.Data.Entity` namespaces.
|
||||
*/
|
||||
module EntityFramework {
|
||||
/** An EF6 or EFCore namespace. */
|
||||
class EFNamespace extends Namespace {
|
||||
@@ -43,12 +52,14 @@ module EntityFramework {
|
||||
class DbContext extends EFClass {
|
||||
DbContext() { this.getName() = "DbContext" }
|
||||
|
||||
/** Gets a `Find` or `FindAsync` method in the `DbContext`. */
|
||||
Method getAFindMethod() {
|
||||
result = this.getAMethod("Find")
|
||||
or
|
||||
result = this.getAMethod("FindAsync")
|
||||
}
|
||||
|
||||
/** Gets an `Update` method in the `DbContext`. */
|
||||
Method getAnUpdateMethod() { result = this.getAMethod("Update") }
|
||||
}
|
||||
|
||||
@@ -119,6 +130,7 @@ module EntityFramework {
|
||||
preservesValue = false
|
||||
}
|
||||
|
||||
/** Gets a conversion operator from `string` to `RawSqlString`. */
|
||||
ConversionOperator getAConversionTo() {
|
||||
result = this.getAMember() and
|
||||
result.getTargetType() instanceof RawSqlStringStruct and
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user