blob: 0cbd955278feb713d495ef3aecbd7a16fbae241f [file] [log] [blame]
Daniel Jasperd07c8402013-07-29 08:19:24 +00001//===--- ClangTidyTest.h - clang-tidy ---------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Alexander Kornienko66580552015-03-09 16:52:33 +000010#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H
11#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H
Daniel Jasperd07c8402013-07-29 08:19:24 +000012
13#include "ClangTidy.h"
14#include "ClangTidyDiagnosticConsumer.h"
15#include "clang/ASTMatchers/ASTMatchFinder.h"
16#include "clang/Frontend/CompilerInstance.h"
17#include "clang/Frontend/FrontendActions.h"
18#include "clang/Tooling/Refactoring.h"
19#include "clang/Tooling/Tooling.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +000020#include <map>
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000021#include <memory>
Daniel Jasperd07c8402013-07-29 08:19:24 +000022
23namespace clang {
24namespace tidy {
Alexander Kornienko09887162014-02-27 14:28:02 +000025namespace test {
Daniel Jasperd07c8402013-07-29 08:19:24 +000026
Manuel Klimek05510652014-10-07 15:49:36 +000027class TestClangTidyAction : public ASTFrontendAction {
Alexander Kornienko09887162014-02-27 14:28:02 +000028public:
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000029 TestClangTidyAction(SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Checks,
30 ast_matchers::MatchFinder &Finder,
Manuel Klimek05510652014-10-07 15:49:36 +000031 ClangTidyContext &Context)
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000032 : Checks(Checks), Finder(Finder), Context(Context) {}
Daniel Jasperd07c8402013-07-29 08:19:24 +000033
34private:
Manuel Klimek05510652014-10-07 15:49:36 +000035 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
36 StringRef File) override {
37 Context.setSourceManager(&Compiler.getSourceManager());
Aaron Ballman01cee3a2015-09-02 16:04:15 +000038 Context.setCurrentFile(File);
39 Context.setASTContext(&Compiler.getASTContext());
40
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000041 for (auto &Check : Checks) {
42 Check->registerMatchers(&Finder);
43 Check->registerPPCallbacks(Compiler);
44 }
Manuel Klimek05510652014-10-07 15:49:36 +000045 return Finder.newASTConsumer();
Alexander Kornienko09887162014-02-27 14:28:02 +000046 }
Daniel Jasperd07c8402013-07-29 08:19:24 +000047
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000048 SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Checks;
Manuel Klimek05510652014-10-07 15:49:36 +000049 ast_matchers::MatchFinder &Finder;
50 ClangTidyContext &Context;
Daniel Jasperd07c8402013-07-29 08:19:24 +000051};
52
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000053template <typename Check, typename... Checks> struct CheckFactory {
54 static void
55 createChecks(ClangTidyContext *Context,
56 SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Result) {
57 CheckFactory<Check>::createChecks(Context, Result);
58 CheckFactory<Checks...>::createChecks(Context, Result);
59 }
60};
61
62template <typename Check> struct CheckFactory<Check> {
63 static void
64 createChecks(ClangTidyContext *Context,
65 SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Result) {
66 Result.emplace_back(llvm::make_unique<Check>(
67 "test-check-" + std::to_string(Result.size()), Context));
68 }
69};
70
71template <typename... CheckList>
Samuel Benzaquen462501e2015-03-31 13:53:03 +000072std::string
73runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,
74 const Twine &Filename = "input.cc",
75 ArrayRef<std::string> ExtraArgs = None,
Manuel Klimekd00d6f12015-08-11 11:37:48 +000076 const ClangTidyOptions &ExtraOptions = ClangTidyOptions(),
Manuel Klimekf6036432015-08-11 12:13:15 +000077 std::map<StringRef, StringRef> PathsToContent =
78 std::map<StringRef, StringRef>()) {
Samuel Benzaquen462501e2015-03-31 13:53:03 +000079 ClangTidyOptions Options = ExtraOptions;
Alexander Kornienkod53d2682014-09-04 14:23:36 +000080 Options.Checks = "*";
81 ClangTidyContext Context(llvm::make_unique<DefaultOptionsProvider>(
82 ClangTidyGlobalOptions(), Options));
Alexander Kornienko09887162014-02-27 14:28:02 +000083 ClangTidyDiagnosticConsumer DiagConsumer(Context);
Manuel Klimek05510652014-10-07 15:49:36 +000084
85 std::vector<std::string> ArgCXX11(1, "clang-tidy");
86 ArgCXX11.push_back("-fsyntax-only");
87 ArgCXX11.push_back("-std=c++11");
Manuel Klimekd00d6f12015-08-11 11:37:48 +000088 ArgCXX11.push_back("-Iinclude");
Manuel Klimek05510652014-10-07 15:49:36 +000089 ArgCXX11.insert(ArgCXX11.end(), ExtraArgs.begin(), ExtraArgs.end());
90 ArgCXX11.push_back(Filename.str());
Aaron Ballman01cee3a2015-09-02 16:04:15 +000091
92 ast_matchers::MatchFinder Finder;
Benjamin Kramerac8517c2015-10-07 08:35:23 +000093 llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
94 new vfs::InMemoryFileSystem);
Manuel Klimek81593db2014-10-09 13:22:46 +000095 llvm::IntrusiveRefCntPtr<FileManager> Files(
Benjamin Kramerac8517c2015-10-07 08:35:23 +000096 new FileManager(FileSystemOptions(), InMemoryFileSystem));
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +000097
98 SmallVector<std::unique_ptr<ClangTidyCheck>, 1> Checks;
99 CheckFactory<CheckList...>::createChecks(&Context, Checks);
Manuel Klimek05510652014-10-07 15:49:36 +0000100 tooling::ToolInvocation Invocation(
Angel Garcia Gomez32af5bc2015-10-06 13:52:51 +0000101 ArgCXX11, new TestClangTidyAction(Checks, Finder, Context), Files.get());
Benjamin Kramerac8517c2015-10-07 08:35:23 +0000102 InMemoryFileSystem->addFile(Filename, 0,
103 llvm::MemoryBuffer::getMemBuffer(Code));
Manuel Klimekf6036432015-08-11 12:13:15 +0000104 for (const auto &FileContent : PathsToContent) {
Benjamin Kramerac8517c2015-10-07 08:35:23 +0000105 InMemoryFileSystem->addFile(
106 Twine("include/") + FileContent.first, 0,
107 llvm::MemoryBuffer::getMemBuffer(FileContent.second));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000108 }
Manuel Klimek05510652014-10-07 15:49:36 +0000109 Invocation.setDiagnosticConsumer(&DiagConsumer);
Manuel Klimek9b2c4532015-08-12 07:57:16 +0000110 if (!Invocation.run()) {
111 std::string ErrorText;
Manuel Klimek0a19e902015-08-13 09:09:28 +0000112 for (const auto &Error : Context.getErrors()) {
Manuel Klimek9b2c4532015-08-12 07:57:16 +0000113 ErrorText += Error.Message.Message + "\n";
114 }
115 llvm::report_fatal_error(ErrorText);
116 }
Manuel Klimek05510652014-10-07 15:49:36 +0000117
Alexander Kornienko09887162014-02-27 14:28:02 +0000118 DiagConsumer.finish();
119 tooling::Replacements Fixes;
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000120 for (const ClangTidyError &Error : Context.getErrors())
Alexander Kornienko33a9bcc2014-04-29 15:20:10 +0000121 Fixes.insert(Error.Fix.begin(), Error.Fix.end());
Alexander Kornienko826b5ad2014-05-09 12:24:09 +0000122 if (Errors)
123 *Errors = Context.getErrors();
Alexander Kornienko09887162014-02-27 14:28:02 +0000124 return tooling::applyAllReplacements(Code, Fixes);
125}
126
Alexander Kornienko37f80452015-03-02 11:55:04 +0000127#define EXPECT_NO_CHANGES(Check, Code) \
128 EXPECT_EQ(Code, runCheckOnCode<Check>(Code))
129
Alexander Kornienko09887162014-02-27 14:28:02 +0000130} // namespace test
Daniel Jasperd07c8402013-07-29 08:19:24 +0000131} // namespace tidy
132} // namespace clang
133
Alexander Kornienko66580552015-03-09 16:52:33 +0000134#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H