44 *--------------------------------------------------------------------------------------------*/
55
66import * as serverUtils from '../omnisharp/utils' ;
7- import { CancellationToken , DefinitionProvider , Location , Position , TextDocument , Uri } from 'vscode' ;
8- import { MetadataRequest , MetadataSource , V2 } from '../omnisharp/protocol' ;
7+ import { CancellationToken , TypeDefinitionProvider , DefinitionProvider , Location , Position , TextDocument , Uri } from 'vscode' ;
8+ import { GoToTypeDefinitionRequest , GoToTypeDefinitionResponse , MetadataRequest , MetadataSource , V2 } from '../omnisharp/protocol' ;
99import { createRequest , toRange3 , toVscodeLocation } from '../omnisharp/typeConversion' ;
1010import AbstractSupport from './abstractProvider' ;
1111import DefinitionMetadataOrSourceGeneratedDocumentProvider from './definitionMetadataDocumentProvider' ;
1212import { OmniSharpServer } from '../omnisharp/server' ;
1313import { LanguageMiddlewareFeature } from '../omnisharp/LanguageMiddlewareFeature' ;
1414import SourceGeneratedDocumentProvider from './sourceGeneratedDocumentProvider' ;
1515
16- export default class CSharpDefinitionProvider extends AbstractSupport implements DefinitionProvider {
16+ export default class CSharpDefinitionProvider extends AbstractSupport implements DefinitionProvider , TypeDefinitionProvider {
1717 constructor (
1818 server : OmniSharpServer ,
1919 private definitionMetadataDocumentProvider : DefinitionMetadataOrSourceGeneratedDocumentProvider ,
@@ -23,76 +23,89 @@ export default class CSharpDefinitionProvider extends AbstractSupport implements
2323 }
2424
2525 public async provideDefinition ( document : TextDocument , position : Position , token : CancellationToken ) : Promise < Location [ ] > {
26-
2726 let req = < V2 . GoToDefinitionRequest > createRequest ( document , position ) ;
2827 req . WantMetadata = true ;
2928
30- const locations : Location [ ] = [ ] ;
3129 try {
3230 const gotoDefinitionResponse = await serverUtils . goToDefinition ( this . _server , req , token ) ;
33- // the defintion is in source
34- if ( gotoDefinitionResponse && gotoDefinitionResponse . Definitions ) {
35-
36- for ( const definition of gotoDefinitionResponse . Definitions ) {
37- if ( definition . MetadataSource ) {
38- // the definition is in metadata
39- const metadataSource : MetadataSource = definition . MetadataSource ;
31+ return await this . GetLocationsFromResponse ( gotoDefinitionResponse , token ) ;
32+ }
33+ catch ( error ) {
34+ return [ ] ;
35+ }
36+ }
4037
41- // Do we already have a document for this metadata reference?
42- if ( definition . Location . FileName . startsWith ( "$metadata$" ) &&
43- this . definitionMetadataDocumentProvider . hasMetadataDocument ( definition . Location . FileName ) ) {
38+ public async provideTypeDefinition ( document : TextDocument , position : Position , token : CancellationToken ) : Promise < Location [ ] > {
39+ let req = < GoToTypeDefinitionRequest > createRequest ( document , position ) ;
40+ req . WantMetadata = true ;
4441
45- // if it is part of an already used metadata file, retrieve its uri instead of going to the physical file
46- const uri = this . definitionMetadataDocumentProvider . getExistingMetadataResponseUri ( definition . Location . FileName ) ;
47- const vscodeRange = toRange3 ( definition . Location . Range ) ;
48- locations . push ( new Location ( uri , vscodeRange ) ) ;
49- continue ;
50- }
42+ try {
43+ const goToTypeDefinitionResponse = await serverUtils . goToTypeDefinition ( this . _server , req , token ) ;
44+ return await this . GetLocationsFromResponse ( goToTypeDefinitionResponse , token ) ;
45+ }
46+ catch ( error ) {
47+ return [ ] ;
48+ }
49+ }
5150
52- // We need to go to the metadata endpoint for more information
53- const metadataResponse = await serverUtils . getMetadata ( this . _server , < MetadataRequest > {
54- Timeout : 5000 ,
55- AssemblyName : metadataSource . AssemblyName ,
56- VersionNumber : metadataSource . VersionNumber ,
57- ProjectName : metadataSource . ProjectName ,
58- Language : metadataSource . Language ,
59- TypeName : metadataSource . TypeName
60- } ) ;
51+ private async GetLocationsFromResponse < TReponse > ( response : GoToTypeDefinitionResponse | V2 . GoToDefinitionResponse , token : CancellationToken ) : Promise < Location [ ] >
52+ {
53+ let locations : Location [ ] = [ ] ;
54+ if ( response && response . Definitions ) {
55+ for ( const definition of response . Definitions ) {
56+ if ( definition . MetadataSource ) {
57+ // the definition is in metadata
58+ const metadataSource : MetadataSource = definition . MetadataSource ;
6159
62- if ( ! metadataResponse || ! metadataResponse . Source || ! metadataResponse . SourceName ) {
63- continue ;
64- }
60+ // Do we already have a document for this metadata reference?
61+ if ( definition . Location . FileName . startsWith ( "$metadata$" ) &&
62+ this . definitionMetadataDocumentProvider . hasMetadataDocument ( definition . Location . FileName ) ) {
6563
66- const uri : Uri = this . definitionMetadataDocumentProvider . addMetadataResponse ( metadataResponse ) ;
64+ // if it is part of an already used metadata file, retrieve its uri instead of going to the physical file
65+ const uri = this . definitionMetadataDocumentProvider . getExistingMetadataResponseUri ( definition . Location . FileName ) ;
6766 const vscodeRange = toRange3 ( definition . Location . Range ) ;
6867 locations . push ( new Location ( uri , vscodeRange ) ) ;
69- } else if ( definition . SourceGeneratedFileInfo ) {
70- // File is source generated
71- let uri = this . sourceGeneratedDocumentProvider . tryGetExistingSourceGeneratedFile ( definition . SourceGeneratedFileInfo ) ;
72- if ( ! uri ) {
73- const sourceGeneratedFileResponse = await serverUtils . getSourceGeneratedFile ( this . _server , definition . SourceGeneratedFileInfo , token ) ;
68+ continue ;
69+ }
70+
71+ // We need to go to the metadata endpoint for more information
72+ const metadataResponse = await serverUtils . getMetadata ( this . _server , < MetadataRequest > {
73+ Timeout : 5000 ,
74+ AssemblyName : metadataSource . AssemblyName ,
75+ VersionNumber : metadataSource . VersionNumber ,
76+ ProjectName : metadataSource . ProjectName ,
77+ Language : metadataSource . Language ,
78+ TypeName : metadataSource . TypeName
79+ } ) ;
80+
81+ if ( ! metadataResponse || ! metadataResponse . Source || ! metadataResponse . SourceName ) {
82+ continue ;
83+ }
7484
75- if ( ! sourceGeneratedFileResponse || ! sourceGeneratedFileResponse . Source || ! sourceGeneratedFileResponse . SourceName ) {
76- continue ;
77- }
85+ const uri : Uri = this . definitionMetadataDocumentProvider . addMetadataResponse ( metadataResponse ) ;
86+ const vscodeRange = toRange3 ( definition . Location . Range ) ;
87+ locations . push ( new Location ( uri , vscodeRange ) ) ;
88+ } else if ( definition . SourceGeneratedFileInfo ) {
89+ // File is source generated
90+ let uri = this . sourceGeneratedDocumentProvider . tryGetExistingSourceGeneratedFile ( definition . SourceGeneratedFileInfo ) ;
91+ if ( ! uri ) {
92+ const sourceGeneratedFileResponse = await serverUtils . getSourceGeneratedFile ( this . _server , definition . SourceGeneratedFileInfo , token ) ;
7893
79- uri = this . sourceGeneratedDocumentProvider . addSourceGeneratedFile ( definition . SourceGeneratedFileInfo , sourceGeneratedFileResponse ) ;
94+ if ( ! sourceGeneratedFileResponse || ! sourceGeneratedFileResponse . Source || ! sourceGeneratedFileResponse . SourceName ) {
95+ continue ;
8096 }
8197
82- locations . push ( new Location ( uri , toRange3 ( definition . Location . Range ) ) ) ;
83- } else {
84- // if it is a normal source definition, convert the response to a location
85- locations . push ( toVscodeLocation ( definition . Location ) ) ;
98+ uri = this . sourceGeneratedDocumentProvider . addSourceGeneratedFile ( definition . SourceGeneratedFileInfo , sourceGeneratedFileResponse ) ;
8699 }
100+
101+ locations . push ( new Location ( uri , toRange3 ( definition . Location . Range ) ) ) ;
102+ } else {
103+ // if it is a normal source definition, convert the response to a location
104+ locations . push ( toVscodeLocation ( definition . Location ) ) ;
87105 }
88106 }
89-
90- // Allow language middlewares to re-map its edits if necessary.
91- const result = await this . _languageMiddlewareFeature . remap ( "remapLocations" , locations , token ) ;
92- return result ;
93- }
94- catch ( error ) {
95- return [ ] ;
96107 }
108+ // Allow language middlewares to re-map its edits if necessary.
109+ return await this . _languageMiddlewareFeature . remap ( "remapLocations" , locations , token ) ;
97110 }
98111}
0 commit comments