Skip to content

C#: Telemetry query updates. #11083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions csharp/ql/lib/semmle/code/csharp/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ class RecordClass extends RecordType, Class {
*/
class AnonymousClass extends Class {
AnonymousClass() { anonymous_types(this) }

override string getAPrimaryQlClass() { result = "AnonymousClass" }
}

/**
Expand Down
73 changes: 35 additions & 38 deletions csharp/ql/src/Telemetry/ExternalApi.qll
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ class TestLibrary extends RefType {
* An external API from either the C# Standard Library or a 3rd party library.
*/
class ExternalApi extends DotNet::Callable {
ExternalApi() { this.isUnboundDeclaration() and this.fromLibrary() }
ExternalApi() {
this.isUnboundDeclaration() and
this.fromLibrary() and
this.(Modifiable).isEffectivelyPublic()
}

/**
* Gets the unbound type, name and parameter types of this API.
*/
bindingset[this]
private string getSignature() {
result =
this.getDeclaringType().getUnboundDeclaration() + "." + this.getName() + "(" +
Expand All @@ -42,41 +47,33 @@ class ExternalApi extends DotNet::Callable {
/**
* Gets the namespace of this API.
*/
private string getNamespace() { this.getDeclaringType().hasQualifiedName(result, _) }

/**
* Gets the assembly file name containing this API.
*/
private string getAssembly() { result = this.getFile().getBaseName() }
bindingset[this]
string getNamespace() { this.getDeclaringType().hasQualifiedName(result, _) }

/**
* Gets the assembly file name and namespace of this API.
* Gets the namespace and signature of this API.
*/
string getInfoPrefix() { result = this.getAssembly() + "#" + this.getNamespace() }

/**
* Gets the assembly file name, namespace and signature of this API.
*/
string getInfo() { result = this.getInfoPrefix() + "#" + this.getSignature() }

/** Gets a call to this API callable. */
DispatchCall getACall() {
this = result.getADynamicTarget().getUnboundDeclaration()
or
this = result.getAStaticTarget().getUnboundDeclaration()
}
bindingset[this]
string getApiName() { result = this.getNamespace() + "#" + this.getSignature() }

/** Gets a node that is an input to a call to this API. */
private ArgumentNode getAnInput() {
result.getCall().(DataFlowDispatch::NonDelegateDataFlowCall).getDispatchCall() = this.getACall()
result
.getCall()
.(DataFlowDispatch::NonDelegateDataFlowCall)
.getATarget(_)
.getUnboundDeclaration() = this
}

/** Gets a node that is an output from a call to this API. */
private DataFlow::Node getAnOutput() {
exists(DataFlowDispatch::NonDelegateDataFlowCall call, DataFlowImplCommon::ReturnKindExt ret |
result = ret.getAnOutNode(call)
exists(
Call c, DataFlowDispatch::NonDelegateDataFlowCall dc, DataFlowImplCommon::ReturnKindExt ret
|
dc.getDispatchCall().getCall() = c and
c.getTarget().getUnboundDeclaration() = this
|
this.getACall() = call.getDispatchCall()
result = ret.getAnOutNode(dc)
)
}

Expand Down Expand Up @@ -125,30 +122,30 @@ signature predicate relevantApi(ExternalApi api);
* for restricting the number or returned results based on a certain limit.
*/
module Results<relevantApi/1 getRelevantUsages> {
private int getUsages(string apiInfo) {
private int getUsages(string apiName) {
result =
strictcount(DispatchCall c, ExternalApi api |
c = api.getACall() and
apiInfo = api.getInfo() and
strictcount(Call c, ExternalApi api |
c.getTarget().getUnboundDeclaration() = api and
apiName = api.getApiName() and
getRelevantUsages(api)
)
}

private int getOrder(string apiInfo) {
apiInfo =
rank[result](string info, int usages |
usages = getUsages(info)
private int getOrder(string apiName) {
apiName =
rank[result](string name, int usages |
usages = getUsages(name)
|
info order by usages desc, info
name order by usages desc, name
)
}

/**
* Holds if there exists an API with `apiInfo` that is being used `usages` times
* Holds if there exists an API with `apiName` that is being used `usages` times
* and if it is in the top results (guarded by resultLimit).
*/
predicate restrict(string apiInfo, int usages) {
usages = getUsages(apiInfo) and
getOrder(apiInfo) <= resultLimit()
predicate restrict(string apiName, int usages) {
usages = getUsages(apiName) and
getOrder(apiName) <= resultLimit()
}
}
24 changes: 12 additions & 12 deletions csharp/ql/src/Telemetry/ExternalLibraryUsage.ql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @name External libraries
* @description A list of external libraries used in the code
* @description A list of external libraries used in the code given by their namespace.
* @kind metric
* @tags summary telemetry
* @id csharp/telemetry/external-libs
Expand All @@ -10,23 +10,23 @@ private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi

private predicate getRelevantUsages(string info, int usages) {
private predicate getRelevantUsages(string namespace, int usages) {
usages =
strictcount(DispatchCall c, ExternalApi api |
c = api.getACall() and
api.getInfoPrefix() = info and
strictcount(Call c, ExternalApi api |
c.getTarget().getUnboundDeclaration() = api and
api.getNamespace() = namespace and
not api.isUninteresting()
)
}

private int getOrder(string info) {
info =
private int getOrder(string namespace) {
namespace =
rank[result](string i, int usages | getRelevantUsages(i, usages) | i order by usages desc, i)
}

from ExternalApi api, string info, int usages
from ExternalApi api, string namespace, int usages
where
info = api.getInfoPrefix() and
getRelevantUsages(info, usages) and
getOrder(info) <= resultLimit()
select info, usages order by usages desc
namespace = api.getNamespace() and
getRelevantUsages(namespace, usages) and
getOrder(namespace) <= resultLimit()
select namespace, usages order by usages desc
4 changes: 2 additions & 2 deletions csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
private import semmle.code.csharp.dataflow.internal.NegativeSummary
private import Telemetry.ExternalApi

from DispatchCall c, ExternalApi api
from Call c, ExternalApi api
where
c = api.getACall() and
c.getTarget().getUnboundDeclaration() = api and
not api.isUninteresting() and
not api.isSupported() and
not api instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
| System.Private.CoreLib.dll#System | 5 |
| System.Private.CoreLib.dll#System.Collections.Generic | 2 |
| System | 5 |
| System.Collections.Generic | 2 |
Original file line number Diff line number Diff line change
@@ -1 +1 @@
| System.Private.CoreLib.dll#System.Collections.Generic#List<>.Add(T) | 2 |
| System.Collections.Generic#List<>.Add(T) | 2 |
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
| System.Web.cs#System.Web#HttpResponse.Write(System.Object) | 2 |
| System.Web.cs#System.Web#HttpResponse.WriteFile(System.String) | 1 |
| System.Web#HttpResponse.Write(System.Object) | 2 |
| System.Web#HttpResponse.WriteFile(System.String) | 1 |
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
| System.Console.dll#System#Console.ReadLine() | 2 |
| System.Console.dll#System#Console.Read() | 1 |
| System#Console.ReadLine() | 2 |
| System#Console.Read() | 1 |