@@ -12,6 +12,13 @@ import * as messages from "./messages";
1212import { QueryServerClient } from "./queryserver-client" ;
1313import { compileAndRunQueryAgainstDatabase , QueryWithResults } from "./run-queries" ;
1414
15+ /**
16+ * Run templated CodeQL queries to find definitions and references in
17+ * source-language files. We may eventually want to find a way to
18+ * generalize this to other custom queries, e.g. showing dataflow to
19+ * or from a selected identifier.
20+ */
21+
1522const TEMPLATE_NAME = "selectedSourceFile" ;
1623const SELECT_QUERY_NAME = "#select" ;
1724
@@ -46,104 +53,62 @@ async function qlpackOfDatabase(cli: CodeQLCliServer, db: DatabaseItem): Promise
4653 return qlpack ;
4754}
4855
49- export async function createDefinitionsHandler ( cli : CodeQLCliServer , qs : QueryServerClient , dbm : DatabaseManager ) : Promise < vscode . DefinitionProvider > {
50- let fileCache = new CachedOperation < vscode . LocationLink [ ] > ( async ( uriString : string ) => {
51- const uri = decodeSourceArchiveUri ( vscode . Uri . parse ( uriString ) ) ;
52- const sourceArchiveUri = vscode . Uri . file ( uri . sourceArchiveZipPath ) . with ( { scheme : zipArchiveScheme } ) ;
53-
54- const db = dbm . findDatabaseItemBySourceArchive ( sourceArchiveUri ) ;
55- if ( db ) {
56- const qlpack = await qlpackOfDatabase ( cli , db ) ;
57- if ( qlpack === undefined ) {
58- throw new Error ( "Can't infer qlpack from database source archive" ) ;
59- }
60- const links : vscode . DefinitionLink [ ] = [ ]
61- for ( const query of await resolveQueries ( cli , qlpack , KeyType . DefinitionQuery ) ) {
62- const templates : messages . TemplateDefinitions = {
63- [ TEMPLATE_NAME ] : {
64- values : {
65- tuples : [ [ {
66- stringValue : uri . pathWithinSourceArchive
67- } ] ]
68- }
69- }
70- } ;
71- const results = await compileAndRunQueryAgainstDatabase ( cli , qs , db , false , vscode . Uri . file ( query ) , templates ) ;
72- if ( results . result . resultType == messages . QueryResultType . SUCCESS ) {
73- links . push ( ...await getLinksFromResults ( results , cli , db , ( src , _dest ) => src === uriString ) ) ;
74- }
75- }
76- return links ;
77- } else {
78- return [ ] ;
79- }
80- } ) ;
81-
82- return {
83- async provideDefinition ( document : vscode . TextDocument , position : vscode . Position , _token : vscode . CancellationToken ) : Promise < vscode . LocationLink [ ] > {
84- const fileLinks = await fileCache . get ( document . uri . toString ( ) ) ;
85- let locLinks : vscode . LocationLink [ ] = [ ] ;
86- for ( const link of fileLinks ) {
87- if ( link . originSelectionRange ! . contains ( position ) ) {
88- locLinks . push ( link ) ;
89- }
90- }
91- return locLinks ;
92- }
93-
94- } ;
95- }
96-
9756interface FullLocationLink extends vscode . LocationLink {
9857 originUri : vscode . Uri ;
9958}
10059
101- export async function createReferencesHander ( cli : CodeQLCliServer , qs : QueryServerClient , dbm : DatabaseManager ) : Promise < vscode . ReferenceProvider > {
102- let fileCache = new CachedOperation < FullLocationLink [ ] > ( async ( uriString : string ) => {
103- const uri = decodeSourceArchiveUri ( vscode . Uri . parse ( uriString ) ) ;
104- const sourceArchiveUri = vscode . Uri . file ( uri . sourceArchiveZipPath ) . with ( { scheme : zipArchiveScheme } ) ;
60+ export class TemplateQueryDefinitionProvider implements vscode . DefinitionProvider {
61+ private cache : CachedOperation < vscode . LocationLink [ ] > ;
10562
106- const db = dbm . findDatabaseItemBySourceArchive ( sourceArchiveUri ) ;
107- if ( db ) {
108- const qlpack = await qlpackOfDatabase ( cli , db ) ;
109- if ( qlpack === undefined ) {
110- throw new Error ( "Can't infer qlpack from database source archive" ) ;
111- }
112- const links : FullLocationLink [ ] = [ ]
113- for ( const query of await resolveQueries ( cli , qlpack , KeyType . ReferenceQuery ) ) {
114- const templates : messages . TemplateDefinitions = {
115- [ TEMPLATE_NAME ] : {
116- values : {
117- tuples : [ [ {
118- stringValue : uri . pathWithinSourceArchive
119- } ] ]
120- }
121- }
122- } ;
123- const results = await compileAndRunQueryAgainstDatabase ( cli , qs , db , false , vscode . Uri . file ( query ) , templates ) ;
124- if ( results . result . resultType == messages . QueryResultType . SUCCESS ) {
125- links . push ( ...await getLinksFromResults ( results , cli , db , ( _src , dest ) => dest === uriString ) ) ;
126- }
63+ constructor (
64+ private cli : CodeQLCliServer ,
65+ private qs : QueryServerClient ,
66+ private dbm : DatabaseManager ,
67+ ) {
68+ this . cache = new CachedOperation < vscode . LocationLink [ ] > ( this . getDefinitions . bind ( this ) ) ;
69+ }
70+
71+ async getDefinitions ( uriString : string ) : Promise < vscode . LocationLink [ ] > {
72+ return getLinksForUriString ( this . cli , this . qs , this . dbm , uriString , ( src , _dest ) => src === uriString ) ;
73+ }
74+
75+ async provideDefinition ( document : vscode . TextDocument , position : vscode . Position , _token : vscode . CancellationToken ) : Promise < vscode . LocationLink [ ] > {
76+ const fileLinks = await this . cache . get ( document . uri . toString ( ) ) ;
77+ let locLinks : vscode . LocationLink [ ] = [ ] ;
78+ for ( const link of fileLinks ) {
79+ if ( link . originSelectionRange ! . contains ( position ) ) {
80+ locLinks . push ( link ) ;
12781 }
128- return links ;
129- } else {
130- return [ ] ;
13182 }
132- } )
133-
134- return {
135- async provideReferences ( document : vscode . TextDocument , position : vscode . Position , _context : vscode . ReferenceContext , _token : vscode . CancellationToken ) : Promise < vscode . Location [ ] > {
136- const fileLinks = await fileCache . get ( document . uri . toString ( ) ) ;
137- let locLinks : vscode . Location [ ] = [ ] ;
138- for ( const link of fileLinks ) {
139- if ( link . targetRange ! . contains ( position ) ) {
140- locLinks . push ( { range : link . originSelectionRange ! , uri : link . originUri } ) ;
141- }
83+ return locLinks ;
84+ }
85+ }
86+
87+ export class TemplateQueryReferenceProvider implements vscode . ReferenceProvider {
88+ private cache : CachedOperation < FullLocationLink [ ] > ;
89+
90+ constructor (
91+ private cli : CodeQLCliServer ,
92+ private qs : QueryServerClient ,
93+ private dbm : DatabaseManager ,
94+ ) {
95+ this . cache = new CachedOperation < FullLocationLink [ ] > ( this . getReferences . bind ( this ) ) ;
96+ }
97+
98+ async getReferences ( uriString : string ) : Promise < FullLocationLink [ ] > {
99+ return getLinksForUriString ( this . cli , this . qs , this . dbm , uriString , ( _src , dest ) => dest === uriString ) ;
100+ }
101+
102+ async provideReferences ( document : vscode . TextDocument , position : vscode . Position , _context : vscode . ReferenceContext , _token : vscode . CancellationToken ) : Promise < vscode . Location [ ] > {
103+ const fileLinks = await this . cache . get ( document . uri . toString ( ) ) ;
104+ let locLinks : vscode . Location [ ] = [ ] ;
105+ for ( const link of fileLinks ) {
106+ if ( link . targetRange ! . contains ( position ) ) {
107+ locLinks . push ( { range : link . originSelectionRange ! , uri : link . originUri } ) ;
142108 }
143- return locLinks ;
144109 }
145-
146- } ;
110+ return locLinks ;
111+ }
147112}
148113
149114interface FileRange {
@@ -175,6 +140,44 @@ async function getLinksFromResults(results: QueryWithResults, cli: CodeQLCliServ
175140 return localLinks ;
176141}
177142
143+ async function getLinksForUriString (
144+ cli : CodeQLCliServer ,
145+ qs : QueryServerClient ,
146+ dbm : DatabaseManager ,
147+ uriString : string ,
148+ filter : ( src : string , dest : string ) => boolean
149+ ) {
150+ const uri = decodeSourceArchiveUri ( vscode . Uri . parse ( uriString ) ) ;
151+ const sourceArchiveUri = vscode . Uri . file ( uri . sourceArchiveZipPath ) . with ( { scheme : zipArchiveScheme } ) ;
152+
153+ const db = dbm . findDatabaseItemBySourceArchive ( sourceArchiveUri ) ;
154+ if ( db ) {
155+ const qlpack = await qlpackOfDatabase ( cli , db ) ;
156+ if ( qlpack === undefined ) {
157+ throw new Error ( "Can't infer qlpack from database source archive" ) ;
158+ }
159+ const links : FullLocationLink [ ] = [ ]
160+ for ( const query of await resolveQueries ( cli , qlpack , KeyType . ReferenceQuery ) ) {
161+ const templates : messages . TemplateDefinitions = {
162+ [ TEMPLATE_NAME ] : {
163+ values : {
164+ tuples : [ [ {
165+ stringValue : uri . pathWithinSourceArchive
166+ } ] ]
167+ }
168+ }
169+ } ;
170+ const results = await compileAndRunQueryAgainstDatabase ( cli , qs , db , false , vscode . Uri . file ( query ) , templates ) ;
171+ if ( results . result . resultType == messages . QueryResultType . SUCCESS ) {
172+ links . push ( ...await getLinksFromResults ( results , cli , db , filter ) ) ;
173+ }
174+ }
175+ return links ;
176+ } else {
177+ return [ ] ;
178+ }
179+ }
180+
178181function fileRangeFromURI ( uri : UrlValue , db : DatabaseItem ) : FileRange | undefined {
179182 if ( typeof uri === "string" ) {
180183 return undefined ;
0 commit comments