Code Analyzer and Code Quality

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Written against MATLAB R2026b. Three small sessions below were run in GNU Octave 11.3.0 and show Octave’s output. Octave has no Code Analyzer, so those sessions only show the code that a message refers to behaving as the message says; everything about the Code Analyzer itself is checked against the R2026b documentation and is "not run here". MATLAB’s tables and message texts are copied in structure from the documentation examples, and the message wording can change between releases.

The Code Analyzer is MATLAB’s static analysis (a linter). It reads a file without running it and reports syntax errors, probable bugs and style or performance suggestions as errors, warnings and info messages. This page covers using it in the Editor, from the command line and in a build, tuning it for a team, formatting code, and checking code against a newer release. It is the quality tool behind every example in this section: the pages aim for files with no Code Analyzer messages, and each suppression is explained where it appears.

Overview of the tools

flowchart LR A[Editor and Live Editor] -->|continuous checking| B[Message indicator and Code Issues panel] C[codeIssues object] -->|fix| D[Automatic fixes] C -->|export| E[SARIF, JSON or SonarQube file] F[codeAnalyzerConfiguration.json] -->|enables, disables, severity, limits, custom checks| A F --> C F --> G[CodeIssuesTask in a build] C --> G H[codeCompatibilityReport] -->|release upgrade| I[Compatibility Analyzer report]

One analysis engine feeds all of them, and the configuration file controls what it reports in every place at once.

In the Editor: continuous checking

Continuous code checking is a setting. To change it, on the Home tab in the Environment section click Settings, choose MATLAB > Code Analyzer, and set Enable continuous code checking and the Underlining option (errors only, or also warnings and info messages). The messages update as you type, even before you save.

  • The message indicator at the top of the indicator bar shows the worst status of the file: errors (red), warnings (orange), info only (blue), nothing (green), or checking disabled. Clicking it jumps to the first code fragment with a message and then to the next ones. Markers in the indicator bar jump to a given line.

  • The messages. Move the pointer over an underlined fragment, or put the cursor in it and press Ctrl+M, to read the message. Many messages have a Details button with an explanation and suggested action. Several messages on one line often come from a single problem, and fixing one can fix or change the others.

  • The Code Issues panel (since R2025a) lists the messages in a side panel. Open it from the Analyze section of the Editor or Live Editor tab, or by clicking the message indicator. A drop-down chooses the current file or all open files, buttons toggle errors, warnings and info messages, and a search field filters by text.

  • Automatic fixes. When a message offers one, the fragment is highlighted and the message has a Fix button; Alt+Enter applies it, and the context menu shows the fix by name. If the same problem occurs several times the menu can offer Fix All (n) Instances of This Issue.

The documentation’s walk-through uses a sample file with a stray semicolon inside an index, data{3}(;), which the analyzer reads as the end of a statement and reports as several errors on one line; changing it to data{3}(:) clears them all. Errors such as syntax errors cannot be suppressed.

Typical messages and what to do

Every message has a check ID, a short code that identifies the rule. The messages shown in the documentation examples are:

Check ID Message (abridged) Usual response

AGROW

A variable appears to change size on every loop iteration; consider preallocating for speed.

Preallocate with zeros, cell, strings or similar (see Vectorization and Preallocation).

NOPRT

Terminate the statement with a semicolon to hide the output (in a function). NOPTS is the same message for a script.

Add the semicolon, unless the output is the point; then suppress it on that line.

STRQUOT

string('...') is not recommended; use a double-quoted literal instead.

Automatic fix available.

NBRAK

A suggestion about brackets, shown in the documentation’s %#ok example for a line with two messages.

Read the message text in the Editor; the check list gives the rule.

GVMIS

A global variable was used (a custom severity example in the configuration documentation).

Pass data as arguments (see Workspaces, Scope, Global and Persistent Variables).

The full list of checks is on the Code Analyzer Checks page of the documentation. The three small examples below show the code behind a few of those messages.

% AGROW: the array grows on every iteration (info message), then preallocated
n = 5;
grown = [];
for k = 1:n
  grown(k) = k^2;
end
pre = zeros(1, n);
for k = 1:n
  pre(k) = k^2;
end
disp(isequal(grown, pre))
disp(pre)

Octave 11.3.0 output (MATLAB’s layout of the row may differ):

1
    1    4    9   16   25

The two versions give the same result, so the message is about speed and memory behavior, not correctness. The second pattern allocates once.

