Repository: OmniSharp/omnisharp-vscode
Pull request #5107 (2022-03-16 06:20:57)

Support inlay hints
Closes https://github.com/OmniSharp/omnisharp-roslyn/issues/1932. Implements the new inlay hint api for vscode, now that it's stable and in LSP. Tests still need to be written.


333fred: This will need https://github.com/OmniSharp/omnisharp-roslyn/pull/2357 to be merged, and I still need to write some integration tests covering the new feature. Some screenshots:

![image](https://user-images.githubusercontent.com/2371880/158528919-26d03995-5d27-4fb1-9410-439f5999ba81.png)
![image](https://user-images.githubusercontent.com/2371880/158528957-fcb51460-d1ec-4b01-981e-903e526e712e.png)

somedeveloperhappy: I just wanted to come here and thank you guys for all your efforts. the inlay hints was one of the main reasons I still have Rider installed on my machine
333fred: I think we should probably avoid razor documents for now, until @NTaylorMullen has a chance to test it out and make sure that everything is working as expected.
somedeveloperhappy: hey. I really need this feature even if it's in beta. can someone help me on how to use this branch in vscode? I could be helpful with my bug reports later :p
333fred: @JoeRobich we'll see, but locally the test doesn't even require that the file is open at all. Something else is happening.
333fred: > hey. I really need this feature even if it's in beta. can someone help me on how to use this branch in vscode? I could be helpful with my bug reports later :p

Check out the branch and build it.
somedeveloperhappy: > > hey. I really need this feature even if it's in beta. can someone help me on how to use this branch in vscode? I could be helpful with my bug reports later :p
> 
> Check out the branch and build it.

yes, trying. but my npm gives out too many errors :(
is there some magic command that installs all needed npm packages?
+ also if you don't have time, I'll still be very glad if you at least tell me what to search/google about that

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fbba3db9..f23d1fd6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -43,8 +43,8 @@ jobs:
           gulp test
           npm run test:artifacts
       env:
-        CODE_VERSION: 1.45.0
+        CODE_VERSION: 1.65.0
         DISPLAY: :99.0
 
     - name: Build platform-specific extension package
-      run: gulp 'vsix:release:package:platform-specific'
\ No newline at end of file
+      run: gulp 'vsix:release:package:platform-specific'
diff --git a/package-lock.json b/package-lock.json
index 71f43f4f..707de5b9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -44,7 +44,7 @@
         "@types/semver": "5.5.0",
         "@types/tmp": "0.0.33",
         "@types/unzipper": "^0.9.1",
-        "@types/vscode": "1.58.0",
+        "@types/vscode": "1.65.0",
         "@types/yauzl": "2.9.1",
         "archiver": "5.3.0",
         "chai": "4.3.4",
@@ -75,7 +75,7 @@
         "webpack-cli": "4.6.0"
       },
       "engines": {
-        "vscode": "^1.61.0"
+        "vscode": "^1.65.0"
       }
     },
     "node_modules/@discoveryjs/json-ext": {
@@ -322,9 +322,9 @@
       }
     },
     "node_modules/@types/vscode": {
-      "version": "1.58.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.58.0.tgz",
-      "integrity": "sha512-enznxcBi4uYt20LWal09E0+VKEHZlq9PZawTu/mpWCVCFWWbiyR8HNI1ikBP1Ypqv8b3A/0md3DY1jcx+oQ8kQ==",
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz",
+      "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==",
       "dev": true
     },
     "node_modules/@types/yauzl": {
@@ -9609,9 +9609,9 @@
       }
     },
     "@types/vscode": {
-      "version": "1.58.0",
-      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.58.0.tgz",
-      "integrity": "sha512-enznxcBi4uYt20LWal09E0+VKEHZlq9PZawTu/mpWCVCFWWbiyR8HNI1ikBP1Ypqv8b3A/0md3DY1jcx+oQ8kQ==",
+      "version": "1.65.0",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz",
+      "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==",
       "dev": true
     },
     "@types/yauzl": {
diff --git a/package.json b/package.json
index d75bc769..e0ba6230 100644
--- a/package.json
+++ b/package.json
@@ -93,7 +93,7 @@
     "@types/semver": "5.5.0",
     "@types/tmp": "0.0.33",
     "@types/unzipper": "^0.9.1",
-    "@types/vscode": "1.58.0",
+    "@types/vscode": "1.65.0",
     "@types/yauzl": "2.9.1",
     "archiver": "5.3.0",
     "chai": "4.3.4",
@@ -539,7 +539,7 @@
     }
   ],
   "engines": {
-    "vscode": "^1.61.0"
+    "vscode": "^1.65.0"
   },
   "activationEvents": [
     "onDebugInitialConfigurations",
@@ -852,6 +852,66 @@
           "default": true,
           "description": "Shows the OmniSharp log in the Output pane when OmniSharp reports an error."
         },
