Skip to content

Commit e2b211a

Browse files
Merge branch 'main' into robertbrignull/data-modeled-method-signature
pick 2db42e3 Pull out createDataExtensionYamls into yaml.ts pick 52f7cac Move saveModeledMethods to a separate file pick ba27230 Move loadModeledMethods to a separate file pick c512a11 Split out listModelFiles from loadModeledMethods pick 752cf8a Add some tests of listModelFiles
2 parents bb11015 + 10d9213 commit e2b211a

File tree

12 files changed

+267
-35
lines changed

12 files changed

+267
-35
lines changed

extensions/ql-vscode/src/data-extensions-editor/bqrs.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { DecodedBqrsChunk } from "../common/bqrs-cli-types";
2-
import { Call, ExternalApiUsage } from "./external-api-usage";
2+
import {
3+
Call,
4+
CallClassification,
5+
ExternalApiUsage,
6+
} from "./external-api-usage";
7+
import { ModeledMethodType } from "./modeled-method";
38

49
export function decodeBqrsToExternalApiUsages(
510
chunk: DecodedBqrsChunk,
@@ -11,6 +16,8 @@ export function decodeBqrsToExternalApiUsages(
1116
const signature = tuple[1] as string;
1217
const supported = (tuple[2] as string) === "true";
1318
const library = tuple[4] as string;
19+
const type = tuple[6] as ModeledMethodType;
20+
const classification = tuple[8] as CallClassification;
1421

1522
const [packageWithType, methodDeclaration] = signature.split("#");
1623

@@ -39,12 +46,16 @@ export function decodeBqrsToExternalApiUsages(
3946
methodName,
4047
methodParameters,
4148
supported,
49+
supportedType: type,
4250
usages: [],
4351
});
4452
}
4553

4654
const method = methodsByApiName.get(signature)!;
47-
method.usages.push(usage);
55+
method.usages.push({
56+
...usage,
57+
classification,
58+
});
4859
});
4960

5061
return Array.from(methodsByApiName.values());

extensions/ql-vscode/src/data-extensions-editor/external-api-usage.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
import { ResolvableLocationValue } from "../common/bqrs-cli-types";
2+
import { ModeledMethodType } from "./modeled-method";
23

34
export type Call = {
45
label: string;
56
url: ResolvableLocationValue;
67
};
78

9+
export enum CallClassification {
10+
Unknown = "unknown",
11+
Source = "source",
12+
Test = "test",
13+
Generated = "generated",
14+
}
15+
16+
export type Usage = Call & {
17+
classification: CallClassification;
18+
};
19+
820
export interface MethodSignature {
921
/**
1022
* A unique signature that can be used to identify this external API usage.
@@ -33,5 +45,6 @@ export interface ExternalApiUsage extends MethodSignature {
3345
* If so, there is no need for the user to model it themselves.
3446
*/
3547
supported: boolean;
36-
usages: Call[];
48+
supportedType: ModeledMethodType;
49+
usages: Usage[];
3750
}

