---
title: "Code intelligence"
---

# Code intelligence

clangd for firmware projects built with the Arm GNU Toolchain, IAR or Arm Compiler 6, how IAR compile commands and keywords are translated, and the register hover.

Language intelligence for C and C++ comes from **clangd**, which you install yourself (version 17 or later). The module starts it for the active build configuration, so go to definition reaches into the CMSIS and vendor headers, target defines resolve, and the vendor's keywords do not show as errors. No Microsoft C/C++ extension or other marketplace extension is involved.

![A clangd hover on uart_init with its parameters and the declaration's documentation comment.](https://neuralinverse.com/docs-images/modules/embedded/clangd-hover.webp)

## How clangd is set up

The module runs clangd with background indexing, clang-tidy diagnostics, detailed completion and formatting, and:

- `--compile-commands-dir` set to the folder of the active configuration's `compile_commands.json`;
- `--query-driver` for the cross compiler's folder (`arm-none-eabi-*`) and for Arm Compiler 6 (`armclang*`), so clangd asks the compiler for its target, system headers and predefined macros. Without it, CMSIS headers and target defines do not resolve.

`neuralInverse.embedded.clangd.arguments` adds your own arguments after these, so they win.

The status bar item **C Language Support** shows clangd's state and the configuration it indexes. If clangd crashes repeatedly (more than a few times in three minutes) it is not restarted; **Restart C Language Server (clangd)** starts it again, and the Embedded log says why it stopped.

![A clangd error typed into a call with too few arguments, linked to the declaration in uart.h.](https://neuralinverse.com/docs-images/modules/embedded/clangd-diagnostic.webp)

## Projects built with IAR

clangd cannot read `iccarm` command lines. For IAR projects the module writes a translated compile database:

- For an IAR project built in place, the compile commands come from `iarbuild -jsondb` (Embedded Workbench 9) for the active configuration. For an IAR CMake project, they come from CMake.
- Each `iccarm` command becomes a clang command with iccarm's own predefined macros (read from its `--predef_macros` output) and its system headers.
- IAR's layout keywords get their GNU meaning: `__packed` is `__attribute__((packed))`; `__no_init` and `__ramfunc` get the sections IAR's guide names (`.noinit`, `.textrw`); `__naked` is `naked`; `__interwork` and `__exception` are defined away.
- IAR writes `__packed` before `struct` or `union`, where clang ignores an attribute. In the text clangd reads, `__packed` is moved after the keyword (same length and lines): for open documents through the language client, and for other sources and the include folders' headers through rewritten copies in the build folder's `.neuralinverse-clangd/` folder. Your files are never changed.

State: unit-tested on an iccarm 9.50 command line and macro file. With Apple clang and clangd 15.0.0 run directly (not through the Editor, which requires clangd 17), packed structures and unions from IAR's guide pass their static size assertions with the translation and fail without it. **Not yet run against `iccarm`** (kit iar-clangd). A `__packed` followed by a line break before `struct` is not moved, and a header outside the include folders of the compile commands is read with IAR's layout only after the next configure or build.

## Projects built with Arm Compiler 6 or GCC

- Arm GNU Toolchain projects: clangd reads CMake's `compile_commands.json` and queries `arm-none-eabi-gcc` through `--query-driver`.
- Arm Compiler 6 projects built through CMake: clangd queries `armclang` through `--query-driver`. Arm Compiler 6's own keywords are not translated as IAR's are.

State: the argument generation is unit-tested; the clangd integration test exists and has not run in a verified audit. No clangd 17 or later has run in a verified audit.

## Register hover

Hover a peripheral access such as `GPIOA->MODER` in C or C++ to see the peripheral, register and field details from the device's SVD file, with a link to open it in the Registers editor. See [Peripheral registers](https://neuralinverse.com/docs/modules/embedded/registers/).

## Generated files and coding standards

Coding standards checks (organisation header, no dynamic allocation in chosen folders, no `#pragma once`) run on save and are described with static analysis: see [Coding standards on save](https://neuralinverse.com/docs/modules/embedded/static-analysis/#coding-standards-on-save).
