@@ -33,157 +33,157 @@ select apiName, supported, usage
3333 dependencies : {
3434 "ExternalApi.qll" : `/** Provides classes and predicates related to handling APIs from external libraries. */
3535
36- private import java
37- private import semmle.code.java.dataflow.DataFlow
38- private import semmle.code.java.dataflow.ExternalFlow
39- private import semmle.code.java.dataflow.FlowSources
40- private import semmle.code.java.dataflow.FlowSummary
41- private import semmle.code.java.dataflow.internal.DataFlowPrivate
42- private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
43- private import semmle.code.java.dataflow.TaintTracking
44-
45- pragma[nomagic]
46- private predicate isTestPackage(Package p) {
47- p.getName()
48- .matches([
49- "org.junit%", "junit.%", "org.mockito%", "org.assertj%",
50- "com.github.tomakehurst.wiremock%", "org.hamcrest%", "org.springframework.test.%",
51- "org.springframework.mock.%", "org.springframework.boot.test.%", "reactor.test%",
52- "org.xmlunit%", "org.testcontainers.%", "org.opentest4j%", "org.mockserver%",
53- "org.powermock%", "org.skyscreamer.jsonassert%", "org.rnorth.visibleassertions",
54- "org.openqa.selenium%", "com.gargoylesoftware.htmlunit%", "org.jboss.arquillian.testng%",
55- "org.testng%"
56- ])
57- }
58-
59- /**
60- * A test library.
61- */
62- private class TestLibrary extends RefType {
63- TestLibrary() { isTestPackage(this.getPackage()) }
64- }
65-
66- private string containerAsJar(Container container) {
67- if container instanceof JarFile then result = container.getBaseName() else result = "rt.jar"
68- }
69-
70- /** Holds if the given callable is not worth supporting. */
71- private predicate isUninteresting(Callable c) {
72- c.getDeclaringType() instanceof TestLibrary or
73- c.(Constructor).isParameterless()
74- }
75-
76- /**
77- * An external API from either the Standard Library or a 3rd party library.
78- */
79- class ExternalApi extends Callable {
80- ExternalApi() { not this.fromSource() and not isUninteresting(this) }
81-
82- /**
83- * Gets information about the external API in the form expected by the MaD modeling framework.
84- */
85- string getApiName() {
86- result =
87- this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() +
88- "#" + this.getName() + paramsString(this)
89- }
90-
91- /**
92- * Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules.
93- */
94- string jarContainer() { result = containerAsJar(this.getCompilationUnit().getParentContainer*()) }
95-
96- /** Gets a node that is an input to a call to this API. */
97- private DataFlow::Node getAnInput() {
98- exists(Call call | call.getCallee().getSourceDeclaration() = this |
99- result.asExpr().(Argument).getCall() = call or
100- result.(ArgumentNode).getCall().asCall() = call
101- )
102- }
103-
104- /** Gets a node that is an output from a call to this API. */
105- private DataFlow::Node getAnOutput() {
106- exists(Call call | call.getCallee().getSourceDeclaration() = this |
107- result.asExpr() = call or
108- result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
109- )
110- }
111-
112- /** Holds if this API has a supported summary. */
113- pragma[nomagic]
114- predicate hasSummary() {
115- this = any(SummarizedCallable sc).asCallable() or
116- TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
117- }
118-
119- pragma[nomagic]
120- predicate isSource() {
121- this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
122- }
123-
124- /** Holds if this API is a known sink. */
125- pragma[nomagic]
126- predicate isSink() { sinkNode(this.getAnInput(), _) }
127-
128- /** Holds if this API is a known neutral. */
129- pragma[nomagic]
130- predicate isNeutral() { this = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() }
131-
132- /**
133- * Holds if this API is supported by existing CodeQL libraries, that is, it is either a
134- * recognized source, sink or neutral or it has a flow summary.
135- */
136- predicate isSupported() {
137- this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
138- }
139- }
140-
141- /** DEPRECATED: Alias for ExternalApi */
142- deprecated class ExternalAPI = ExternalApi;
143-
144- /**
145- * Gets the limit for the number of results produced by a telemetry query.
146- */
147- int resultLimit() { result = 1000 }
148-
149- /**
150- * Holds if it is relevant to count usages of \`api\`.
151- */
152- signature predicate relevantApi(ExternalApi api);
153-
154- /**
155- * Given a predicate to count relevant API usages, this module provides a predicate
156- * for restricting the number or returned results based on a certain limit.
157- */
158- module Results<relevantApi/1 getRelevantUsages> {
159- private int getUsages(string apiName) {
160- result =
161- strictcount(Call c, ExternalApi api |
162- c.getCallee().getSourceDeclaration() = api and
163- not c.getFile() instanceof GeneratedFile and
164- apiName = api.getApiName() and
165- getRelevantUsages(api)
166- )
167- }
168-
169- private int getOrder(string apiInfo) {
170- apiInfo =
171- rank[result](string info, int usages |
172- usages = getUsages(info)
173- |
174- info order by usages desc, info
175- )
176- }
177-
178- /**
179- * Holds if there exists an API with \`apiName\` that is being used \`usages\` times
180- * and if it is in the top results (guarded by resultLimit).
181- */
182- predicate restrict(string apiName, int usages) {
183- usages = getUsages(apiName) and
184- getOrder(apiName) <= resultLimit()
185- }
186- }
36+ private import java
37+ private import semmle.code.java.dataflow.DataFlow
38+ private import semmle.code.java.dataflow.ExternalFlow
39+ private import semmle.code.java.dataflow.FlowSources
40+ private import semmle.code.java.dataflow.FlowSummary
41+ private import semmle.code.java.dataflow.internal.DataFlowPrivate
42+ private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
43+ private import semmle.code.java.dataflow.TaintTracking
44+
45+ pragma[nomagic]
46+ private predicate isTestPackage(Package p) {
47+ p.getName()
48+ .matches([
49+ "org.junit%", "junit.%", "org.mockito%", "org.assertj%",
50+ "com.github.tomakehurst.wiremock%", "org.hamcrest%", "org.springframework.test.%",
51+ "org.springframework.mock.%", "org.springframework.boot.test.%", "reactor.test%",
52+ "org.xmlunit%", "org.testcontainers.%", "org.opentest4j%", "org.mockserver%",
53+ "org.powermock%", "org.skyscreamer.jsonassert%", "org.rnorth.visibleassertions",
54+ "org.openqa.selenium%", "com.gargoylesoftware.htmlunit%", "org.jboss.arquillian.testng%",
55+ "org.testng%"
56+ ])
57+ }
58+
59+ /**
60+ * A test library.
61+ */
62+ private class TestLibrary extends RefType {
63+ TestLibrary() { isTestPackage(this.getPackage()) }
64+ }
65+
66+ private string containerAsJar(Container container) {
67+ if container instanceof JarFile then result = container.getBaseName() else result = "rt.jar"
68+ }
69+
70+ /** Holds if the given callable is not worth supporting. */
71+ private predicate isUninteresting(Callable c) {
72+ c.getDeclaringType() instanceof TestLibrary or
73+ c.(Constructor).isParameterless()
74+ }
75+
76+ /**
77+ * An external API from either the Standard Library or a 3rd party library.
78+ */
79+ class ExternalApi extends Callable {
80+ ExternalApi() { not this.fromSource() and not isUninteresting(this) }
81+
82+ /**
83+ * Gets information about the external API in the form expected by the MaD modeling framework.
84+ */
85+ string getApiName() {
86+ result =
87+ this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() +
88+ "#" + this.getName() + paramsString(this)
89+ }
90+
91+ /**
92+ * Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules.
93+ */
94+ string jarContainer() { result = containerAsJar(this.getCompilationUnit().getParentContainer*()) }
95+
96+ /** Gets a node that is an input to a call to this API. */
97+ private DataFlow::Node getAnInput() {
98+ exists(Call call | call.getCallee().getSourceDeclaration() = this |
99+ result.asExpr().(Argument).getCall() = call or
100+ result.(ArgumentNode).getCall().asCall() = call
101+ )
102+ }
103+
104+ /** Gets a node that is an output from a call to this API. */
105+ private DataFlow::Node getAnOutput() {
106+ exists(Call call | call.getCallee().getSourceDeclaration() = this |
107+ result.asExpr() = call or
108+ result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
109+ )
110+ }
111+
112+ /** Holds if this API has a supported summary. */
113+ pragma[nomagic]
114+ predicate hasSummary() {
115+ this = any(SummarizedCallable sc).asCallable() or
116+ TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
117+ }
118+
119+ pragma[nomagic]
120+ predicate isSource() {
121+ this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
122+ }
123+
124+ /** Holds if this API is a known sink. */
125+ pragma[nomagic]
126+ predicate isSink() { sinkNode(this.getAnInput(), _) }
127+
128+ /** Holds if this API is a known neutral. */
129+ pragma[nomagic]
130+ predicate isNeutral() { this = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() }
131+
132+ /**
133+ * Holds if this API is supported by existing CodeQL libraries, that is, it is either a
134+ * recognized source, sink or neutral or it has a flow summary.
135+ */
136+ predicate isSupported() {
137+ this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
138+ }
139+ }
140+
141+ /** DEPRECATED: Alias for ExternalApi */
142+ deprecated class ExternalAPI = ExternalApi;
143+
144+ /**
145+ * Gets the limit for the number of results produced by a telemetry query.
146+ */
147+ int resultLimit() { result = 1000 }
148+
149+ /**
150+ * Holds if it is relevant to count usages of \`api\`.
151+ */
152+ signature predicate relevantApi(ExternalApi api);
153+
154+ /**
155+ * Given a predicate to count relevant API usages, this module provides a predicate
156+ * for restricting the number or returned results based on a certain limit.
157+ */
158+ module Results<relevantApi/1 getRelevantUsages> {
159+ private int getUsages(string apiName) {
160+ result =
161+ strictcount(Call c, ExternalApi api |
162+ c.getCallee().getSourceDeclaration() = api and
163+ not c.getFile() instanceof GeneratedFile and
164+ apiName = api.getApiName() and
165+ getRelevantUsages(api)
166+ )
167+ }
168+
169+ private int getOrder(string apiInfo) {
170+ apiInfo =
171+ rank[result](string info, int usages |
172+ usages = getUsages(info)
173+ |
174+ info order by usages desc, info
175+ )
176+ }
177+
178+ /**
179+ * Holds if there exists an API with \`apiName\` that is being used \`usages\` times
180+ * and if it is in the top results (guarded by resultLimit).
181+ */
182+ predicate restrict(string apiName, int usages) {
183+ usages = getUsages(apiName) and
184+ getOrder(apiName) <= resultLimit()
185+ }
186+ }
187187` ,
188188 } ,
189189} ;
0 commit comments