Another typical finding is | or & in an if or while condition, where || and && were meant. The short-circuit operators stop evaluating when the left side decides, which makes tests such as "empty, or the first element is positive" safe:

% || short-circuits: the right side is not evaluated when the left decides
x = [];
if isempty(x) || x(1) > 0
  disp("short-circuit: x(1) never evaluated")
end
% | evaluates both sides and works element by element
disp([1 0 1] | [0 0 1])

Octave 11.3.0 output:

short-circuit: x(1) never evaluated
  1  0  1

See The Logical Type and Conditions for the rules about if on arrays.

Suppressing messages with %#ok

A message you have judged not to apply can be suppressed. Prefer a narrow suppression and explain the reason in a comment, because the documentation notes that code analysis sometimes reports things that do not apply to your situation and recommends a rationale for a subtle or obscure suppression.

Scope How it looks Effect

One instance on one line

x = 1 %#ok<NOPRT>

Hides the NOPRT message for that line. Several IDs are separated by commas: %#ok<NBRAK,NOPRT>.

Every instance in the file

%#ok<*NOPRT> at the end of one line

Hides that message everywhere in the current file. Several: %#ok<*NBRAK,*NOPRT>.

Every file

Settings > MATLAB > Code Analyzer, clear the message

Changes the settings (or use the configuration file below).

The Editor writes these comments for you: right-click an underline and choose Suppress '…​' > On This Line, In This File or In All Files. A %#ok directive takes precedence over the settings, so a suppressed instance stays hidden until you delete the comment. To a MATLAB or Octave interpreter, %#ok is only a comment. The snippet below is a script, so the message to suppress is NOPTS, the script form of NOPRT:

% %#ok is an ordinary comment to the interpreter
total = 0;
for k = 1:3
  total = total + k  %#ok<NOPTS>
end
disp(total)

Octave 11.3.0 output (the three lines total = ... are the printed assignments the message is about; the suppression does not stop them):

total = 1
total = 3
total = 6
6

The suppression only hides the Code Analyzer message; it does not change what the code prints. Add the semicolon unless the printing is intended.

To see what is hidden in a file you received, call codeIssues on it and read the SuppressedIssues table, which also records how each issue is suppressed. Messages are suppressed by a %#ok directive, by being cleared in the settings, or by being disabled by default.

Limits of the analysis

Static analysis cannot know everything, and it is designed to report fewer false alarms even if some real problems go undetected. The documentation gives these examples; each is also a reason to write code that the analyzer can see through:

  • A name that may be a variable or a function. After load abc.mat the analyzer cannot tell whether xyz came from the file. Name the variables in the load command (load abc.mat xyz) or assign the result of load to a variable. The same blindness applies to variables created by eval, evalc, evalin and assignin (see eval and Its Alternatives).

  • A structure or a handle object. In function foo(x), x.a = 3; end the code is a probable bug if x is a structure (the change is lost) and correct if x is a handle object, so the analyzer says nothing.

  • Overloaded built-in functions. A message about a built-in function can be wrong when a class or a path folder overloads the name.

Error messages are almost always real problems; many warnings only point at something unusual that may be correct in your case.

From code: codeIssues

codeIssues (since R2022b) runs the analysis and stores the result. The documentation recommends it over the older checkcode, which remains available (and is still the function that measures cyclomatic complexity, with its -cyc and -modcyc options, which codeIssues does not).

issues = codeIssues
issues = codeIssues(names)
issues = codeIssues(names,Name=Value)

names is a file or folder (or an array of them); the files must be .m, .mlx or .mlapp. With no argument it analyzes the current folder.

Name-value argument Meaning

IncludeSubfolders

true (default) includes subfolders of the folders in names.

CodeAnalyzerConfiguration

"active" (default) uses the current settings, "factory" the defaults, or a file name uses that configuration file.

The result is a codeIssues object with these read-only properties: Date, Release, Files, IgnoredFiles (since R2026b), CodeAnalyzerConfiguration, Issues and SuppressedIssues. Issues is a table with the columns Location, Severity (info, warning or error), Fixability (auto or manual), Description, CheckID, LineStart, LineEnd, ColumnStart, ColumnEnd and FullFilename; SuppressedIssues adds a Suppression column. Because it is an ordinary table you can filter it with table indexing, and jsonencode turns the object into JSON.