+        "csharp.inlayHints.parameters.enabled": {
+          "type": "boolean",
+          "default": false,
+          "description": "Display inline parameter name hints"
+        },
+        "csharp.inlayHints.parameters.forLiteralParameters": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for literals"
+        },
+        "csharp.inlayHints.parameters.forObjectCreationParameters": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for 'new' expressions"
+        },
+        "csharp.inlayHints.parameters.forIndexerParameters": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for indexers"
+        },
+        "csharp.inlayHints.parameters.forOtherParameters": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for everything else"
+        },
+        "csharp.inlayHints.parameters.suppressForParametersThatDifferOnlyBySuffix": {
+          "type": "boolean",
+          "default": false,
+          "description": "Suppress hints when parameter names differ only by suffix"
+        },
+        "csharp.inlayHints.parameters.suppressForParametersThatMatchMethodIntent": {
+          "type": "boolean",
+          "default": false,
+          "description": "Suppress hints when parameter name matches the method's intent"
+        },
+        "csharp.inlayHints.parameters.suppressForParametersThatMatchArgumentName": {
+          "type": "boolean",
+          "default": false,
+          "description": "Suppress hints when argument matches parameter name"
+        },
+        "csharp.inlayHints.types.enabled": {
+          "type": "boolean",
+          "default": false,
+          "description": "Display inline type hints"
+        },
+        "csharp.inlayHints.types.forImplicitVariableTypes": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for variables with inferred types"
+        },
+        "csharp.inlayHints.types.forLambdaParameterTypes": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for lambda parameter types"
+        },
+        "csharp.inlayHints.types.forImplicitObjectCreation": {
+          "type": "boolean",
+          "default": false,
+          "description": "Show hints for implicit object creation"
+        },
         "omnisharp.path": {
           "type": [
             "string",
@@ -4011,4 +4071,4 @@
       }
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/src/features/fileOpenCloseProvider.ts b/src/features/fileOpenCloseProvider.ts
index 3c258fa3..e1e8e778 100644
--- a/src/features/fileOpenCloseProvider.ts
+++ b/src/features/fileOpenCloseProvider.ts
@@ -49,8 +49,8 @@ class FileOpenCloseProvider implements IDisposable {
         await serverUtils.fileClose(this._server, { FileName: e.fileName });
     }
 
-    private async _onActiveTextEditorChange(e: vscode.TextEditor) {
-        if (shouldIgnoreDocument(e.document)) {
+    private async _onActiveTextEditorChange(e: vscode.TextEditor | undefined) {
+        if (e === undefined || shouldIgnoreDocument(e.document)) {
             return;
         }
 
@@ -71,4 +71,4 @@ function shouldIgnoreDocument(document: vscode.TextDocument) {
     }
 
     return false;
-}
\ No newline at end of file
+}
diff --git a/src/features/inlayHintProvider.ts b/src/features/inlayHintProvider.ts
new file mode 100644
index 00000000..b6f0f8ae
--- /dev/null
+++ b/src/features/inlayHintProvider.ts
@@ -0,0 +1,79 @@
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+import * as serverUtils from '../omnisharp/utils';
+import * as vscode from 'vscode';
+import AbstractProvider from './abstractProvider';
+import { OmniSharpServer } from '../omnisharp/server';
+import { LanguageMiddlewareFeature } from '../omnisharp/LanguageMiddlewareFeature';
+import CompositeDisposable from '../CompositeDisposable';
+import { InlayHint, InlayHintRequest, InlayHintResolve as InlayHintResolveRequest } from '../omnisharp/protocol';
+import { fromVSCodeRange, toVSCodePosition } from '../omnisharp/typeConversion';
+import { isVirtualCSharpDocument } from './virtualDocumentTracker';
+
+export default class CSharpInlayHintProvider extends AbstractProvider implements vscode.InlayHintsProvider {
+    private readonly _onDidChangeInlayHints = new vscode.EventEmitter<void>();
+    public readonly onDidChangeInlayHints = this._onDidChangeInlayHints.event;
+
+    private readonly _hintsMap = new Map<vscode.InlayHint, InlayHint>();
+
+    constructor(server: OmniSharpServer, languageMiddlewareFeature: LanguageMiddlewareFeature) {
+        super(server, languageMiddlewareFeature);
+        this.addDisposables(new CompositeDisposable(
+            this._onDidChangeInlayHints,
+            vscode.workspace.onDidChangeTextDocument(e => {
+                if (e.document.languageId === 'csharp') {
+                    this._onDidChangeInlayHints.fire();
+                }
+            })));
+    }
+
+    async provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise<vscode.InlayHint[]> {
+        if (isVirtualCSharpDocument(document)) {
+            return [];
+        }
+
+        const request: InlayHintRequest = {
+            Location: {
+                FileName: document.fileName,
+                Range: fromVSCodeRange(range)
+            }
+        };
+
+        try {
+            const hints = await serverUtils.getInlayHints(this._server, request, token);
+
+            return hints.InlayHints.map((inlayHint): vscode.InlayHint => {
+                const mappedHint = this.toVscodeHint(inlayHint);
+                this._hintsMap.set(mappedHint, inlayHint);
+                return mappedHint;
+            });
+        } catch (error) {
+            return Promise.reject(`Problem invoking 'GetInlayHints' on OmniSharpServer: ${error}`);
+        }
+    }
+
+    async resolveInlayHint?(hint: vscode.InlayHint, token: vscode.CancellationToken): Promise<vscode.InlayHint> {
+        if (!this._hintsMap.has(hint)) {
+            return Promise.reject(`Outdated inlay hint was requested to be resolved, aborting.`);
+        }
+
+        const request: InlayHintResolveRequest = { Hint: this._hintsMap.get(hint) };
+
+        try {
+            const result = await serverUtils.resolveInlayHints(this._server, request, token);
+            return this.toVscodeHint(result);
+        } catch (error) {
+            return Promise.reject(`Problem invoking 'ResolveInlayHints' on OmniSharpServer: ${error}`);
+        }
+    }
+
+    private toVscodeHint(inlayHint: InlayHint): vscode.InlayHint {
+        return {
+            label: inlayHint.Label,
+            position: toVSCodePosition(inlayHint.Position),
+            tooltip: new vscode.MarkdownString(inlayHint.Tooltip ?? "")
+        };
+    }
+}
diff --git a/src/observers/OptionChangeObserver.ts b/src/observers/OptionChangeObserver.ts
index 52b88a7a..3553131c 100644
--- a/src/observers/OptionChangeObserver.ts
+++ b/src/observers/OptionChangeObserver.ts
@@ -25,7 +25,19 @@ const omniSharpOptions: ReadonlyArray<OptionsKey> = [
     "enableAsyncCompletion",
     "useModernNet",
     "analyzeOpenDocumentsOnly",
-    "enableRoslynAnalyzers"
+    "enableRoslynAnalyzers",
+    "inlayHintsEnableForParameters",
+    "inlayHintsForLiteralParameters",
+    "inlayHintsForObjectCreationParameters",
+    "inlayHintsForIndexerParameters",
+    "inlayHintsForOtherParameters",
+    "inlayHintsSuppressForParametersThatDifferOnlyBySuffix",
+    "inlayHintsSuppressForParametersThatMatchMethodIntent",
+    "inlayHintsSuppressForParametersThatMatchArgumentName",
+    "inlayHintsEnableForTypes",
+    "inlayHintsForImplicitVariableTypes",
+    "inlayHintsForLambdaParameterTypes",
+    "inlayHintsForImplicitObjectCreation",
 ];
 
 function OmniSharpOptionChangeObservable(optionObservable: Observable<Options>): Observable<Options> {
diff --git a/src/omnisharp/extension.ts b/src/omnisharp/extension.ts
index d7add1c5..01171fa3 100644
--- a/src/omnisharp/extension.ts
+++ b/src/omnisharp/extension.ts
@@ -44,6 +44,7 @@ import SemanticTokensProvider from '../features/semanticTokensProvider';
 import SourceGeneratedDocumentProvider from '../features/sourceGeneratedDocumentProvider';
 import { getDecompilationAuthorization } from './decompilationPrompt';
 import { OmniSharpDotnetResolver } from './OmniSharpDotnetResolver';
+import CSharpInlayHintProvider from '../features/inlayHintProvider';
 import fileOpenClose from '../features/fileOpenCloseProvider';
 
 export interface ActivationResult {
@@ -119,6 +120,9 @@ export async function activate(context: vscode.ExtensionContext, packageJSON: an
         const semanticTokensProvider = new SemanticTokensProvider(server, optionProvider, languageMiddlewareFeature);
         localDisposables.add(vscode.languages.registerDocumentSemanticTokensProvider(documentSelector, semanticTokensProvider, semanticTokensProvider.getLegend()));
         localDisposables.add(vscode.languages.registerDocumentRangeSemanticTokensProvider(documentSelector, semanticTokensProvider, semanticTokensProvider.getLegend()));
+
+        const inlayHintsProvider = new CSharpInlayHintProvider(server, languageMiddlewareFeature);
+        localDisposables.add(vscode.languages.registerInlayHintsProvider(documentSelector, inlayHintsProvider));
     }));
 
     disposables.add(server.onServerStop(() => {
diff --git a/src/omnisharp/options.ts b/src/omnisharp/options.ts
index f262027b..1025f5b0 100644
--- a/src/omnisharp/options.ts
+++ b/src/omnisharp/options.ts
@@ -36,6 +36,18 @@ export class Options {
         public enableAsyncCompletion: boolean,
         public analyzeOpenDocumentsOnly: boolean,
         public useSemanticHighlighting: boolean,
+        public inlayHintsEnableForParameters: boolean,
+        public inlayHintsForLiteralParameters: boolean,
+        public inlayHintsForObjectCreationParameters: boolean,
+        public inlayHintsForIndexerParameters: boolean,
+        public inlayHintsForOtherParameters: boolean,
+        public inlayHintsSuppressForParametersThatDifferOnlyBySuffix: boolean,
+        public inlayHintsSuppressForParametersThatMatchMethodIntent: boolean,
+        public inlayHintsSuppressForParametersThatMatchArgumentName: boolean,
+        public inlayHintsEnableForTypes: boolean,
+        public inlayHintsForImplicitVariableTypes: boolean,
+        public inlayHintsForLambdaParameterTypes: boolean,
+        public inlayHintsForImplicitObjectCreation: boolean,
         public razorPluginPath?: string,
         public defaultLaunchSolution?: string,
         public monoPath?: string,
@@ -94,6 +106,19 @@ export class Options {
 
         const useSemanticHighlighting = csharpConfig.get<boolean>('semanticHighlighting.enabled', false);
 
+        const inlayHintsEnableForParameters = csharpConfig.get<boolean>('inlayHints.parameters.enabled', false);
+        const inlayHintsForLiteralParameters = csharpConfig.get<boolean>('inlayHints.parameters.forLiteralParameters', false);
+        const inlayHintsForObjectCreationParameters = csharpConfig.get<boolean>('inlayHints.parameters.forObjectCreationParameters', false);
+        const inlayHintsForIndexerParameters = csharpConfig.get<boolean>('inlayHints.parameters.forIndexerParameters', false);
+        const inlayHintsForOtherParameters = csharpConfig.get<boolean>('inlayHints.parameters.forOtherParameters', false);
+        const inlayHintsSuppressForParametersThatDifferOnlyBySuffix = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatDifferOnlyBySuffix', false);
+        const inlayHintsSuppressForParametersThatMatchMethodIntent = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatMatchMethodIntent', false);
+        const inlayHintsSuppressForParametersThatMatchArgumentName = csharpConfig.get<boolean>('inlayHints.parameters.suppressForParametersThatMatchArgumentName', false);
+        const inlayHintsEnableForTypes = csharpConfig.get<boolean>('inlayHints.types.enabled', false);
+        const inlayHintsForImplicitVariableTypes = csharpConfig.get<boolean>('inlayHints.types.forImplicitVariableTypes', false);
+        const inlayHintsForLambdaParameterTypes = csharpConfig.get<boolean>('inlayHints.types.forLambdaParameterTypes', false);
+        const inlayHintsForImplicitObjectCreation = csharpConfig.get<boolean>('inlayHints.types.forImplicitObjectCreation', false);
+
         const disableCodeActions = csharpConfig.get<boolean>('disableCodeActions', false);
 
         const disableMSBuildDiagnosticWarning = omnisharpConfig.get<boolean>('disableMSBuildDiagnosticWarning', false);
@@ -145,6 +170,18 @@ export class Options {
             enableAsyncCompletion,
             analyzeOpenDocumentsOnly,
             useSemanticHighlighting,
+            inlayHintsEnableForParameters,
+            inlayHintsForLiteralParameters,
+            inlayHintsForObjectCreationParameters,
+            inlayHintsForIndexerParameters,
+            inlayHintsForOtherParameters,
+            inlayHintsSuppressForParametersThatDifferOnlyBySuffix,
+            inlayHintsSuppressForParametersThatMatchMethodIntent,
+            inlayHintsSuppressForParametersThatMatchArgumentName,
+            inlayHintsEnableForTypes,
+            inlayHintsForImplicitVariableTypes,
+            inlayHintsForLambdaParameterTypes,
+            inlayHintsForImplicitObjectCreation,
             razorPluginPath,
             defaultLaunchSolution,
             monoPath,
diff --git a/src/omnisharp/protocol.ts b/src/omnisharp/protocol.ts
index f028cf42..977a8991 100644
--- a/src/omnisharp/protocol.ts
+++ b/src/omnisharp/protocol.ts
@@ -38,6 +38,8 @@ export module Requests {
     export const SourceGeneratedFile = '/sourcegeneratedfile';
     export const UpdateSourceGeneratedFile = '/updatesourcegeneratedfile';
     export const SourceGeneratedFileClosed = '/sourcegeneratedfileclosed';
+    export const InlayHint = '/inlayHint';
+    export const InlayHintResolve = '/inlayHint/resolve';
     export const FileOpen = '/open';
     export const FileClose = '/close';
 }
@@ -581,6 +583,25 @@ export enum UpdateType {
 export interface SourceGeneratedFileClosedRequest extends SourceGeneratedFileInfo {
 }
 
+export interface InlayHintRequest {
+    Location: V2.Location;
+}
+
+export interface InlayHint {
+    Position: V2.Point;
+    Label: string;
+    Tooltip?: string;
+    Data: any;
+}
+
+export interface InlayHintResponse {
+    InlayHints: InlayHint[];
+}
+
+export interface InlayHintResolve {
+    Hint: InlayHint;
+}
+
 export interface Definition {
     Location: V2.Location;
     MetadataSource?: MetadataSource;
diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts
index 19ad8314..b8927b49 100644
--- a/src/omnisharp/server.ts
+++ b/src/omnisharp/server.ts
@@ -391,6 +391,24 @@ export class OmniSharpServer {
             args.push('RoslynExtensionsOptions:EnableAsyncCompletion=true');
         }
 
+        if (options.inlayHintsEnableForParameters === true) {
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:EnableForParameters=${options.inlayHintsEnableForParameters.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForLiteralParameters=${options.inlayHintsForLiteralParameters.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForIndexerParameters=${options.inlayHintsForIndexerParameters.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForObjectCreationParameters=${options.inlayHintsForObjectCreationParameters.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForOtherParameters=${options.inlayHintsForOtherParameters.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:SuppressForParametersThatDifferOnlyBySuffix=${options.inlayHintsSuppressForParametersThatDifferOnlyBySuffix.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:SuppressForParametersThatMatchMethodIntent=${options.inlayHintsSuppressForParametersThatMatchMethodIntent.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:SuppressForParametersThatMatchArgumentName=${options.inlayHintsSuppressForParametersThatMatchArgumentName.toString()}`);
+        }
+
+        if (options.inlayHintsEnableForTypes === true) {
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:EnableForTypes=${options.inlayHintsEnableForTypes.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForImplicitVariableTypes=${options.inlayHintsForImplicitVariableTypes.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForLambdaParameterTypes=${options.inlayHintsForLambdaParameterTypes.toString()}`);
+            args.push(`RoslynExtensionsOptions:InlayHintsOptions:ForImplicitObjectCreation=${options.inlayHintsForImplicitObjectCreation.toString()}`);
+        }
+
         if (options.analyzeOpenDocumentsOnly === true) {
             args.push('RoslynExtensionsOptions:AnalyzeOpenDocumentsOnly=true');
         }
diff --git a/src/omnisharp/typeConversion.ts b/src/omnisharp/typeConversion.ts
index 6771d754..f6b183c9 100644
--- a/src/omnisharp/typeConversion.ts
+++ b/src/omnisharp/typeConversion.ts
@@ -47,6 +47,21 @@ export function toVSCodeRange(StartLine: number, StartColumn: number, EndLine: n
     return new vscode.Range(StartLine, StartColumn, EndLine, EndColumn);
 }
 
+export function fromVSCodeRange(range: vscode.Range): protocol.V2.Range {
+    return {
+        Start: fromVSCodePosition(range.start),
+        End: fromVSCodePosition(range.end)
+    };
+}
+
+export function fromVSCodePosition(position: vscode.Position): protocol.V2.Point {
+    return { Line: position.line, Column: position.character };
+}
+
+export function toVSCodePosition(point: protocol.V2.Point): vscode.Position {
+    return new vscode.Position(point.Line, point.Column);
+}
+
 export function createRequest<T extends protocol.Request>(document: vscode.TextDocument, where: vscode.Position | vscode.Range, includeBuffer: boolean = false): T {
 
     let Line: number, Column: number;
diff --git a/src/omnisharp/utils.ts b/src/omnisharp/utils.ts
index 0bd5d558..cac8b3dc 100644
--- a/src/omnisharp/utils.ts
+++ b/src/omnisharp/utils.ts
@@ -209,6 +209,14 @@ export async function isNetCoreProject(project: protocol.MSBuildProject) {
     return project.TargetFrameworks.find(tf => tf.ShortName.startsWith('netcoreapp') || tf.ShortName.startsWith('netstandard')) !== undefined;
 }
 
+export async function getInlayHints(server: OmniSharpServer, request: protocol.InlayHintRequest, context: vscode.CancellationToken) {
+    return server.makeRequest<protocol.InlayHintResponse>(protocol.Requests.InlayHint, request, context);
+}
+
+export async function resolveInlayHints(server: OmniSharpServer, request: protocol.InlayHintResolve, context: vscode.CancellationToken) {
+    return server.makeRequest<protocol.InlayHint>(protocol.Requests.InlayHintResolve, request, context);
+}
+
 function isBlazorWebAssemblyHosted(project: protocol.MSBuildProject, isProjectBlazorWebAssemblyProject: boolean): boolean {
     if (!isProjectBlazorWebAssemblyProject) {
         return false;
diff --git a/src/statusBarItemAdapter.ts b/src/statusBarItemAdapter.ts
index 6aea6c90..1bf6ddbc 100644
--- a/src/statusBarItemAdapter.ts
+++ b/src/statusBarItemAdapter.ts
@@ -25,7 +25,7 @@ export class StatusBarItemAdapter implements vscodeAdapter.StatusBarItem {
     }
 
     get tooltip(): string {
-        return this.statusBarItem.tooltip;
+        return <string>this.statusBarItem.tooltip;
     }
 
     set tooltip(value: string) {
@@ -70,4 +70,4 @@ export class StatusBarItemAdapter implements vscodeAdapter.StatusBarItem {
 
     constructor(private statusBarItem: vscode.StatusBarItem) {
     }
-}
\ No newline at end of file
+}


Test patch:
diff --git a/test/integrationTests/inlayHints.integration.test.ts b/test/integrationTests/inlayHints.integration.test.ts
new file mode 100644
index 00000000..455fec06
--- /dev/null
+++ b/test/integrationTests/inlayHints.integration.test.ts
@@ -0,0 +1,78 @@
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import * as vscode from 'vscode';
+
+import { should, assert } from 'chai';
+import { activateCSharpExtension, isRazorWorkspace, isSlnWithGenerator, restartOmniSharpServer } from './integrationHelpers';
+import testAssetWorkspace from './testAssets/testAssetWorkspace';
+import * as path from 'path';
+
+const chai = require('chai');
+chai.use(require('chai-arrays'));
+chai.use(require('chai-fs'));
+
+suite(`Inlay Hints ${testAssetWorkspace.description}`, function () {
+    let fileUri: vscode.Uri;
+
+    suiteSetup(async function () {
+        should();
+
+        if (isRazorWorkspace(vscode.workspace) || isSlnWithGenerator(vscode.workspace)) {
+            this.skip();
+        }
+
+        const editorConfig = vscode.workspace.getConfiguration('editor');
+        await editorConfig.update('inlayHints.enabled', true);
+
+        const csharpConfig = vscode.workspace.getConfiguration('csharp');
+        await csharpConfig.update('inlayHints.parameters.enabled', true);
+        await csharpConfig.update('inlayHints.parameters.forLiteralParameters', true);
+        await csharpConfig.update('inlayHints.parameters.forObjectCreationParameters', true);
+        await csharpConfig.update('inlayHints.parameters.forIndexerParameters', true);
+        await csharpConfig.update('inlayHints.parameters.forOtherParameters', true);
+        await csharpConfig.update('inlayHints.parameters.suppressForParametersThatDifferOnlyBySuffix', true);
+        await csharpConfig.update('inlayHints.parameters.suppressForParametersThatMatchMethodIntent', true);
+        await csharpConfig.update('inlayHints.parameters.suppressForParametersThatMatchArgumentName', true);
+        await csharpConfig.update('inlayHints.types.enabled', true);
+        await csharpConfig.update('inlayHints.types.forImplicitVariableTypes', true);
+        await csharpConfig.update('inlayHints.types.forLambdaParameterTypes', true);
+        await csharpConfig.update('inlayHints.types.forImplicitObjectCreation', true);
+
+        await restartOmniSharpServer();
+        const activation = await activateCSharpExtension();
+        await testAssetWorkspace.restore();
+
+        const fileName = 'inlayHints.cs';
+        const projectDirectory = testAssetWorkspace.projects[0].projectDirectoryPath;
+        const filePath = path.join(projectDirectory, fileName);
+        fileUri = vscode.Uri.file(filePath);
+        
+        await vscode.commands.executeCommand("vscode.open", fileUri);
+        await testAssetWorkspace.waitForIdle(activation.eventStream);
+    });
+
+    suiteTeardown(async () => {
+        await testAssetWorkspace.cleanupWorkspace();
+    });
+
+    test("Hints retrieved for region", async () => {
+        const range = new vscode.Range(new vscode.Position(4, 8), new vscode.Position(15, 85));
+        const hints : vscode.InlayHint[] = await vscode.commands.executeCommand('vscode.executeInlayHintProvider', fileUri, range);
+        assert.lengthOf(hints, 6);
+        assertValues(hints[0], 'InlayHints ', 6, 12);
+        assertValues(hints[1], ' InlayHints', 7, 27);
+        assertValues(hints[2], 'string ', 8, 28);
+        assertValues(hints[3], 'i: ', 9, 17);
+        assertValues(hints[4], 'param1: ', 10, 15);
+        assertValues(hints[5], 'param1: ', 11, 27);
+
+        function assertValues(hint: vscode.InlayHint, expectedLabel: string, expectedLine: number, expectedCharacter: number) {
+            assert.equal(hint.label, expectedLabel);
+            assert.equal(hint.position.line, expectedLine);
+            assert.equal(hint.position.character, expectedCharacter);
+        }
+    });
+});
diff --git a/test/integrationTests/testAssets/singleCsproj/inlayHints.cs b/test/integrationTests/testAssets/singleCsproj/inlayHints.cs
new file mode 100644
index 00000000..c34ad62d
--- /dev/null
+++ b/test/integrationTests/testAssets/singleCsproj/inlayHints.cs
@@ -0,0 +1,29 @@
+using System;
+
+class InlayHints
+{
+    public void M()
+    {
+        var l1 = new InlayHints();
+        InlayHints l2 = new();
+        Action<string> a = (s) => { };
+        _ = this[1];
+        _ = M1(1);
+        _ = new InlayHints(1);
+        _ = M2(1, 2); // No hint here, suppressForParametersThatDifferOnlyBySuffix
+
+        int param1 = 1;
+        _ = M1(param1); // No hint here, suppressForParametersThatMatchArgumentName
+
+        _ = EnableM(true); // No hint here, suppressForParametersThatMatchMethodIntent
+    }
+
+    public void M1(int param1) { }
+    public void M2(int param1, int param2) { }
+    public void EnableM(bool enable) { }
+
+    public int this[int i] { get { return 0; } set { } }
+
+    public InlayHints() {}
+    public InlayHints(int param1) {}
+}
diff --git a/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/inlayHints.cs b/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/inlayHints.cs
new file mode 100644
index 00000000..c34ad62d
--- /dev/null
+++ b/test/integrationTests/testAssets/slnFilterWithCsproj/src/app/inlayHints.cs
@@ -0,0 +1,29 @@
+using System;
+
+class InlayHints
+{
+    public void M()
+    {
+        var l1 = new InlayHints();
+        InlayHints l2 = new();
+        Action<string> a = (s) => { };
+        _ = this[1];
+        _ = M1(1);
+        _ = new InlayHints(1);
+        _ = M2(1, 2); // No hint here, suppressForParametersThatDifferOnlyBySuffix
+
+        int param1 = 1;
+        _ = M1(param1); // No hint here, suppressForParametersThatMatchArgumentName
+
+        _ = EnableM(true); // No hint here, suppressForParametersThatMatchMethodIntent
+    }
+
+    public void M1(int param1) { }
+    public void M2(int param1, int param2) { }
+    public void EnableM(bool enable) { }
+
+    public int this[int i] { get { return 0; } set { } }
+
+    public InlayHints() {}
+    public InlayHints(int param1) {}
+}
diff --git a/test/integrationTests/testAssets/slnWithCsproj/src/app/inlayHints.cs b/test/integrationTests/testAssets/slnWithCsproj/src/app/inlayHints.cs
new file mode 100644
index 00000000..c34ad62d
--- /dev/null
+++ b/test/integrationTests/testAssets/slnWithCsproj/src/app/inlayHints.cs
@@ -0,0 +1,29 @@
+using System;
+
+class InlayHints
+{
+    public void M()
+    {
+        var l1 = new InlayHints();
+        InlayHints l2 = new();
+        Action<string> a = (s) => { };
+        _ = this[1];
+        _ = M1(1);
+        _ = new InlayHints(1);
+        _ = M2(1, 2); // No hint here, suppressForParametersThatDifferOnlyBySuffix
+
+        int param1 = 1;
+        _ = M1(param1); // No hint here, suppressForParametersThatMatchArgumentName
+
+        _ = EnableM(true); // No hint here, suppressForParametersThatMatchMethodIntent
+    }
+
+    public void M1(int param1) { }
+    public void M2(int param1, int param2) { }
+    public void EnableM(bool enable) { }
+
+    public int this[int i] { get { return 0; } set { } }
+
+    public InlayHints() {}
+    public InlayHints(int param1) {}
+}
diff --git a/test/unitTests/Fakes/FakeOptions.ts b/test/unitTests/Fakes/FakeOptions.ts
index 7164c6a8..f4b940a9 100644
--- a/test/unitTests/Fakes/FakeOptions.ts
+++ b/test/unitTests/Fakes/FakeOptions.ts
@@ -6,5 +6,53 @@
 import { Options } from "../../../src/omnisharp/options";
 
 export function getEmptyOptions(): Options {
-    return new Options("", false, "", false, "", false, 0, 0, false, false, false, false, false, [], false, false, false, 0, 0, false, false, false, false, false, false, false, false, false, undefined, "", "", "");
+    return new Options(
+        /* path */"",
+        /* useModernNet */false,
+        /* useGlobalMono */"",
+        /* waitForDebugger */false,
+        /* loggingLevel */"",
+        /* autoStart */false,
+        /* projectLoadTimeout */0,
+        /* maxProjectResults */0,
+        /* useEditorFormattingSettings */false,
+        /* useFormatting */false,
+        /* organizeImportsOnFormat */false,
+        /* showReferencesCodeLens */false,
+        /* showTestsCodeLens */false,
+        /* filteredSymbolsCodeLens */undefined,
+        /* disableCodeActions */false,
+        /* disableMSBuildDiagnosticWarning */false,
+        /* showOmnisharpLogOnError */false,
+        /* minFindSymbolsFilterLength */0,
+        /* maxFindSymbolsItems */0,
+        /* razorDisabled */false,
+        /* razorDevMode */false,
+        /* enableMsBuildLoadProjectsOnDemand */false,
+        /* enableRoslynAnalyzers */false,
+        /* enableEditorConfigSupport */false,
+        /* enableDecompilationSupport */false,
+        /* enableImportCompletion */false,
+        /* enableAsyncCompletion */false,
+        /* analyzeOpenDocumentsOnly */false,
+        /* useSemanticHighlighting */false,
+        /* inlayHintsEnableForParameters */false,
+        /* inlayHintsForLiteralParameters */false,
+        /* inlayHintsForObjectCreationParameters */false,
+        /* inlayHintsForIndexerParameters */false,
+        /* inlayHintsForOtherParameters */false,
+        /* inlayHintsSuppressForParametersThatDifferOnlyBySuffix */false,
+        /* inlayHintsSuppressForParametersThatMatchMethodIntent */false,
+        /* inlayHintsSuppressForParametersThatMatchArgumentName */false,
+        /* inlayHintsEnableForTypes */false,
+        /* inlayHintsForImplicitVariableTypes */false,
+        /* inlayHintsForLambdaParameterTypes */false,
+        /* inlayHintsForImplicitObjectCreation */false,
+        /* razorPluginPath */"",
+        /* defaultLaunchSolution */"",
+        /* monoPath */"",
+        /* dotnetPath */"",
+        /* excludePaths */null,
+        /* maxProjectFileCountForDiagnosticAnalysis */null,
+        /* testRunSettings */"");
 }