extensions/ql-vscode/src/data-extensions-editor/queries/csharp.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ class ExternalApi extends CallableMethod {
2222
2323
private Call aUsage(ExternalApi api) { result.getTarget().getUnboundDeclaration() = api }
2424
25-
from ExternalApi api, string apiName, boolean supported, Call usage
25+
from
26+
ExternalApi api, string apiName, boolean supported, Call usage, string type, string classification
2627
where
2728
apiName = api.getApiName() and
2829
supported = isSupported(api) and
29-
usage = aUsage(api)
30-
select usage, apiName, supported.toString(), "supported", api.getFile().getBaseName(), "library"
30+
usage = aUsage(api) and
31+
type = supportedType(api) and
32+
classification = methodClassification(usage)
33+
select usage, apiName, supported.toString(), "supported", api.getFile().getBaseName(), "library",
34+
type, "type", classification, "classification"
3135
`,
3236
frameworkModeQuery: `/**
3337
* @name Public methods
@@ -46,12 +50,13 @@ class PublicMethod extends CallableMethod {
4650
PublicMethod() { this.fromSource() and not this.getFile() instanceof TestFile }
4751
}
4852
49-
from PublicMethod publicMethod, string apiName, boolean supported
53+
from PublicMethod publicMethod, string apiName, boolean supported, string type
5054
where
5155
apiName = publicMethod.getApiName() and
52-
supported = isSupported(publicMethod)
56+
supported = isSupported(publicMethod) and
57+
type = supportedType(publicMethod)
5358
select publicMethod, apiName, supported.toString(), "supported",
54-
publicMethod.getFile().getBaseName(), "library"
59+
publicMethod.getFile().getBaseName(), "library", type, "type", "unknown", "classification"
5560
`,
5661
dependencies: {
5762
"AutomodelVsCode.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
@@ -66,6 +71,7 @@ private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
6671
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
6772
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
6873
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
74+
private import semmle.code.csharp.frameworks.Test
6975
private import semmle.code.csharp.security.dataflow.flowsources.Remote
7076
7177
pragma[nomagic]
@@ -180,6 +186,25 @@ boolean isSupported(CallableMethod callableMethod) {
180186
result = false
181187
}
182188
189+
string supportedType(CallableMethod method) {
190+
method.isSink() and result = "sink"
191+
or
192+
method.isSource() and result = "source"
193+
or
194+
method.hasSummary() and result = "summary"
195+
or
196+
method.isNeutral() and result = "neutral"
197+
or
198+
not method.isSupported() and result = "none"
199+
}
200+
201+
string methodClassification(Call method) {
202+
method.getFile() instanceof TestFile and result = "test"
203+
or
204+
not method.getFile() instanceof TestFile and
205+
result = "source"
206+
}
207+
183208
/**
184209
* Gets the nested name of the declaration.
185210
*

extensions/ql-vscode/src/data-extensions-editor/queries/java.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@ class ExternalApi extends CallableMethod {
1616
ExternalApi() { not this.fromSource() }
1717
}
1818
19-
private Call aUsage(ExternalApi api) {
20-
result.getCallee().getSourceDeclaration() = api and
21-
not result.getFile() instanceof GeneratedFile
22-
}
19+
private Call aUsage(ExternalApi api) { result.getCallee().getSourceDeclaration() = api }
2320
24-
from ExternalApi externalApi, string apiName, boolean supported, Call usage
21+
from
22+
ExternalApi externalApi, string apiName, boolean supported, Call usage, string type,
23+
string classification
2524
where
2625
apiName = externalApi.getApiName() and
2726
supported = isSupported(externalApi) and
28-
usage = aUsage(externalApi)
29-
select usage, apiName, supported.toString(), "supported", externalApi.jarContainer(), "library"
27+
usage = aUsage(externalApi) and
28+
type = supportedType(externalApi) and
29+
classification = methodClassification(usage)
30+
select usage, apiName, supported.toString(), "supported", externalApi.jarContainer(), "library",
31+
type, "type", classification, "classification"
3032
`,
3133
frameworkModeQuery: `/**
3234
* @name Public methods
@@ -41,12 +43,14 @@ import AutomodelVsCode
4143
4244
class PublicMethodFromSource extends CallableMethod, ModelApi { }
4345
44-
from PublicMethodFromSource publicMethod, string apiName, boolean supported
46+
from PublicMethodFromSource publicMethod, string apiName, boolean supported, string type
4547
where
4648
apiName = publicMethod.getApiName() and
47-
supported = isSupported(publicMethod)
49+
supported = isSupported(publicMethod) and
50+
type = supportedType(publicMethod)
4851
select publicMethod, apiName, supported.toString(), "supported",
49-
publicMethod.getCompilationUnit().getParentContainer().getBaseName(), "library"
52+
publicMethod.getCompilationUnit().getParentContainer().getBaseName(), "library", type, "type",
53+
"unknown", "classification"
5054
`,
5155
dependencies: {
5256
"AutomodelVsCode.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
@@ -147,6 +151,28 @@ boolean isSupported(CallableMethod method) {
147151
not method.isSupported() and result = false
148152
}
149153
154+
string supportedType(CallableMethod method) {
155+
method.isSink() and result = "sink"
156+
or
157+
method.isSource() and result = "source"
158+
or
159+
method.hasSummary() and result = "summary"
160+
or
161+
method.isNeutral() and result = "neutral"
162+
or
163+
not method.isSupported() and result = "none"
164+
}
165+
166+
string methodClassification(Call method) {
167+
isInTestFile(method.getLocation().getFile()) and result = "test"
168+
or
169+
method.getFile() instanceof GeneratedFile and result = "generated"
170+
or
171+
not isInTestFile(method.getLocation().getFile()) and
172+
not method.getFile() instanceof GeneratedFile and
173+
result = "source"
174+
}
175+
150176
// The below is a copy of https://github.com/github/codeql/blob/249f9f863db1e94e3c46ca85b49fb0ec32f8ca92/java/ql/lib/semmle/code/java/dataflow/internal/ModelExclusions.qll
151177
// to avoid the use of internal modules.
152178
/** Holds if the given package \`p\` is a test package. */

extensions/ql-vscode/src/data-extensions-editor/queries/query.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export type Query = {
99
* - "supported": a string literal. This is required to make the query a valid problem query.
1010
* - libraryName: the name of the library that contains the external API. This is a string and usually the basename of a file.
1111
* - "library": a string literal. This is required to make the query a valid problem query.
12+
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
13+
* - "type": a string literal. This is required to make the query a valid problem query.
14+
* - classification: the classification of the use of the method, either "source", "test", "generated", or "unknown"
15+
* - "classification: a string literal. This is required to make the query a valid problem query.
1216
*/
1317
applicationModeQuery: string;
1418
/**
@@ -22,6 +26,10 @@ export type Query = {
2226
* - "supported": a string literal. This is required to make the query a valid problem query.
2327
* - libraryName: an arbitrary string. This is required to make it match the structure of the application query.
2428
* - "library": a string literal. This is required to make the query a valid problem query.
29+
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
30+
* - "type": a string literal. This is required to make the query a valid problem query.
31+
* - "unknown": a string literal. This is required to make it match the structure of the application query.
32+
* - "classification: a string literal. This is required to make the query a valid problem query.
2533
*/
2634
frameworkModeQuery: string;
2735
dependencies?: {

extensions/ql-vscode/src/stories/data-extensions-editor/DataExtensionsEditor.stories.tsx

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ComponentMeta, ComponentStory } from "@storybook/react";
44

55
import { Mode } from "../../data-extensions-editor/shared/mode";
66
import { DataExtensionsEditor as DataExtensionsEditorComponent } from "../../view/data-extensions-editor/DataExtensionsEditor";
7+
import { CallClassification } from "../../data-extensions-editor/external-api-usage";
78

89
export default {
910
title: "Data Extensions Editor/Data Extensions Editor",
@@ -39,6 +40,7 @@ DataExtensionsEditor.args = {
3940
methodName: "createQuery",
4041
methodParameters: "(String)",
4142
supported: true,
43+
supportedType: "summary",
4244
usages: Array(10).fill({
4345
label: "createQuery(...)",
4446
url: {
@@ -48,6 +50,7 @@ DataExtensionsEditor.args = {
4850
endLine: 15,
4951
endColumn: 56,
5052
},
53+
classification: CallClassification.Source,
5154
}),
5255
},
5356
{
@@ -58,6 +61,7 @@ DataExtensionsEditor.args = {
5861
methodName: "executeScalar",
5962
methodParameters: "(Class)",
6063
supported: true,
64+
supportedType: "neutral",
6165
usages: Array(2).fill({
6266
label: "executeScalar(...)",
6367
url: {
@@ -67,6 +71,7 @@ DataExtensionsEditor.args = {
6771
endLine: 15,
6872
endColumn: 85,
6973
},
74+
classification: CallClassification.Source,
7075
}),
7176
},
7277
{
@@ -77,6 +82,7 @@ DataExtensionsEditor.args = {
7782
methodName: "open",
7883
methodParameters: "()",
7984
supported: false,
85+
supportedType: "none",
8086
usages: Array(28).fill({
8187
label: "open(...)",
8288
url: {
@@ -86,6 +92,7 @@ DataExtensionsEditor.args = {
8692
endLine: 14,
8793
endColumn: 35,
8894
},
95+
classification: CallClassification.Source,
8996
}),
9097
},
9198
{
@@ -96,6 +103,7 @@ DataExtensionsEditor.args = {
96103
methodName: "println",
97104
methodParameters: "(String)",
98105
supported: true,
106+
supportedType: "summary",
99107
usages: [
100108
{
101109
label: "println(...)",
@@ -106,6 +114,18 @@ DataExtensionsEditor.args = {
106114
endLine: 29,
107115
endColumn: 49,
108116
},
117+
classification: CallClassification.Source,
118+
},
119+
{
120+
label: "println(...)",
121+
url: {
122+
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/test/java/org/example/HelloControllerTest.java",
123+
startLine: 29,
124+
startColumn: 9,
125+
endLine: 29,
126+
endColumn: 49,
127+
},
128+
classification: CallClassification.Test,
109129
},
110130
],
111131
},
@@ -118,6 +138,7 @@ DataExtensionsEditor.args = {
118138
methodName: "run",
119139
methodParameters: "(Class,String[])",
120140
supported: false,
141+
supportedType: "none",
121142
usages: Array(7).fill({
122143
label: "run(...)",
123144
url: {
@@ -127,6 +148,7 @@ DataExtensionsEditor.args = {
127148
endLine: 9,
128149
endColumn: 66,
129150
},
151+
classification: CallClassification.Source,
130152
}),
131153
},
132154
{
@@ -137,6 +159,7 @@ DataExtensionsEditor.args = {
137159
methodName: "Sql2o",
138160
methodParameters: "(String,String,String)",
139161
supported: false,
162+
supportedType: "none",
140163
usages: Array(106).fill({
141164
label: "new Sql2o(...)",
142165
url: {
@@ -145,6 +168,7 @@ DataExtensionsEditor.args = {
145168
startColumn: 33,
146169
endLine: 10,
147170
endColumn: 88,
171+
classification: CallClassification.Test,
148172
},
149173
}),
150174
},
@@ -156,16 +180,31 @@ DataExtensionsEditor.args = {
156180
methodName: "Sql2o",
157181
methodParameters: "(String)",
158182
supported: false,
159-
usages: Array(4).fill({
160-
label: "new Sql2o(...)",
161-
url: {
162-
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
163-
startLine: 23,
164-
startColumn: 23,
165-
endLine: 23,
166-
endColumn: 36,
183+
supportedType: "none",
184+
usages: [
185+
...Array(4).fill({
186+
label: "new Sql2o(...)",
187+
url: {
188+
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
189+
startLine: 23,
190+
startColumn: 23,
191+
endLine: 23,
192+
endColumn: 36,
193+
},
194+
classification: CallClassification.Test,
195+
}),
196+
{
197+
label: "new Sql2o(...)",
198+
url: {
199+
uri: "file:/home/runner/work/sql2o-example/sql2o-example/build/generated/java/org/example/HelloControllerGenerated.java",
200+
startLine: 23,
201+
startColumn: 23,
202+
endLine: 23,
203+
endColumn: 36,
204+
},
205+
classification: CallClassification.Generated,
167206
},
168-
}),
207+
],
169208
},
170209
],
171210
initialModeledMethods: {

0 commit comments

Comments
 (0)