How Copilot is being used by the Time Travel Debugging team for repetitive C++ coding

Sinem Akinci

Background 

Ken Sykes and Juan Carlos Arevalo Baeza (JCAB) are both Principal Software Engineers who work on Time Travel Debugging at Microsoft. They are part of the team that maintains and develops the Windows Debugger (WinDbg) and related technologies. Their codebase is developed with C++ and CMake and they primarily use VS Code for day-to-day development of their code. 

They have been integrating GitHub Copilot and GitHub Copilot Chat into their C++ development in VS Code and have found many useful workflows for the AI pair programming tool.  


Download GitHub Copilot

To access GitHub Copilot and Copilot Chat, you will need an active subscription to GitHub Copilot. If you’re just getting started, please check out the VS Code documentation.


This blog post series has been written in partnership with Ken and JCAB to highlight their workflows with Copilot and Copilot Chat respectively and inspire other C++ developers on potential use cases to integrate with their code. 


How we use Copilot for C++

Copilot provides AI-generated autocomplete-style suggestions as we code. Copilot has greatly helped our team with reaching new levels of productivity when interacting with our large codebases.  

For example, it has been good at following our coding styles for repetitive tasks. We highly recommend Copilot to save you some time with repetitive typing. 

This has been widely applicable to many areas of our C++ workflows, from writing test code to implementing classes. Two specific examples that have been greatly impactful in that we will expand upon below are adding additional methods to a class and generating classes after migrating library dependencies. 

You can follow along with the examples in this sample repo: KenSykes/ExampleLibraryConversion: Demonstration of Copilot code completion (github.com). Please note that Copilot suggestions are probabilistic, not deterministic, and you may not see the exact same suggestions as you follow along. 

Adding additional methods to a class

Reference code: Branch: main, file: ExampleLibraryConversion.cpp 

One of our favorite ways to use Copilot is to have it follow existing coding patterns to save typing. For example, we have a class that interacts with dbghelp.dll through function pointers (GetProcAddress-based delay loading). Recently we needed to add some additional dbghelp methods to this class, such as SymInitializeW. All we need to do is go to the places that define existing structs, press enter and start to type, and Copilot will dynamically update to fill in the rest. Then, we can edit down the results to get to the desired outcome. 

a GIF representing GH Copilot automatically helping fill in the SymInitializeW method declaration after typing in decltype.

After adding this new class member, we can scroll up to the constructor and notice that Copilot is able to offer a valid initialization suggestion for us.

Copilot automatically generated the constructor for the SymInitialize function generated.

Then, add the prototype for the wrapper and Copilot can offer a reasonable implementation.

A GIF showcasing once you type out an Initialize function in the struct, GitHub Copilot is able to fill in the necessary information below to initialize the object

 

A more complex example of Copilot helping with initializations can be viewed below for now a new Load Module object.

A gif showcasing now declaring a new type of object called SymLoadModules and copilot assisting with the initialization

In this example, Copilot can generate the implementation of the method with great default options. These default options are also commented by Copilot to document what the zeros and nullptrs mean.A Gif showcasing the initialization of a function Load Module. Once the function has been initialized, Copilot filled in the implementation of the method and commented on each default option recommended

Generating code when migrating libraries

Reference code: Branch: convert_to_nlohmann, file:ExampleLibraryConversion.cpp

We have found Copilot helpful with managing libraries in our repository and refactoring code. Specifically, we previously used the rapidJSON library, managed through a vcpkg.json file, to serialize our structs into JSON.

An example of such a struct of information can be viewed here:

An example struct of system information such as major/minor version, and struct of processor architecture related information

The original rapidJSON code was hand-written and took hours to do (including time to become familiar with the library). While producing this blog, we found that Copilot could generate much of the code correctly once some rapidJSON boilerplate code is provided. See how easily Copilot can generate the JSON object using pre-determined o and s objects for rapidJSON:

a GIF showcasing generating all the objects under object o and object s using the struct information above and rapidJSON library construct with Copilot.

We recently had a desire to update this library dependency from rapidJSON to nlohmann-json, since the nlohmann-json library is better-maintained.  To start updating the code, all we needed to do was update our vcpkg.json dependencies to have a nlohmann-json entry and include this new dependency in our cpp file per official library documentation.

From there, Copilot was able to produce 80% of the code for this process with the proper formatting for nlohmann-json, letting the team focus on reviewing the generated code rather than implementing the fixes in applicable areas.

Image JSONGeneratev2 ezgif com crop

Generating code based on input data

Reference code: Branch: convert_to_nlohmann, File: ExampleParser.cpp

Copilot can also save you time writing parsing code. Given some sample input data pasted in a comment, Copilot can generate C++ structures and parsing code for you. To demonstrate this, we started with the nlohmann JSON parser, added a conversion for std::string, and then pasted some sample JSON from openweathermap.org in a comment.

An example of JSON data from openweather.org passed into a comment in the code

Now, watch Copilot go to work. Move cursor below the comment and hit Enter. You will start to get suggestions for code. Keep pressing Tab and Enter as Copilot writes out all the structures to represent the data and the nlohmann to_json() / from_json() methods, culminating in a ParseWeatherData() method that can fully parse the sample text.

An example of Copilot generating all the data for to_json and from_json functions for the library parser based on the weather data commented.

The full Copilot-generated code can be found here.

If you look closely that the Weather field of WeatherData is a single element but the JSON is an array, so a std::vector<> would have been a better choice. Things like this are easy to fix up on your own, or perhaps add more representative JSON samples to the comment to give Copilot more context.

Image weatherdatastruct


Wrap up

A big thanks to Ken and JCAB from the Time Travel Debugging Team for collaborating with us on this blog post!

Copilot can provide you with AI-powered assistance at many points in your C++ development, such as migrating libraries and initializing new methods. Download Copilot and try out utilizing it in your areas of repetitive coding! Please note that responses are generated by AI, so we recommend reviewing any responses provided and iterating when necessary.

Our team is working hard on improving C++ integrations, so please let us know any improvements you’d like to see to your C++ workflows. Additionally, let us know what other types of content you’d like to see regarding use cases or additional information about Copilot.

We welcome all types of feedback on your experience with the product. The comments below are open, or you can find us via email at visualcpp@microsoft.com or via Twitter at @VisualC.

3 comments

Leave a comment

  • Окченос Пупкін 1

    How one can enable header file visibility in Copilot?
    Or let Copilot to see entire workspace files to be aware of the whole context…

    • Sinem AkinciMicrosoft employee 1

      Hi,

      We recommend opening any relevant header files or workspace files to improve quality of Copilot completions results. Copilot will take these opened files into context to improve relevant completions results.

      • Окченос Пупкін 0

        Hi,
        Thanks for the answer, still it looks like Copilot in VSCode completely ignores all the stuff like #editor, #selection, #file, for example:

        Me: please find any problems in #selection
        Copilot: I’m sorry for any confusion, but as an AI, I can’t directly access your local system or files. You need to paste the code you want me to analyze into the conversation. Once you’ve done that, I’ll be able to help you find any potential issues with it.

        meanwhile there is a “Used one reference MyFileName.h:1-2281 #selection” so definitely Copilot shall be able to see it instead of repeating “I cannot access your local files” mantra…

        Or another example:
        Me: Please find any problems in #editor taking into account that #file:doctest.h is also included
        Copilot: As an AI, I need the actual code from your editor to analyze it for potential problems. The provided context doesn’t contain any specific code from your editor. Could you please provide the code you want me to analyze?

        While it displays “Used 2 references” with right files mentioned in references but those references are completely ignored by the Copilot chat

Feedback usabilla icon