The session below is the documentation’s example for a script with three messages (not run here; the path and date are the documentation’s).

issues = codeIssues("test.m")
issues =
  codeIssues with properties:
                         Date: 18-Oct-2022 14:18:54
                      Release: "R2023a"
                        Files: "C:\MyCode\test.m"
    CodeAnalyzerConfiguration: "active"
                       Issues: [3×10 table]
             SuppressedIssues: [0×11 table]

The issues table preview in the documentation lists AGROW (info, manual), NOPTS (info, auto) and STRQUOT (info, auto). A script that takes the table and stops the build on severity:

issues = codeIssues("heatflow");
severe = issues.Issues(issues.Issues.Severity ~= "info", :);
if ~isempty(severe)
  disp(severe(:, ["Location" "LineStart" "CheckID" "Description"]))
end

Not run here (it needs MATLAB and the heatflow folder of the running scenario). Whether Severity compares directly to a string depends on the column type, so check class(issues.Issues.Severity) in your release.

fix and export

[status,results = fix(issues,checkID)] applies the automatic fixes for one check ID, optionally only in named files (fix(issues,checkID,filenames)), or for the rows of an issues table. status is a new codeIssues object with the issues that remain and results is a table with Success, ErrorMessage and the location of each attempt. Fixing issues in live scripts (.mlx) and apps (.mlapp) is not supported. Only issues whose Fixability is auto can be fixed; manual ones such as AGROW need an edit.

export (since R2023b) writes the result to a file for other tools:

export(issues)
export(issues,filename)
export(___,Name=Value)

Without a file name it writes codeIssues.sarif in the current folder. A file name without an extension also gets .sarif; with an extension the format follows it. The FileFormat option chooses "auto" (default), "json" (the format of jsonencode), "sarif" or "sonarqube". SourceRoot sets the source folder that the paths are made relative to and is valid only with SARIF. SARIF (Static Analysis Results Interchange Format) is understood by code hosting and review tools, which can show the messages on a pull request. The documentation’s example exports two NOPRT/AGROW info messages as the following (shortened):

{
  "version": "2.1.0",
  "properties": {
    "Date": "28-Apr-2023 10:49:26",
    "Release": "R2023b",
    "CodeAnalyzerConfiguration": "active"
  },
  "runs": [
    {
      "tool": { "driver": { "name": "Code Analyzer" } },
      "results": [
        {
          "ruleId": "AGROW",
          "level": "note",
          "message": { "text": "Variable appears to change size on every loop iteration. Consider preallocating for speed." },
          "locations": [
            { "physicalLocation": {
                "artifactLocation": { "uri": "file:///C:/MyCode/myfun.m" },
                "region": { "startLine": 4, "endLine": 4, "startColumn": 8, "endColumn": 9 } } }
          ]
        }
      ]
    }
  ]
}

Note that the info severity is written as the SARIF level note. The object is the documentation’s output, not run here.

The Code Analyzer report and the app

For a whole folder, the Code Analyzer app (Apps tab, or codeAnalyzer at the prompt, or codeAnalyzer("C:\MyCode") for a given path) shows a report: counts of files, errors, warnings and info messages, grouped by severity by default (a Group By list changes it), with filters by severity and by issue type, and a Fix All button where an automated replacement exists. The app and the report are available since R2022b. A codeIssues object can also be explored in the app.

Configuring the Code Analyzer

Two mechanisms change what is reported:

  • Settings files (older). In Settings > MATLAB > Code Analyzer enable or disable messages, use the Actions button and Save As to write them to a text file, and select that file in the Active settings list. The file stays in effect for all MATLAB files until you choose another.

  • codeAnalyzerConfiguration.json (since R2023a). A JSON file in a folder named resources configures the checks for the parent of that resources folder and all of its subfolders. It travels with the code (and can be committed), so every team member and every CI run uses the same rules. For each analyzed file the Code Analyzer looks up the folder hierarchy and uses the first configuration file it finds in a resources folder.

The properties are:

Property Meaning

name, description, author, schemaVersion, guidelineVersion

Optional information; they do not affect the configuration.

baseConfiguration

"closestParentFolder" (default) inherits from the configuration found in the closest parent folder; "factory" inherits from MATLAB’s standard configuration. The documentation advises "factory" at the root of a code base and "closestParentFolder" deeper down.

ignoredFiles (since R2026b)

