1515 * that should be changed to fix the alert.
1616 */
1717
18- import javascript
19-
20- /**
21- * The name of a VS Code command.
22- */
23- class CommandName extends string {
24- CommandName() { exists(CommandUsage e | e.getCommandName() = this) }
25-
26- /**
27- * In how many ways is this command used. Will always be at least 1.
28- */
29- int getNumberOfUsages() { result = count(this.getAUse()) }
30-
31- /**
32- * Get a usage of this command.
33- */
34- CommandUsage getAUse() { result.getCommandName() = this }
35-
36- /**
37- * Get the canonical first usage of this command, to use for the location
38- * of the alert. The implementation of this ordering of usages is arbitrary
39- * and the usage given may not be the one that should be changed when fixing
40- * the alert.
41- */
42- CommandUsage getFirstUsage() {
43- result =
44- max(CommandUsage use |
45- use = this.getAUse()
46- |
47- use
48- order by
49- use.getFile().getRelativePath(), use.getLocation().getStartLine(),
50- use.getLocation().getStartColumn()
51- )
52- }
53- }
54-
55- /**
56- * Represents a single usage of a command, either from within code or
57- * from the command's definition in package.json
58- */
59- abstract class CommandUsage extends Locatable {
60- abstract string getCommandName();
61- }
62-
63- /**
64- * A usage of a command from the typescript code, by calling `executeCommand`.
65- */
66- class CommandUsageCallExpr extends CommandUsage, CallExpr {
67- CommandUsageCallExpr() {
68- this.getCalleeName() = "executeCommand" and
69- this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
70- not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
71- }
72-
73- override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
74- }
75-
76- /**
77- * A usage of a command from the typescript code, by calling `CommandManager.execute`.
78- */
79- class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr {
80- CommandUsageCommandManagerMethodCallExpr() {
81- this.getCalleeName() = "execute" and
82- this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and
83- this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
84- not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
85- }
86-
87- override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
88- }
89-
90- /**
91- * A usage of a command from any menu that isn't the command palette.
92- * This means a user could invoke the command by clicking on a button in
93- * something like a menu or a dropdown.
94- */
95- class CommandUsagePackageJsonMenuItem extends CommandUsage, JsonObject {
96- CommandUsagePackageJsonMenuItem() {
97- exists(this.getPropValue("command")) and
98- exists(PackageJson packageJson, string menuName |
99- packageJson
100- .getPropValue("contributes")
101- .getPropValue("menus")
102- .getPropValue(menuName)
103- .getElementValue(_) = this and
104- menuName != "commandPalette"
105- )
106- }
107-
108- override string getCommandName() { result = this.getPropValue("command").getStringValue() }
109- }
110-
111- /**
112- * Is the given command disabled for use in the command palette by
113- * a block with a `"when": "false"` field.
114- */
115- predicate isDisabledInCommandPalette(string commandName) {
116- exists(PackageJson packageJson, JsonObject commandPaletteObject |
117- packageJson
118- .getPropValue("contributes")
119- .getPropValue("menus")
120- .getPropValue("commandPalette")
121- .getElementValue(_) = commandPaletteObject and
122- commandPaletteObject.getPropValue("command").getStringValue() = commandName and
123- commandPaletteObject.getPropValue("when").getStringValue() = "false"
124- )
125- }
126-
127- /**
128- * Represents a command being usable from the command palette.
129- * This means that a user could choose to manually invoke the command.
130- */
131- class CommandUsagePackageJsonCommandPalette extends CommandUsage, JsonObject {
132- CommandUsagePackageJsonCommandPalette() {
133- this.getFile().getBaseName() = "package.json" and
134- exists(this.getPropValue("command")) and
135- exists(PackageJson packageJson |
136- packageJson.getPropValue("contributes").getPropValue("commands").getElementValue(_) = this
137- ) and
138- not isDisabledInCommandPalette(this.getPropValue("command").getStringValue())
139- }
140-
141- override string getCommandName() { result = this.getPropValue("command").getStringValue() }
142- }
143-
144- from CommandName c
145- where c.getNumberOfUsages() > 1
146- select c.getFirstUsage(),
147- "The " + c + " command is used from " + c.getNumberOfUsages() + " locations"
148-
18+ import javascript
19+
20+ /**
21+ * The name of a VS Code command.
22+ */
23+ class CommandName extends string {
24+ CommandName() { exists(CommandUsage e | e.getCommandName() = this) }
25+
26+ /**
27+ * In how many ways is this command used. Will always be at least 1.
28+ */
29+ int getNumberOfUsages() { result = count(this.getAUse()) }
30+
31+ /**
32+ * Get a usage of this command.
33+ */
34+ CommandUsage getAUse() { result.getCommandName() = this }
35+
36+ /**
37+ * Get the canonical first usage of this command, to use for the location
38+ * of the alert. The implementation of this ordering of usages is arbitrary
39+ * and the usage given may not be the one that should be changed when fixing
40+ * the alert.
41+ */
42+ CommandUsage getFirstUsage() {
43+ result =
44+ max(CommandUsage use |
45+ use = this.getAUse()
46+ |
47+ use
48+ order by
49+ use.getFile().getRelativePath(), use.getLocation().getStartLine(),
50+ use.getLocation().getStartColumn()
51+ )
52+ }
53+ }
54+
55+ /**
56+ * Matches one of the members of `BuiltInVsCodeCommands` from `extensions/ql-vscode/src/common/commands.ts`.
57+ */
58+ class BuiltInVSCodeCommand extends string {
59+ BuiltInVSCodeCommand() {
60+ exists(TypeAliasDeclaration tad |
61+ tad.getIdentifier().getName() = "BuiltInVsCodeCommands" and
62+ tad.getDefinition().(InterfaceTypeExpr).getAMember().getName() = this
63+ )
64+ }
65+ }
66+
67+ /**
68+ * Represents a single usage of a command, either from within code or
69+ * from the command's definition in package.json
70+ */
71+ abstract class CommandUsage extends Locatable {
72+ abstract string getCommandName();
73+ }
74+
75+ /**
76+ * A usage of a command from the typescript code, by calling `executeCommand`.
77+ */
78+ class CommandUsageCallExpr extends CommandUsage, CallExpr {
79+ CommandUsageCallExpr() {
80+ this.getCalleeName() = "executeCommand" and
81+ this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
82+ not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
83+ }
84+
85+ override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
86+ }
87+
88+ /**
89+ * A usage of a command from the typescript code, by calling `CommandManager.execute`.
90+ */
91+ class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr {
92+ CommandUsageCommandManagerMethodCallExpr() {
93+ this.getCalleeName() = "execute" and
94+ this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and
95+ this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
96+ not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
97+ }
98+
99+ override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
100+ }
101+
102+ /**
103+ * A usage of a command from any menu that isn't the command palette.
104+ * This means a user could invoke the command by clicking on a button in
105+ * something like a menu or a dropdown.
106+ */
107+ class CommandUsagePackageJsonMenuItem extends CommandUsage, JsonObject {
108+ CommandUsagePackageJsonMenuItem() {
109+ exists(this.getPropValue("command")) and
110+ exists(PackageJson packageJson, string menuName |
111+ packageJson
112+ .getPropValue("contributes")
113+ .getPropValue("menus")
114+ .getPropValue(menuName)
115+ .getElementValue(_) = this and
116+ menuName != "commandPalette"
117+ )
118+ }
119+
120+ override string getCommandName() { result = this.getPropValue("command").getStringValue() }
121+ }
122+
123+ /**
124+ * Is the given command disabled for use in the command palette by
125+ * a block with a `"when": "false"` field.
126+ */
127+ predicate isDisabledInCommandPalette(string commandName) {
128+ exists(PackageJson packageJson, JsonObject commandPaletteObject |
129+ packageJson
130+ .getPropValue("contributes")
131+ .getPropValue("menus")
132+ .getPropValue("commandPalette")
133+ .getElementValue(_) = commandPaletteObject and
134+ commandPaletteObject.getPropValue("command").getStringValue() = commandName and
135+ commandPaletteObject.getPropValue("when").getStringValue() = "false"
136+ )
137+ }
138+
139+ /**
140+ * Represents a command being usable from the command palette.
141+ * This means that a user could choose to manually invoke the command.
142+ */
143+ class CommandUsagePackageJsonCommandPalette extends CommandUsage, JsonObject {
144+ CommandUsagePackageJsonCommandPalette() {
145+ this.getFile().getBaseName() = "package.json" and
146+ exists(this.getPropValue("command")) and
147+ exists(PackageJson packageJson |
148+ packageJson.getPropValue("contributes").getPropValue("commands").getElementValue(_) = this
149+ ) and
150+ not isDisabledInCommandPalette(this.getPropValue("command").getStringValue())
151+ }
152+
153+ override string getCommandName() { result = this.getPropValue("command").getStringValue() }
154+ }
155+
156+ from CommandName c
157+ where c.getNumberOfUsages() > 1 and not c instanceof BuiltInVSCodeCommand
158+ select c.getFirstUsage(),
159+ "The " + c + " command is used from " + c.getNumberOfUsages() + " locations"
0 commit comments