diff --git a/packages/cpp/README.md b/packages/cpp/README.md index bb9a30bbddeb1..f5fe3a62cab67 100644 --- a/packages/cpp/README.md +++ b/packages/cpp/README.md @@ -81,14 +81,14 @@ To get this working, you need to enable clangd's global index using the ## Using the clang-tidy linter -Note: This functionality is available when using clangd 9 and later. +**Note: This functionality is available when using clangd 9 and later.** -You can set the preference 'cpp.clangTidy' to enable the clang-tidy linter included in clangd. When the preference is set, there are two ways to chose which of its built-in checks clang-tidy will use: +You can set the preference 'cpp.clangTidy' to enable the clang-tidy linter included in clangd. When the preference is enabled, there are two ways to choose which of its built-in checks clang-tidy will use: - using the preferences: 'cpp.clangTidyChecks' -- using the file '.clang-tidy' . The file is located in the same folder of the files or a parent folder. +- using the file '.clang-tidy' . This file is located in the same folder of the files or a parent folder. -Note: using the preference checks will supersede the value found in the .clang-tidy file. +**Note**: When the preference setting for "cpp.clangTidyChecks" is set, the configs will be merged with the configuration found in the ".clang-tidy" file. If you want to drop the configs from ".clang-tidy", you'd need to disable it in "cpp.clangTidyChecks" with **"cpp.clangTidyChecks": "-*"**. The syntax used to fill the checks can be found at http://clang.llvm.org/extra/clang-tidy/ @@ -102,6 +102,58 @@ There are two ways to configure clang-tidy's checks: through a Theia preference - for the .clang-tidy file: Checks: "-*,readability-*" - Meaning: disable all list-checks and enable all readability-* checks +### Running clang-tidy as a task + +To be able to run clang-tidy as a task, you need to install the program. + +```bash +UNIX + sudo apt-get install clang-tidy +Note: not all operating system are currently supported with this linter yet. +``` + +``` +The clang-tidy task will read the "checks" and other configuration fields from the ".clang-tidy" file located in the closest parent directory of the source file. +P.S. You do not need to provide a value for each field. + +Those configurations fields can be: + Checks + CheckOptions + FormatStyle + HeaderFilterRegex + User + WarningsAsErrors + +You can run the following command to have an idea of the fields found in file ".clang-tidy" + clang-tidy -dump-config +``` + +In .theia/tasks.json, add the following: + +```json + { + "label": "[Task] clang-tidy", + "type": "shell", + "cwd": "${workspaceFolder}", + "command": "clang-tidy", + "args": [ + "*" + ], + "options": {}, + "problemMatcher": [ + "$clangTidyMatcher" + ] + } +``` + +If you want a description for each task field, see [theia/packages/task/src/browser/task-schema-updater.ts]( https://github.com/theia-ide/theia/blob/531aa3bde8dea7f022ea41beaee3aace65ce54de/packages/task/src/browser/task-schema-updater.ts#L62 ) + +```bash +When there is no compilation database, clang-tidy could run but you may need to be more specific which files to select. One way is to replace the "args" from the "*" to +"**/*.cpp" to only parse files with the "cpp" extension or +"**/*.c" to parse the "c" files extension. +``` + ## License - [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/) diff --git a/packages/cpp/src/browser/cpp-task-provider.spec.ts b/packages/cpp/src/browser/cpp-task-provider.spec.ts index 69d398dab2a7d..d41da0d04689a 100644 --- a/packages/cpp/src/browser/cpp-task-provider.spec.ts +++ b/packages/cpp/src/browser/cpp-task-provider.spec.ts @@ -20,9 +20,11 @@ import { TaskResolverRegistry } from '@theia/task/lib/browser/task-contribution' import { CppBuildConfigurationManager, CppBuildConfiguration } from './cpp-build-configurations'; import { Event } from '@theia/core'; import { expect } from 'chai'; -import { TaskConfiguration } from '@theia/task/src/common'; +import { TaskConfiguration } from '@theia/task/lib/common'; import { ProcessTaskConfiguration } from '@theia/task/lib/common/process/task-protocol'; -import { TaskDefinitionRegistry } from '@theia/task/lib/browser'; +import { TaskDefinitionRegistry } from '@theia/task/lib/browser/task-definition-registry'; +import { ProblemMatcherRegistry } from '@theia/task/lib/browser/task-problem-matcher-registry'; +import { ProblemPatternRegistry } from '@theia/task/lib/browser/task-problem-pattern-registry'; // The object under test. let taskProvider: CppTaskProvider; @@ -67,9 +69,12 @@ class MockCppBuildConfigurationManager implements CppBuildConfigurationManager { beforeEach(function () { const container: Container = new Container(); container.bind(CppTaskProvider).toSelf().inSingletonScope(); + container.bind(CppBuildConfigurationManager).to(MockCppBuildConfigurationManager); container.bind(TaskResolverRegistry).toSelf().inSingletonScope(); container.bind(TaskDefinitionRegistry).toSelf().inSingletonScope(); - container.bind(CppBuildConfigurationManager).to(MockCppBuildConfigurationManager); + container.bind(ProblemMatcherRegistry).toSelf().inSingletonScope(); + container.bind(ProblemPatternRegistry).toSelf().inSingletonScope(); + taskProvider = container.get(CppTaskProvider); // Register a task resolver of type 'shell', on which the cpp build tasks diff --git a/packages/cpp/src/browser/cpp-task-provider.ts b/packages/cpp/src/browser/cpp-task-provider.ts index 0c8287e0210a0..e6dbb715d57dd 100644 --- a/packages/cpp/src/browser/cpp-task-provider.ts +++ b/packages/cpp/src/browser/cpp-task-provider.ts @@ -17,10 +17,12 @@ import parseArgv = require('string-argv'); import { inject, injectable, postConstruct } from 'inversify'; import { ProcessTaskConfiguration } from '@theia/task/lib/common/process/task-protocol'; -import { TaskDefinitionRegistry } from '@theia/task/lib/browser'; import { TaskContribution, TaskProvider, TaskProviderRegistry, TaskResolver, TaskResolverRegistry } from '@theia/task/lib/browser/task-contribution'; import { CppBuildConfigurationManager, CppBuildConfiguration } from './cpp-build-configurations'; -import { ContributedTaskConfiguration, TaskConfiguration, } from '@theia/task/lib/common/task-protocol'; +import { ContributedTaskConfiguration, TaskConfiguration } from '@theia/task/lib/common/task-protocol'; +import { TaskDefinitionRegistry } from '@theia/task/lib/browser/task-definition-registry'; +import { ProblemMatcherRegistry } from '@theia/task/lib/browser/task-problem-matcher-registry'; +import { ProblemPatternRegistry } from '@theia/task/lib/browser/task-problem-pattern-registry'; /** * Data required to define a C/C++ build task the user could run. @@ -38,10 +40,33 @@ export class CppTaskProvider implements TaskContribution, TaskProvider, TaskReso @inject(TaskResolverRegistry) protected readonly taskResolverRegistry: TaskResolverRegistry; @inject(TaskDefinitionRegistry) protected readonly taskDefinitionRegistry: TaskDefinitionRegistry; @inject(CppBuildConfigurationManager) protected readonly cppBuildConfigurationManager: CppBuildConfigurationManager; + @inject(ProblemMatcherRegistry) protected readonly problemMatcherRegistry: ProblemMatcherRegistry; + @inject(ProblemPatternRegistry) protected readonly problemPatternRegistry: ProblemPatternRegistry; @postConstruct() protected init(): void { this.registerTaskDefinition(); + this.problemPatternRegistry.register({ + 'name': 'clangTidyPattern', + 'regexp': '^(.+):(\\d+):(\\d+):\\s+(error|warning|info|note):\\s+(.+?)\\s+\\[(.+)\\]$', + 'file': 1, + 'line': 2, + 'character': 3, + 'severity': 4, + 'message': 5, + 'code': 6 + }); + this.problemMatcherRegistry.register({ + 'name': 'clangTidyMatcher', + 'label': 'Clang-tidy problems', + 'owner': 'clang-tidy', + 'source': 'clang-tidy-task', + 'applyTo': 'alldocuments', + 'fileLocation': [ + 'absolute' + ], + 'pattern': 'clangTidyPattern' + }); } registerProviders(registry: TaskProviderRegistry) { @@ -77,7 +102,7 @@ export class CppTaskProvider implements TaskContribution, TaskProvider, TaskReso type: 'shell', command, args, - options: { cwd: task.config.directory } + cwd: task.config.directory, }; return resolver.resolveTask(resolvedTask); }