Patterns of files and folders to skip, relative to the folder that contains the resources folder, with forward slashes, no absolute paths and no ...

checks

Changes to existing checks and new custom checks.

naming

Naming conventions for identifiers (since R2025a): maximum length, casing, regular expression, prefixes, suffixes and disallowed phrases.

In checks, each check ID can set enabled (true or false), severity ("error", "warning" or "info"), messageText, and limit for the checks that count something: FCNIL (input arguments of a function), FCNOL (output arguments), LLMNC (characters per line), FCNLL (lines in a function) and MNCSN (nesting depth of control statements). A custom check has a new ID (a valid MATLAB identifier) and a rule: the functionCall template with functionNames, or the variableName template with variableNames. The next file, adapted from the documentation’s sample (not run here), makes global variables and evalin errors and limits names and function length:

{
  "name": "heatflow team guideline",
  "guidelineVersion": "1.0.0",
  "baseConfiguration": "factory",
  "checks": {
    "GVMIS": { "severity": "error", "messageText": "Do not use global variables." },
    "FCNLL": { "limit": 80, "severity": "warning", "enabled": true },
    "NoEvalin": {
      "rule": { "template": "functionCall", "functionNames": "evalin" },
      "severity": "error",
      "messageText": "Do not use evalin.",
      "enabled": true
    }
  },
  "naming": {
    "function": { "maxLength": 32, "casing": ["lowerCamelCase", "lowercase"] }
  }
}

Changing a severity to error does not stop the code from running; only syntax errors do. The file is read when MATLAB starts a session, so after adding or editing it run matlab.codeanalysis.refreshConfiguration, and check that it is valid with issuesTable = matlab.codeanalysis.validateConfiguration(pathname), which returns a table of problems in the file. When you pass a configuration file to codeIssues with CodeAnalyzerConfiguration, the relative paths in ignoredFiles are read relative to your current folder instead.

The official MATLAB Coding Guidelines

MathWorks publishes the MATLAB Coding Guidelines as an open repository: version 1.0 is for R2025a and later. The guidelines are for large teams that want regularity in a code base, and their use is optional. They separate Rules, which are checked by the Code Analyzer, from Best Practices, which are recommendations (some can be enabled as optional checks). Each version comes with a codeAnalyzerConfiguration.json that contains the checks used to detect the rule violations, and the repository suggests copying it as a starting point for your own local guidelines. The repository also links a rule file for AI coding assistants that follow the same standards.

To adopt them, place the repository’s codeAnalyzerConfiguration.json in a resources folder at the root of the project, refresh the configuration and run codeIssues over the project. The conventions that this section follows are described on Coding Style and Idioms.

Code analysis in a build

The build tool has a built-in task for the analysis: matlab.buildtool.tasks.CodeIssuesTask (since R2023b). task = matlab.buildtool.tasks.CodeIssuesTask(sourceFiles, Name=Value) analyzes the given files and folders (and their subfolders by default) and fails when thresholds are exceeded.

Property Meaning

SourceFiles, IncludeSubfolders

What to analyze.

Configuration

"active" (default), "factory" or a configuration file. With "active", a codeAnalyzerConfiguration.json in a resources folder in the plan root folder configures the checks for the whole project.

ErrorThreshold

Number of errors allowed; default 0.

WarningThreshold

Number of warnings allowed; default Inf.

InfoThreshold (since R2026a)

Number of info messages allowed; default Inf.

Results (since R2024a)

The code analysis results of the task (see the class page for the exact form).

A task created with no thresholds therefore fails only on errors; WarningThreshold=0 also fails on warnings. The task always runs (it does not support incremental builds). A buildfile.m that uses it looks like the following (not run here; src is the heatflow source folder that holds the +heatflow namespace, as set up on Projects and Source Control):

function plan = buildfile
import matlab.buildtool.tasks.CodeIssuesTask
plan = buildplan(localfunctions);
plan("check") = CodeIssuesTask("src", WarningThreshold=0);
plan.DefaultTasks = "check";
end

See Build Automation with buildtool and Continuous Integration for running it on every push.

Formatting code in the Editor

The Editor helps keep layout consistent; none of these features checks style rules the way the Code Analyzer does (naming and line limits come from the configuration above).

  • Smart indent. By default the Editor indents as you type. If it is disabled, the Smart Indent button in the Code section of the Editor or Live Editor tab applies it to selected lines. Increase Indent and Decrease Indent (or Tab and Shift+Tab) change indentation by hand. It is turned off, and its details changed, in Settings > MATLAB > Editor/Debugger > MATLAB Language (before R2025a, Language), where the Function indenting format also chooses how functions indent. Before R2025a, s.matlab.editor.indent.SmartIndentEntireDocument.PersonalValue = 1 (through settings) made automatic indenting format the entire document.

  • Right-hand text limit. A light gray vertical line at column 75 marks where a line exceeds 75 characters. It is only a visual cue and does not stop longer lines; the LLMNC check can report them. Comment formatting settings can wrap comment text at a chosen column automatically. Wrap Code Lines (View tab) wraps long lines for display only.

  • Refactoring. Select code and click Refactor in the Code section to turn it into a function or a local function; MATLAB creates it and replaces the selection with a call.

  • Code folding. Click the plus or minus sign beside a code section, a for or parfor block, a function, a class or a multiline comment to collapse it, or use Expand All and Collapse All on the View tab. Not supported in live scripts.

  • Outline panel (since R2025a). The View tab opens a structured outline of the file’s functions and sections, with filtering and sorting.

  • Other editing aids. Column (block) selection with Alt (Option on macOS), change case (Ctrl+Shift+A), duplicate line, and automatic completion of parentheses, quotes and block endings (configured under Suggestions and Autocompletions). Since R2026a, settings choose the default end-of-line sequence of new files (LF or CRLF), and since R2026b the sequence of the open file can be changed from the status area.

Checking code before a release upgrade: the Code Compatibility Analyzer

Before moving to a newer MATLAB release, the Code Compatibility Analyzer lists the compatibility issues in your code in a table, with instructions to fix them. It helps to find what must change for the code to run in the current release, to estimate the effort of the upgrade, and to replace functionality that is no longer recommended. Open it from the Apps tab, or run:

Command Result

codeCompatibilityReport

A report for the current folder and its subfolders, opened in the HTML viewer.

codeCompatibilityReport(names)

A report for the given files or folders; the option 'IncludeSubfolders',tf controls subfolders.

codeCompatibilityAnalyzer

Opens the analyzer for a specified folder.

cca = analyzeCodeCompatibility(names)

Returns a CodeCompatibilityAnalysis object with the findings, which codeCompatibilityReport(cca) can display later.

The report starts with Syntax Errors (they make the code unrunnable and also limit the analysis) and then groups the other findings by the recommended action: functionality that has been removed (update now), that changed behavior (confirm the change is acceptable), that is unsupported or undocumented (use documented functionality), that will be removed or will change behavior (update now or later), and new functionality that might improve the code. Each finding links to the lines it affects and to the help. The analyzer also reports use of undocumented functions that are subject to change without notice.

Run it before an upgrade and keep its output with the release notes; see What Is New and Migrating Older Code.

Pitfalls

  • Treating info messages as noise. Messages such as AGROW are low severity, but a clean analysis of every file makes a real warning easy to see. Fix or explain them.

  • Suppressing without a reason. A bare %#ok hides the symptom. Suppress the narrowest scope and write the rationale in a comment.

  • Suppressing a whole file at once. %#ok<*NOPRT> hides every instance in the file, including the ones you did not intend; use it deliberately.

  • Trusting a green indicator. Static analysis misses what it cannot see (see the limits above). Tests and debugging remain necessary; see Debugging and Unit Testing with matlab.unittest.

  • Changing severity and expecting it to block execution. A check configured as error does not stop the code from running; fail the build instead (CodeIssuesTask).

  • A configuration that is not applied. A new codeAnalyzerConfiguration.json is cached at session start; call matlab.codeanalysis.refreshConfiguration, and validate it.

  • Using checkcode output in new tools. Its message text can change between releases; codeIssues returns a structured table.

  • A resources folder in the wrong place. The configuration affects the parent of resources and below, nothing above it.

Where older books differ

Older books describe the Editor’s "M-Lint" messages, the mlint function and the Code Analyzer Report of the old Current Folder browser, with their menus and dialogs. Today the analysis is in the Editor, the Code Issues panel (since R2025a) and the Code Analyzer app; codeIssues (R2022b) replaces checkcode and mlint, and export (R2023b), codeAnalyzerConfiguration.json (R2023a) and CodeIssuesTask (R2023b) did not exist. The ideas, namely preallocate, end statements with a semicolon, and use || in conditions, are unchanged.